Factur-X / ZUGFeRD hybrid e-invoices in pure Elixir.
A Factur-X invoice is a PDF/A-3 document with a machine-readable CII XML (EN 16931) embedded inside it. This module is the public facade; the work is split across:
Facturx.CII— build/parse the CII XML (pure Elixir)Facturx.Extract— pull the embedded XML out of a PDF (pure Elixir)Facturx.Embed— inject XML into an existing PDF/A-3 (pure Elixir)Facturx.Validate— optional Schematron validation over a Saxon endpoint
See docs/adr/0001-perimetre-et-architecture.md for scope decisions.
Summary
Functions
Build a CII XML binary from an Facturx.Invoice struct.
The invoicing framework codes (BT-23) accepted by the French mandate.
Extract the embedded CII XML (and metadata) from a Factur-X PDF.
Build a Factur-X PDF: embed the CII XML for invoice into a PDF/A-3.
Parse a CII XML binary into an Facturx.Invoice struct.
The supported Factur-X profiles.
Validate CII XML against the EN 16931 Schematron (business rules).
Validate CII XML against the EN 16931 XSD (structure/types).
The VAT point date codes (BT-8) allowed by EN 16931 in CII syntax.
Types
Functions
@spec build( Facturx.Invoice.t(), keyword() ) :: {:ok, binary()} | {:error, term()}
Build a CII XML binary from an Facturx.Invoice struct.
@spec business_processes() :: [String.t()]
The invoicing framework codes (BT-23) accepted by the French mandate.
B1/S1/M1 goods / services / mixed
B2/S2/M2 same, already paid
B4/S4/M4 same, final invoice after a down payment
S5 services, filed by a subcontractor
S6 services, filed by a co-contractor
B7/S7 goods / services already e-reported (VAT already collected)
@spec extract(binary()) :: {:ok, %{xml: binary(), profile: profile() | nil, filename: String.t()}} | {:error, term()}
Extract the embedded CII XML (and metadata) from a Factur-X PDF.
@spec generate(binary(), Facturx.Invoice.t() | binary(), keyword()) :: {:ok, binary()} | {:error, term()}
Build a Factur-X PDF: embed the CII XML for invoice into a PDF/A-3.
pdf_a3 must already be a valid PDF/A-3 (the visual invoice). Pass either an
Facturx.Invoice struct or a ready CII XML binary as the payload.
@spec parse(binary()) :: {:ok, Facturx.Invoice.t()} | {:error, term()}
Parse a CII XML binary into an Facturx.Invoice struct.
@spec profiles() :: [profile()]
The supported Factur-X profiles.
@spec validate( binary(), keyword() ) :: {:ok, :valid} | {:error, {:invalid, [map()]}} | {:error, term()}
Validate CII XML against the EN 16931 Schematron (business rules).
Optional: requires a reachable Saxon endpoint (:endpoint opt) and the req
dependency. See Facturx.Validate.
@spec validate_xsd( binary(), keyword() ) :: {:ok, :valid} | {:error, {:invalid, [String.t()]}} | {:error, term()}
Validate CII XML against the EN 16931 XSD (structure/types).
Pure Elixir, in-process (OTP :xmerl_xsd) — no external tool. See Facturx.XSD.
@spec vat_point_date_codes() :: [String.t()]
The VAT point date codes (BT-8) allowed by EN 16931 in CII syntax.
"5" date of invoice — VAT due on invoicing ("TVA sur les débits")
"29" delivery date — VAT due on delivery (goods)
"72" date of payment — VAT due on collection ("à l'encaissement")Unlike BT-23, this list is imposed by the standard (not by France), so it is always enforced.