In-memory representation of an invoice, mapped to/from CII XML by
Facturx.CII.
Monetary amounts and quantities are Decimal (never floats). Nested parties,
lines, tax breakdown and totals use plain maps with the shapes documented
below. This models the EN 16931 essentials — enough for a valid CII document —
not every optional business term.
Two fields exist for the French e-invoicing mandate and are nil (unemitted)
by default, so cross-border EN 16931 use is unaffected:
:business_process (BT-23) and :tax_due_date_type_code (BT-8). See
docs/reference/reforme-fr.md.
Summary
Types
@type address() :: %{ optional(:line_one) => String.t(), optional(:postcode) => String.t(), optional(:city) => String.t(), optional(:country) => String.t() }
A postal address.
@type contact() :: %{ optional(:name) => String.t(), optional(:phone) => String.t(), optional(:email) => String.t() }
An optional trade contact.
@type line() :: %{ optional(:id) => String.t(), optional(:name) => String.t(), optional(:net_price) => Decimal.t(), optional(:quantity) => Decimal.t(), optional(:unit) => String.t(), optional(:vat_category) => String.t(), optional(:vat_rate) => Decimal.t(), optional(:line_total) => Decimal.t() }
An invoice line.
@type party() :: %{ optional(:name) => String.t(), optional(:legal_id) => String.t(), optional(:legal_scheme) => String.t(), optional(:vat) => String.t(), optional(:address) => address(), optional(:contact) => contact() | nil }
A seller/buyer/ship-to party.
@type t() :: %Facturx.Invoice{ business_process: String.t() | nil, buyer: party() | nil, currency: String.t(), delivery_date: Date.t() | nil, due_date: Date.t() | nil, issue_date: Date.t() | nil, lines: [line()], number: String.t() | nil, profile: Facturx.profile(), seller: party() | nil, ship_to: party() | nil, tax_breakdown: [tax()], tax_due_date_type_code: String.t() | nil, totals: totals(), type_code: String.t() }
@type tax() :: %{ optional(:type) => String.t(), optional(:category) => String.t(), optional(:rate) => Decimal.t(), optional(:basis) => Decimal.t(), optional(:calculated) => Decimal.t(), optional(:due_date_type_code) => String.t() }
A VAT breakdown entry (one per rate/category).
:due_date_type_code is BT-8 for this entry. It overrides the document-level
:tax_due_date_type_code and only exists because EN 16931 allows the code to
differ per entry; French rule S1.13 forbids that, so domestic invoices should
use the document-level field instead.
@type totals() :: %{ optional(:line_total) => Decimal.t(), optional(:tax_basis_total) => Decimal.t(), optional(:tax_total) => Decimal.t(), optional(:grand_total) => Decimal.t(), optional(:due_payable) => Decimal.t() }
Document-level monetary summation.