Skip to content

Latest commit

 

History

History
109 lines (92 loc) · 6.13 KB

DONE-8f896692.md

File metadata and controls

109 lines (92 loc) · 6.13 KB

DONE evidence — task 8f896692 (Finance dashboards: money in/out and net per month/year/YTD, portal + dataops finance summary CLI)

Verified against origin/main 41f16668 (2026-11-05) in a dedicated worktree (fix/finance-dashboards). The whole task is already implemented across backend, CLI and portal and covered by existing tests; no code change was needed. This file is the evidence record; the PR is docs-only.

The feature landed in October 2026 in three commits that reference this intake:

  • 83d68a93 feat(finance): money in/out, net and VAT summary per month/year/YTD (backend)
  • daf6317b feat(cli): dataops finance summary --month/--year/--ytd
  • 59f7aac5 feat(portal): Finance overview page at /finance
  • af13e806 feat(finance): tax ledger (dataops finance taxes) and owner pay line (intake 8f896692 h,k)

Computation lives in one place: backend/src/finance/summary.ts

  • backend/src/finance/summary.ts:19 — PeriodQuery is { month } | { year } | { ytd: true }; :125-139 — resolvePeriod builds the period for each kind: month = from 01 to monthEnd, months [month]; year = YYYY-01-01 to YYYY-12-31 with all 12 months; YTD = YYYY-01-01 to today with months up to the current one, label <year> YTD (to <today>).
  • :66-88 — Totals carries moneyIn, moneyOut, net (plus net profit excluding VAT, VAT lines, taxes, TK, owner pay); :303-356 — total() sums per entry in integer cents and derives net = moneyIn - moneyOut (:346). Income rows count as money in, expense rows as money out (:324); supplier credit notes are contra-expense, neither in nor out (:313-323).
  • :433-520 — summarize filters rows into the period by booking date and returns per-month totals (:465-469 — every month of the period with its own Totals, future months flagged), byCurrency (:471-514) and gaps.
  • Rules are documented in SOURCE_RULES (:106-120) and docs/finance-summary.md; both are returned/rendered as rules.
  • backend/src/finance/service.ts:84 — financeSummary loads the ledger, statements, coverage and ECB rates and calls summarize; :130 — parsePeriodQuery validates exactly one of month=, year=, ytd=1.
  • backend/src/routes/finance.ts:10,17-22 — GET /api/finance/summary?month=|year=|ytd=1 serves it (400 on a bad query, 405 on non-GET).

CLI: dataops finance summary --month/--year/--ytd

  • cli/src/commands/finance.mjs:6 — command description; :57-69 — periodArgs requires exactly one of --month YYYY-MM, --year YYYY, --ytd with format validation; :145-149 — summaryCommand calls GET /api/finance/summary and prints it; --json prints the payload the portal renders, so the two cannot disagree.
  • :86-143 — printSummary: net profit ex VAT and projected VAT on top, then a per-month grid with Month / Money in / Money out / Net / Profit ex VAT / Taxes / TK / Owner pay / VAT position / VAT paid and a Total row for multi-month periods (:93), the P&L lines (:108-120), currencies in original + EUR with inline conversions (:121-130), and data gaps (:131-140).

Portal: Finance overview surface at /finance

  • frontend/src/surfaces/finance/overview.js:1-5 — same payload contract as the CLI (GET /api/finance/summary); :11-16 — period from URL params (month, year, ytd, implicit YTD default); :317 — fetches the summary.
  • :52-58 — headline stats Money in, Money out, Net (cash) plus taxes, TK, owner pay, net after owner pay; :33-49 — hero tiles for net profit ex VAT and the projected VAT position.
  • :89-120 — cash chart: money in above the baseline, money out below, a dot for the month's net (year/YTD views, :266-268); :122-149 — net profit ex VAT per month chart.
  • :151-167 — per-month table Month / Money in / Money out / Net / … with a Total row (:152); :217-232 — period controls (Year to date button, Year select, Month input); :269-272 — "By month" / "This month" section; :169-199 currencies, :202-215 data gaps and source rules.

Docs

docs/finance-summary.md documents the three commands (:11-23), what counts, no-double-counting, dedup and EUR conversion rules, and states the portal and CLI show the same numbers because both render GET /api/finance/summary.

Read-only prod check (2026-11-05, dataops CLI against prod)

  • dataops finance summary --ytd — "Finance summary 2026 YTD (to 2026-11-05) (EUR)": per-month rows 2026-01..2026-11 each with Money in / Money out / Net / Profit ex VAT / Taxes / TK / Owner pay / VAT position / VAT paid, a Total row (287,373.78 in / 123,816.90 out / 163,556.88 net), the P&L lines, EUR+USD currency rows with inline conversions, and data gaps.
  • dataops finance summary --month 2026-10 — single row 2026-10 (91,082.01 in / 9,366.71 out / 81,715.30 net) plus the P&L and currency blocks.
  • dataops finance summary --year 2025 — 12 month rows + Total (197,800.00 in / 134,787.69 out / 63,012.31 net).
  • No writes were performed; all three invocations are GETs.

Test runs (this worktree, node v24.14.0)

  • backend/tests/finance-summary.test.ts — 25 pass, 0 fail. Month math: :16-30 (money in 3000, out 120.50, net 2879.50, only October rows count); year/YTD: :245-255 — a year splits into 12 months, November/December are marked future, YTD has 10 months and stops at the current month; :287-293 — period-query validation (bad month, month+year together, empty).
  • cli/test/finance.test.mjs — 10 pass, 0 fail (table rendering, period flags, owner pay line).
  • frontend/test/finance-overview.test.mjs — 8 pass, 0 fail (headline, charts, month table, currencies, gaps, upcoming debits).

Remaining gaps

None for this task. Two observations outside its scope, visible in the prod output but pre-existing and separately handled: unclassified bank statement lines are reported as a data gap (63 in YTD) by design, and the 2026-10 Taxes figure is negative (-43,633.73) because a prepayment refund larger than the period's tax payments was booked — a data question, not a summary-math bug (the summary follows its documented SOURCE_RULES).