cadrumo.adapters.inbound.einvoice.parsers module¶
Deterministic parsers for EN16931 (CII and UBL) and Facturae 3.2.x.
All three map onto ONE line-carrying extraction draft, so a downstream consumer
never branches on which syntax a document happened to arrive in. Every parser
runs through parse_hardened_xml(), so entity resolution and external DTD
loading are off and size and depth are bounded before any field is read.
Three behaviours here are deliberate and each closes a diagnosed defect.
The IVA number is selected as the party tax identifier, not the first identifier in the tree. ZUGFeRD is a Franco-German format and its supplier block routinely carries a French SIRET or a German Steuernummer alongside the IVA id; taking the first one produced 22 of the 34 wrong fields measured corpus-wide, with zero missing fields – the parser was finding every field and choosing the wrong one.
Emisor and destinatario are mapped by role, never by position. A received-invoice record whose supplier and customer are swapped reports the taxpayer as the issuer, which inverts the direction of the whole record.
A rate that matches no closed slot refuses loudly and is never rounded to the nearest member. The transient 2022-2024 5% rate is exactly this case: no slot exists for it, so a pre-2025 document must refuse rather than silently resolve to the nearest slot and mint an invoice whose cuota disagrees with its face.
- class FacturaeInvoiceClass(*values)[source]¶
Bases:
StrEnumClass code stated by Facturae’s
InvoiceHeader/InvoiceClass.- ORIGINAL¶
- ORIGINAL_CORRECTIVE¶
- ORIGINAL_SUMMARY¶
- COPY¶
- COPY_CORRECTIVE¶
- COPY_SUMMARY¶
- class ParsedEInvoiceLine(*, description=None, quantity=None, unit_price=None, taxable_base=None, iva_rate=None, iva_amount=None)[source]¶
Bases:
objectOne parsed line item, syntax-independent.
- Parameters:
description (str | None)
quantity (Decimal | None)
unit_price (Decimal | None)
taxable_base (Decimal | None)
iva_rate (Decimal | None)
iva_amount (Decimal | None)
- description¶
- quantity¶
- unit_price¶
- taxable_base¶
- iva_rate¶
- iva_amount¶
- class ParsedEInvoice(*, shape)[source]¶
Bases:
objectA structured invoice read exactly from its own machine-readable record.
- Parameters:
shape (DocumentShape)
- shape¶
-
facturae_invoice_class:
FacturaeInvoiceClass|None¶
-
lines:
list[ParsedEInvoiceLine]¶
- parse_einvoice_document(data)[source]¶
Read a structured e-invoice exactly, in whichever syntax it arrives.
Handles a standalone XML document and a ZUGFeRD / Factur-X PDF carrying its invoice as an embedded file, resolving the embedded payload transparently.
- Parameters:
data (
bytes) – The document’s full in-memory bytes.- Return type:
- Returns:
A
ParsedEInvoicewith whatever the document states.- Raises:
EInvoiceXmlParseError – If the document carries no structured record, or its record is malformed. Refuses outright rather than returning a partial record: a structured reader that returned half a record on malformed input would look exact while being wrong.