Audit fixes: party money, reconciliations, require policy, K-1 property
An independent recompute of the real books found no numeric disagreements; review found 15 defects, all fixed with spec-first regression tests: - k1: a prepaid credited straight to capital is property; a member paying a vendor through 2100 is cash. Docs and B-13 match. - parties: a reversal of a reversal counts on its root's side; liability-to-liability payments (member pays the card) count as paid. - viewer: party money uses the server's cash accounts and full calendar year; per-party "What for" scales multi-party entries. - reconciliations: refuse a withdrawn statement before journaling; new books.void_statement; reconciled lines can't be un-cleared; one shared reconcilable-accounts rule for digest and viewer. - CPA package includes receipts linked to entries; a file can't be both filed on and linked to one entry. - parties = "require" covers payroll, tax remittance (agency) and disposal (buyer); no-party marks follow reversal chains and clear when a vendor is tagged. - derived member shares are frozen to exact amounts when posted, so a settings change never re-splits history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
This commit is contained in:
1 parent
e1b2509c22
commit
8498e6cfab
22 files changed
+1802
-343
No files matched your search
@@ -603,3 +603,49 @@ fn books_show_opens_a_reconciliation() {
|
||||
h.state_mut().show(ViewerTarget::Reconciliation { id: 999 });
|
||||
assert_eq!(h.state_mut().route(), &Route::Reconciliation(r));
|
||||
}
|
||||
|
||||
/// ledger_store::reconcilable INVARIANT 1, the digest's rule: a liability
|
||||
/// not named for a card (an Amex) joins the accounts to reconcile once it
|
||||
/// has a recorded statement, so Needs attention asks for it as the digest
|
||||
/// does (it used to be listed by the digest only).
|
||||
#[test]
|
||||
fn a_liability_with_a_statement_needs_reconciling_whatever_its_name() {
|
||||
let mut f = fixture("amex");
|
||||
let amex = f
|
||||
.store
|
||||
.add_account("2060", "Amex", AccountType::Liability, None, false)
|
||||
.unwrap();
|
||||
let software = f.store.ledger().chart().find_by_code("6300").unwrap().id;
|
||||
let e = f.store.create_entry(d(2026, 9, 3), "Amex charge").unwrap();
|
||||
f.store
|
||||
.add_line(e, software, Side::Debit, usd(1_000))
|
||||
.unwrap();
|
||||
f.store.add_line(e, amex, Side::Credit, usd(1_000)).unwrap();
|
||||
f.store.post_entry(e).unwrap();
|
||||
let b = load(&f.dir.0);
|
||||
assert!(!b.reconcilable_accounts().contains(&amex));
|
||||
let (att, _, _) = f
|
||||
.store
|
||||
.file_document(
|
||||
"statement",
|
||||
"amex-aug.pdf",
|
||||
"application/pdf",
|
||||
b"amex aug",
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
f.store
|
||||
.record_statement(Statement {
|
||||
attachment_id: att,
|
||||
account_id: amex,
|
||||
period_start: d(2026, 8, 1),
|
||||
period_end: d(2026, 8, 31),
|
||||
opening_balance: Decimal::ZERO,
|
||||
closing_balance: Decimal::ZERO,
|
||||
})
|
||||
.unwrap();
|
||||
let b = load(&f.dir.0);
|
||||
assert!(b.reconcilable_accounts().contains(&amex));
|
||||
assert_eq!(b.reconciliation_due(amex), Some(d(2026, 9, 30)));
|
||||
assert!(reconcile_items(&b).contains(&"Reconcile Amex through Sep 30, 2026".to_string()));
|
||||
}
|
||||
Reference in new issue
Block a user