feat(attention): unsent and unreminded invoices (P4b S5)
The books record that an invoice went out but do not chase it. U0b's one attention engine now lists two items the sent record makes possible, in the viewer's Needs attention and in books.start's next steps alike: - "Invoice INV-0007 was never sent": an issued invoice (a number) still Open or Partial, with no send recorded, once today is past its issue date plus invoicing.unsent_days (default 2). A legacy invoice with no number is exempt, and so is a void or settled one. - "Invoice INV-0007 is overdue: remind the customer": the invoice is overdue and its last send is older than invoicing.reminder_days (default 14). An invoice never sent gets the first item, not this one. Both are Todo, open the invoice, and offer books.mark_sent with its invoice and the tool's defaults. The viewer maps the new Target::Invoice to its invoice page (one line; items still come only from ledger-package), and the two lists cannot drift. Tests: an_unsent_invoice_is_listed_until_a_send_clears_it (the overview draws it; attention-unsent-invoice.png; a send clears it), a_legacy_invoice_with_no_number_is_never_listed_as_unsent, an_overdue_invoice_with_an_old_send_is_asked_to_remind, and an_unsent_invoice_is_on_both_lists (viewer and books.start, step books.mark_sent on invoice:1). The existing attention parity test stays green.
This commit is contained in:
1 parent
adc8804f61
commit
485bd4ae5f
4 files changed
+263
-3
No files matched your search
@@ -250,3 +250,50 @@ fn the_viewer_and_books_start_see_the_same_attention() {
|
||||
compare_and_expect(&place, &mut wire, today, "doesn't match the journal");
|
||||
}
|
||||
}
|
||||
|
||||
/// Plan P4b S5, step 4 (R-F): an issued invoice nobody marked sent is on
|
||||
/// the viewer's list and in `books.start`'s next steps, from the one
|
||||
/// engine, with the step naming `books.mark_sent`.
|
||||
#[test]
|
||||
fn an_unsent_invoice_is_on_both_lists() {
|
||||
let today = ledger_core::settings::today_in(None);
|
||||
let place = common::Place::new("attention-unsent-parity");
|
||||
let dir = place.books_data();
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let mut st = ledger_store::Store::create(&dir, Currency::USD).unwrap();
|
||||
st.add_account("1000", "Checking", AccountType::Asset, None, false)
|
||||
.unwrap();
|
||||
let client = st.add_customer("Harbor Client").unwrap();
|
||||
st.create_invoice_with(
|
||||
client,
|
||||
today - chrono::Days::new(40),
|
||||
today + chrono::Days::new(20),
|
||||
vec![ledger_core::arap::DocumentLine {
|
||||
description: "Consulting".into(),
|
||||
amount: Decimal::new(50_000, 2),
|
||||
class_id: None,
|
||||
account: None,
|
||||
quantity: None,
|
||||
unit_price: None,
|
||||
}],
|
||||
ledger_core::arap::InvoiceFields {
|
||||
number: Some("INV-0001".into()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
drop(st);
|
||||
let mut wire = place.start(Some(SETTINGS));
|
||||
wire.initialize("attention-unsent-parity");
|
||||
compare_and_expect(&place, &mut wire, today, "Invoice INV-0001 was never sent");
|
||||
// The step offers the fix: books.mark_sent on that invoice.
|
||||
let answer = start(&mut wire);
|
||||
let step = answer["next_steps"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|s| s["why"] == json!("Invoice INV-0001 was never sent"))
|
||||
.unwrap_or_else(|| panic!("no unsent step: {answer}"));
|
||||
assert_eq!(step["tool"], json!("books.mark_sent"), "{answer}");
|
||||
assert_eq!(step["args"]["invoice"], json!("invoice:1"), "{answer}");
|
||||
}
|
||||
Reference in new issue
Block a user