Skip to content

[1.8] Implement Facturae 3.2.1 XML template #20

Description

@nielsdrost7

Context

Facturae 3.2 is Spain's national e-invoice format, mandatory for all B2G invoices and being phased in for B2B (large companies from 2025, others from 2026).

Version note: The actual version implemented in the e-invoices repository is 3.2 (Facturaev32.php), not 3.2.1. Verify the SchemaVersion element in the XML output — if the official standard requires 3.2.1, update the config and generator accordingly.

Critical design constraint: Facturae files must be digitally signed (XAdES-EPES) before submission. InvoicePlane generates unsigned XML only. The signing step is external — the user applies the signature using AutoFirma or an equivalent tool. The generated file must be valid unsigned Facturae XML.

B2G invoices require three government routing codes from the purchase order, which map to invoice_routing_code_1, invoice_routing_code_2, and invoice_routing_code_3.

Repository status (develop branch):

File Status
application/helpers/XMLconfigs/Facturaev32.php Exists
application/libraries/XMLtemplates/Facturaev32Xml.php Exists — uses Composer packages in Facturae/ subdir

Important notes:

  • XMLname = '' in the existing config (empty string)
  • The generator uses Composer dependencies installed under application/libraries/XMLtemplates/Facturae/; that directory must contain a working vendor/autoload.php
  • This issue is about auditing and completing the existing files, not creating from scratch

Depends on: #15 (routing codes — all three map to Spanish B2G routing)


Deliverables

Audit and complete existing files

  • application/helpers/XMLconfigs/Facturaev32.php — verify countrycode: 'ES', XMLname = '', unsigned-only constraint; clarify target schema version (3.2 vs 3.2.1)
  • application/libraries/XMLtemplates/Facturaev32Xml.php — verify routing code mapping, PersonTypeCode derivation, credit note type code, absence of any <ds:Signature> block in output
  • Add install note documenting the Composer dependency in Facturae/

Config structure (reference)

$xml_setting = [
    'full-name'   => 'Facturae 3.2 (unsigned)',
    'countrycode' => 'ES',
    'embedXML'    => false,
    'XMLname'     => '',
];

Routing code mapping (B2G only)

invoice_routing_code_* Facturae B2G element
invoice_routing_code_1 Managing body code (Órgano gestor)
invoice_routing_code_2 Processing unit code (Unidad tramitadora)
invoice_routing_code_3 Accounting office code (Oficina contable)

Include all three when set. Omit the entire B2G routing block when all three are null (B2B scenario).

Entity type

Situation PersonTypeCode
Client has a company name J (legal entity)
Client is an individual F (individual)

Acceptance criteria

  • Config and generator audited; all required Facturae elements present
  • Schema version clarified — 3.2 or 3.2.1 confirmed and consistent across config and XML output
  • Three routing codes included in B2G routing block when set; block absent when all three null
  • PersonTypeCode correctly derived from whether client is a company or individual
  • Credit notes use the correct Facturae document type code
  • Generated XML has no <ds:Signature> element — signing is always external
  • Composer dependency (Facturae/ subdir) documented in install instructions
  • XML validates against Facturae XSD
  • Download UI indicates the file is unsigned and must be signed before submission

AAA tests

Test 1 — Spanish central government B2G invoice

Arrange: Spanish government client with client_vat_id = 'ESQ2826004J'; invoice with invoice_routing_code_1 = 'E00120001', invoice_routing_code_2 = 'E00120101', invoice_routing_code_3 = 'E00120102'
Act: Generate Facturae XML via Facturaev32.php + Facturaev32Xml.php
Assert:

  • TaxIdentificationNumber = ESQ2826004J
  • All three routing codes present in the B2G routing block
  • No <ds:Signature> element anywhere in the document
  • XML validates against Facturae XSD

Test 2 — Spanish B2B invoice, no routing codes

Arrange: Spanish private company client; all three routing code fields NULL
Act: Generate Facturae XML
Assert: Valid XML produced; B2G routing block absent from the document


Test 3 — individual client

Arrange: Client with no company name, individual name set
Act: Generate Facturae XML
Assert: PersonTypeCode = F; individual identifier in the correct element


Test 4 — credit note

Arrange: Credit note referencing an original invoice
Act: Generate Facturae XML
Assert: Correct credit note document type code; reference to original invoice present; no signature block; XML validates


Test 5 — no signature block under any input

Arrange: Any client and invoice combination
Act: Generate Facturae XML
Assert: Parsed XML contains no element with local name Signature in any namespace — signing is always external

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions