feat(mcp): payments on terms, bills due, and the agings' tie-out (P4b S6)

books.receive_payment and books.pay_bill take applications, each
document's cash with an optional discount and reason, and a customer
payment may carry the processor's fee; the result names every document it
settled and what reached the account. books.bills_due lists what to pay
and the running total by due date. The agings take detail and return the
control account's tie-out, and books.export writes ar_aging/ap_aging.

The handlers live in tools/settlements.rs (the EM's split, so S4.4's
documents.rs stays free); documents.rs keeps the documents, the void and
the control check. docs/mcp-interface.md documents every changed tool and
the new one; docs/architecture.md names the group; docs/testing.md
records the tests and P12's mutation targets.

Old names (document_id, cash_account) still work; the output keeps
remaining/status for one document. A fee's processor is named in the
description, not tagged as the entry's vendor: ledger tags are entry-wide
and tagging would move the customer's party totals and 1099-NEC.

The handbook's invoices-and-bills section gains the payment, discount,
fee and bounce-replacement procedures (S4.5 can extend it). Over the wire:
one_payment_settles_two_invoices, late_discount_needs_a_reason,
a_fee_posts_gross_to_receivables_and_net_to_the_bank,
card_paid_bill_is_not_1099_nec,
multi_document_payment_counts_once_for_1099_and_party_totals,
overpayment_refused_with_the_excess,
bills_due_orders_by_due_and_discount and the_aging_export_ties_out.

Terms cannot yet be journaled on a document (S4.3) and a bill line's
account is not an MCP field (S4.4), so bill_on_terms_with_discount,
equipment_bill_payment_is_investing_cash and the discount half of
bills_due are core tests until those land; the unit's As-built block
records this.
This commit is contained in:
swaits committed 2026-10-27 12:59:40 -06:00
1 parent 78a2385440
commit 57f04dbb0c
17 files changed
+1467 -231

No files matched your search

+9 -1
View File
@@ -1358,7 +1358,15 @@ Each unit follows the 8.0.4 template. "A-n" is an owner answer numbered in 8.3.1
5. **Files:** owns `Ledger::settle` and its tests, the payment events' new fields and arms, `books.bills_due`, the aging exports; touches the 8.0.3 files, `crates/ledger-mcp/src/tools/documents.rs` (after S4.4; coordinate with the S4 engineer on `tools/documents.rs`: S6 adds its handlers in a second file `tools/settlements.rs` if S4.4 is still open).
6. **Tests and proofs:** named above; Kani `settle_is_exact`; Lean: none new (the posting step is `Step.document` with more lines; `control_agrees` covers it because every control line is tagged).
7. **Done when:** (1) the tests pass; (2) `several_payment_events_on_one_entry_tag_its_lines_in_order` still passes (the legacy rule); (3) the 1099 worksheet and party totals count a two-invoice payment once (`multi_document_payment_counts_once_for_1099_and_party_totals`); (4) the CPA package's aging CSVs tie to `control_check` on the demo books; (5) 8.0.6 in the PR, no golden figure moved; (6) `just check`, `just prove` green.
8. **As built:** none yet.
8. **As built** (2026-10-27, `S6`): the steps above are built except the departures below.
- **The handlers live in `crates/ledger-mcp/src/tools/settlements.rs`**, not `tools/documents.rs` (the EM approved this group, because S4.4 works in `documents.rs`). `books.receive_payment`, `books.pay_bill`, `books.ar_aging` and `books.ap_aging` moved there; `books.bills_due` is new. `docs/architecture.md` names the group.
- **`Ledger::settle` is a public command**, as Build 2 asks, so `Store::settle` calls it; its posting is still `Step.document` (every control line carries its document), and Lean gained `Documents.settle_posts_a_document_step` and `Documents.settle_unattached` instead of a new `Step` constructor (plan 8.2 S6, Tests and proofs: "the posting step is `Step.document` with more lines").
- **Terms cannot yet be journaled on a document** (S4.3 owns `invoice.created`/`bill.created`'s `terms`). `Ledger::settle` reads `doc.terms` wherever it is set, and the core tests (`bill_on_terms_with_discount`, `late_discount_needs_a_reason`) build documents through `create_invoice_with`/`create_bill_with`; the over-the-wire `bill_on_terms_with_discount` and the discount half of `bills_due_orders_by_due_and_discount` wait for S4.3. A bill line's account is likewise S4.4's MCP field, so `equipment_bill_payment_is_investing_cash` is a core test (`spec_cash_flow.rs`) until then.
- **A fee's processor is recorded in the entry's description, not as the entry's vendor tag.** Ledger party/vendor tags are entry-wide, not line-level; tagging the entry with the processor would move the customer's party total and muddy 1099-NEC. `fee.vendor` is resolved and named in the description, and only cash movements count toward a 1099.
- **`confirmed` is not added**: P4 owns preview/confirm for every mutating tool, and adding a preview now would duplicate that sweep. The older `document_id`/`cash_account` names still work beside `invoice`/`bill` and `deposit_to`/`paid_from`.
- **No schema change**: discounts and fees are tagged ledger lines and payment-event fields, so the projection needs no column and schema 18 is not taken.
- **No bookspec examples yet**: `payment-terms-early-discount` needs S4.3's journaled terms; `arap-settlement-exact` and `processor-fee-gross-presentation` are recorded here as the next step for the bookspec unit, not written.
- **8.0.6:** item 1 is in `books_written_under_older_rules_still_open`; item 2 is the pre-S1 (therefore pre-S6) fixture `tests/fixtures/p4-arap-before`, whose figures still hold; item 3 is `settlement_waits_for_documents_v2`; item 4 is `tests/format.rs` unchanged (no new event type) plus `format_upgrade.rs` unchanged (the `documents_v2` setting is S4.2's); item 5 is the same fixture's `figures.json` and `legacy_reversal_now_counts` (no figure moved); item 6 is in the PR/report.
#### P4b S7: bad debts (`write_off_invoice`)