feat(settings): invoicing, bills and contact settings (P4b S4.2)

Eleven settings the invoice and bill workflow reads: the number prefix and
first number, default terms, payment methods with their bank details and
QR links, a footer, the unsent and reminder day counts, the bill reminder
and discount-warning day counts, and the company's email and website that
the seller snapshot prints.

Three new kinds keep them exact: a count is a positive whole number, terms
are canonicalized through Terms so "net 30" is stored once as "Net 30"
(B-39), and a payment method list admits at most eight methods whose lines
are at most 120 characters. A routing number is nine digits, so an ach or
wire method's bank-detail lines are the one text exempt from the full-TIN
check (A-3); every other text in a method is scanned.

The keys need the documents_v2 feature (D-52): an older version doesn't
know them, and the settings replay refuses an unknown key as newer. The
constant, the known-features entry and the gate test land with this slice
(its 8.0.6 work); S4.3 adds the document write call sites and must not
redeclare them.

A settings file now exports the [invoicing] and [bills] tables, a payment
method as an inline table (never a [[payment_methods]] section that would
land outside its table), and imports them back to the same values. The
unknown-key test uses fax instead of website, which is now a setting.
This commit is contained in:
swaits committed 2026-10-27 03:44:24 -06:00
1 parent 6995ebfee6
commit 1fa77cff02
5 files changed
+591 -24

No files matched your search

+19
View File
@@ -70,6 +70,25 @@ fn candidates() -> Vec<(&'static str, Value)> {
("policy.evidence.exempt_accounts", json!(["6999", "6998"])),
("policy.parties", json!("require")),
("policy.approval_rules", json!("enforce")),
// P4b S4.2: invoicing, bills and contact details.
("invoicing.number_prefix", json!("ACME-")),
("invoicing.first_number", json!(1000)),
("invoicing.default_terms", json!("2/10 net 30")),
("invoicing.default_terms", json!("Net 15 EOM")),
(
"invoicing.payment_methods",
json!([{"kind": "ach", "label": "Bank transfer",
"lines": ["Routing 123456789", "Account 000123456789"]},
{"kind": "link", "label": "Card", "lines": [],
"link": "https://pay.example/acme", "qr": true}]),
),
("invoicing.footer", json!("Thank you for your business.")),
("invoicing.unsent_days", json!(2)),
("invoicing.reminder_days", json!(14)),
("bills.remind_days", json!(7)),
("bills.discount_warn_days", json!(3)),
("company.email", json!("billing@acme.example")),
("company.website", json!("https://acme.example")),
]
}