Hide nested budget categories in the Budget spent donut (#1544)

* Initial plan

* Hide nested budget categories in spent donut

Agent-Logs-Url: https://github.com/we-promise/sure/sessions/aea0de69-f123-4417-ba31-d08300fb852d

Co-authored-by: jjmata <187772+jjmata@users.noreply.github.com>

* Harden budget donut segment test

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jjmata <187772+jjmata@users.noreply.github.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
Copilot
2026-04-23 21:28:38 +02:00
committed by GitHub
parent 6fa3be7d87
commit 6f195c6c9c
2 changed files with 56 additions and 1 deletions

View File

@@ -209,7 +209,7 @@ class Budget < ApplicationRecord
# Continuous gray segment for empty budgets
return [ { color: "var(--budget-unallocated-fill)", amount: 1, id: unused_segment_id } ] unless allocations_valid?
segments = budget_categories.map do |bc|
segments = budget_categories.reject(&:subcategory?).map do |bc|
{ color: bc.category.color, amount: budget_category_actual_spending(bc), id: bc.id }
end

View File

@@ -225,6 +225,61 @@ class BudgetTest < ActiveSupport::TestCase
)
end
test "to_donut_segments_json only includes top-level budget categories" do
family = @family
budget = Budget.find_or_bootstrap(family, start_date: Date.current.beginning_of_month)
budget.update!(budgeted_spending: 500, currency: family.currency)
parent_category = Category.create!(
name: "Transport #{Time.now.to_f}",
family: family,
color: "#6471eb"
)
child_category = Category.create!(
name: "Petrol #{Time.now.to_f}",
family: family,
parent: parent_category,
color: "#61c9ea"
)
standalone_category = Category.create!(
name: "Shopping #{Time.now.to_f}",
family: family,
color: "#df4e92"
)
budget.sync_budget_categories
parent_budget_category = budget.budget_categories.find_by!(category: parent_category)
child_budget_category = budget.budget_categories.find_by!(category: child_category)
standalone_budget_category = budget.budget_categories.find_by!(category: standalone_category)
parent_budget_category.update!(budgeted_spending: 150, currency: family.currency)
child_budget_category.update!(budgeted_spending: 50, currency: family.currency)
standalone_budget_category.update!(budgeted_spending: 100, currency: family.currency)
budget.stubs(:allocations_valid?).returns(true)
budget.stubs(:available_to_spend).returns(200)
budget.stubs(:budget_category_actual_spending).with(parent_budget_category).returns(63.11)
budget.stubs(:budget_category_actual_spending).with(standalone_budget_category).returns(25)
segments = budget.to_donut_segments_json
segment_ids = segments.pluck(:id)
segments_by_id = segments.index_by { |segment| segment[:id] }
assert_equal 3, segments.size
assert_includes segment_ids, parent_budget_category.id
assert_includes segment_ids, standalone_budget_category.id
assert_includes segment_ids, "unused"
refute_includes segment_ids, child_budget_category.id
assert_equal 63.11, segments_by_id[parent_budget_category.id][:amount]
assert_equal 25, segments_by_id[standalone_budget_category.id][:amount]
assert_equal 200, segments_by_id["unused"][:amount]
end
test "actual_spending subtracts uncategorized refunds" do
family = families(:dylan_family)
budget = Budget.find_or_bootstrap(family, start_date: Date.current.beginning_of_month)