feat(store): journal a write-off with its evidence (P4b S7)
A bad debt is deducted on evidence it is worthless (Treas. Reg.
§1.166-2), so the store will not journal one without it:
Store::write_off_invoice takes the evidence as bytes to file or as an
attachment already filed, and files it in the same call — a
receipt.attached on the write-off's entry and an attachment.linked to
the invoice (rules.md B-41). With no evidence it refuses, journaling
nothing.
The entry (Dr 6990 Bad Debt Expense / Cr 1200) and its evidence are
journaled after the engine's whole check and after the feature gate: the
new event type invoice.written_off needs documents_v2, so an older
version stops at the declaration rather than reading a written-off
invoice as still owed (B-27, D-52). Its payload is the invoice, the
entry, the day, the amount and the reason; replay tags the receivable
line WriteOff, and the projection keeps no written-off figure — it is
the tagged lines' sum (B-38).
`meta::invoice_written_off_of` reads and writes the payload; the replay
fuzzer draws the type.
8.0.6: (1) `books_written_under_older_rules_still_open` hand-writes the
new event and its entry through JournalWriter and still opens, with the
figures tailing; (2) a new fixture old-books/p4_s7_before was written by
main 4cad2cfc (the version before this unit) through the old-books-writer
harness — a numbered invoice with terms and snapshots, a partial payment,
a voided invoice and a paid bill — with its expected.json; this version
opens it and reports the same figures, the viewer included; (3) the
cut-over entry is in format_upgrade.rs's books_p2_served_cut_over_whole;
(4) documents_v2_is_its_own_feature is green and the event gate's arms
pass; (5) no figure moves: no golden changed (the previous version's
expected.json is the comparison); (6) merge does not need the owner's
go-ahead; the live books refuse the new write until he gives it.
Tests: write_off_waits_for_documents_v2, write_off_replays_and_projects,
write_off_without_evidence_is_refused; arap_props.rs gains WriteOff.
This commit is contained in:
1 parent
62f2fb058e
commit
4e71cf6320
13 files changed
+1005
-7
No files matched your search
@@ -361,6 +361,54 @@ pub fn entry_approved_of(p: &Value, seq: u64) -> Result<(u64, Approval), StoreEr
|
||||
))
|
||||
}
|
||||
|
||||
/// A bad-debt write-off as journaled (plan P4b S7; rules.md B-41):
|
||||
/// `invoice.written_off {invoice_id, entry_id, date, amount, reason}`.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WrittenOff {
|
||||
/// The invoice written off.
|
||||
pub invoice_id: u64,
|
||||
/// The entry that posted it (already rebuilt from its own events).
|
||||
pub entry_id: u64,
|
||||
/// The write-off's day.
|
||||
pub date: NaiveDate,
|
||||
/// What was written off.
|
||||
pub amount: rust_decimal::Decimal,
|
||||
/// Why (it has no resolution: the evidence is the receipt).
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
/// `invoice.written_off {invoice_id, entry_id, date, amount, reason}`.
|
||||
pub fn invoice_written_off(
|
||||
invoice_id: u64,
|
||||
entry_id: u64,
|
||||
date: NaiveDate,
|
||||
amount: rust_decimal::Decimal,
|
||||
reason: &str,
|
||||
) -> Value {
|
||||
json!({
|
||||
"invoice_id": invoice_id,
|
||||
"entry_id": entry_id,
|
||||
"date": date.to_string(),
|
||||
"amount": amount.to_string(),
|
||||
"reason": reason,
|
||||
})
|
||||
}
|
||||
|
||||
/// Read an `invoice.written_off` payload.
|
||||
pub fn invoice_written_off_of(p: &Value) -> Result<WrittenOff, StoreError> {
|
||||
const E: &str = "invoice.written_off";
|
||||
let amount = str_of(p, E, "amount")?
|
||||
.parse()
|
||||
.map_err(|_| corrupt(E, "amount"))?;
|
||||
Ok(WrittenOff {
|
||||
invoice_id: u64_of(p, E, "invoice_id")?,
|
||||
entry_id: u64_of(p, E, "entry_id")?,
|
||||
date: date_of(&str_of(p, E, "date")?, E, "date")?,
|
||||
amount,
|
||||
reason: str_of(p, E, "reason")?,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in new issue
Block a user