Facturx.Invoice (Facturx v0.3.0)

Copy Markdown View Source

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

A postal address.

An optional trade contact.

An invoice line.

A seller/buyer/ship-to party.

t()

A VAT breakdown entry (one per rate/category).

Document-level monetary summation.

Types

address()

@type address() :: %{
  optional(:line_one) => String.t(),
  optional(:postcode) => String.t(),
  optional(:city) => String.t(),
  optional(:country) => String.t()
}

A postal address.

contact()

@type contact() :: %{
  optional(:name) => String.t(),
  optional(:phone) => String.t(),
  optional(:email) => String.t()
}

An optional trade contact.

line()

@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.

party()

@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.

t()

@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()
}

tax()

@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.

totals()

@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.