Skip to content

Leave cash that only passed through the card out of spending - #16

Merged
armysyn merged 1 commit into
mainfrom
fix/pass-through-cash
Oct 9, 2026
Merged

armysyn merged 1 commit into
mainfrom
fix/pass-through-cash

Conversation

@armysyn

@armysyn armysyn commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Why

Every cash withdrawal counted as spending. A person who tops the card up with tens of millions a month from another bank and cashes it out had all of it counted as spent, so a year of spending came out in the hundreds of millions and the financial independence target came out in the billions.

What changed

  • Pass-through cash, by code (analytics.MarkPassThrough). Money put on the card that is not income (own money from another bank, an ATM or terminal deposit, money from a person) and taken out as cash within 7 days is marked as passing through. Such a withdrawal is not spending (IsSpend). The part of a top-up from a person that left as cash also no longer counts as money from people in the cash flow.
    • A withdrawal counts only when that money covers it whole. A withdrawal the person gave a category stays spending.
    • Salary and the income sources the person chose never pay for a withdrawal.
    • Statements carry dates without times, so on the same day money coming in is ordered before cash going out.
    • Every ledger reader applies it: web pages on SQLite or ClickHouse, and the Telegram insights. Drill-downs still add up, and statement reconciliation is unchanged because it sums raw rows by kind.
  • Per-account switch, on by default (kv key cash_pass_through). It is on the operations page when that page is filtered to cash (m=#cash or the Cash category).
  • Bulk skip. The same card can skip every cash withdrawal of the period that has no category (status ignored, questions dropped) and can count them again (back to review, as on import).
  • Visibility. The analytics page shows a "Passed through" line next to Cash. The income page and the financial independence card on Net worth say how much was left out and link to it. Under All operations these withdrawals carry a "passed through" tag.

Checks

  • gofmt -l . prints nothing; go vet ./... passes; go test -race ./... passes; CLICKHOUSE_TEST_URL=… go test ./... passes; golangci-lint run ./... reports 0 issues.
  • New tests:
    • TestMarkPassThrough: covered, same-day, salary, from a person (partial), not covered, too old, categorised, income source, totals and drill-downs.
    • TestSkipWithdrawals and the default of the switch.
    • TestPassThroughCash (web): notes on every page, the switch, skip and count, a bad period.
    • The cash-filtered operations page is added to TestPagesRender.
  • Screenshots on invented data (a 20M ₸ top-up and cash-out every month): 12-month spending drops from ~255M to 5.2M and the FI target to 129M. Checked in light, dark and in a 375px iframe.

🤖 Generated with Claude Code

Every cash withdrawal counted as spending. Someone who puts tens of millions a month on the
card from another bank and takes it out as cash had all of it counted as spent: a year of
spending in the hundreds of millions and a financial independence target in the billions.

Now money put on the card that is not income (own money from another bank, an ATM or
terminal deposit, money from a person) and taken out as cash within a week only passes
through: the withdrawal is not spending, and the part of a top-up from a person that left
as cash is not money from people either. It is decided in Go over the ledger rows
(analytics.MarkPassThrough) for SQLite, ClickHouse and the insights alike. A withdrawal
counts only when such money covers it whole; one the person gave a category stays spending.
Salary and income sources never pay for it.

The rule is on by default and can be turned off per account on the operations page filtered
to cash, which also skips a period's cash withdrawals by hand and undoes it. The analytics,
income and net worth pages say how much was left out, with a link to review it; such
withdrawals carry a "passed through" tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@armysyn
armysyn merged commit 7a6d4fd into main Oct 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant