Skip to content

EN 16931 e-invoices (khata-en16931)

crates/khata-en16931 is a pure, country-neutral crate for the European standard on electronic invoicing, EN 16931: a semantic invoice model, its core business rules as checks, and writers for the standard's two syntaxes. A country pack maps its books' invoice to the model; Germany does so in khata_de::xrechnung (see docs/germany-vat.md).

Sources: the CEN/TC 434 validation artefacts, github.com/ConnectingEurope/eInvoicing-EN16931 (EUPL 1.2): Schematron ubl/schematron/abstract/EN16931-model.sch (rule texts), ubl/schematron/UBL/EN16931-UBL-model.sch (tests and tolerances), the code lists, the D16B CII subset schemas and example invoices; the OASIS UBL 2.1 schemas (docs.oasis-open.org/ubl/os-UBL-2.1); KoSIT's XRechnung Schematron v2.6.0 and docs.peppol.eu for the CIUS identifiers (docs/research/germany-compliance.md §9 to §11). The EN 16931-1 text itself is a paid CEN standard and was not read.

Use

let mut inv = Invoice::new("RE-1", date, TypeCode::Commercial, "EUR");
inv.seller = …; inv.buyer = …; inv.lines = …;   // BT/BG fields
inv.finalise();                                  // BG-23 and BG-22
let problems = validate_for(&inv, Specification::XRechnung3);
let xml = ubl::write(&inv, Specification::XRechnung3);   // or cii::write

The writers do not validate: write only an invoice whose fatal violations (rules::fatal) are empty, or show them to the user.

Model (model.rs)

Group / term Field
BT-1, 2, 3, 5 number, issue_date, type_code (380, 381, 384, 389, 326), currency
BT-7, 9, 10, 13, 20, BG-1/BT-22 tax_point_date, due_date, buyer_reference, order_reference, payment_terms, notes
BG-3 (BT-25, 26) preceding
BG-4 Seller (BT-27, 28, 30, 31, 32, 34, BG-5, BG-6) seller: Party (name, trading name, legal id, VAT id, tax registration, electronic address, address, contact)
BG-7 Buyer (BT-44 ff.) buyer: Party
BT-72, 80, BG-14 delivery_date, deliver_to_country, period
BG-16, BG-17 (BT-81 to 86) payment: PaymentInstructions (means code, text, remittance, IBAN/name/BIC)
BG-20, BG-21 allowances_charges (amount, base, percent, category, rate, reason, reason code)
BG-22 (BT-106 to 115) totals
BG-23 (BT-116 to 121) vat_breakdown
BG-25 (BT-126 to 131, 146, 149, 151 to 155) lines

VAT categories (BT-118/151): S, Z, E, AE, K, G, O, L, M, with their rule names. units::rec20 maps free-text unit symbols to UN/ECE Rec 20 codes (BT-130), all from the artefacts' code list.

Not modelled: payee (BG-10), tax representative (BG-11), deliver-to address (BG-15), line allowances/charges (BG-27/28), item attributes and classifications, attachments (BG-24), card and direct-debit payment (BG-18/19), accounting-currency VAT (BT-6/111), Skonto.

Invoice::finalise works out the breakdown (one per category, and per rate for S/L/M; taxable = lines − allowances + charges; tax = taxable × rate ÷ 100 rounded to two decimals, half away from zero) and the totals, keeping exemption reasons given beforehand (VatBreakdown::exemption) and adding the CEF VATEX defaults for AE (VATEX-EU-AE), K (VATEX-EU-IC), G (VATEX-EU-G) and O (VATEX-EU-O) [PRIMARY: code list].

Rules (rules.rs)

validate checks the core rules; validate_for(inv, spec) adds the CIUS's. Each Violation has the rule id, a message and warning (the rule's flag is not "fatal").

  • Presence: BR-02, 05 to 11, 16, 21, 23, 25, 27, 29, 33/BR-CO-21, 38/BR-CO-22, 48, 49, 50, 61. (BR-01 is the writers'; the rest hold by construction.)
  • BR-CO-09 (VAT id prefix shape), BR-CO-10 to 18, BR-CO-19, BR-CO-26.
  • BR-DEC-*: at most two decimals on amounts.
  • Category rules -01, -02, -05/-06, -08, -09, -10 for S, Z, E, AE, K (BR-IC-*), G and O, plus BR-O-11 to 13 and BR-IC-11/12; for L and M only the rate sign.
  • BR-CO-17 and BR-S-09 accept a tax amount strictly within ±1 of taxable × rate, as the artefacts test it (the rule text says "rounded to two decimals"; finalise produces the exact value).
  • XRechnung 3.0 (rules::xrechnung), flags from the KoSIT Schematron v2.6.0 [PRIMARY]: BR-DE-1 to 9, 14, 15, 16, 23-a/b (fatal); BR-DE-17, 19 (IBAN check), 26, 27, 28 (warnings). Two more warnings under KhataOS ids, KHATA-XR-BT-34 / -BT-49: XRechnung 3.0 is reported to require the electronic addresses, but no rule was found [UNCERTAIN]. Not checked: BR-DE-10/11, 18, 22, 24, 25, 30, 31 (groups not modelled).

Not checked: the code lists (BR-CL-*), XSD validity. Run KoSIT's validator (itplr-kosit/validator-configuration-xrechnung) or the Peppol validator on real output.

Syntaxes

Specification sets BT-24 (and BT-23):

Specification CustomizationID (BT-24) ProfileID (BT-23)
En16931 urn:cen.eu:en16931:2017 —
XRechnung3 urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 [PRIMARY] urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 (optional in XRechnung [UNCERTAIN])
PeppolBis3 urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 [PRIMARY] urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 [PRIMARY]
  • UBL 2.1 (ubl.rs): Invoice, or CreditNote for type 381, in the UBL 2.1 schema order (checked against the OASIS XSDs). BT-32 is a second PartyTaxScheme with scheme FC; BT-9 on a CreditNote goes in PaymentMeans/PaymentDueDate.
  • UN/CEFACT CII D16B (cii.rs): rsm:CrossIndustryInvoice in the D16B subset order (checked against the artefacts' XSD); BT-31/32 as SpecifiedTaxRegistration with VA / FC; dates in format 102; BT-84 as IBANID (or ProprietaryID). The same XML is what a ZUGFeRD / Factur-X PDF embeds (profile EN 16931 or XRECHNUNG).
  • Category O writes no rate, except on the breakdown of an XRechnung (BR-DE-14 asks for BT-119 everywhere; the artefacts' XRechnung example writes 0).

Amounts are written with two decimals, prices, quantities and rates without trailing zeros. Text is escaped; XML-invalid control characters are dropped.

Tests

cargo test -p khata-en16931: breakdown and totals; each totals rule (BR-CO-10 to 16, BR-DEC); the tolerance of BR-CO-17/BR-S-09; S, Z, E, AE, K, G and O rules; presence and payment rules; XRechnung rules; golden XML snippets for both syntaxes (Invoice and CreditNote, allowances, exemptions, O without rate), all parsed as well-formed XML.

Peppol PINT (pint.rs)

Peppol PINT billing (the international core, urn:peppol:pint:billing-1) reuses the EN 16931 terms but not the EU VAT rules: each jurisdiction has its own tax category codes and rules. pint::PintInvoice wraps an Invoice (parties, lines, payment, totals) and carries a PINT tax category per line and per document allowance/charge (LineTax); finalise builds the breakdown from those, validate checks the shared PINT rules (ibr-*) and the jurisdiction's, and write writes UBL 2.1. Two specialisations:

PINT SG Billing 1.4.1 PINT AE Billing 1.0.4
BT-24 urn:peppol:pint:billing-1@sg-1 urn:peppol:pint:billing-1@ae-1
BT-23 urn:peppol:bis:billing urn:peppol:bis:billing
Categories SR, SRCA-S, SRCA-C, SRRC, SROVR-RS, SROVR-LVG, SRLVG, ZR, ES33, ESN33, DS, OS, NA, NG (tax scheme GST) S, Z, E, O, AE (tax scheme VAT; N not modelled)
Endpoint 0195 + SGUEN<UEN> 0235 + TIN
Extra cbc:UUID, single Note cbc:ProfileExecutionID, cbc:UUID, gross price, ItemPriceExtension, legal id type, credit note reason

Sources: docs.peppol.eu PINT SG and PINT AE pages, Schematron, code lists and examples [PRIMARY]; see docs/peppol.md and docs/research/einvoicing-peppol.md. The golden samples validate against the UBL 2.1 XSDs; the official Schematron (XSLT 2.0) was not run.

Factur-X / ZUGFeRD PDF (facturx.rs)

facturx::pdf(inv, cii_xml, opts) writes a PDF/A-3b file (by hand, no PDF crate) that shows the invoice as monospaced text and embeds the CII XML (cii::write(inv, Specification::En16931), guideline urn:cen.eu:en16931:2017) as factur-x.xml with /AFRelationship /Alternative, the Factur-X XMP properties (fx:ConformanceLevel EN 16931) and their PDF/A extension schema, an sRGB output intent and an embedded TrueType font (Courier Prime, SIL OFL 1.1, in assets/). facturx::CONFORMANCE_GAPS lists what is not verified (no veraPDF or Factur-X validator run, level B only, WinAnsi text only, D16B vs D22B…). See docs/peppol.md.

cargo test -p khata-en16931 also covers both PINT jurisdictions (rules, golden UBL snippets for Invoice and CreditNote, NG, exports, allowances) and the Factur-X PDF (structure, xref offsets, XMP, embedded XML, widths, pagination).