refactor(settings): the slice's contracts and notes (P4b S4.2)

invoicing.first_number's refusal (LedgerError::FirstNumberLocked) lands
as the contract the store's check raises once invoices carry numbers
(S4.3): a series that has begun is never renumbered (B-40, A-2).

Also: the settings invariants name the number prefix's bound, update_party's
doc says which facts wait for documents_v2, and the email check no longer
reads as a single-arm match. Terms is S4.1's as it landed; this slice no
longer carries a copy.
This commit is contained in:
swaits committed 2026-10-27 03:44:24 -06:00
1 parent 02cb7f0254
commit 962b52c991
4 files changed
+19 -5

No files matched your search

+9
View File
@@ -655,6 +655,15 @@ pub enum LedgerError {
)] )]
TermsDiscountNeedsNetDays, TermsDiscountNeedsNetDays,
/// `invoicing.first_number` asked to move after a numbered invoice
/// exists: the series has begun, and a number is never reused or
/// renumbered (rules.md B-40, A-2). The store's check lands with the
/// invoice numbers it reads (P4b S4.3).
#[error(
"invoicing.first_number is locked: a numbered invoice already exists, so the series has begun and its numbers are never reused"
)]
FirstNumberLocked,
/// A date computed from another (payment terms' due or discount date) /// A date computed from another (payment terms' due or discount date)
/// falls past the calendar the books keep. /// falls past the calendar the books keep.
#[error( #[error(
+4 -5
View File
@@ -4702,12 +4702,11 @@ impl Ledger {
} }
} }
Archived(true) => {} Archived(true) => {}
Email(v) => match v { Email(v) => {
Some(e) => { if let Some(e) = v {
crate::parties::check_email("email", e).map_err(LedgerError::InvalidParty)? crate::parties::check_email("email", e).map_err(LedgerError::InvalidParty)?;
} }
None => {} }
},
// Terms are typed and already canonical (`crate::Terms`), so // Terms are typed and already canonical (`crate::Terms`), so
// there is nothing here a string could get wrong. // there is nothing here a string could get wrong.
DefaultTermsAsCustomer(_) | DefaultTermsAsVendor(_) => {} DefaultTermsAsCustomer(_) | DefaultTermsAsVendor(_) => {}
+2
View File
@@ -40,6 +40,8 @@
//! `lines`) are the one text the full-TIN check doesn't scan, because //! `lines`) are the one text the full-TIN check doesn't scan, because
//! a routing number is nine digits (A-3); every other text in the //! a routing number is nine digits (A-3); every other text in the
//! list is scanned. //! list is scanned.
//! 8. An invoice number's prefix is 1 to 12 visible ASCII characters:
//! longer, blank or holding a space would not read as one number.
//! ``` //! ```
use crate::TaxForm; use crate::TaxForm;
+4
View File
@@ -1597,6 +1597,10 @@ impl Store {
} }
/// Change one of a party's facts. Journaled as `party.updated`. /// Change one of a party's facts. Journaled as `party.updated`.
///
/// An email or a default terms fact needs the `documents_v2` feature
/// (plan P4b S4.2): books that haven't declared it refuse the write
/// with the upgrade remedy, journaling nothing.
pub fn update_party( pub fn update_party(
&mut self, &mut self,
id: ledger_core::PartyId, id: ledger_core::PartyId,