docs: sent tracking in the rules, parity and test records (P4b S5)
rules.md B-27 lists `documents_v2`, the one feature S4 to S7 share (D-52), including `invoice.sent`; receipt-store.md lists the event; parity.md gains the sent-tracking row (done: implemented, tested, and golden-covered by the trial balance of the fixture book around a send); testing.md records the tests and what P12 must mutate, and names the two attention predicates as deferred with step 4 until U0b lands.
This commit is contained in:
1 parent
47c0e4396e
commit
7c5a2fe3ce
4 files changed
+72
-4
No files matched your search
@@ -45,6 +45,7 @@ No other statuses.
|
||||
| 1099 vendor tracking + year-end worksheet | Vendors → Track payments for 1099; 1099 report | partial | hand-verified fixture (bill payments, card exclusion, reversal, year boundary); no golden file yet |
|
||||
| Prepaid expense + deferred revenue amortization | Amortization schedules (Xero/QBO add-ons) | partial | hand-verified fixture, to the cent; no golden file yet |
|
||||
| Automated cross-implementation diff harness (GnuCash first) | — (our `xtask oracle`) | todo | roadmap phase 3 |
|
||||
| Invoice sent tracking (who, how, to whom, when, original or reminder, the channel's reference) | Business → Invoices (Xero's "Sent"; QBO's email) | done | P4b S5; records, never sends (A-4); a send changes no figure; `invoice.sent` under `documents_v2` (D-52) |
|
||||
|
||||
Workflow/UI parity (QuickBooks/Xero reference) gets its own catalog when the
|
||||
egui phase starts; semantics come first.
|
||||
@@ -104,3 +105,14 @@ door on loopback for Caddy or a tunnel. `crates/ledger-cli/tests/two_user.rs`
|
||||
proves the account boundary and the move's head in CI
|
||||
(`.github/workflows/two-user.yml`); the recipe is `deploy/README.md`.
|
||||
The cutover rule in `docs/capability-parity.md` is unchanged.
|
||||
|
||||
### P4b S5: sent tracking (2026-10-27)
|
||||
|
||||
The catalog gains one row: an invoice's recorded sends. The books never
|
||||
send (A-4): `books.mark_sent` records who sent an invoice, how, to whom,
|
||||
when, whether it was the original or a reminder, and the channel's own
|
||||
reference, for an owner or a delegate such as an agent. The record is
|
||||
`invoice.sent`, under `documents_v2` (D-52), and it moves no figure, so
|
||||
the A/R and A/P rows' figures are unchanged. The floor never decreases:
|
||||
the row is `done`, tested by `sends_replay_and_project`,
|
||||
`a_send_changes_no_figure` and `mark_sent_records_who_and_how`.
|
||||
@@ -58,8 +58,10 @@ apply is safe — on startup the applier replays every journal line with
|
||||
- `ts`: UTC, RFC 3339. Recorded, never trusted for ordering (`seq` orders).
|
||||
- `type`: `account.added`, `entry.posted`, `entry.reversed`, `invoice.created`,
|
||||
`bill.created`, `receipt.attached`, `receipt.linked`, `receipt.unlinked`,
|
||||
`document.filed`, `attachment.withdrawn` (plus the A/R, A/P, asset,
|
||||
period, payroll, and class events listed on `JournalLine`).
|
||||
`document.filed`, `attachment.withdrawn`, `invoice.sent` (a recorded
|
||||
send: a document's record, never a ledger line or a figure; P4b S5)
|
||||
(plus the A/R, A/P, asset, period, payroll, and class events listed on
|
||||
`JournalLine`).
|
||||
- `payload`: the full domain facts (account fields, entry with lines, blob
|
||||
sha, ...). Everything the applier needs; nothing it must look up elsewhere.
|
||||
An `invoice.created` or `bill.created` written after the `documents_v2`
|
||||
|
||||
+5
-2
@@ -1744,8 +1744,11 @@ which an earlier version refuses (S4.2); a `party.updated` with an email
|
||||
or a default terms fact (S4.2); an `invoice.created` or `bill.created`
|
||||
carrying a number, terms, a bill-to or seller snapshot, a customer
|
||||
reference or memo, a vendor reference, a receipt date or a duplicate's
|
||||
reason, or a line naming its account, quantity or unit price (S4.3); and
|
||||
S5 to S7's sends, settlements and write-offs. An older version would
|
||||
reason, or a line naming its account, quantity or unit price (S4.3);
|
||||
S5's `invoice.sent` (who sent an invoice, how, to whom and when: a record
|
||||
that moves no figure); S6's payments with `line`, `discount`,
|
||||
`discount_line`, `discount_reason`, `fee` or `fee_line`; and S7's
|
||||
`invoice.written_off`. An older version would
|
||||
restore the document without them silently: every invoice line would post
|
||||
to the revenue role and every bill line to general expenses, and every new
|
||||
event type would be refused. A command asks for
|
||||
|
||||
@@ -3050,3 +3050,54 @@ and `BooksServer::new`'s copy (a dropped field must fail
|
||||
`isolation_label_is_enforced_under_the_unit`); the host's `server_flags`
|
||||
extension and `parse_args`' passthrough of `--isolation` and its optional
|
||||
`--http` value.
|
||||
|
||||
## P4b S5: sent tracking (2026-10-27)
|
||||
|
||||
The books record that an invoice went out; they never send it (A-4). A
|
||||
send is `invoice.sent`, under `documents_v2` (D-52), and moves no figure:
|
||||
`Ledger::mark_sent` pushes a `Sent` onto the invoice, the store journals
|
||||
one line and no entry, replay restores it and the projection keeps it in
|
||||
`schema` v17's `invoice_sends` (S4.3 took 16).
|
||||
|
||||
- **`ledger-store` `tests/arap_standing.rs`:** `mark_sent_waits_for_documents_v2`
|
||||
(books with no features: refused, nothing journaled; after `upgrade`,
|
||||
taken, and the reopen equals what was live), `sends_replay_and_project`
|
||||
(two sends: the journal's `invoice.sent` carries the whole record in
|
||||
order, `verify` passes, the reopened invoice holds both),
|
||||
`a_send_changes_no_figure` (on the `p4-arap-before` fixture: the report
|
||||
snapshot, the invoice's `DocState` and every derived cache are equal
|
||||
before and after), `mark_sent_on_void_refused` (`DocumentVoid`,
|
||||
nothing journaled; a send dated before the void is taken).
|
||||
- **`ledger-store` `tests/arap_props.rs`:** `status_is_a_function_of_journal_and_date`
|
||||
gains `Op::Sent` (random sends on invoices, skipped on bills): every
|
||||
figure, the control check and both agings still agree across live,
|
||||
replay and snapshot.
|
||||
- **`ledger-store` `tests/format.rs`:** `an_older_version_stops_at_invoice_sent`
|
||||
(`invoice.sent` is this version's, a reader without `documents_v2` waits,
|
||||
and the books declare the feature before the first send line).
|
||||
- **8.0.6:** `books_written_under_older_rules_still_open` hand-writes an
|
||||
`invoice.sent` and still opens; the fixture `old-books/p4_s5_before`
|
||||
was written by eeee9658 (the revision before this unit) and opens to
|
||||
the same figures; `books_p2_served_cut_over_whole` refuses a send before
|
||||
consent and takes it after.
|
||||
- **`ledger-cli` `tests/documents.rs`:** `mark_sent_records_who_and_how`
|
||||
(two sends over the wire: the token's name, email and original by
|
||||
default, then a reminder with a message id; `books.documents` shows
|
||||
`last_sent`, `books.document` both sends, and the invoice still owes its
|
||||
total).
|
||||
- **`ledger-mcp/src/handbook.rs`:** the new `invoices-and-bills` section
|
||||
renders, and its id is unique (the existing handbook tests).
|
||||
|
||||
**For P12 (mutation targets):** `Ledger::mark_sent`'s refusals (unknown
|
||||
invoice, a send dated before it, `DocumentVoid`, empty `to`, and each of
|
||||
the three `check_text` calls; the note's check is stricter than the plan's
|
||||
list, to keep a full TIN out of the journal); `SentVia::parse`'s arms and
|
||||
its `other:` prefix; `SendKind::parse`'s two arms; `sent_via`'s arms and
|
||||
its empty fallback; `send_kind`'s error arm; the handler's `kind` default
|
||||
(`original` when `sends` is empty, `reminder` after), its `to` fallback
|
||||
(bill-to, then party, then refused) and its `by` fallback; `invoice_id`'s
|
||||
`invoice:` strip; `last_sent`'s `max`; and the replay reader's
|
||||
`newer_content` arms for an unknown channel or kind. The two attention
|
||||
predicates ("invoice never sent", "overdue invoice not reminded") and
|
||||
their day comparisons are deferred with the unit's step 4 until U0b
|
||||
lands, and are named here when they do.
|
||||
Reference in new issue
Block a user