Skip to content
Guillermo Ubeda edited this page Sep 1, 2026 · 2 revisions

🇬🇧 English first · 🇪🇸 Español más abajo

facturae-es

A zero-dependency Python library that builds Facturae 3.2.2 invoices — the Spanish electronic invoice format required for invoicing the public sector through FACe.

It produces a valid, unsigned document. Signing is not here, and Design decisions explains why that is a decision and not an omission.


Pages in this wiki

Page What you will find
The invoice model How the object model maps to the XML, the tax codes, and why totals cannot disagree with the lines
Design decisions Why money is Decimal, why unknown JSON keys are an error, and why the library stops before the signature

Task-oriented documentation — installing, the CLI, the JSON format, signing and FACe — lives in the docs/ folder. This wiki covers the why; docs/ covers the how.


Where it sits

flowchart LR
    A[Your data] --> B["Factura object<br/>(or JSON)"]
    B --> C[validation]
    C --> D["totals computed<br/>from the lines"]
    D --> E["Facturae 3.2.2 XML<br/>unsigned"]
    E -.->|"your signing step<br/>XAdES"| F[FACe]
    style F stroke-dasharray: 5 5
Loading

The dashed part is deliberately outside the library.


The honest summary

What it does

  • Models an invoice — issuer, recipient, lines, taxes — as plain Python objects with type hints and a shipped py.typed.
  • Computes the totals from the lines. They are not fields you fill in, so they cannot disagree with the detail.
  • Generates Facturae 3.2.2 XML, and can also hand you the element tree if you need to post-process it.
  • Round-trips through JSON (desde_json / a_dict), which is what makes it usable from a language that is not Python.
  • Ships a CLI — plantilla, validar, totales, generar, autocomprobar — every one of which reads - as stdin, so it composes with jq and friends.

What it does not do

  • It does not sign. Facturae requires an XAdES signature before it can be submitted, and this library stops at the document. Handling a private key belongs in your application's security model, and a signature library would end the zero-dependency guarantee. A library that produced almost a signature would be worse than one that is clear about where it stops. See docs/signing.md.
  • It does not submit anything to FACe.
  • It does not decide your tax treatment. You say which tax applies; it formats and totals it.

Verified. 66 tests, 91 % statement coverage, ruff clean, and a runtime autocomprobar that recomputes a hand-written invoice — 1 250,00 net, 262,50 output VAT, 150,00 withheld, 1 362,50 total — so a broken install fails loudly.



🇪🇸 Español

facturae-es

Biblioteca de Python sin dependencias que construye facturas Facturae 3.2.2, el formato de factura electrónica española exigido para facturar al sector público a través de FACe.

Produce un documento válido y sin firmar. La firma no está aquí, y Design decisions explica por qué eso es una decisión y no un olvido.


Páginas de esta wiki

Página Qué encontrarás
The invoice model Cómo se corresponde el modelo de objetos con el XML, los códigos de impuesto y por qué los totales no pueden discrepar de las líneas
Design decisions Por qué el dinero es Decimal, por qué una clave JSON desconocida es un error y por qué la biblioteca se detiene antes de la firma

La documentación de uso —instalación, CLI, formato JSON, firma y FACe— está en la carpeta docs/. Esta wiki cuenta el porqué; docs/ cuenta el cómo.


Dónde encaja

flowchart LR
    A[Tus datos] --> B["objeto Factura<br/>(o JSON)"]
    B --> C[validación]
    C --> D["totales calculados<br/>desde las líneas"]
    D --> E["XML Facturae 3.2.2<br/>sin firmar"]
    E -.->|"tu paso de firma<br/>XAdES"| F[FACe]
    style F stroke-dasharray: 5 5
Loading

La parte discontinua queda fuera de la biblioteca a propósito.


El resumen honesto

Lo que hace

  • Modela una factura —emisor, receptor, líneas, impuestos— como objetos de Python normales, con anotaciones de tipo y un py.typed incluido.
  • Calcula los totales a partir de las líneas. No son campos que rellenes, así que no pueden discrepar del detalle.
  • Genera XML Facturae 3.2.2, y también puede devolverte el árbol de elementos si necesitas post-procesarlo.
  • Va y vuelve por JSON (desde_json / a_dict), que es lo que la hace utilizable desde un lenguaje que no sea Python.
  • Trae una CLI —plantilla, validar, totales, generar, autocomprobar— y todos los subcomandos leen - como entrada estándar, así que se combinan con jq y compañía.

Lo que no hace

  • No firma. Facturae exige una firma XAdES antes de poder presentarse, y esta biblioteca se detiene en el documento. Manejar una clave privada le corresponde al modelo de seguridad de tu aplicación, y una biblioteca de firma acabaría con la garantía de cero dependencias. Una biblioteca que produjera casi una firma sería peor que una que deja claro dónde para. Ver docs/signing.md.
  • No presenta nada en FACe.
  • No decide tu tratamiento fiscal. Tú dices qué impuesto aplica; ella lo formatea y lo totaliza.

Verificado. 66 pruebas, 91 % de cobertura de sentencias, ruff limpio y un autocomprobar en tiempo de ejecución que recalcula una factura escrita a mano —1.250,00 de base, 262,50 de IVA repercutido, 150,00 de retención y 1.362,50 de total— para que una instalación rota falle de forma ruidosa.

Clone this wiki locally