mirror of
https://github.com/we-promise/sure.git
synced 2026-04-18 03:24:09 +00:00
58 lines
1.8 KiB
Ruby
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
|