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
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
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).
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, andinvoice_routing_code_3.Repository status (
developbranch):application/helpers/XMLconfigs/Facturaev32.phpapplication/libraries/XMLtemplates/Facturaev32Xml.phpFacturae/subdirImportant notes:
XMLname = ''in the existing config (empty string)application/libraries/XMLtemplates/Facturae/; that directory must contain a workingvendor/autoload.phpDepends on: #15 (routing codes — all three map to Spanish B2G routing)
Deliverables
Audit and complete existing files
application/helpers/XMLconfigs/Facturaev32.php— verifycountrycode: 'ES',XMLname = '', unsigned-only constraint; clarify target schema version (3.2 vs 3.2.1)application/libraries/XMLtemplates/Facturaev32Xml.php— verify routing code mapping,PersonTypeCodederivation, credit note type code, absence of any<ds:Signature>block in outputFacturae/Config structure (reference)
Routing code mapping (B2G only)
invoice_routing_code_*invoice_routing_code_1invoice_routing_code_2invoice_routing_code_3Include all three when set. Omit the entire B2G routing block when all three are null (B2B scenario).
Entity type
PersonTypeCodeJ(legal entity)F(individual)Acceptance criteria
3.2or3.2.1confirmed and consistent across config and XML outputPersonTypeCodecorrectly derived from whether client is a company or individual<ds:Signature>element — signing is always externalFacturae/subdir) documented in install instructionsAAA tests
Test 1 — Spanish central government B2G invoice
Arrange: Spanish government client with
client_vat_id = 'ESQ2826004J'; invoice withinvoice_routing_code_1 = 'E00120001',invoice_routing_code_2 = 'E00120101',invoice_routing_code_3 = 'E00120102'Act: Generate Facturae XML via
Facturaev32.php+Facturaev32Xml.phpAssert:
TaxIdentificationNumber = ESQ2826004J<ds:Signature>element anywhere in the documentTest 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 elementTest 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
Signaturein any namespace — signing is always external