2025-07-15 11:42:41 -04:00
|
|
|
class Balance::ForwardCalculator < Balance::BaseCalculator
|
2025-05-15 10:19:56 -04:00
|
|
|
def calculate
|
|
|
|
Rails.logger.tagged("Balance::ForwardCalculator") do
|
2025-07-15 11:42:41 -04:00
|
|
|
start_cash_balance = derive_cash_balance_on_date_from_total(
|
|
|
|
total_balance: account.opening_anchor_balance,
|
|
|
|
date: account.opening_anchor_date
|
|
|
|
)
|
|
|
|
start_non_cash_balance = account.opening_anchor_balance - start_cash_balance
|
2025-03-07 17:35:55 -05:00
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
calc_start_date.upto(calc_end_date).map do |date|
|
|
|
|
valuation = sync_cache.get_reconciliation_valuation(date)
|
2025-03-07 17:35:55 -05:00
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
if valuation
|
|
|
|
end_cash_balance = derive_cash_balance_on_date_from_total(
|
|
|
|
total_balance: valuation.amount,
|
|
|
|
date: date
|
|
|
|
)
|
|
|
|
end_non_cash_balance = valuation.amount - end_cash_balance
|
2025-03-07 17:35:55 -05:00
|
|
|
else
|
2025-07-15 11:42:41 -04:00
|
|
|
end_cash_balance = derive_end_cash_balance(start_cash_balance: start_cash_balance, date: date)
|
|
|
|
end_non_cash_balance = derive_end_non_cash_balance(start_non_cash_balance: start_non_cash_balance, date: date)
|
2025-03-07 17:35:55 -05:00
|
|
|
end
|
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
output_balance = build_balance(
|
|
|
|
date: date,
|
|
|
|
cash_balance: end_cash_balance,
|
|
|
|
non_cash_balance: end_non_cash_balance
|
|
|
|
)
|
|
|
|
|
|
|
|
# Set values for the next iteration
|
|
|
|
start_cash_balance = end_cash_balance
|
|
|
|
start_non_cash_balance = end_non_cash_balance
|
2025-03-07 17:35:55 -05:00
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
output_balance
|
2025-03-07 17:35:55 -05:00
|
|
|
end
|
2025-07-15 11:42:41 -04:00
|
|
|
end
|
|
|
|
end
|
2025-03-07 17:35:55 -05:00
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
private
|
|
|
|
def calc_start_date
|
|
|
|
account.opening_anchor_date
|
2025-03-07 17:35:55 -05:00
|
|
|
end
|
2025-05-15 10:19:56 -04:00
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
def calc_end_date
|
|
|
|
[ account.entries.order(:date).last&.date, account.holdings.order(:date).last&.date ].compact.max || Date.current
|
2025-05-15 10:19:56 -04:00
|
|
|
end
|
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
# Negative entries amount on an "asset" account means, "account value has increased"
|
|
|
|
# Negative entries amount on a "liability" account means, "account debt has decreased"
|
|
|
|
# Positive entries amount on an "asset" account means, "account value has decreased"
|
|
|
|
# Positive entries amount on a "liability" account means, "account debt has increased"
|
|
|
|
def signed_entry_flows(entries)
|
|
|
|
entry_flows = entries.sum(&:amount)
|
|
|
|
account.asset? ? -entry_flows : entry_flows
|
|
|
|
end
|
|
|
|
|
|
|
|
# Derives cash balance, starting from the start-of-day, applying entries in forward to get the end-of-day balance
|
|
|
|
def derive_end_cash_balance(start_cash_balance:, date:)
|
|
|
|
derive_cash_balance(start_cash_balance, date)
|
2025-05-15 10:19:56 -04:00
|
|
|
end
|
|
|
|
|
2025-07-15 11:42:41 -04:00
|
|
|
# Derives non-cash balance, starting from the start-of-day, applying entries in forward to get the end-of-day balance
|
|
|
|
def derive_end_non_cash_balance(start_non_cash_balance:, date:)
|
|
|
|
derive_non_cash_balance(start_non_cash_balance, date, direction: :forward)
|
2025-05-15 10:19:56 -04:00
|
|
|
end
|
2025-03-07 17:35:55 -05:00
|
|
|
end
|