Invoice authoring API¶
The bidirectional CIUS-RO invoice models: flat document models with computed totals, the translated EN 16931 + CIUS-RO rule set, and the flat ⇄ UBL mapping. See the authoring guide for usage.
anafpy.efactura.authoring.models ¶
Bidirectional flat models for CIUS-RO electronic invoices.
One semantic model — EN 16931's — covers both UBL document types:
:class:InvoiceDocument authors and views an Invoice or a CreditNote
(:attr:~InvoiceDocument.kind picks the render target). The same models are
produced by :func:~.read.read_invoice and consumed by :func:~.build.build_invoice
/ :func:~.build.render_invoice, mirroring the e-Transport flat models.
Validation is two-tier:
- Construction enforces what a single model can know unconditionally: field
formats and lengths (the
BR-RO-L*limits), closed code lists (BR-CL-*), decimal budgets (BR-DEC-*), and local consistency (a period needs a start or an end, a VAT category pins its rate shape, ...). Data violating these is rejected by ANAF with certainty, so failing fast is data hygiene. - :func:
~.rules.validateruns the cross-aggregate EN 16931 / CIUS-RO rule set (totals arithmetic, VAT breakdown consistency, regime-dependent identifier requirements) and returns a findings report instead of raising.
Totals and the VAT breakdown are computed by default from the lines,
allowances and charges (correct by construction); explicit values may be supplied
— e.g. when reproducing an upstream document — and are then checked against the
computed ones by :func:~.rules.validate.
Contact ¶
Bases: BaseModel
A contact point (BG-6 seller / BG-9 buyer).
PostalAddress ¶
Bases: BaseModel
A postal address (BG-5/8/12/15).
CIUS-RO requires the street and city everywhere an address appears
(BR-RO-080/090/140/150/180/200); the county (CountrySubentity) is
required for Romanian addresses and must be an ISO 3166-2:RO code
(BR-RO-110), with Bucharest city names drawn from the SECTOR list
(BR-RO-100) — "sector 3" is normalised to "SECTOR3".
ElectronicAddress ¶
Bases: BaseModel
An electronic delivery address (BT-34/49) with its mandatory scheme
(BR-62/63), e.g. ElectronicAddress(address="0000000000000", scheme="0088").
PartyIdentifier ¶
Bases: BaseModel
A party identifier (BT-29/46/60); the scheme, when given, is an ISO 6523 ICD code (BR-CL-10).
Party ¶
Bases: BaseModel
A buyer (BG-7); also the base of :class:Seller (BG-4).
name is the legal name (BT-27/44) and the address is mandatory
(BR-08/10). The VAT identifier must carry its ISO 3166 country prefix
(BR-CO-09; Greece may use EL).
Payee ¶
Bases: BaseModel
The payee (BG-10), when different from the seller (BR-17).
TaxRepresentative ¶
Bases: BaseModel
The seller's tax representative (BG-11); the VAT identifier (BT-63) and postal address (BG-12) are mandatory (BR-56/19).
Period ¶
Bases: BaseModel
An invoicing (BG-14) or line (BG-26) period: at least one bound (BR-CO-19/20), end not before start (BR-29/30).
DeliveryInformation ¶
Bases: BaseModel
Delivery details (BG-13): recipient (BT-70), location (BT-71), actual delivery date (BT-72) and address (BG-15).
CreditTransfer ¶
Bases: BaseModel
A credit-transfer account (BG-17); the account identifier is mandatory (BR-50).
PaymentCard ¶
Bases: BaseModel
Payment card information (BG-18). Card-security standards allow at most the first 6 and last 4 digits of the account number (BR-51, a warning).
DirectDebit ¶
Bases: BaseModel
Direct-debit terms (BG-19).
PaymentInstructions ¶
Bases: BaseModel
Payment instructions (BG-16); the means code (BT-81) is mandatory
(BR-49) and drawn from UNTDID 4461 — e.g. "30" credit transfer,
"58" SEPA credit transfer, "42" bank account payment.
DocumentAllowance ¶
Bases: _DocumentAllowanceChargeBase
A document-level allowance (BG-20).
DocumentCharge ¶
Bases: _DocumentAllowanceChargeBase
A document-level charge (BG-21).
LineAllowance ¶
Bases: _AllowanceChargeBase
An invoice-line allowance (BG-27).
LineCharge ¶
Bases: _AllowanceChargeBase
An invoice-line charge (BG-28).
ItemAttribute ¶
Bases: BaseModel
An item attribute (BG-32): name and value are both required (BR-54).
ItemClassification ¶
Bases: BaseModel
An item classification (BT-158); the scheme is mandatory (BR-65).
InvoiceLine ¶
Bases: BaseModel
One invoice / credit-note line (BG-25) with its item and price flattened in.
net_amount (BT-131) is computed from quantity x price and the line
allowances/charges when omitted; supply it explicitly to reproduce an
upstream document's own rounding.
effective_net_amount
property
¶
effective_net_amount: Decimal
BT-131: the explicit net amount, else quantity x unit price (per base quantity) minus line allowances plus line charges, rounded to 2.
VatBreakdownEntry ¶
Bases: BaseModel
One VAT breakdown group (BG-23), keyed by category + rate.
Amounts left None are computed from the lines and document-level
allowances/charges of the same category and rate. Exemption reasons cannot be
computed: categories E/AE/K/G/O require one here (BR-E/AE/IC/G/O-10), which is
the main reason to pass explicit entries when authoring an exempt invoice.
Totals ¶
Bases: BaseModel
The document totals (BG-22). Every member is optional: whatever is left
None is computed (see :meth:InvoiceDocument.effective_totals); whatever
is supplied is preserved and checked by :func:~.rules.validate.
PrecedingInvoice ¶
Bases: BaseModel
A preceding invoice reference (BG-3); the number is mandatory (BR-55). CIUS-RO requires at least one on credit notes referencing the corrected invoice in practice, and caps them at 500 (BR-RO-A500).
SupportingDocument ¶
Bases: BaseModel
An additional supporting document (BG-24); the reference is mandatory (BR-52). Embedded content requires its MIME code and filename.
Note ¶
Bases: BaseModel
An invoice note (BG-1): free text (BT-22) with an optional UNCL 4451
subject qualifier (BT-21); on the wire the two ride one cbc:Note as
#CODE#text.
InvoiceDocument ¶
Bases: BaseModel
A CIUS-RO electronic invoice or credit note, flat and bidirectional.
Author one with the business fields and let the totals and VAT breakdown be
computed; or obtain one from wire XML via :func:~.read.read_invoice /
:func:~.read.parse_invoice, with every wire amount preserved. Render with
:func:~.build.render_invoice; check the full EN 16931 + CIUS-RO rule set
with :func:~.rules.validate.
compute_vat_breakdown ¶
compute_vat_breakdown() -> list[VatBreakdownEntry]
The VAT breakdown (BG-23) computed from lines, allowances and charges:
one entry per (category, rate), tax = taxable x rate rounded to 2
(BR-CO-17), zero for the exempt-style categories. Exemption reasons are
carried over from matching explicit :attr:vat_breakdown entries.
effective_vat_breakdown ¶
effective_vat_breakdown() -> list[VatBreakdownEntry]
The breakdown to render: the computed one when no explicit entries were
given; otherwise the explicit entries with any None amounts filled
from the matching computed group.
compute_totals ¶
compute_totals() -> Totals
The document totals (BG-22) computed per BR-CO-10..16.
prepaid and rounding are never computed (they are facts, not
sums) and are read from the explicit :attr:totals;
vat_total_tax_currency (BT-111) needs an exchange rate this library
does not know, so it also stays explicit-only.
round2 ¶
round2(value: Decimal) -> Decimal
EN 16931 Annex-B rounding: two decimals, half away from zero.
anafpy.efactura.authoring.codes ¶
Hand-curated codes for the CIUS-RO invoice models.
The big closed lists (currencies, countries, units, ...) are generated into
:mod:._codelists; this module carries the small, semantically-named subsets the
CIUS-RO Schematron restricts beyond the base UNTDID/ISO lists, plus the Romanian
sub-national code lists that exist only in the RO rules.
DocumentKind ¶
Bases: StrEnum
Which UBL document a :class:~.models.InvoiceDocument renders to.
InvoiceTypeCode ¶
Bases: StrEnum
BT-3 document type codes CIUS-RO admits (BR-RO-020, UNTDID 1001 subset).
CREDIT_NOTE (381) is the only code valid on a UBL CreditNote; the other
four are valid on a UBL Invoice.
VatCategory ¶
Bases: StrEnum
BT-95/102/118/151 VAT category codes (UNCL 5305, EN16931 subset).
SPLIT_PAYMENT (B) is on the list but only valid on domestic Italian
invoices (BR-B-01) — a CIUS-RO filing using it is rejected.
VatPointDateCode ¶
Bases: StrEnum
BT-8 VAT point date codes (UNTDID 2005 restricted by BR-RO-040).
anafpy.efactura.authoring.rules ¶
The cross-aggregate EN 16931 / CIUS-RO rule set over :class:InvoiceDocument.
:func:validate hand-translates the Schematron rules that construction-time
shape checks cannot express — totals arithmetic (BR-CO-10..17), VAT breakdown
consistency (BR-S/Z/E/AE/K/G/O/L/M-01..09), regime-dependent identifier
requirements, and the RO-specific document rules — and returns a
:class:ValidationReport of findings instead of raising. Rule ids and
severities match the official CIUS-RO 1.0.9 Schematron so findings line up with
what ANAF's validare endpoint reports; numeric comparisons mirror the
Schematron's own tolerances (the per-rate sums and the tax formula accept a
strict ±1 slack, the BR-CO totals are exact).
ANAF's validator remains the authority: a clean local report is a strong signal, never a guarantee.
Severity ¶
Bases: StrEnum
Finding severity, matching the Schematron flag.
Finding ¶
Bases: BaseModel
One rule violation.
ValidationReport ¶
Bases: BaseModel
The outcome of :func:validate: all findings, worst first.
InvoiceValidationError ¶
InvoiceValidationError(report: ValidationReport)
Bases: AnafError
Raised by :func:~.build.render_invoice when the document fails
:func:validate and validation was not explicitly skipped.
validate ¶
validate(document: InvoiceDocument) -> ValidationReport
Run the translated EN 16931 + CIUS-RO rule set and report findings.
Covers the cross-aggregate rules construction cannot enforce: totals arithmetic, VAT breakdown presence/consistency per category, VAT-regime identifier requirements, payment-instruction coherence. Field formats, lengths, code lists and decimal budgets were already enforced when the models were constructed.
Returns:
| Name | Type | Description |
|---|---|---|
A |
ValidationReport
|
class: |
ValidationReport
|
finding remains. ANAF's server-side |
anafpy.efactura.authoring.build ¶
Compose a flat :class:~.models.InvoiceDocument into UBL wire XML.
:func:build_invoice produces the generated UBL model (Invoice or
CreditNote per the document's :attr:~.models.InvoiceDocument.kind);
:func:render_invoice serializes it to upload-ready bytes, running
:func:~.rules.validate first unless explicitly skipped.
Syntax-mapping notes (the EN 16931 UBL binding's quirks, mirrored by
:mod:.read):
- BT-21/22 ride one
cbc:Noteas#SUBJECTCODE#text. - BT-8 (VAT point date code) rides
cac:InvoicePeriod/cbc:DescriptionCode. - BT-32 (seller tax registration) is a second
cac:PartyTaxSchemewhoseTaxScheme/IDis notVAT(rendered asFC). - BT-90 (bank-assigned creditor id) is a
cac:PartyIdentificationwithschemeID="SEPA"on the payee (or the seller when there is no payee). - On a credit note, BT-9 (due date) rides
cac:PaymentMeansand BT-11 (project reference) anAdditionalDocumentReferencewith type code 50. - UBL requires
cac:CardAccount/cbc:NetworkID, which EN 16931 does not model; it is rendered asZZZand dropped on read.
render_invoice ¶
render_invoice(document: InvoiceDocument, *, skip_validation: bool = False) -> bytes
Compose and serialize a document to upload-ready UTF-8 XML bytes.
Runs :func:~.rules.validate first and raises
:class:~.rules.InvoiceValidationError on fatal findings; pass
skip_validation=True to render regardless (e.g. to reproduce a faulty
upstream document byte-for-byte for ANAF's own validator to judge).
build_invoice ¶
build_invoice(document: InvoiceDocument) -> Invoice | CreditNote
Compose the flat document into its generated UBL model.
Pure translation — no validation, no defaulting beyond what the flat model already computed (line ids, totals, VAT breakdown).
anafpy.efactura.authoring.read ¶
Read UBL wire XML back into the flat :class:~.models.InvoiceDocument.
The inverse of :mod:.build, sharing its syntax-mapping conventions (#CODE#
note prefixes, the FC tax-registration scheme, SEPA-schemed creditor ids,
type-130/50 document references). Every wire amount — line nets, totals, the VAT
breakdown — is read into the explicit fields, so a round-trip preserves the
source document's own arithmetic instead of recomputing it; run
:func:~.rules.validate on the result to judge that arithmetic.
The reader is strict by design: a document that violates the construction-time
CIUS-RO shape checks (a seller without a city, an unknown currency, ...) raises
a pydantic ValidationError. That is safe for inbox content — every filed
document already passed ANAF's validation, whose rules the checks mirror —
and DownloadedMessage.view wraps the reader to return None instead of
raising; the raw bytes and the full UBL model remain the fallback tiers.
parse_invoice ¶
parse_invoice(xml: bytes) -> InvoiceDocument
Parse e-Factura wire XML straight into an :class:InvoiceDocument.
Raises:
| Type | Description |
|---|---|
ValueError
|
when the bytes are not a parseable UBL invoice/credit note. |
ValidationError
|
when the document violates the flat models' construction-time shape checks. |
read_invoice ¶
read_invoice(doc: Invoice | CreditNote) -> InvoiceDocument
Translate a generated UBL model into the flat :class:InvoiceDocument.
Wire totals, line net amounts and the VAT breakdown land in the explicit
fields (never recomputed); :func:~.rules.validate afterwards tells whether
the source document's arithmetic holds up.