1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//! # en16931 — the European e-invoice, as Rust types
//!
//! `billing` proves an invoice is *arithmetically* correct. This crate proves it
//! is *legally meaningful*: it holds the EN 16931 semantic data model, decides
//! what the standard and its national usage specifications demand, and hands a
//! proof of that decision to the syntax layer.
//!
//! **It never emits a byte of XML.** UBL, CII and PDF/A-3 belong to `xrechnung`
//! and `zugferd`; the 1 339 syntax-binding rules belong with them. This crate
//! owns the 222 that are syntax-independent, which are the only ones it can
//! meaningfully check.
//!
//! ## Validate the model, not the document
//!
//! Every other implementation in this space is *XML in, Schematron out*, so the
//! loop is build → serialise → validate → parse the error → guess which field it
//! meant. Here a finding points at `lines[3]` BT-151, and you can validate an
//! invoice you are still assembling.
//!
//! ## Design invariants
//!
//! - **No `f64`.** Amounts are fixed-point; rates and quantities are `Decimal`.
//! - **No I/O, no async, no `unsafe`** — so `wasm32` works, and an invoice never
//! has to leave the client.
//! - **Rounding is never implicit.** An amount that does not fit two decimals is
//! an error, not a rounding opportunity. Reduce precision at the source.
//! - **Mandatory means non-`Option`.** Where EN 16931 says 1..1, the type says
//! so. Rules exist for the cardinalities the type system cannot express, not
//! as a substitute for it.
//! - **Invariants survive deserialisation**, via `#[serde(try_from = ...)]` —
//! asserted in `tests/serde_invariants.rs`, not merely intended.
//!
//! ## The ten semantic data types
//!
//! EN 16931-1 §6.5 defines exactly ten, and every one of the 164 business terms
//! has one. Mirroring them one-for-one is the crate's organising principle, so
//! "which Rust type does BT-*n* get?" is a lookup in Table 2 rather than a
//! judgement call.
//!
//! | §6.5 | Semantic type | Here |
//! |---|---|---|
//! | 6.5.2 | Amount | [`InvoiceAmount`] — `i64` minor units, no third decimal |
//! | 6.5.3 | Unit Price Amount | [`UnitPriceAmount`] — `Decimal`, **no** cap |
//! | 6.5.4 | Quantity | [`Quantity`] — `Decimal`, may be negative |
//! | 6.5.5 | Percentage | [`Percentage`] — per cent (`19`), not a fraction |
//! | 6.5.6 | Identifier | [`Identifier`] — content + scheme + scheme **version** |
//! | 6.5.7 | Document Reference | [`DocumentReference`] — deliberately no scheme |
//! | 6.5.8 | Code | [`codes`] — 4 887 values, generated and re-verified |
//! | 6.5.9 | Date | [`Date`] — a calendar day, no time of day |
//! | 6.5.10 | Text | `String` — 62 of the 164 terms |
//! | 6.5.11 | Binary Object | [`Attachment`] — mime and filename mandatory |
//!
//! ## Status
//!
//! The ten semantic data types, all eighteen code lists, the [`invoice`] model,
//! and a [`validation`] engine that registers **all 223 syntax-independent
//! rules** of the pinned CEN artefacts — every `BR-*`, `BR-CO-*`, `BR-CL-*` and
//! all nine VAT category families. `tests/codelists.rs` asserts that 223 against
//! the artefacts on any machine that has them, so it is measured rather than
//! claimed.
//!
//! Of the **316** rules registered across every shipped profile:
//!
//! | | | |
//! |---|---:|---|
//! | retired by the types | 53 | no state can make them fire — `BT-112` is not an `Option` |
//! | undecidable | 4 | `BR-CO-05`…`-08`; **CEN's own binding is `value="true()"`** |
//! | checkable | 259 | **every one exercised by its own failing fixture** |
//!
//! And the profile rule sets are complete against *their* authorities too,
//! asserted the same way:
//!
//! | [`profiles`] | Rules run | Artefact coverage |
//! |---|---:|---|
//! | EN 16931 core | 225 | 223 / 223 CEN syntax-independent |
//! | XRechnung 3.0 | 280 | **55 / 55** KoSIT asserts + **21 / 21** merged Peppol |
//! | XRechnung 3.0 CVD | 287 | + all 8 Clean Vehicles Directive rules |
//! | XRechnung 3.0 Extension | 289 | + all 14 `BR-DEX-*` |
//! | Peppol BIS Billing 3.0 | 271 | **46 / 46** `PEPPOL-EN16931-*` |
//!
//! And the rules agree with the authorities' **own conformance suites**, not
//! only with their rule lists: 1 017 of CEN's unit-test assertions, all 382
//! runnable KoSIT mutations, and all 58 published example invoices — 100 % on
//! each. See `tests/conformance.rs`.
//!
//! Each comes with the typed [`Validated`] proof, and there is a `billing`
//! adapter. Checked against the standard's own Annex A worked examples.
//!
//! A five-line invoice validates in **1.5 µs** through the core rules and under
//! 5 µs through XRechnung's 280; `proptest` properties assert validation never
//! panics, is deterministic, and never cites an unresolvable rule id.
//!
//! Out of scope, deliberately and named rather than quietly dropped: the 1 339
//! *syntax* rules (`UBL-*`, `CII-*`) belong to `en16931-formats`, and Peppol's
//! ~90 national rules (`DK-R-*`, `SE-R-*`, …) are country registry-format and
//! check-digit checks. See
//! `FEEDBACK_BILLING.md` for the upstream work it rests on.
//!
//! ```
//! use en16931::{validate, prelude::*};
//!
//! let invoice = Invoice::default(); // nothing filled in
//! let report = validate(&invoice);
//!
//! assert!(!report.is_valid());
//! assert!(report.has("BR-02")); // no invoice number
//! assert!(report.has("BR-16")); // no invoice line
//! // Findings point at business terms, never at an XPath.
//! assert_eq!(report.fatal().next().unwrap().path.to_string(), "BT-1");
//! ```
//!
//! ## Attribution
//!
//! This crate is an implementation of the semantic data model of EN 16931-1 and
//! of the two mandatory syntaxes listed in CEN/TS 16931-2. EN 16931-1 and
//! CEN/TS 16931-2 are made available free of charge by CEN and the European
//! Commission under their 2018 licence agreement, which permits derivative use
//! on condition that derivative applications carry a statement to this effect.
//! Copyright in the standard remains with CEN.
//!
//! ## README
//!
//! The crate README is included below, so **every Rust example in it is compiled
//! and run as a doctest**. Documentation that drifts out of compiling is the
//! most expensive kind, and this makes that class of rot impossible.
pub use ;
pub use ;
pub use ;
pub use VatCategory;
pub use Date;
pub use Edition;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use Report;
pub use ;
pub use ;
/// The notice the CEN–EC licence agreement **requires** this crate to carry.
///
/// # Not decoration — a licence condition
///
/// EN 16931-1 and CEN/TS 16931-2 are free of charge under the 2018 agreement
/// between CEN and the European Commission, which permits derivative use *on
/// condition* that a derivative carries a statement, visible to users, that it
/// is an implementation of the semantic data model. Everything this crate does
/// rests on that permission, so the notice appears in three places: the crate
/// documentation, `README.md`, and the header of every
/// [`ValidationReport`]'s `Display`.
///
/// It is a `const` rather than three string literals because three copies drift,
/// and `tests/attribution.rs` asserts all three still agree. Losing this by
/// reformatting would forfeit the licence the whole crate depends on, and
/// nothing else would notice.
///
/// **Written on one line on purpose.** A `\`-continued literal reads better in
/// source and `rustfmt` collapses it, keeping the indentation — which put a run
/// of 32 spaces inside the notice this crate emits. Every report carried it that
/// way, and the test did not catch it because it normalised whitespace on *both*
/// sides. The constant is canonical now, and
/// `the_notice_is_canonical_not_merely_present` asserts it.
pub const ATTRIBUTION: &str = "implementation of the EN 16931-1 semantic data model; © CEN, used under the 2018 CEN–EC licence agreement";
/// The CEN validation-artefacts release this crate's rule metadata and code
/// lists are generated from.
///
/// Exposed so a bug report can say which rule text was in force. The artefacts
/// and the standard do not always agree — so knowing
/// which artefact revision produced a finding is part of reproducing it.
pub const ARTEFACT_VERSION: &str = "validation-1.3.16";
/// The edition of EN 16931-1 this crate's core rule set targets by default.
///
/// EN 16931-1:2026 is published and the 2017 edition formally withdrawn, but
/// every deployed validator — XRechnung 3.0.2, Peppol BIS Billing 3.0,
/// ZUGFeRD 2.x — is a usage specification of 2017+A1:2019. Leading with :2026
/// would produce a crate that fails all of them. See [`Edition`].
pub const DEFAULT_EDITION: Edition = En2017A1;
/// Convenience glob import.