feat(arap): a write-off on the timeline, and the CPA's note (P4b S7)
The viewer's invoice page already drew a WriteOff movement; now the fixture proves it: a written-off invoice reads Written off, owes nothing, and its timeline's "Written off" row opens the entry (the screenshot invoice-written-off). Needs attention gains the one item the tax rule asks for: a write-off made this calendar year is listed, one per invoice, as "Write-off awaiting the CPA's note", with what was written off, the day, and the prompt that opens the document. Whether a debt is worthless, and in which year, is a tax judgment that stays with the CPA (plan 8.3.16); the books flag it and keep the evidence beside it until the year ends. The item is computed in ledger-package's one attention function, so the viewer and books.start see it alike; view_model.rs compares the two reads on the same books. The handbook's invoices-and-bills section starts here (S4.5 adds the issue, terms and payment steps around it): step 4 says when to void, to write off, or to reverse, and the recovery procedures D-49 records — the same year, reverse the write-off and record the payment; a later year, a plain entry to a bad-debt-recoveries revenue account, the invoice staying written off (IRC §111). Tests: a_write_off_shows_on_the_timeline, a_write_off_is_flagged_for_the_cpa.
This commit is contained in:
1 parent
0f1c7786ab
commit
b731d7ed04
5 files changed
+294
-1
No files matched your search
@@ -37,7 +37,10 @@
|
||||
//! books.set_entry_instrument; a year whose worksheet can't be made
|
||||
//! for want of named cash accounts while vendors were paid in it
|
||||
//! (Todo); overdue bills, and overdue
|
||||
//! invoices (Problem, one each, with the total); money owed to
|
||||
//! invoices (Problem, one each, with the total); a written-off
|
||||
//! invoice whose write-off is dated this calendar year and stands
|
||||
//! (Todo, one per invoice, "Write-off awaiting the CPA's note",
|
||||
//! its prompt naming books.document); money owed to
|
||||
//! owners (Info, per account with a balance); the database differing
|
||||
//! from the journal or unreadable, and damaged or missing stored
|
||||
//! files (Problem); depreciation due through the last finished month
|
||||
@@ -717,6 +720,63 @@ pub fn find_with(
|
||||
});
|
||||
}
|
||||
|
||||
// A write-off this year waits for the CPA's note: the deduction rests
|
||||
// on evidence of worthlessness a human signs off, and §166's judgments
|
||||
// stay with the CPA (plan P4b S7, 8.3.16; IRC §166(a); Treas. Reg.
|
||||
// §1.166-2(a)). Listed until the year ends.
|
||||
let mut written_off: Vec<(u64, Option<String>, NaiveDate, Decimal)> = Vec::new();
|
||||
for inv in ledger.invoices() {
|
||||
let doc = ledger_core::DocRef::Invoice(inv.id);
|
||||
let state = ledger.invoice_state(inv.id, today).ok().flatten();
|
||||
if state.map(|s| s.status) != Some(ledger_core::DocStatus::WrittenOff) {
|
||||
continue;
|
||||
}
|
||||
let lines: Vec<ledger_core::DocLine> = ledger
|
||||
.doc_lines(doc)
|
||||
.into_iter()
|
||||
.filter(|l| {
|
||||
l.movement == ledger_core::Movement::WriteOff
|
||||
&& l.date.year() == today.year()
|
||||
&& ledger.stands_on(l.entry, today)
|
||||
})
|
||||
.collect();
|
||||
let Some(last) = lines.last() else {
|
||||
continue;
|
||||
};
|
||||
match lines
|
||||
.iter()
|
||||
.try_fold(Decimal::ZERO, |t, l| t.checked_sub(l.amount))
|
||||
{
|
||||
Some(amount) => written_off.push((inv.id, inv.number.clone(), last.date, amount)),
|
||||
None => out.push(cant_compute(
|
||||
format!("Invoice {}", inv.id),
|
||||
&LedgerError::TooLargeToCompute("what was written off".into()),
|
||||
Target::Documents,
|
||||
)),
|
||||
}
|
||||
}
|
||||
for (id, number, on, amount) in written_off {
|
||||
let name = number.unwrap_or_else(|| format!("Invoice {id}"));
|
||||
out.push(Attention {
|
||||
severity: Severity::Todo,
|
||||
kind: "write_off_note",
|
||||
title: format!("Write-off awaiting the CPA's note: {name}"),
|
||||
detail: format!(
|
||||
"{} written off on {} (IRC §166; Treas. Reg. §1.166-2: the evidence of worthlessness is filed with the write-off).",
|
||||
dollars(amount),
|
||||
date(on)
|
||||
),
|
||||
target: Target::Documents,
|
||||
prompt: format!(
|
||||
"In wanderbooks, show me invoice {id}'s write-off (books.document), with its reason and the evidence filed with it, and note it for the CPA at year end."
|
||||
),
|
||||
tool: Some((
|
||||
"books.document".into(),
|
||||
serde_json::json!({ "ref": format!("invoice:{id}") }),
|
||||
)),
|
||||
});
|
||||
}
|
||||
|
||||
for a in ledger.chart().all().filter(|a| {
|
||||
a.account_type == AccountType::Liability && {
|
||||
let n = a.name.to_lowercase();
|
||||
|
||||
Reference in new issue
Block a user