refactor(arap): rustfmt the unit's files, and the write-off's SOURCE line (P4b S7)

No behaviour: the files as rustfmt leaves them after the unit's edits
(the commits before this one were made before the formatter ran), and the
Ledger::write_off spec block cites A-5 alone for the direct write-off
method (A-6 is the hand-entry refusal, not this command).
This commit is contained in:
swaits committed 2026-10-27 12:44:45 -06:00
1 parent f31dd2640b
commit 22cdfcf34b
9 files changed
+75 -50

No files matched your search

+18 -4
View File
@@ -87,7 +87,12 @@ fn write_off_then_recovery() {
}), }),
); );
// The write-off's evidence, uploaded as an agent uploads it (D-46). // The write-off's evidence, uploaded as an agent uploads it (D-46).
let upload = wire.upload(LETTER, "collection-letter.pdf", "application/pdf", "document"); let upload = wire.upload(
LETTER,
"collection-letter.pdf",
"application/pdf",
"document",
);
let out = ok( let out = ok(
&mut wire, &mut wire,
"books.write_off_invoice", "books.write_off_invoice",
@@ -110,7 +115,10 @@ fn write_off_then_recovery() {
// invoice: get_entry shows the one, the document's timeline the other. // invoice: get_entry shows the one, the document's timeline the other.
let got = ok(&mut wire, "books.get_entry", json!({ "entry_id": entry })); let got = ok(&mut wire, "books.get_entry", json!({ "entry_id": entry }));
assert_eq!(got["receipts"].as_array().map(Vec::len), Some(1), "{got}"); assert_eq!(got["receipts"].as_array().map(Vec::len), Some(1), "{got}");
assert_eq!(got["receipts"][0]["file_name"], json!("collection-letter.pdf")); assert_eq!(
got["receipts"][0]["file_name"],
json!("collection-letter.pdf")
);
let doc = ok( let doc = ok(
&mut wire, &mut wire,
"books.document", "books.document",
@@ -225,6 +233,12 @@ fn write_off_needs_evidence() {
json!({ "attachment_id": attachment }), json!({ "attachment_id": attachment }),
); );
let links = receipt["links"].as_array().cloned().unwrap_or_default(); let links = receipt["links"].as_array().cloned().unwrap_or_default();
assert!(links.iter().any(|l| l["kind"] == json!("invoice")), "{receipt}"); assert!(
assert!(links.iter().any(|l| l["kind"] == json!("entry")), "{receipt}"); links.iter().any(|l| l["kind"] == json!("invoice")),
"{receipt}"
);
assert!(
links.iter().any(|l| l["kind"] == json!("entry")),
"{receipt}"
);
} }
+3 -3
View File
@@ -6329,9 +6329,9 @@ impl Ledger {
/// §1.166-2(a) (worthlessness on all the pertinent evidence), /// §1.166-2(a) (worthlessness on all the pertinent evidence),
/// §1.166-3(a) (a partial write-off, to the extent charged /// §1.166-3(a) (a partial write-off, to the extent charged
/// off); docs/spec/rules.md B-41; plan/served.md P4b S7, /// off); docs/spec/rules.md B-41; plan/served.md P4b S7,
/// A-5 (direct write-off), A-6; ASC 326-20 noted (an allowance /// A-5 (the direct write-off method); ASC 326-20 noted (an
/// is the GAAP preference; a small company's CPA accepts the /// allowance is the GAAP preference; a small company's CPA
/// direct method, stated). /// accepts the direct method, stated).
/// INVARIANTS: /// INVARIANTS:
/// 1. MUST post one balanced entry: Dr the bad_debts role (6990 Bad /// 1. MUST post one balanced entry: Dr the bad_debts role (6990 Bad
/// Debt Expense), Cr receivables, for the amount, dated the /// Debt Expense), Cr receivables, for the amount, dated the
+8 -7
View File
@@ -1171,13 +1171,14 @@ impl<'a> Books<'a> {
.unwrap_or_else(|| panic!("{what}: event {} posted no invoice", w.invoice)); .unwrap_or_else(|| panic!("{what}: event {} posted no invoice", w.invoice));
let amount = match &w.amount { let amount = match &w.amount {
Some(a) => exact(a, what), Some(a) => exact(a, what),
None => self None => {
.store self.store
.ledger() .ledger()
.invoice_state(invoice, day()) .invoice_state(invoice, day())
.expect("the invoice's figures") .expect("the invoice's figures")
.expect("dated by its own day") .expect("dated by its own day")
.outstanding, .outstanding
}
}; };
self.store self.store
.write_off_invoice( .write_off_invoice(
+1 -2
View File
@@ -252,8 +252,7 @@ fn a_write_off_shows_on_the_timeline() {
let mut h = open(&dir, Route::Invoice(inv)); let mut h = open(&dir, Route::Invoice(inv));
shot(&mut h, "invoice-written-off"); shot(&mut h, "invoice-written-off");
assert!( assert!(
h.query_by_label_contains("Written off, entry #") h.query_by_label_contains("Written off, entry #").is_some(),
.is_some(),
"the timeline shows the write-off" "the timeline shows the write-off"
); );
// The status chip reads its label ("Written off"), not "late". // The status chip reads its label ("Written off"), not "late".
+13 -10
View File
@@ -892,10 +892,12 @@ fn a_write_off_is_flagged_for_the_cpa() {
}, },
); );
let want = format!("Write-off awaiting the CPA's note: Invoice {inv}"); let want = format!("Write-off awaiting the CPA's note: Invoice {inv}");
let said = server let said = server.iter().find(|a| a.title == want).unwrap_or_else(|| {
.iter() panic!(
.find(|a| a.title == want) "the server's list has no {want:?}: {:?}",
.unwrap_or_else(|| panic!("the server's list has no {want:?}: {:?}", server.iter().map(|a| &a.title).collect::<Vec<_>>())); server.iter().map(|a| &a.title).collect::<Vec<_>>()
)
});
assert_eq!(said.severity, ledger_package::Severity::Todo); assert_eq!(said.severity, ledger_package::Severity::Todo);
assert!(said.prompt.contains("wanderbooks"), "{}", said.prompt); assert!(said.prompt.contains("wanderbooks"), "{}", said.prompt);
assert!(said.detail.contains("100.00"), "{}", said.detail); assert!(said.detail.contains("100.00"), "{}", said.detail);
@@ -910,14 +912,15 @@ fn a_write_off_is_flagged_for_the_cpa() {
.attention .attention
.iter() .iter()
.find(|a| a.title == want) .find(|a| a.title == want)
.unwrap_or_else(|| panic!("the viewer shows no {want:?}: {:?}", books.attention.iter().map(|a| &a.title).collect::<Vec<_>>())); .unwrap_or_else(|| {
panic!(
"the viewer shows no {want:?}: {:?}",
books.attention.iter().map(|a| &a.title).collect::<Vec<_>>()
)
});
assert_eq!(shown.target, Some(ledger_gui::nav::Route::Documents)); assert_eq!(shown.target, Some(ledger_gui::nav::Route::Documents));
// The viewer reads the same figures from the journal it replayed. // The viewer reads the same figures from the journal it replayed.
let st = books let st = books.ledger.invoice_state(inv, today).unwrap().unwrap();
.ledger
.invoice_state(inv, today)
.unwrap()
.unwrap();
assert_eq!(st.status, ledger_core::DocStatus::WrittenOff); assert_eq!(st.status, ledger_core::DocStatus::WrittenOff);
assert!(books.ledger.get_entry(entry).is_some()); assert!(books.ledger.get_entry(entry).is_some());
} }
+1 -5
View File
@@ -128,10 +128,6 @@ impl BooksServer {
entry_id entry_id
} }
}; };
Ok(Json(write_off_out( Ok(Json(write_off_out(store.ledger(), p.invoice, entry_id)?))
store.ledger(),
p.invoice,
entry_id,
)?))
} }
} }
+2 -2
View File
@@ -49,6 +49,6 @@ pub use snapshot::{DiskCheck, Snapshot};
pub use store::{ pub use store::{
Attachment, BillPreview, DepreciationRun, DisposalPreview, EntryRow, EventRow, InvoicePreview, Attachment, BillPreview, DepreciationRun, DisposalPreview, EntryRow, EventRow, InvoicePreview,
JOURNAL_FILE, LEGACY_DB_FILE, LOCK_FILE, MAX_RECURRING_RUN, PayrollLineInput, Reconciliation, JOURNAL_FILE, LEGACY_DB_FILE, LOCK_FILE, MAX_RECURRING_RUN, PayrollLineInput, Reconciliation,
Statement, Store, Subject, VerifyReport, WriteOffEvidence, database_in_use, db_file, db_file_for, Statement, Store, Subject, VerifyReport, WriteOffEvidence, database_in_use, db_file,
is_database_file, db_file_for, is_database_file,
}; };
+2 -7
View File
@@ -3747,13 +3747,8 @@ impl Store {
let description = format!("Write off invoice {invoice}: {}", reason.trim()); let description = format!("Write off invoice {invoice}: {}", reason.trim());
let (entry_id, mut journaled) = let (entry_id, mut journaled) =
self.journal_auto_entry(date, &description, bad, ar, amount)?; self.journal_auto_entry(date, &description, bad, ar, amount)?;
let written_off = crate::meta::invoice_written_off( let written_off =
invoice, crate::meta::invoice_written_off(invoice, entry_id, date, amount, reason.trim());
entry_id,
date,
amount,
reason.trim(),
);
journaled.push(self.append_journal("invoice.written_off", written_off)?); journaled.push(self.append_journal("invoice.written_off", written_off)?);
let live = self.ledger.write_off(invoice, date, amount, reason)?; let live = self.ledger.write_off(invoice, date, amount, reason)?;
debug_assert_eq!(live, entry_id, "id allocator diverged from journal"); debug_assert_eq!(live, entry_id, "id allocator diverged from journal");
+27 -10
View File
@@ -1100,10 +1100,7 @@ fn write_off_waits_for_documents_v2() {
.unwrap(); .unwrap();
s.verify().unwrap(); s.verify().unwrap();
let live = s.ledger().clone(); let live = s.ledger().clone();
let st = live let st = live.invoice_state(1, d(2026, 12, 31)).unwrap().unwrap();
.invoice_state(1, d(2026, 12, 31))
.unwrap()
.unwrap();
assert_eq!(st.status, ledger_core::DocStatus::WrittenOff); assert_eq!(st.status, ledger_core::DocStatus::WrittenOff);
assert_eq!(st.written_off, cents(10_000)); assert_eq!(st.written_off, cents(10_000));
// The evidence is on the write-off's entry and on its invoice. // The evidence is on the write-off's entry and on its invoice.
@@ -1135,7 +1132,12 @@ fn write_off_replays_and_projects() {
.unwrap(); .unwrap();
let c = s.add_customer("Fernhill Labs").unwrap(); let c = s.add_customer("Fernhill Labs").unwrap();
let inv = s let inv = s
.create_invoice(c, d(2026, 4, 1), d(2026, 5, 1), vec![line("Design", 10_000)]) .create_invoice(
c,
d(2026, 4, 1),
d(2026, 5, 1),
vec![line("Design", 10_000)],
)
.unwrap(); .unwrap();
// Half paid, the rest written off: the invoice reads Written off with // Half paid, the rest written off: the invoice reads Written off with
// 50 paid and 50 written off (B-38 SCENARIO 7). // 50 paid and 50 written off (B-38 SCENARIO 7).
@@ -1175,10 +1177,16 @@ fn write_off_replays_and_projects() {
assert!(got.iter().any(|(t, v)| t == "receipt.attached" assert!(got.iter().any(|(t, v)| t == "receipt.attached"
&& v["attachment_id"] == json!(attachment) && v["attachment_id"] == json!(attachment)
&& v["entry_id"] == json!(entry))); && v["entry_id"] == json!(entry)));
assert!(got.iter().any(|(t, v)| t == "attachment.linked" assert!(
&& v["attachment_id"] == json!(attachment))); got.iter()
.any(|(t, v)| t == "attachment.linked" && v["attachment_id"] == json!(attachment))
);
// The figures, live. // The figures, live.
let st = s.ledger().invoice_state(inv, d(2026, 5, 1)).unwrap().unwrap(); let st = s
.ledger()
.invoice_state(inv, d(2026, 5, 1))
.unwrap()
.unwrap();
assert_eq!(st.status, ledger_core::DocStatus::WrittenOff); assert_eq!(st.status, ledger_core::DocStatus::WrittenOff);
assert_eq!( assert_eq!(
(st.paid, st.written_off, st.outstanding), (st.paid, st.written_off, st.outstanding),
@@ -1206,7 +1214,11 @@ fn write_off_replays_and_projects() {
"{:?}", "{:?}",
live.differs_from(s.ledger()) live.differs_from(s.ledger())
); );
let replayed = s.ledger().invoice_state(inv, d(2026, 5, 1)).unwrap().unwrap(); let replayed = s
.ledger()
.invoice_state(inv, d(2026, 5, 1))
.unwrap()
.unwrap();
assert_eq!(replayed, st); assert_eq!(replayed, st);
s.verify().unwrap(); s.verify().unwrap();
} }
@@ -1220,7 +1232,12 @@ fn write_off_without_evidence_is_refused() {
let mut s = Store::create(&dir.0, Currency::USD).unwrap(); let mut s = Store::create(&dir.0, Currency::USD).unwrap();
let c = s.add_customer("Fernhill Labs").unwrap(); let c = s.add_customer("Fernhill Labs").unwrap();
let inv = s let inv = s
.create_invoice(c, d(2026, 4, 1), d(2026, 5, 1), vec![line("Design", 10_000)]) .create_invoice(
c,
d(2026, 4, 1),
d(2026, 5, 1),
vec![line("Design", 10_000)],
)
.unwrap(); .unwrap();
let head = s.head(); let head = s.head();
let len = journal_len(&dir.0); let len = journal_len(&dir.0);