Files
sure/app/models/account/balance/calculator.rb
Zach Gollwitzer 263d65ea7e Basic account onboarding (#1328)
* Basic account onboarding

* Cleanup
2024-10-18 17:18:54 -04:00

58 lines
1.8 KiB
Ruby

class Account::Balance::Calculator
def initialize(account, sync_start_date)
@account = account
@sync_start_date = sync_start_date
end
def calculate(is_partial_sync: false)
cached_entries = account.entries.where("date >= ?", sync_start_date).to_a
sync_starting_balance = is_partial_sync ? find_start_balance_for_partial_sync : find_start_balance_for_full_sync(cached_entries)
prior_balance = sync_starting_balance
(sync_start_date..Date.current).map do |date|
current_balance = calculate_balance_for_date(date, entries: cached_entries, prior_balance:)
prior_balance = current_balance
build_balance(date, current_balance)
end
end
private
attr_reader :account, :sync_start_date
def find_start_balance_for_partial_sync
account.balances.find_by(currency: account.currency, date: sync_start_date - 1.day)&.balance
end
def find_start_balance_for_full_sync(cached_entries)
account.balance + net_entry_flows(cached_entries.select { |e| e.account_transaction? })
end
def calculate_balance_for_date(date, entries:, prior_balance:)
valuation = entries.find { |e| e.date == date && e.account_valuation? }
return valuation.amount if valuation
entries = entries.select { |e| e.date == date }
prior_balance - net_entry_flows(entries)
end
def net_entry_flows(entries, target_currency = account.currency)
converted_entry_amounts = entries.map { |t| t.amount_money.exchange_to(target_currency, date: t.date) }
flows = converted_entry_amounts.sum(&:amount)
account.liability? ? flows * -1 : flows
end
def build_balance(date, balance, currency = nil)
account.balances.build \
date: date,
balance: balance,
currency: currency || account.currency
end
end