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

+24
View File
@@ -62,6 +62,7 @@ pub const KNOWN_FEATURES: &[&str] = &[
PROJECTS,
DOCUMENT_LINE_PROJECTS,
DOCUMENT_STANDING,
DOCUMENTS_V2,
];
/// Feature: `period.closed` closes to members with `"rounding":
@@ -88,6 +89,19 @@ pub(crate) fn setting_feature(key: &str) -> Option<&'static str> {
match key {
"policy.require_tax_category" => Some(FEATURE_REQUIRE_TAX_CATEGORY),
"books.schedule_convention" => Some(SCHEDULE_CONVENTION),
// P4b S4.2: the invoicing and bills settings, and the company's
// contact details an invoice's seller snapshot reads.
"invoicing.number_prefix"
| "invoicing.first_number"
| "invoicing.default_terms"
| "invoicing.payment_methods"
| "invoicing.footer"
| "invoicing.unsent_days"
| "invoicing.reminder_days"
| "bills.remind_days"
| "bills.discount_warn_days"
| "company.email"
| "company.website" => Some(DOCUMENTS_V2),
_ => None,
}
}
@@ -174,6 +188,16 @@ pub const DOCUMENT_LINE_PROJECTS: &str = "document_line_projects";
/// Every other payment is written as before and needs no feature.
pub const DOCUMENT_STANDING: &str = "document_standing";
/// Feature: `documents_v2` (D-52; plan P4b S4 to S7): an `invoice.created`
/// or `bill.created` carrying a number, terms, snapshots, references or
/// line accounts; a `party.updated` with an email or default terms; a
/// `settings.set` of the invoicing or bills keys or the company's contact
/// details. S4.2 writes the settings and party fields; S4.3 to S7 add the
/// document fields, sends, settlements and write-offs. An older version
/// would drop the line accounts (posting to the role accounts), the
/// discount and the fee, or refuse the unknown values, silently.
pub const DOCUMENTS_V2: &str = "documents_v2";
/// The line type that declares the journal format.
pub const FORMAT_SET: &str = "journal.format_set";