mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 03:54:08 +00:00
Fix foreign currency accounts using wrong exchange rate in balance sheet totals (#1010)
Balance sheet totals and accountable type summaries used a SQL JOIN on exchange_rates matching only today's date, which returned NULL (defaulting to 1:1) when no rate existed for that exact date. This caused foreign currency accounts to show incorrect totals. Changes: - Refactor BalanceSheet::AccountTotals to batch-fetch exchange rates via ExchangeRate.rates_for, with provider fallback, instead of a SQL join - Refactor Accountable.balance_money to use the same batch approach - Add ExchangeRate.rates_for helper for deduplicated rate lookups - Fix net worth chart query to fall back to the nearest future rate when no historical rate exists for a given date - Add composite index on accounts (family_id, status, accountable_type) - Reuse nearest cached exchange rate within a 5-day lookback window before calling the provider, preventing redundant API calls on weekends and holidays when providers return prior-day rates https://claude.ai/code/session_01GyssBJxQqdWnuYofQRjUu8 Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -62,15 +62,21 @@ module Accountable
|
||||
self.name.pluralize.titleize
|
||||
end
|
||||
|
||||
# Sums the balances of all active accounts of this type, converting foreign currencies to the family's currency.
|
||||
# @return [BigDecimal] total balance in the family's currency
|
||||
def balance_money(family)
|
||||
family.accounts
|
||||
.active
|
||||
.joins(sanitize_sql_array([
|
||||
"LEFT JOIN exchange_rates ON exchange_rates.date = :current_date AND accounts.currency = exchange_rates.from_currency AND exchange_rates.to_currency = :family_currency",
|
||||
{ current_date: Date.current.to_s, family_currency: family.currency }
|
||||
]))
|
||||
.where(accountable_type: self.name)
|
||||
.sum("accounts.balance * COALESCE(exchange_rates.rate, 1)")
|
||||
accounts = family.accounts.active.where(accountable_type: self.name).to_a
|
||||
|
||||
foreign_currencies = accounts.filter_map { |a| a.currency if a.currency != family.currency }
|
||||
rates = ExchangeRate.rates_for(foreign_currencies, to: family.currency, date: Date.current)
|
||||
|
||||
accounts.sum(BigDecimal(0)) { |account|
|
||||
if account.currency == family.currency
|
||||
account.balance
|
||||
else
|
||||
account.balance * (rates[account.currency] || 1)
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user