fix(reports/cartes): Budget Adherence card filtered out all expense categories #113

Merged
maximus merged 1 commit from issue-112-budget-adherence-signed-fix into main 2026-04-19 13:39:12 +00:00
Owner

Fixes #112

What

The Cartes budget-adherence card was always telling the user "no budgeted categories this month" even when they had set budgets on expense categories. The filter r.monthBudget > 0 was rejecting every expense row because budgetService signs expense budgets as negative.

Fix

Route every adherence computation through Math.abs():

  • Filter: Math.abs(r.monthBudget) > 0 instead of r.monthBudget > 0
  • In-target count: Math.abs(r.monthActual) <= Math.abs(r.monthBudget)
  • Overrun calc: actual and budget both absolute before computing overrunAbs / overrunPct
  • The budget field returned on worstOverruns entries is now the absolute value (was previously signed)

Added an explanatory code comment on the signed-value pitfall so this doesn't get reintroduced.

Test

New regression test in reportService.cartes.test.ts that:

  • Seeds 2 budgeted expense categories (one in-target, one overrunning) and one unbudgeted category
  • Verifies categoriesTotal = 2, categoriesInTarget = 1, exactly one worstOverruns entry
  • Checks the overrun values: actual = 350, budget = 200, overrunAbs = 150, overrunPct ≈ 75

This test fails on main (with AssertionError: expected 0 to be 2) and passes after the fix — confirming the bug was reproducible and is now resolved.

Verification

  • npm test -- --run: 122/122 passing (+1 regression test)
  • npm run build: green
  • CHANGELOG.md + CHANGELOG.fr.md updated under [Unreleased] > Fixed
Fixes #112 ## What The Cartes budget-adherence card was always telling the user "no budgeted categories this month" even when they had set budgets on expense categories. The filter `r.monthBudget > 0` was rejecting every expense row because `budgetService` signs expense budgets as negative. ## Fix Route every adherence computation through `Math.abs()`: - **Filter**: `Math.abs(r.monthBudget) > 0` instead of `r.monthBudget > 0` - **In-target count**: `Math.abs(r.monthActual) <= Math.abs(r.monthBudget)` - **Overrun calc**: `actual` and `budget` both absolute before computing `overrunAbs` / `overrunPct` - The `budget` field returned on `worstOverruns` entries is now the absolute value (was previously signed) Added an explanatory code comment on the signed-value pitfall so this doesn't get reintroduced. ## Test New regression test in `reportService.cartes.test.ts` that: - Seeds 2 budgeted expense categories (one in-target, one overrunning) and one unbudgeted category - Verifies `categoriesTotal = 2`, `categoriesInTarget = 1`, exactly one `worstOverruns` entry - Checks the overrun values: `actual = 350`, `budget = 200`, `overrunAbs = 150`, `overrunPct ≈ 75` This test fails on `main` (with `AssertionError: expected 0 to be 2`) and passes after the fix — confirming the bug was reproducible and is now resolved. ## Verification - `npm test -- --run`: 122/122 passing (+1 regression test) - `npm run build`: green - CHANGELOG.md + CHANGELOG.fr.md updated under `[Unreleased] > Fixed`
maximus added 1 commit 2026-04-19 13:35:54 +00:00
fix(reports/cartes): Budget Adherence card was filtering out all expense categories
All checks were successful
PR Check / rust (push) Successful in 21m31s
PR Check / frontend (push) Successful in 2m13s
PR Check / rust (pull_request) Successful in 22m0s
PR Check / frontend (pull_request) Successful in 2m14s
2ec48d4e90
Expense budgets are stored signed-negative by budgetService. The Cartes
budget-adherence card used raw values in its filter (monthBudget > 0),
its in-target comparison (|actual| <= monthBudget), and its overrun
calculation — all of which silently rejected every expense row. Route
every amount through Math.abs() so the card reflects real budget data.

Test: regression fixture with a signed-negative monthBudget that must
pass the filter and count as in-target or overrun based on absolute
values.

Fixes #112
maximus merged commit d834ffeb9c into main 2026-04-19 13:39:12 +00:00
maximus deleted branch issue-112-budget-adherence-signed-fix 2026-04-19 13:39:13 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#113
No description provided.