Commit Graph
45 Commits
Author SHA1 Message Date
swaitsandClaude Opus 5.5 8f623ba810 feat: canonical report set in QuickBooks-style presentation
Every report a CPA expects, laid out the way US small-business books
read (QuickBooks as the reference):

- Exports: books.export gains general_ledger (by account, running
  balances, splits), general_journal (the entry-ordered listing, which
  the CPA package used to mislabel "general ledger"; alias journal),
  members_equity, and trial_balance as of a date, in xlsx/csv/json, and
  PDF for all five statements (P&L, balance sheet, cash flow, trial
  balance, members' equity). books.trial_balance takes as_of.
- CPA package: every statement as PDF and XLSX, plus the general ledger
  and general journal, all for the fiscal year to date.
- Layout (ledger-import::report): multi-column statements (Total;
  Debit/Credit; one column per member plus Total), "$" on subtotals and
  totals, a rule above every sum (none over an empty section), a double
  rule under statement totals, zero as 0.00, negatives in parentheses
  with the closing paren hanging so decimal points align.
- Terms: "Net income (loss)"; for a multi-member LLC, "Members' equity",
  member contributions and distributions named in the cash flow, and the
  balance sheet splitting retained earnings (the Retained Earnings
  account plus earnings not yet closed from earlier years) from the
  fiscal year's net income (loss); the cash flow's "Adjustments to
  reconcile net income (loss) to net cash from operating activities" and
  "Net increase (decrease) in cash".
- PDF: Inter replaces the typst-assets serif fonts (bundled, SIL OFL 1.1,
  license in fonts/; from the official v4.1 release), centered title
  block, column-header row, full-width rules, footer "Accrual basis ·
  Prepared <date> · Journal seq N" with page numbers. Amounts on total
  rows stay regular weight so bold figures can't leave the decimal
  column. typst-assets dependency removed.
- XLSX: centered title block, header row, Excel accounting formats with
  "$" attached on sums, general ledger and general journal workbooks.
- Config: wanderbooks.toml [[company.members]] (name, share "50%" or
  "0.5", capital_account; shares must total 100%) and [books]
  accounting_basis (accrual | cash).
- Core: RETAINED_EARNINGS_CODE names the "3999" that period close uses.
- Fix: "today" is local time, not UTC; in US evenings UTC is tomorrow,
  so reports defaulting to "through today" included the next day and
  footers carried the wrong date.

Tests: layout (currency and rule placement, retained earnings vs. this
year's net income for a member LLC, footer text); exact template data;
deterministic PDFs; config parsing (members, shares, basis); stdio:
trial balance as of, February general ledger (beginning 1,004.00, splits,
ending 1,003.50), members' equity (contributions 1,000.00, net income
3.50, ending 1,003.50), members' equity PDF, the CPA package's ten files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 20:29:12 -07:00
swaitsandClaude Opus 5.5 02b3b9c053 feat: general ledger by account, trial balance as of, members' equity
Three reports a CPA expects that the engine could not produce:

- general_ledger(start, end): the canonical general ledger, organized by
  account in code order. Each account has its beginning balance, every
  posting in the period (date, entry, description, debit, credit, running
  balance on the normal side) and its ending balance, which ties to the
  trial balance. Each posting names its split: the one account on the
  opposite side of its entry, or "-Split-" when that side has several,
  so a compound entry (one debit, several credits) reads correctly from
  every account it touches. The entry-ordered listing the exports called a
  "general ledger" is really the general journal.
- trial_balance_as_of(as_of): a trial balance is always as of a date.
- members_equity(start, end, members): the statement of changes in
  members' equity for a multi-member LLC taxed as a partnership. Each
  member's capital roll-forward: beginning (capital plus their share of
  undistributed earnings), contributions, allocated net income (loss),
  distributions, ending. Allocation is by ownership share to the cent,
  the last member absorbing rounding, so totals are exact and the ending
  total equals balance-sheet equity; any equity change the roll-forward
  can't explain shows as "other" instead of disappearing. Shares must be
  positive and sum to exactly 1; capital accounts must be distinct
  equity accounts (LedgerError::InvalidMembers).
- CashFlowLine.account: the account a line is about, so renderers can
  name members instead of account codes.

Tests (every expectation computed by hand): trial balance as of Jan 31;
February general ledger with beginning balances, running balances, a
card that nets to zero, an inactive account still listed, and every
ending balance tied to the trial balance; a compound entry's splits from
all three sides; a two-member partnership where 666.67 and 100.01 split
unevenly (333.34/333.33, 50.01/50.00), with and without closing January,
tying to the balance sheet each month; bad member configuration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 20:16:25 -07:00
swaitsandClaude Opus 5.5 42e600bbf2 chore: clippy clean across the workspace, all targets
Zero warnings from `cargo clippy --workspace --all-targets`, which is now
a hard rule rather than "clean except pre-existing":

- ChartOfAccounts::add takes the Account it registers instead of eight
  loose parameters (too_many_arguments); Ledger::add_account builds it.
  Same validation, same errors.
- close_period tool: collapse the nested if-let into a let chain.
- iif.rs docs: the IIF layout example shows tabs as `\t` instead of
  literal tab characters (tabs_in_doc_comments).
- Tests: drop an unused binding; assert! instead of assert_eq! against a
  literal bool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
2026-10-11 19:24:10 -07:00
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 61b6e48df7 Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:32:02 +00:00
swaits ab67dccf8e Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:32:00 +00:00
swaits 005dcbb803 Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:31:58 +00:00
swaits d50b844476 Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:31:56 +00:00
swaits 3d80a270ca Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:31:55 +00:00
swaits f521d7d8c6 Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:31:53 +00:00
swaits 6fdd8898a9 Payroll accounting, class tracking, CPA handoff package (48 MCP tools) 2026-10-11 15:31:51 +00:00
swaits eb30becb95 Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:25 +00:00
swaits 71d415d2a8 Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:24 +00:00
swaits 727bdc61e6 Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:22 +00:00
swaits 747f0c951e Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:20 +00:00
swaits 26f15eb867 Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:18 +00:00
swaits dc852d5f7e Period close, bank rec, AR/AP, multi-currency (41 MCP tools) 2026-10-11 08:15:16 +00: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 78915fc3bb Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:01:22 +00:00
swaits 9fa4232664 Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:01:20 +00:00
swaits 5225abb9dd Next steps 5-10: resources, cash flow, QB interop, backfill, HTTP, parallel-run plan 2026-10-11 03:01:19 +00:00
swaits afcbc4bbdf asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:22 +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 008b5d2d52 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:13 +00:00
swaits eb28e87662 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:12 +00:00
swaits 1f9f441a16 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:08 +00:00
swaits 291451f725 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:04 +00:00
swaits 090be37107 asset slice + testing initiative: fixed assets, property/mutation/fuzz testing, docs 2026-10-11 02:25:03 +00:00
swaits e72b3542d2 First slice: ledger-store (journal+blobs+sqlite) and ledger-mcp (18 tools, receipt policy) 2026-10-11 01:37:07 +00:00
swaits e313fec903 First slice: ledger-store (journal+blobs+sqlite) and ledger-mcp (18 tools, receipt policy) 2026-10-11 01:37:05 +00:00
swaits 3c33c79a75 First slice: ledger-store (journal+blobs+sqlite) and ledger-mcp (18 tools, receipt policy) 2026-10-11 01:37:03 +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
swaits bd6ea3e67e Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:21 +00:00
swaits 0d05da02dc Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:19 +00:00
swaits 7fbe8a1193 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:17 +00:00
swaits 3abd5ff7a1 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:16 +00:00
swaits 593a8bbfa4 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:14 +00:00
swaits a614600a87 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:13 +00:00
swaits d3a0b097b2 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:11 +00:00
swaits 3489554f57 Initial commit: wanderbooks accounting semantics engine 2026-10-11 00:46:09 +00:00