diff --git a/app/models/income_statement.rb b/app/models/income_statement.rb index f885e3f81..6082f8e74 100644 --- a/app/models/income_statement.rb +++ b/app/models/income_statement.rb @@ -30,14 +30,23 @@ class IncomeStatement end def expense_totals(period: Period.current_month) - build_period_total(classification: "expense", period: period) + # Memoized per instance so callers that also invoke `net_category_totals` + @expense_totals_by_period ||= {} + @expense_totals_by_period[period_cache_key(period)] ||= + build_period_total(classification: "expense", period: period) end def income_totals(period: Period.current_month) - build_period_total(classification: "income", period: period) + @income_totals_by_period ||= {} + @income_totals_by_period[period_cache_key(period)] ||= + build_period_total(classification: "income", period: period) end def net_category_totals(period: Period.current_month) + @net_category_totals_by_period ||= {} + cached = @net_category_totals_by_period[period_cache_key(period)] + return cached if cached + expense = expense_totals(period: period) income = income_totals(period: period) @@ -87,7 +96,7 @@ class IncomeStatement CategoryTotal.new(category: r[:category], total: r[:total], currency: family.currency, weight: weight) end - NetCategoryTotals.new( + @net_category_totals_by_period[period_cache_key(period)] = NetCategoryTotals.new( net_expense_categories: net_expense_categories, net_income_categories: net_income_categories, total_net_expense: total_net_expense, @@ -126,6 +135,10 @@ class IncomeStatement @categories ||= family.categories.all.to_a end + def period_cache_key(period) + [ period.start_date, period.end_date ] + end + def build_period_total(classification:, period:) # Exclude pending transactions from budget calculations totals = totals_query(transactions_scope: family.transactions.visible.excluding_pending.in_period(period), date_range: period.date_range).select { |t| t.classification == classification }