Commit Graph
9 Commits
Author SHA1 Message Date
swaitsandClaude Opus 5.5 03212265ce feat: Typst-typeset statements in US accounting format
The printpdf statements padded columns with spaces in a proportional font
(amounts didn't line up), had no company name, printed negatives as
"-207.68", and put everything on one page (a long statement was silently
cut off past ~70 lines). Now:

- PDFs are typeset by Typst from one template,
  ledger-import/templates/statement.typ. The laid-out statement goes in as
  JSON data (sys.inputs), so account names are never parsed as markup.
  Fonts are bundled (typst-assets: Libertinus Serif), so output doesn't
  depend on the machine and is byte-for-byte deterministic. Statements
  paginate, with the company/title repeated on later pages and "Page n of
  m" plus "Prepared from journal through seq N" in the footer.
- US accounting presentation, decided once in ledger-import::report and
  applied by both PDF and XLSX: tabular figures; "$" on each section's
  first amount and on every subtotal and total, pinned to the column's
  left edge; negatives in parentheses with the closing paren hanging (its
  width reserved on every row, so decimal points align); zero as a dash;
  a single rule above sums (none over an empty section) and a double rule
  under statement totals; amounts never bold, because bold figures are
  wider and would leave the decimal column. XLSX uses Excel's own
  Accounting formats for the same result.
- Cash flow: "Net change in cash" is a subtotal; only "Cash at end of
  period" takes the double rule.
- Core fix: cash_flow walked the chart in HashMap order, so the order of
  working-capital and financing lines could change between runs. Lines
  now follow account code. Test: five owners, twenty runs, always
  3000/3001/3003/3005/3009; fails without the sort.

New dependencies (ledger-import): typst, typst-layout, typst-pdf,
typst-assets (fonts), typst-as-lib (World/font plumbing), serde_json (the
template's data). Removed: printpdf. Release ledger-mcp grows by the
bundled fonts.

Tests: exact template data for a hand-built P&L (like a golden); same
statement renders to identical bytes; 200 rows of Typst markup
characters render literally and span several pages; currency-sign and
rule placement; amount splitting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 19:23:01 -07:00
swaitsandClaude Opus 5.5 c6faeeb827 feat: period-scoped P&L and as-of balance sheet; closes don't zero periods
The engine only had life-of-ledger P&L and balance sheet totals, so every
export labeled with a date range or as-of date (PDF, XLSX, CPA package)
printed all-time numbers under that label. Core now has:

- profit_and_loss_for_period(start, end, class?) and
  balance_sheet_as_of(as_of), each with a line per account
  (StatementLine: code, name, normal-side amount) and exact totals.
- Ledger::closing_entry_ids(). Period statements exclude closing entries.
  A close (Dr revenue / Cr expense / net to Retained Earnings, dated at
  period end) moves earnings; it doesn't earn or spend. Counting it made a
  closed period's P&L read as break-even, and made the cash flow show zero
  net income plus a fake "owner contribution" to Retained Earnings. The
  as-of balance sheet keeps closing entries: after a close the earnings
  belong in Retained Earnings, not current earnings.

Tests: tests/statements.rs, a two-month fixture with every expected number
computed by hand (Jan NI 1,700; Feb 880; balance sheets on four dates; a
closed January still reporting 1,700 and a cash flow with one financing
line). Mutation-checked: dropping the closing exclusion fails it (0 vs
1,700). Properties: period P&Ls partition a year at any split, and a
range's net income equals the change in current earnings across it, with
A = L + E on both dates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 19:04:18 -07:00
swaits 9ba4917899 Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:01:24 +00:00
swaits 41acb73b5b asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:21 +00:00
swaits a7a8a70496 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:19 +00:00
swaits 99b5b5d0b8 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:18 +00:00
swaits 31d3c61e32 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:16 +00:00
swaits afce942e3c Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:24 +00:00
swaits b7b34d9fe5 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:23 +00:00