Module: Einvoicing

Defined in:
lib/einvoicing.rb,
lib/einvoicing/fr.rb,
lib/einvoicing/tax.rb,
lib/einvoicing/i18n.rb,
lib/einvoicing/party.rb,
lib/einvoicing/errors.rb,
lib/einvoicing/invoice.rb,
lib/einvoicing/version.rb,
lib/einvoicing/line_item.rb,
lib/einvoicing/ppf/client.rb,
lib/einvoicing/ppf/errors.rb,
lib/einvoicing/formats/cii.rb,
lib/einvoicing/formats/ubl.rb,
lib/einvoicing/invoiceable.rb,
lib/einvoicing/xml_builder.rb,
lib/einvoicing/rails/engine.rb,
lib/einvoicing/siret_lookup.rb,
lib/einvoicing/ppf/submitter.rb,
lib/einvoicing/validators/fr.rb,
lib/einvoicing/formats/facturx.rb,
lib/einvoicing/fr/siret_lookup.rb,
lib/einvoicing/validators/base.rb,
lib/einvoicing/validators/peppol.rb,
lib/einvoicing/ppf/invoice_adapter.rb

Overview

Einvoicing — EU electronic invoicing for Ruby.

Generates EN 16931-compliant invoices in Factur-X (PDF/A-3 + CII XML), UBL 2.1, and CII D16B formats. Validates French B2B compliance (SIREN, SIRET, TVA). Provides a Rails concern for ActiveRecord models.

Examples:

Quick start

seller = Einvoicing::Party.new(name: "Acme SAS", siren: "356000000", vat_number: "FR83356000000")
buyer  = Einvoicing::Party.new(name: "Client SA", siren: "552032534")
line   = Einvoicing::LineItem.new(description: "Consulting", quantity: 1, unit_price: 1000.00)

invoice = Einvoicing::Invoice.new(
  invoice_number: "INV-2024-001",
  issue_date: Date.today,
  seller: seller,
  buyer: buyer,
  lines: [line]
)

xml = Einvoicing::Formats::CII.generate(invoice)
ubl = Einvoicing::Formats::UBL.generate(invoice)

Defined Under Namespace

Modules: Errors, FR, Formats, I18n, Invoiceable, PPF, Rails, SiretLookup, Validators Classes: Invoice, LineItem, Party, Tax, XMLBuilder

Constant Summary collapse

VERSION =
"0.7.0"

Class Method Summary collapse

Class Method Details

.embed(pdf_data, invoice_or_xml) ⇒ String

Embed a Factur-X CII XML into a PDF, returning a PDF/A-3 binary.

Parameters:

  • pdf_data (String)

    raw PDF binary

  • invoice_or_xml (Invoice, String)

    Invoice (CII generated internally) or raw XML string

Returns:

  • (String)

    Factur-X PDF/A-3 binary



73
74
75
76
# File 'lib/einvoicing.rb', line 73

def self.embed(pdf_data, invoice_or_xml)
  xml_str = invoice_or_xml.is_a?(String) ? invoice_or_xml : xml(invoice_or_xml, format: :cii)
  Formats::FacturX.embed(pdf_data, xml_str)
end

.process(invoice, format: :cii, market: :fr, pdf: nil) ⇒ Hash

Full pipeline: validate → generate XML → optionally embed in PDF. Never raises — errors are returned in the result hash.

Parameters:

  • invoice (Einvoicing::Invoice)
  • format (Symbol) (defaults to: :cii)

    :cii or :ubl

  • market (Symbol) (defaults to: :fr)

    :fr

  • pdf (String, nil) (defaults to: nil)

    optional raw PDF binary to embed into

Returns:

  • (Hash)

    { valid:, errors:, xml:, pdf: }



96
97
98
99
100
101
102
103
# File 'lib/einvoicing.rb', line 96

def self.process(invoice, format: :cii, market: :fr, pdf: nil)
  errors  = validate(invoice, market: market)
  xml_str = xml(invoice, format: format)
  pdf_out = pdf ? embed(pdf, xml_str) : nil
  { valid: errors.empty?, errors: errors, xml: xml_str, pdf: pdf_out }
rescue StandardError => e
  { valid: false, errors: [ { field: :unknown, error: :exception, message: e.message } ], xml: nil, pdf: nil }
end

.validate(invoice, market: :fr) ⇒ Array<Hash>

Validate an invoice against a market's rules.

Parameters:

Returns:

  • (Array<Hash>)

    array of { field:, error:, message: } — empty means valid



82
83
84
85
86
87
# File 'lib/einvoicing.rb', line 82

def self.validate(invoice, market: :fr)
  case market
  when :fr then Validators::FR.validate(invoice)
  else raise ArgumentError, Einvoicing::I18n.t("formats.unknown_market", market: market.inspect)
  end
end

.xml(invoice, format: :cii, profile: :en16931) ⇒ String

Generate XML from an invoice.

Parameters:

  • invoice (Einvoicing::Invoice)
  • format (Symbol) (defaults to: :cii)

    :cii (default, Factur-X) or :ubl (Peppol BIS 3.0)

  • profile (Symbol) (defaults to: :en16931)

    :en16931 (default) or :chorus_pro (French B2G portal)

Returns:

  • (String)

    XML document



61
62
63
64
65
66
67
# File 'lib/einvoicing.rb', line 61

def self.xml(invoice, format: :cii, profile: :en16931)
  case format
  when :cii then Formats::CII.generate(invoice, profile: profile)
  when :ubl then Formats::UBL.generate(invoice)
  else raise ArgumentError, Einvoicing::I18n.t("formats.unknown_format", fmt: format.inspect)
  end
end