fix(reports): say which month the Cash Flow tiles measure, and count spending - #155
Merged
Conversation
…spending The four tiles above Money Flow are a whole-calendar-month view, but they sat under a date chip reading "Last 3 months" with nothing to say otherwise. On Sep 2 that meant Total Income $0.00 and Spent So Far $0.00 next to an Income vs Expense tab reporting $33,185.24 for the same chip. There was a guard for this, and it fired backwards. `isCurrentMonth` was true whenever the selected range merely *overlapped* the current month, so Jun 2 – Sep 2 counted as "the current month" and the "(current month)" note was hidden — in exactly the case a reader needed it. It also only ever marked the Safe to Spend tile, though all four are month-scoped. Rather than push the filter into the query, the panel now names its own window: a "September 2026 — this month only, not affected by the date filter" heading over the group. Safe to Spend is income received this month less bills still due and what has already gone out; over a three-month range it would be asking how much is left to spend in the past, which is not a number. Scoping it to the month is right — hiding that fact was the bug. Safe to Spend also gains a line saying what it means, since an unexplained negative in red is alarming on first read. Two query bugs surfaced while pinning this down: Spent So Far selected `normalizedAmount > 0`. Negative is a charge everywhere else in Reports, so this collected the refunds and left out every real charge: the tile read $0.00 in every month regardless of spending. On August's demo data it counted 0 rows where 42 charges totalling $4,383.06 were sitting. A household with no income category hit `sql`0`` as a WHERE term and took a Postgres 42804 (`argument of AND must be type boolean, not type integer`) — the whole tab failed, not just the tile. It is `sql`false`` now. `getSafeToSpend` takes an optional month (defaulting to the current one) and reports it back, so the panel labels the window the query actually measured instead of deriving it separately. Verified against demo data seeded into September: Total Income $7,700.00, Spent So Far $120.00 — the charge counted, the refund not — and Safe to Spend $4,828.02 = 7,700.00 − 2,751.98 − 120.00. Closes #145
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #145. Rebased onto
mainnow that #150 has landed, so this diff is only its own change.Supersedes #151, which GitHub auto-closed when its stacked base branch was deleted on merge and would not reopen.
The tiles are month-scoped, and said nothing about it
On Sep 2, under a chip reading Last 3 months: Total Income $0.00, Spent So Far $0.00 — beside an Income vs Expense tab reporting $33,185.24 for the same chip.
There was a guard, and it fired backwards:
isCurrentMonthis true whenever the range merely overlaps the current month, so Jun 2 – Sep 2 counted as "the current month" and the note was hidden — in exactly the case that needed it. It also only ever marked Safe to Spend, though all four tiles are month-scoped.What this does instead
Per the decision on the issue's "either/or": label the panel, don't push the filter into the query.
Safe to Spend is income received this month, less bills still due, less what has already gone out. Over a three-month range it would be asking how much is left to spend in the past — not a number. Scoping it to the month is correct; hiding that fact was the bug. The tile also gains a line saying what it means, since an unexplained negative in red is alarming on first load.
getSafeToSpendnow takes an optionalmonth(defaulting to the current one) and returns it, so the heading names the window the query actually measured rather than deriving it separately. The invertedisCurrentMonthflag is gone frompage.tsxandReportTabs.Two query bugs found while pinning this down
Spent So Far had the sign backwards. It selected
normalizedAmount > 0; negative is a charge everywhere else in Reports. So it collected the refunds and left out every real charge — the tile read $0.00 in every month, whatever the household had spent. On August's demo data it counted 0 rows where 42 charges totalling $4,383.06 were sitting.A household with no income category crashed the tab.
sql\0`was used as a WHERE term and Postgres rejects it with 42804,argument of AND must be type boolean, not type integer. Nowsql`false``.Tests
New
tests/integration/safe-to-spend.test.ts(8 tests). Fixtures derive fromnew Date()per CLAUDE.md, since the query resolves its own window from the calendar.7 of the 8 were red before the fix.
Verification
Seeded September rows into demo data and read the panel live: Total Income $7,700.00, Spent So Far $120.00 (the charge counted, the $25 refund not), Safe to Spend $4,828.02 = 7,700.00 − 2,751.98 − 120.00. Rows removed afterwards.
🤖 Generated with Claude Code