mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 12:04:08 +00:00
Use new balance components in activity feed (#2511)
* Balance reconcilations with new components * Fix materializer and test assumptions * Fix investment valuation calculations and recon display * Lint fixes * Balance series uses new component fields
This commit is contained in:
@@ -8,21 +8,21 @@ class Balance::ChartSeriesBuilder
|
||||
end
|
||||
|
||||
def balance_series
|
||||
build_series_for(:balance)
|
||||
build_series_for(:end_balance)
|
||||
rescue => e
|
||||
Rails.logger.error "Balance series error: #{e.message} for accounts #{@account_ids}"
|
||||
raise
|
||||
end
|
||||
|
||||
def cash_balance_series
|
||||
build_series_for(:cash_balance)
|
||||
build_series_for(:end_cash_balance)
|
||||
rescue => e
|
||||
Rails.logger.error "Cash balance series error: #{e.message} for accounts #{@account_ids}"
|
||||
raise
|
||||
end
|
||||
|
||||
def holdings_balance_series
|
||||
build_series_for(:holdings_balance)
|
||||
build_series_for(:end_holdings_balance)
|
||||
rescue => e
|
||||
Rails.logger.error "Holdings balance series error: #{e.message} for accounts #{@account_ids}"
|
||||
raise
|
||||
@@ -37,13 +37,20 @@ class Balance::ChartSeriesBuilder
|
||||
|
||||
def build_series_for(column)
|
||||
values = query_data.map do |datum|
|
||||
# Map column names to their start equivalents
|
||||
previous_column = case column
|
||||
when :end_balance then :start_balance
|
||||
when :end_cash_balance then :start_cash_balance
|
||||
when :end_holdings_balance then :start_holdings_balance
|
||||
end
|
||||
|
||||
Series::Value.new(
|
||||
date: datum.date,
|
||||
date_formatted: I18n.l(datum.date, format: :long),
|
||||
value: Money.new(datum.send(column), currency),
|
||||
trend: Trend.new(
|
||||
current: Money.new(datum.send(column), currency),
|
||||
previous: Money.new(datum.send("previous_#{column}"), currency),
|
||||
previous: Money.new(datum.send(previous_column), currency),
|
||||
favorable_direction: favorable_direction
|
||||
)
|
||||
)
|
||||
@@ -88,66 +95,57 @@ class Balance::ChartSeriesBuilder
|
||||
WITH dates AS (
|
||||
SELECT generate_series(DATE :start_date, DATE :end_date, :interval::interval)::date AS date
|
||||
UNION DISTINCT
|
||||
SELECT :end_date::date -- Pass in date to ensure timezone-aware "today" date
|
||||
), aggregated_balances AS (
|
||||
SELECT
|
||||
d.date,
|
||||
-- Total balance (assets positive, liabilities negative)
|
||||
SUM(
|
||||
CASE WHEN accounts.classification = 'asset'
|
||||
THEN COALESCE(last_bal.balance, 0)
|
||||
ELSE -COALESCE(last_bal.balance, 0)
|
||||
END * COALESCE(er.rate, 1) * :sign_multiplier::integer
|
||||
) AS balance,
|
||||
-- Cash-only balance
|
||||
SUM(
|
||||
CASE WHEN accounts.classification = 'asset'
|
||||
THEN COALESCE(last_bal.cash_balance, 0)
|
||||
ELSE -COALESCE(last_bal.cash_balance, 0)
|
||||
END * COALESCE(er.rate, 1) * :sign_multiplier::integer
|
||||
) AS cash_balance,
|
||||
-- Holdings value (balance ‑ cash)
|
||||
SUM(
|
||||
CASE WHEN accounts.classification = 'asset'
|
||||
THEN COALESCE(last_bal.balance, 0) - COALESCE(last_bal.cash_balance, 0)
|
||||
ELSE 0
|
||||
END * COALESCE(er.rate, 1) * :sign_multiplier::integer
|
||||
) AS holdings_balance
|
||||
FROM dates d
|
||||
JOIN accounts ON accounts.id = ANY(array[:account_ids]::uuid[])
|
||||
|
||||
-- Last observation carried forward (LOCF), use the most recent balance on or before the chart date
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT b.balance, b.cash_balance
|
||||
FROM balances b
|
||||
WHERE b.account_id = accounts.id
|
||||
AND b.date <= d.date
|
||||
ORDER BY b.date DESC
|
||||
LIMIT 1
|
||||
) last_bal ON TRUE
|
||||
|
||||
-- Last observation carried forward (LOCF), use the most recent exchange rate on or before the chart date
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT er.rate
|
||||
FROM exchange_rates er
|
||||
WHERE er.from_currency = accounts.currency
|
||||
AND er.to_currency = :target_currency
|
||||
AND er.date <= d.date
|
||||
ORDER BY er.date DESC
|
||||
LIMIT 1
|
||||
) er ON TRUE
|
||||
GROUP BY d.date
|
||||
SELECT :end_date::date -- Ensure end date is included
|
||||
)
|
||||
SELECT
|
||||
date,
|
||||
balance,
|
||||
cash_balance,
|
||||
holdings_balance,
|
||||
COALESCE(LAG(balance) OVER (ORDER BY date), 0) AS previous_balance,
|
||||
COALESCE(LAG(cash_balance) OVER (ORDER BY date), 0) AS previous_cash_balance,
|
||||
COALESCE(LAG(holdings_balance) OVER (ORDER BY date), 0) AS previous_holdings_balance
|
||||
FROM aggregated_balances
|
||||
ORDER BY date
|
||||
d.date,
|
||||
-- Use flows_factor: already handles asset (+1) vs liability (-1)
|
||||
COALESCE(SUM(last_bal.end_balance * last_bal.flows_factor * COALESCE(er.rate, 1) * :sign_multiplier::integer), 0) AS end_balance,
|
||||
COALESCE(SUM(last_bal.end_cash_balance * last_bal.flows_factor * COALESCE(er.rate, 1) * :sign_multiplier::integer), 0) AS end_cash_balance,
|
||||
-- Holdings only for assets (flows_factor = 1)
|
||||
COALESCE(SUM(
|
||||
CASE WHEN last_bal.flows_factor = 1
|
||||
THEN last_bal.end_non_cash_balance
|
||||
ELSE 0
|
||||
END * COALESCE(er.rate, 1) * :sign_multiplier::integer
|
||||
), 0) AS end_holdings_balance,
|
||||
-- Previous balances
|
||||
COALESCE(SUM(last_bal.start_balance * last_bal.flows_factor * COALESCE(er.rate, 1) * :sign_multiplier::integer), 0) AS start_balance,
|
||||
COALESCE(SUM(last_bal.start_cash_balance * last_bal.flows_factor * COALESCE(er.rate, 1) * :sign_multiplier::integer), 0) AS start_cash_balance,
|
||||
COALESCE(SUM(
|
||||
CASE WHEN last_bal.flows_factor = 1
|
||||
THEN last_bal.start_non_cash_balance
|
||||
ELSE 0
|
||||
END * COALESCE(er.rate, 1) * :sign_multiplier::integer
|
||||
), 0) AS start_holdings_balance
|
||||
FROM dates d
|
||||
CROSS JOIN accounts
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT b.end_balance,
|
||||
b.end_cash_balance,
|
||||
b.end_non_cash_balance,
|
||||
b.start_balance,
|
||||
b.start_cash_balance,
|
||||
b.start_non_cash_balance,
|
||||
b.flows_factor
|
||||
FROM balances b
|
||||
WHERE b.account_id = accounts.id
|
||||
AND b.date <= d.date
|
||||
ORDER BY b.date DESC
|
||||
LIMIT 1
|
||||
) last_bal ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT er.rate
|
||||
FROM exchange_rates er
|
||||
WHERE er.from_currency = accounts.currency
|
||||
AND er.to_currency = :target_currency
|
||||
AND er.date <= d.date
|
||||
ORDER BY er.date DESC
|
||||
LIMIT 1
|
||||
) er ON TRUE
|
||||
WHERE accounts.id = ANY(array[:account_ids]::uuid[])
|
||||
GROUP BY d.date
|
||||
ORDER BY d.date
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user