mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-07 06:25:19 +02:00
Initial data objects
This commit is contained in:
parent
8c97c9d31a
commit
df367b420a
4 changed files with 85 additions and 4 deletions
70
app/models/account/activity_feed_data.rb
Normal file
70
app/models/account/activity_feed_data.rb
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# Data used to build the paginated feed of account "activity" (events like transfers, deposits, withdrawals, etc.)
|
||||||
|
# This data object is useful for avoiding N+1 queries and having an easy way to pass around the required data to the
|
||||||
|
# activity feed component in controllers and background jobs that refresh it.
|
||||||
|
class Account::ActivityFeedData
|
||||||
|
attr_reader :account
|
||||||
|
|
||||||
|
def initialize(account, entries)
|
||||||
|
@account = account
|
||||||
|
@entries = entries
|
||||||
|
end
|
||||||
|
|
||||||
|
# We read balances so we can show "start of day" -> "end of day" balances for each entry date group in the feed
|
||||||
|
def balances
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def transfers
|
||||||
|
return [] unless has_transfers?
|
||||||
|
|
||||||
|
@transfers ||= Transfer.where(inflow_transaction_id: transaction_ids).or(Transfer.where(outflow_transaction_id: transaction_ids))
|
||||||
|
end
|
||||||
|
|
||||||
|
# If the account has entries denominated in a different currency than the main account, we attach necessary
|
||||||
|
# exchange rates required to "roll up" the entry group balance into the normal account currency.
|
||||||
|
def exchange_rates
|
||||||
|
return [] unless needs_exchange_rates?
|
||||||
|
|
||||||
|
@exchange_rates ||= begin
|
||||||
|
rate_requirements = required_exchange_rates
|
||||||
|
return [] if rate_requirements.empty?
|
||||||
|
|
||||||
|
# Build a single SQL query with all date/currency pairs
|
||||||
|
conditions = rate_requirements.map do |req|
|
||||||
|
"(date = ? AND from_currency = ? AND to_currency = ?)"
|
||||||
|
end.join(" OR ")
|
||||||
|
|
||||||
|
# Flatten the parameters array in the same order
|
||||||
|
params = rate_requirements.flat_map do |req|
|
||||||
|
[ req.date, req.from, req.to ]
|
||||||
|
end
|
||||||
|
|
||||||
|
ExchangeRate.where(conditions, *params)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
attr_reader :entries
|
||||||
|
|
||||||
|
RequiredExchangeRate = Data.define(:date, :from, :to)
|
||||||
|
|
||||||
|
def needs_exchange_rates?
|
||||||
|
entries.any? { |entry| entry.currency != account.currency }
|
||||||
|
end
|
||||||
|
|
||||||
|
def required_exchange_rates
|
||||||
|
multi_currency_entries = entries.select { |entry| entry.currency != account.currency }
|
||||||
|
|
||||||
|
multi_currency_entries.map do |entry|
|
||||||
|
RequiredExchangeRate.new(date: entry.date, from: entry.currency, to: account.currency)
|
||||||
|
end.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_transfers?
|
||||||
|
entries.any? { |entry| entry.transaction? && entry.transaction.transfer? }
|
||||||
|
end
|
||||||
|
|
||||||
|
def transaction_ids
|
||||||
|
entries.select { |entry| entry.transaction? }.pluck(:entryable_id)
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,13 +3,13 @@ module Account::Reconcileable
|
||||||
|
|
||||||
def create_reconciliation(balance:, date:, dry_run: false)
|
def create_reconciliation(balance:, date:, dry_run: false)
|
||||||
result = reconciliation_manager.reconcile_balance(balance: balance, date: date, dry_run: dry_run)
|
result = reconciliation_manager.reconcile_balance(balance: balance, date: date, dry_run: dry_run)
|
||||||
sync_later if result.success?
|
sync_later if result.success? && !dry_run
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_reconciliation(existing_valuation_entry, balance:, date:, dry_run: false)
|
def update_reconciliation(existing_valuation_entry, balance:, date:, dry_run: false)
|
||||||
result = reconciliation_manager.reconcile_balance(balance: balance, date: date, existing_valuation_entry: existing_valuation_entry, dry_run: dry_run)
|
result = reconciliation_manager.reconcile_balance(balance: balance, date: date, existing_valuation_entry: existing_valuation_entry, dry_run: dry_run)
|
||||||
sync_later if result.success?
|
sync_later if result.success? && !dry_run
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
11
app/models/transactions_feed_data.rb
Normal file
11
app/models/transactions_feed_data.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class TransactionsFeedData
|
||||||
|
attr_reader :family
|
||||||
|
|
||||||
|
def initialize(family, transactions)
|
||||||
|
@family = family
|
||||||
|
@transactions = transactions
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
attr_reader :transactions
|
||||||
|
end
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
<div class="space-y-4 text-sm text-secondary">
|
<div class="space-y-4 text-sm text-secondary">
|
||||||
<% if account.investment? %>
|
<% if account.investment? %>
|
||||||
<% holdings_value = reconciliation_dry_run.new_balance - reconciliation_dry_run.new_cash_balance %>
|
<% brokerage_cash = reconciliation_dry_run.new_cash_balance || 0 %>
|
||||||
<% brokerage_cash = reconciliation_dry_run.new_cash_balance %>
|
<% holdings_value = reconciliation_dry_run.new_balance - brokerage_cash %>
|
||||||
|
|
||||||
<p>This will <%= action_verb %> the account value on <span class="font-medium text-primary"><%= entry.date.strftime("%B %d, %Y") %></span> to:</p>
|
<p>This will <%= action_verb %> the account value on <span class="font-medium text-primary"><%= entry.date.strftime("%B %d, %Y") %></span> to:</p>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue