The canonical model
The core is still EN 16931-1, field for field, so every EN-based format maps 1:1. National formats carry concepts EN has no term for. Those go, in order of preference:
- EU-wide additions to the core, used by several countries:
withholdings+totals.withholdingTotal(IT ritenuta, ES IRPF, PT retenção).payable = taxInclusive − prepaid + rounding − withholdingTotal − splitPaymentVat(the last term is Italian split payment,EsigibilitaIVA = S).otherTaxesfor non-VAT taxes (ES recargo de equivalencia, IT stamp duty).payments[](several means/accounts) and a separatepaymentSchedule[](due dates and amounts, optionally pointing at a payment entry). FatturaPA, Facturae and KSeF allow several of each; EN allows one.additionalParties[]with a role for parties EN has no slot for: KSeFPodmiot3(factor, issuer on the seller’s behalf, payer, additional buyer…), FatturaPA third-party issuer, Facturae third party, e-arve factor.nationalTaxIdson parties (codice fiscale, NIP, NIF, OIB, AFM, IČO), because several formats identify parties only that way.nationalTypenext to the UNCL 1001typeCode(FatturaPATD04, KSeFKOR, FacturaeOR…), andcorrectionfor corrective-invoice reasons and methods.nationalCodeon VAT categories (FatturaPA NaturaN6.2→AE, KSeFoo→AE), so the mapping can be audited.- On lines:
correctionState(before/after/delta) for KSeF corrections that list each line before and after (StanPrzed),otherTaxes/withholdingsfor Facturae lines with several taxes, andsubLines(XRechnung extension, Factur-X EXTENDED, France EXTENDED-CTC-FR). issueTime,exchangeRate,unitTextfor free-text units.
clearance[]: tax-authority IDs (SdI ID, KSeF number, ANAF index, myDATA MARK), status and QR payload. Signatures go insource.signatures(CAdES, XAdES, detached).extensions.{it,pl,es,hr,gr,pt,fr,de,cz,at,fi,ee}for country-only fields: split payment (ITEsigibilitaIVA=S, PLP_18A), Italian pension funds, CUP/CIG codes, KSeF annotations, DIR3 units in Facturae, Croatian operator OIB, ISDOC symbols…source.unmapped(XPath → value) for anything left.source.derivedrecords every inferred value andsource.warningsrecords every lossy mapping.
source also carries fileSha256 and payloadSha256 (one received file can hold several invoices, so deduplicate on file hash + indexInFile/fragmentPath, not on invoice number), optional field-level provenance (canonical path → source XPath), and a validation summary kept per layer (parse, schema, semantic, profile, signature, clearance), where unavailable (validator could not run) is distinct from failed.
Other design rules are unchanged from the PEPPOL/Svefaktura version: decimal strings for money, YYYY-MM-DD dates, open code-list unions, credit notes keep their source signs (effectiveSign()), and EN-mandatory fields are optional in the type with a separate completeness check.