diff --git a/crates/ledger-cli/tests/documents.rs b/crates/ledger-cli/tests/documents.rs index 520eabf..4c43781 100644 --- a/crates/ledger-cli/tests/documents.rs +++ b/crates/ledger-cli/tests/documents.rs @@ -496,18 +496,18 @@ fn terms_fall_back_in_order() { assert_eq!(bill["terms"], "Net 10", "{bill}"); } -/// `party_id` is the old spelling of `customer`/`vendor` and still names -/// the same record (until P5); a number that is one record's id and +/// A customer given by id and by name is the same record (the old +/// `party_id` spelling is gone, P5); a number that is one record's id and /// another's name is refused, never guessed. #[test] -fn party_id_alias_still_works() { +fn a_customer_by_id_and_by_name_is_one_record() { let books = Books::new("documents-alias"); let mut m = Mcp::spawn(&books); let harbor = m.customer("Harbor Coffee"); let line = json!([{"description": "Work", "amount": "10.00"}]); - let by_alias = m.call( + let by_id = m.call( "books.create_invoice", - json!({"party_id": harbor, "date": "2026-02-01", "terms": "Net 30", + json!({"customer": (harbor).to_string(), "date": "2026-02-01", "terms": "Net 30", "lines": line, "confirmed": true}), ); let by_name = m.call( @@ -520,8 +520,8 @@ fn party_id_alias_still_works() { .iter() .map(|e| e["payload"]["customer_id"].as_u64().unwrap()) .collect(); - assert_eq!(parties, [harbor, harbor], "one customer, two spellings"); - assert_eq!(by_alias["total"], by_name["total"]); + assert_eq!(parties, [harbor, harbor], "one customer, an id and a name"); + assert_eq!(by_id["total"], by_name["total"]); // A customer named "2" that is not customer 2: the number is // ambiguous, and is refused rather than guessed. @@ -730,7 +730,7 @@ fn mark_sent_records_who_and_how() { .unwrap(); let invoice = common::answer_of(&wire.call( "books.create_invoice", - json!({"party_id": customer, "date": "2026-03-01", "due_date": "2026-03-31", + json!({"customer": (customer).to_string(), "date": "2026-03-01", "due_date": "2026-03-31", "lines": [{"description": "Design", "amount": "1200.00"}], "confirmed": true}), )) .unwrap()["id"] @@ -876,7 +876,7 @@ mod paying_on_terms { ok( &mut self.wire, "books.create_invoice", - json!({"party_id": self.customer, "date": date, "due_date": due, + json!({"customer": (self.customer).to_string(), "date": date, "due_date": due, "lines": [{"description": "Consulting", "amount": amount}], "confirmed": true}), )["id"] @@ -897,7 +897,7 @@ mod paying_on_terms { ok( &mut self.wire, "books.create_bill", - json!({"party_id": self.vendor, "date": date, "due_date": due, + json!({"vendor": (self.vendor).to_string(), "date": date, "due_date": due, "vendor_ref": format!("TH-{}", self.bills), "lines": [{"description": "Paper", "amount": amount, "account": "6999"}], "upload_id": file, "confirmed": true}), @@ -1258,7 +1258,7 @@ mod bad_debts { wire, "books.create_invoice", json!({ - "party_id": customer, + "customer": (customer).to_string(), "date": "2026-01-05", "due_date": "2026-02-04", "lines": [{ "description": "Design", "amount": "100.00" }], @@ -1286,10 +1286,10 @@ mod bad_debts { &mut wire, "books.receive_payment", json!({"confirmed": true, - "document_id": inv, + "invoice": inv, "date": "2026-01-20", "amount": "40.00", - "cash_account": "1000", + "deposit_to": "1000", }), ); // The write-off's evidence, uploaded as an agent uploads it (D-46). @@ -1361,10 +1361,10 @@ mod bad_debts { &mut wire, "books.receive_payment", json!({"confirmed": true, - "document_id": inv, + "invoice": inv, "date": "2026-03-02", "amount": "60.00", - "cash_account": "1000", + "deposit_to": "1000", }), ); let doc = ok( diff --git a/crates/ledger-cli/tests/format_upgrade.rs b/crates/ledger-cli/tests/format_upgrade.rs index 4a4d513..75ea276 100644 --- a/crates/ledger-cli/tests/format_upgrade.rs +++ b/crates/ledger-cli/tests/format_upgrade.rs @@ -767,7 +767,7 @@ fn books_p2_served_cut_over_whole() { let invoice = a .call( "books.create_invoice", - json!({"party_id": 1, "date": "2026-01-05", "due_date": "2026-02-04", + json!({"customer": (1).to_string(), "date": "2026-01-05", "due_date": "2026-02-04", "lines": [{"description": "Design", "amount": "400.00"}], "confirmed": true}), ) .unwrap()["id"] @@ -789,7 +789,7 @@ fn books_p2_served_cut_over_whole() { let unpaid = a .call( "books.create_invoice", - json!({"party_id": customer, "date": "2026-01-10", "due_date": "2026-02-09", + json!({"customer": (customer).to_string(), "date": "2026-01-10", "due_date": "2026-02-09", "lines": [{"description": "Survey", "amount": "300.00"}], "confirmed": true}), ) .unwrap()["id"] diff --git a/crates/ledger-cli/tests/hostile_args.rs b/crates/ledger-cli/tests/hostile_args.rs index 1dcfc86..6cc3ca9 100644 --- a/crates/ledger-cli/tests/hostile_args.rs +++ b/crates/ledger-cli/tests/hostile_args.rs @@ -1017,13 +1017,13 @@ fn inputs_that_once_panicked_are_refused_or_answered() { ), ( "books.create_invoice", - json!({"party_id": client, "date": "2026-05-01", "due_date": "2026-06-01", + json!({"customer": (client).to_string(), "date": "2026-05-01", "due_date": "2026-06-01", "lines": [{"description": "a", "amount": MAX}, {"description": "b", "amount": "1"}], "confirmed": true}), ), ( "books.create_bill", - json!({"party_id": acme, "date": "2026-05-01", "due_date": "2026-06-01", + json!({"vendor": (acme).to_string(), "date": "2026-05-01", "due_date": "2026-06-01", "vendor_ref": "H-1", "lines": [{"description": "a", "amount": MAX, "account": "6000"}, {"description": "b", "amount": "1", "account": "6000"}], @@ -1031,7 +1031,7 @@ fn inputs_that_once_panicked_are_refused_or_answered() { ), ( "books.create_invoice", - json!({"party_id": client, "date": "2026-05-01", "due_date": "+262142-12-31", + json!({"customer": (client).to_string(), "date": "2026-05-01", "due_date": "+262142-12-31", "lines": [{"description": "a", "amount": "1"}], "confirmed": true}), ), ( diff --git a/crates/ledger-cli/tests/projects_parity.rs b/crates/ledger-cli/tests/projects_parity.rs index 4328f7a..93261b2 100644 --- a/crates/ledger-cli/tests/projects_parity.rs +++ b/crates/ledger-cli/tests/projects_parity.rs @@ -274,7 +274,7 @@ fn invoiced_and_billed_project_figures_are_the_same_in_the_viewer_and_from_the_s let bill = server.tool("books.create_bill", bill_args); server.tool( "books.receive_payment", - json!({"confirmed": true, "document_id": inv["id"], "date": "2026-02-20", "amount": "1830.00", "cash_account": "1000"}), + json!({"confirmed": true, "invoice": inv["id"], "date": "2026-02-20", "amount": "1830.00", "deposit_to": "1000"}), ); let b = data::load_once(&Source { data_dir: data.clone(), diff --git a/crates/ledger-cli/tests/spec_attachments.rs b/crates/ledger-cli/tests/spec_attachments.rs index afa85c7..d826849 100644 --- a/crates/ledger-cli/tests/spec_attachments.rs +++ b/crates/ledger-cli/tests/spec_attachments.rs @@ -424,7 +424,7 @@ fn a_file_links_to_every_kind_of_subject() { let rent_invoice = m.upload(b"rent invoice", "rent.pdf", "application/pdf", "receipt"); let bill = m.ok( "books.create_bill", - json!({"party_id": vendor, "date": "2026-02-01", "due_date": "2026-02-28", + json!({"vendor": (vendor).to_string(), "date": "2026-02-01", "due_date": "2026-02-28", "vendor_ref": "RENT-2", "lines": [{"description": "Rent", "amount": "300.00", "account": "6000"}], "upload_id": rent_invoice, "confirmed": true}), @@ -432,7 +432,7 @@ fn a_file_links_to_every_kind_of_subject() { .clone(); let invoice = m.ok( "books.create_invoice", - json!({"party_id": customer, "date": "2026-02-01", "due_date": "2026-03-01", + json!({"customer": (customer).to_string(), "date": "2026-02-01", "due_date": "2026-03-01", "lines": [{"description": "Work", "amount": "500.00"}], "confirmed": true}), )["id"] diff --git a/crates/ledger-cli/tests/spec_mcp.rs b/crates/ledger-cli/tests/spec_mcp.rs index 89d31e3..6cf443b 100644 --- a/crates/ledger-cli/tests/spec_mcp.rs +++ b/crates/ledger-cli/tests/spec_mcp.rs @@ -911,7 +911,7 @@ fn happy_path(name: &str) -> Mcp { // A/R and A/P. let inv = m.ok( "books.create_invoice", - json!({"party_id": customer, "date": "2026-02-01", "due_date": "2026-03-01", + json!({"customer": (customer).to_string(), "date": "2026-02-01", "due_date": "2026-03-01", "lines": [{"description": "Consulting", "amount": "500.00"}], "confirmed": true}), )["id"] @@ -919,7 +919,7 @@ fn happy_path(name: &str) -> Mcp { .unwrap(); m.ok( "books.receive_payment", - json!({"confirmed": true, "document_id": inv, "date": "2026-02-10", "amount": "200.00", "cash_account": "1000"}), + json!({"confirmed": true, "invoice": inv, "date": "2026-02-10", "amount": "200.00", "deposit_to": "1000"}), ); let vendor_invoice = m.upload( b"vendor invoice", @@ -929,7 +929,7 @@ fn happy_path(name: &str) -> Mcp { ); let bill = m.ok( "books.create_bill", - json!({"party_id": vendor, "date": "2026-02-01", "due_date": "2026-02-28", + json!({"vendor": (vendor).to_string(), "date": "2026-02-01", "due_date": "2026-02-28", "vendor_ref": "V-1001", "lines": [{"description": "Office rent", "amount": "300.00", "account": "6000"}], "upload_id": vendor_invoice, "confirmed": true}), @@ -938,7 +938,7 @@ fn happy_path(name: &str) -> Mcp { .unwrap(); m.ok( "books.pay_bill", - json!({"confirmed": true, "document_id": bill, "date": "2026-02-05", "amount": "300.00", "cash_account": "1000"}), + json!({"confirmed": true, "bill": bill, "date": "2026-02-05", "amount": "300.00", "paid_from": "1000"}), ); m.ok("books.ar_aging", json!({"as_of": "2026-06-30"})); m.ok("books.ap_aging", json!({"as_of": "2026-06-30"})); @@ -946,7 +946,7 @@ fn happy_path(name: &str) -> Mcp { // P4b S1: a document voided, and the control accounts' tie-out. let dup = m.ok( "books.create_invoice", - json!({"party_id": customer, "date": "2026-02-02", "due_date": "2026-03-02", + json!({"customer": (customer).to_string(), "date": "2026-02-02", "due_date": "2026-03-02", "lines": [{"description": "Consulting, entered twice", "amount": "500.00"}], "confirmed": true}), )["id"] @@ -972,7 +972,7 @@ fn happy_path(name: &str) -> Mcp { // P4b S7: a bad debt, its evidence uploaded and filed with it. let bad = m.ok( "books.create_invoice", - json!({"party_id": customer, "date": "2026-02-03", "due_date": "2026-03-03", + json!({"customer": (customer).to_string(), "date": "2026-02-03", "due_date": "2026-03-03", "lines": [{"description": "Consulting, never paid", "amount": "400.00"}], "confirmed": true}), )["id"] @@ -1685,15 +1685,15 @@ fn run_op(m: &mut Mcp, k: &mut Known, op: &Op) { vendor_ref, } => ( "books.create_bill", - json!({"party_id": party.resolve(&k.vendors), "date": "2026-03-01", + json!({"vendor": (party.resolve(&k.vendors)).to_string(), "date": "2026-03-01", "due_date": "2026-03-31", "vendor_ref": vendor_ref, "lines": [{"description": "thing", "amount": amount, "account": "6000"}], "existing_attachment_id": k.vendor_invoice, "confirmed": true}), ), Op::PayBill { doc, amount } => ( "books.pay_bill", - json!({"confirmed": true, "document_id": doc.resolve(&k.bills), "date": "2026-03-15", "amount": amount, - "cash_account": "1000"}), + json!({"confirmed": true, "bill": doc.resolve(&k.bills), "date": "2026-03-15", "amount": amount, + "paid_from": "1000"}), ), Op::Payout { deposit } => ( "books.record_payout", @@ -1834,7 +1834,7 @@ fn inv3_other_tools_refuse_ungrammatical_amounts() { ); m.refuse( "books.create_bill", - json!({"party_id": vendor, "date": "2026-03-01", "due_date": "2026-03-31", + json!({"vendor": (vendor).to_string(), "date": "2026-03-01", "due_date": "2026-03-31", "lines": [{"description": "x", "amount": bad}]}), ); m.refuse( @@ -2591,7 +2591,7 @@ fn assigned_roles_steer_invoices() { .unwrap(); m.ok( "books.create_invoice", - json!({"party_id": customer, "date": "2026-02-01", "due_date": "2026-03-01", + json!({"customer": (customer).to_string(), "date": "2026-02-01", "due_date": "2026-03-01", "lines": [{"description": "Consulting", "amount": "500.00"}], "confirmed": true}), ); @@ -2654,7 +2654,7 @@ fn documents_void_and_tie_out_over_the_wire() { ); let inv = m.ok( "books.create_invoice", - json!({"party_id": customer, "date": "2026-02-01", "due_date": "2026-03-01", + json!({"customer": (customer).to_string(), "date": "2026-02-01", "due_date": "2026-03-01", "lines": [{"description": "Consulting", "amount": "500.00"}], "confirmed": true}), )["id"] @@ -2662,8 +2662,8 @@ fn documents_void_and_tie_out_over_the_wire() { .unwrap(); let paid = m.ok( "books.receive_payment", - json!({"confirmed": true, "document_id": inv, "date": "2026-02-10", "amount": "200.00", - "cash_account": "1000", "instrument": "Harbor checking", "reference": "tr_8812"}), + json!({"confirmed": true, "invoice": inv, "date": "2026-02-10", "amount": "200.00", + "deposit_to": "1000", "instrument": "Harbor checking", "reference": "tr_8812"}), ); assert_eq!(paid["remaining"], "300.00", "{paid}"); assert_eq!(paid["status"], "partial", "{paid}"); @@ -2685,7 +2685,7 @@ fn documents_void_and_tie_out_over_the_wire() { let dup = m.ok( "books.create_invoice", - json!({"party_id": customer, "date": "2026-02-02", "due_date": "2026-03-02", + json!({"customer": (customer).to_string(), "date": "2026-02-02", "due_date": "2026-03-02", "lines": [{"description": "Consulting, entered twice", "amount": "500.00"}], "confirmed": true}), )["id"] @@ -2753,7 +2753,7 @@ fn documents_list_and_timeline_over_the_wire() { let invoice = |m: &mut Mcp, date: &str, due: &str, amount: &str| { m.ok( "books.create_invoice", - json!({"party_id": customer, "date": date, "due_date": due, + json!({"customer": (customer).to_string(), "date": date, "due_date": due, "lines": [{"description": "Consulting", "amount": amount}], "confirmed": true}), )["id"] @@ -2764,7 +2764,7 @@ fn documents_list_and_timeline_over_the_wire() { let later = invoice(&mut m, "2026-02-05", "2026-04-30", "80.00"); let pay = m.ok( "books.receive_payment", - json!({"confirmed": true, "document_id": late, "date": "2026-02-10", "amount": "200.00", "cash_account": "1000"}), + json!({"confirmed": true, "invoice": late, "date": "2026-02-10", "amount": "200.00", "deposit_to": "1000"}), )["entry_id"] .as_u64() .unwrap(); diff --git a/crates/ledger-cli/tests/spec_parties.rs b/crates/ledger-cli/tests/spec_parties.rs index 00e6661..bea7d00 100644 --- a/crates/ledger-cli/tests/spec_parties.rs +++ b/crates/ledger-cli/tests/spec_parties.rs @@ -835,15 +835,15 @@ fn party_totals_match_a_hand_computed_year() { ); let bill = m.ok( "books.create_bill", - json!({"party_id": v, "date": "2026-07-01", "due_date": "2026-07-31", + json!({"vendor": (v).to_string(), "date": "2026-07-01", "due_date": "2026-07-31", "vendor_ref": "D-1041", "lines": [{"description": "Logo", "amount": "800.00", "account": "6000"}], "upload_id": logo_invoice, "confirmed": true}), ); let pay = m.ok( "books.pay_bill", - json!({"confirmed": true, "document_id": bill["id"], "date": "2026-07-15", "amount": "300.00", - "cash_account": "1000"}), + json!({"confirmed": true, "bill": bill["id"], "date": "2026-07-15", "amount": "300.00", + "paid_from": "1000"}), )["entry_id"] .as_u64() .unwrap(); @@ -917,14 +917,14 @@ fn party_totals_for_a_customer_a_member_and_a_prepaid() { .unwrap(); let inv = m.ok( "books.create_invoice", - json!({"party_id": c, "date": "2026-03-01", "due_date": "2026-03-31", + json!({"customer": (c).to_string(), "date": "2026-03-01", "due_date": "2026-03-31", "lines": [{"description": "Work", "amount": "1000.00"}], "confirmed": true}), ); let pay = m.ok( "books.receive_payment", - json!({"confirmed": true, "document_id": inv["id"], "date": "2026-03-20", "amount": "600.00", - "cash_account": "1000"}), + json!({"confirmed": true, "invoice": inv["id"], "date": "2026-03-20", "amount": "600.00", + "deposit_to": "1000"}), )["entry_id"] .as_u64() .unwrap(); diff --git a/crates/ledger-cli/tests/spec_projects.rs b/crates/ledger-cli/tests/spec_projects.rs index 04522bb..26cdc2b 100644 --- a/crates/ledger-cli/tests/spec_projects.rs +++ b/crates/ledger-cli/tests/spec_projects.rs @@ -1231,7 +1231,7 @@ fn invoice_and_bill_lines_count_toward_their_projects() { ); let inv = m.ok( "books.create_invoice", - json!({"party_id": cedar, "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ + json!({"customer": (cedar).to_string(), "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ {"description": "Design", "amount": "3000.00", "class": "Zeta site"}, {"description": "Hosting", "amount": "200.00", "class": harbor.to_string()}, {"description": "Rush fee", "amount": "100.00"}, @@ -1264,7 +1264,7 @@ fn invoice_and_bill_lines_count_toward_their_projects() { ); let bill = m.ok( "books.create_bill", - json!({"party_id": dana_vendor, "date": "2026-03-09", "due_date": "2026-04-08", + json!({"vendor": (dana_vendor).to_string(), "date": "2026-03-09", "due_date": "2026-04-08", "vendor_ref": "DANA-77", "lines": [ {"description": "Illustration", "amount": "1200.00", "account": "6000", "class": "Zeta site"}, @@ -1284,11 +1284,11 @@ fn invoice_and_bill_lines_count_toward_their_projects() { // Payments are balance-sheet only: no project. let got = m.ok( "books.receive_payment", - json!({"confirmed": true, "document_id": inv["id"], "date": "2026-03-20", "amount": "3800.00", "cash_account": "1000"}), + json!({"confirmed": true, "invoice": inv["id"], "date": "2026-03-20", "amount": "3800.00", "deposit_to": "1000"}), ); let paid = m.ok( "books.pay_bill", - json!({"confirmed": true, "document_id": bill["id"], "date": "2026-03-30", "amount": "1250.00", "cash_account": "1000"}), + json!({"confirmed": true, "bill": bill["id"], "date": "2026-03-30", "amount": "1250.00", "paid_from": "1000"}), ); for e in [&got["entry_id"], &paid["entry_id"]] { let e = e.as_u64().unwrap(); @@ -1356,7 +1356,7 @@ fn a_document_naming_an_unknown_project_is_refused_whole() { for (tool, party) in [("books.create_invoice", &cedar), ("books.create_bill", &v)] { let why = m.refuse( tool, - json!({"party_id": party, "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ + json!({"customer": (party).to_string(), "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ {"description": "a", "amount": "10.00", "class": "Zeta site"}, {"description": "b", "amount": "10.00", "class": "Nowhere"}, ]}), @@ -1379,7 +1379,7 @@ fn a_document_for_a_finished_project_says_so() { let cedar = m.ok("books.add_customer", json!({"name": "Cedar"}))["id"].clone(); let out = m.ok( "books.create_invoice", - json!({"party_id": cedar, "date": "2026-10-05", "due_date": "2026-11-04", "lines": [ + json!({"customer": (cedar).to_string(), "date": "2026-10-05", "due_date": "2026-11-04", "lines": [ {"description": "Final", "amount": "10.00", "class": "Harbor"}, {"description": "Again", "amount": "10.00", "class": "harbor"}, {"description": "Old", "amount": "10.00", "class": "Dock"}, @@ -1424,7 +1424,7 @@ fn an_invoice_for_an_on_spec_project_asks_about_an_agreement() { let v = m.ok("books.add_vendor", json!({"name": "Dana"}))["id"].clone(); let out = m.ok( "books.create_invoice", - json!({"party_id": cedar, "date": "2026-10-05", "due_date": "2026-11-04", "lines": [ + json!({"customer": (cedar).to_string(), "date": "2026-10-05", "due_date": "2026-11-04", "lines": [ {"description": "Build", "amount": "10.00", "class": "Kestrel"}, {"description": "More", "amount": "5.00", "class": "kestrel"}, {"description": "Site", "amount": "7.00", "class": "Zeta"}, @@ -1450,7 +1450,7 @@ fn an_invoice_for_an_on_spec_project_asks_about_an_agreement() { ); let bill = m.ok( "books.create_bill", - json!({"party_id": v, "date": "2026-10-05", "due_date": "2026-11-04", + json!({"vendor": (v).to_string(), "date": "2026-10-05", "due_date": "2026-11-04", "vendor_ref": "V-512", "lines": [ {"description": "Icons", "amount": "10.00", "account": "6000", "class": "Kestrel"}, @@ -1475,7 +1475,7 @@ fn books_without_the_feature_refuse_a_tagged_document() { for (tool, party) in [("books.create_invoice", &cedar), ("books.create_bill", &v)] { let why = m.refuse( tool, - json!({"party_id": party, "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ + json!({"customer": (party).to_string(), "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ {"description": "a", "amount": "10.00", "class": "Zeta site"}, ]}), ); @@ -1487,7 +1487,7 @@ fn books_without_the_feature_refuse_a_tagged_document() { assert_eq!(m.journal(), head, "nothing journaled"); m.ok( "books.create_invoice", - json!({"party_id": cedar, "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ + json!({"customer": (cedar).to_string(), "date": "2026-03-02", "due_date": "2026-04-01", "lines": [ {"description": "a", "amount": "10.00"}, ], "confirmed": true}), ); diff --git a/crates/ledger-cli/tests/spec_tax_policy.rs b/crates/ledger-cli/tests/spec_tax_policy.rs index c4e7433..cc9339e 100644 --- a/crates/ledger-cli/tests/spec_tax_policy.rs +++ b/crates/ledger-cli/tests/spec_tax_policy.rs @@ -278,7 +278,7 @@ fn require_tax_category_refuses_defect_8() { ); let bill = m.call( "books.create_bill", - json!({"party_id": vendor["id"], "date": "2026-02-01", "due_date": "2026-03-01", + json!({"vendor": (vendor["id"]).to_string(), "date": "2026-02-01", "due_date": "2026-03-01", "vendor_ref": "CH-1", "lines": [{"description": "hosting", "amount": "42.00", "account": "6150"}], "upload_id": first_invoice, "confirmed": true}), @@ -303,7 +303,7 @@ fn require_tax_category_refuses_defect_8() { ); let again = m.call( "books.create_bill", - json!({"party_id": vendor["id"], "date": "2026-02-02", "due_date": "2026-03-02", + json!({"vendor": (vendor["id"]).to_string(), "date": "2026-02-02", "due_date": "2026-03-02", "vendor_ref": "CH-2", "lines": [{"description": "hosting", "amount": "1.00", "account": "6150"}], "upload_id": second_invoice, "confirmed": true}), diff --git a/crates/ledger-mcp/src/tools/documents.rs b/crates/ledger-mcp/src/tools/documents.rs index 56178db..c5cc3ed 100644 --- a/crates/ledger-mcp/src/tools/documents.rs +++ b/crates/ledger-mcp/src/tools/documents.rs @@ -455,17 +455,7 @@ impl BooksServer { ) -> Result, String> { let p = params.0; let mut store = self.lock()?; - let customer = match (&p.customer, p.party_id) { - (Some(c), None) => c.trim().to_string(), - (None, Some(id)) => id.to_string(), - (Some(c), Some(id)) if c.trim() == id.to_string() => c.trim().to_string(), - (Some(_), Some(_)) => { - return Err("give the customer once: customer or party_id, not both".into()); - } - (None, None) => { - return Err("give customer: a customer id, a party id or a name".into()); - } - }; + let customer = p.customer.trim().to_string(); let customer_id = resolve_customer(&store, &customer)?; let date = parse_date(&p.date)?; let lines = document_lines(&store, p.lines)?; @@ -606,17 +596,7 @@ impl BooksServer { ) -> Result, String> { let p = params.0; let mut store = self.lock()?; - let vendor = match (&p.vendor, p.party_id) { - (Some(v), None) => v.trim().to_string(), - (None, Some(id)) => id.to_string(), - (Some(v), Some(id)) if v.trim() == id.to_string() => v.trim().to_string(), - (Some(_), Some(_)) => { - return Err("give the vendor once: vendor or party_id, not both".into()); - } - (None, None) => { - return Err("give vendor: a vendor id, a party id or a name".into()); - } - }; + let vendor = p.vendor.trim().to_string(); let vendor_id = resolve_vendor_arg(&store, &vendor)?; let date = parse_date(&p.date)?; let received_on = p.received_on.as_deref().map(parse_date).transpose()?; diff --git a/crates/ledger-mcp/src/tools/settlements.rs b/crates/ledger-mcp/src/tools/settlements.rs index 5aef5c5..8806f05 100644 --- a/crates/ledger-mcp/src/tools/settlements.rs +++ b/crates/ledger-mcp/src/tools/settlements.rs @@ -39,35 +39,17 @@ fn doc_party(ledger: &Ledger, doc: ledger_core::DocRef) -> Result { } } -/// The one id a payment tool's single form names: `invoice`/`bill`, or -/// the older `document_id`. Both at once is refused unless they agree. -fn single_document(primary: Option, alias: Option, what: &str) -> Result { - match (primary, alias) { - (Some(a), Some(b)) if a != b => Err(format!( - "pass {what} or document_id, not both: {} and {b} differ", - a - )), - (Some(id), _) | (None, Some(id)) => Ok(id), - (None, None) => Err(format!( - "pass {what} (or an applications list): see books.documents" - )), - } +/// The one id a payment tool's single form names: `invoice` or `bill`. +fn single_document(primary: Option, what: &str) -> Result { + primary.ok_or_else(|| format!("pass {what} (or an applications list): see books.documents")) } -/// The one account a payment tool's single form names: `deposit_to`/ -/// `paid_from`, or the older `cash_account`. -fn single_account( - primary: &Option, - alias: &Option, - what: &str, -) -> Result { - match (primary, alias) { - (Some(a), Some(b)) if a != b => Err(format!( - "pass {what} or cash_account, not both: {a:?} and {b:?} differ" - )), - (Some(a), _) | (None, Some(a)) => Ok(a.clone()), - (None, None) => Err(format!("pass {what} (or cash_account)")), - } +/// The one account a payment tool's single form names: `deposit_to` or +/// `paid_from`. +fn single_account(primary: &Option, what: &str) -> Result { + primary + .clone() + .ok_or_else(|| format!("pass {what}: the account the cash moves through")) } /// Every document a payment tool's parameters name, as the core takes @@ -128,7 +110,6 @@ fn applications( } let id = single_document( if invoices { p.invoice } else { p.bill }, - p.document_id, if invoices { "invoice" } else { "bill" }, )?; let amount = p @@ -178,7 +159,6 @@ fn settlement( } else { &p.paid_from }, - &p.cash_account, if invoices { "deposit_to" } else { "paid_from" }, )?, )?; diff --git a/crates/ledger-mcp/src/types.rs b/crates/ledger-mcp/src/types.rs index 42642c9..0dc3318 100644 --- a/crates/ledger-mcp/src/types.rs +++ b/crates/ledger-mcp/src/types.rs @@ -3265,10 +3265,7 @@ pub struct CreateInvoiceParams { pub preview: Option, /// The customer: a customer id, its party's id, or its name. A name /// that two customers answer to is refused. - pub customer: Option, - /// The old spelling of `customer` (accepted until P5): a customer id. - #[serde(default)] - pub party_id: Option, + pub customer: String, /// The invoice date, YYYY-MM-DD. pub date: String, /// Its payment terms ("Net 30", "Net 15 EOM", "2/10 net 30", "Due on @@ -3300,10 +3297,7 @@ pub struct CreateBillParams { pub preview: Option, /// The vendor: a vendor id, its party's id, or its name. A name that /// two vendors answer to is refused. - pub vendor: Option, - /// The old spelling of `vendor` (accepted until P5): a vendor id. - #[serde(default)] - pub party_id: Option, + pub vendor: String, /// The bill's date, YYYY-MM-DD. pub date: String, /// The day the bill was received, when it differs from its date. @@ -3383,10 +3377,6 @@ pub struct PaymentParams { /// preview: nothing posts. #[serde(default)] pub confirmed: Option, - /// Invoice id (receive_payment) or bill id (pay_bill); the older name - /// of `invoice` / `bill`. - #[serde(default)] - pub document_id: Option, /// The invoice, by id (books.receive_payment). #[serde(default)] pub invoice: Option, @@ -3399,10 +3389,6 @@ pub struct PaymentParams { /// applications' amounts are the cash; a discount is beside it. #[serde(default)] pub amount: Option, - /// Cash account id or code; the older name of `deposit_to` / - /// `paid_from`. - #[serde(default)] - pub cash_account: Option, /// The account the cash reaches (receive_payment): a bank or card that /// holds no role. #[serde(default)] diff --git a/docs/mcp-interface.md b/docs/mcp-interface.md index 688be57..d91f42b 100644 --- a/docs/mcp-interface.md +++ b/docs/mcp-interface.md @@ -2195,8 +2195,8 @@ snapshots; see plan 8.2 S4. receivable line tagged with the invoice and the receivable side one line per (account, project) part. - `customer` is the customer's id, its party's id or its name (a name - two customers answer to is refused); `party_id` is the old spelling of - the same thing (a customer id), kept until P5. + two customers answer to is refused); it is required (the old `party_id` + spelling is gone, P5). - The due date: `due_date` as given (and it overrides `terms`); else `terms` ("Net 30", "Net 15 EOM", "2/10 net 30", "Due on receipt", "Due 2026-11-15", rules.md B-39); else the customer's @@ -2247,8 +2247,8 @@ snapshots; see plan 8.2 S4. sha256 }, warnings?, notes? }`. Confirmed it posts Dr each line's account / Cr `2000` Accounts Payable, the payable line tagged with the bill and one debit line per (account, - project) part; `vendor` is a vendor id, its party's id or its name, and - `party_id` the old spelling (a vendor id). + project) part; `vendor` is a vendor id, its party's id or its name + (required; the old `party_id` spelling is gone, P5). - `vendor_ref` is the vendor's own invoice number: required in books that have declared `documents_v2` (B-40). The same vendor and number twice is refused unless `duplicate_reason` says why, which is @@ -2271,8 +2271,8 @@ snapshots; see plan 8.2 S4. - `warnings` names an expense account it created with no tax category; `notes` one per finished or abandoned project a line names (none for on-spec: a cost of on-spec work is an expense like any other). -- `books.receive_payment { date, deposit_to | cash_account, instrument?, - reference?, invoice | document_id, amount? | applications: [{ invoice, +- `books.receive_payment { date, deposit_to, instrument?, + reference?, invoice, amount? | applications: [{ invoice, amount, discount?, discount_reason? }], fee?: { amount, account?, vendor? }, paid_in_full_marking?, confirmed?, preview? }` → `{ preview?, entry_id, documents: [{ ref, number?, outstanding, status }], deposited, @@ -2294,11 +2294,11 @@ snapshots; see plan 8.2 S4. repeat the single document's figures. An overpayment is refused with the excess and the remedy (a plain entry to 2300 Customer Deposits). `paid_in_full_marking: true` adds a UCC §3-311 warning and records - nothing else. `document_id` and `cash_account` are the older names of - `invoice`/`bill` and `deposit_to`/`paid_from`. The books record + nothing else. (The older names `document_id` and `cash_account` are + gone, P5.) The books record payments; they never collect them (D-45). -- `books.pay_bill { date, paid_from | cash_account, instrument?, - reference?, bill | document_id, amount? | applications: [{ bill, amount, +- `books.pay_bill { date, paid_from, instrument?, + reference?, bill, amount? | applications: [{ bill, amount, discount?, discount_reason? }], confirmed?, preview? }` → as `receive_payment`, per bill and one vendor (B-42): Dr A/P each bill's cash and discount, Cr the payer account the cash, Cr purchase discounts the discounts. A discount on a