mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 06:21:23 +00:00
Fix nil-key collision in budget category hash lookups (#1136)
Both Uncategorized and Other Investments are synthetic categories with id=nil. When expense_totals_by_category indexes by category.id, Other Investments overwrites Uncategorized at the nil key, causing uncategorized actual spending to always return 0. Use category.name as fallback key (id || name) to differentiate the two synthetic categories in all hash builders and lookup sites. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
f8d3678a40
commit
388f249e4e
@@ -218,9 +218,9 @@ class Budget < ApplicationRecord
|
||||
end
|
||||
|
||||
def budget_category_actual_spending(budget_category)
|
||||
cat_id = budget_category.category_id
|
||||
expense = expense_totals_by_category[cat_id]&.total || 0
|
||||
refund = income_totals_by_category[cat_id]&.total || 0
|
||||
key = budget_category.category_id || budget_category.category.name
|
||||
expense = expense_totals_by_category[key]&.total || 0
|
||||
refund = income_totals_by_category[key]&.total || 0
|
||||
[ expense - refund, 0 ].max
|
||||
end
|
||||
|
||||
@@ -318,10 +318,10 @@ class Budget < ApplicationRecord
|
||||
end
|
||||
|
||||
def expense_totals_by_category
|
||||
@expense_totals_by_category ||= expense_totals.category_totals.index_by { |ct| ct.category.id }
|
||||
@expense_totals_by_category ||= expense_totals.category_totals.index_by { |ct| ct.category.id || ct.category.name }
|
||||
end
|
||||
|
||||
def income_totals_by_category
|
||||
@income_totals_by_category ||= income_totals.category_totals.index_by { |ct| ct.category.id }
|
||||
@income_totals_by_category ||= income_totals.category_totals.index_by { |ct| ct.category.id || ct.category.name }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -304,4 +304,30 @@ class BudgetTest < ActiveSupport::TestCase
|
||||
|
||||
assert_not_nil budget.previous_budget_param
|
||||
end
|
||||
|
||||
test "uncategorized budget category actual spending reflects uncategorized transactions" do
|
||||
family = families(:dylan_family)
|
||||
budget = Budget.find_or_bootstrap(family, start_date: Date.current.beginning_of_month)
|
||||
account = accounts(:depository)
|
||||
|
||||
# Create an uncategorized expense
|
||||
Entry.create!(
|
||||
account: account,
|
||||
entryable: Transaction.create!(category: nil),
|
||||
date: Date.current,
|
||||
name: "Uncategorized lunch",
|
||||
amount: 75,
|
||||
currency: "USD"
|
||||
)
|
||||
|
||||
budget = Budget.find(budget.id)
|
||||
budget.sync_budget_categories
|
||||
|
||||
uncategorized_bc = budget.uncategorized_budget_category
|
||||
spending = budget.budget_category_actual_spending(uncategorized_bc)
|
||||
|
||||
# Must be > 0 — the nil-key collision between Uncategorized and
|
||||
# Other Investments synthetic categories previously caused this to return 0
|
||||
assert spending >= 75, "Uncategorized actual spending should include the $75 transaction, got #{spending}"
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user