LEFA implementa los requisitos técnicos del Sistema de Información de Facturación (SIF) definidos en el Real Decreto de facturación y la Orden HAC/1177/2024, a través de cuatro módulos independientes ubicados enDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/entreunosyceros/lefa/llms.txt
Use this file to discover all available pages before exploring further.
lefa/verifactu/. El módulo hash.py calcula el hash SHA-256 encadenado de cada factura emitida. El módulo registro.py genera y persiste en disco el registro JSON inmutable de cada emisión. El módulo qr.py construye la URL de cotejo AEAT y produce la imagen PNG del código QR. El módulo export.py empaqueta todos los registros en un archivo ZIP apto para auditoría o envío futuro a la AEAT. La cadena de hash es única para todo el SIF: las series FACT, RECT y cualquier otra comparten el mismo hilo cronológico; una rectificativa enlaza con la última factura emitida, no con la rectificativa anterior.
RegistroVerifactuService — registro.py
Crea y almacena registros encadenados en disco y en la base de datos. Debe operar siempre dentro de una transacción BEGIN IMMEDIATE para garantizar que la lectura del último hash y la escritura del nuevo sean atómicas.
crear_registro_emision
- Bloquea la transacción con
BEGIN IMMEDIATEsi aún no está en curso. - Consulta la última factura emitida del sistema (cualquier serie) que tenga
verifactu_hashasignado, excluyendo la factura actual. - Lee
verifactu_hashde esa factura comohash_anterior(cadena vacía si es la primera). - Llama a
calcular_hash_registrocon los datos de la factura actual y elhash_anterior. - Construye el objeto
RegistroVerifactucon todos los campos. - Escribe
factura.verifactu_hashyfactura.verifactu_hash_anterioren el objeto ORM (dentro de la transacción, antes del commit). - Si
persistir_json=True, persiste el JSON en disco en este momento; de lo contrario, el llamador debe invocarguardar_jsontras el commit.
Sesión SQLAlchemy activa, idealmente abierta con
session_scope_immediate() (transacción BEGIN IMMEDIATE).Objeto
Factura ORM con numero_factura y fecha_emision ya asignados (dentro de la misma transacción de emisión).Si es
True, escribe el JSON en disco inmediatamente. Por defecto False; la escritura en disco se realiza tras el commit exitoso para evitar archivos huérfanos en caso de rollback.RegistroVerifactu con todos los campos populados, incluidos los hashes.
guardar_json
{factura_id}_{numero_factura}.json (con / sustituido por -). Debe llamarse tras el commit de la transacción de emisión para evitar archivos con datos de una transacción fallida.
Objeto
RegistroVerifactu devuelto por crear_registro_emision.Path del archivo JSON creado en ~/.lefa/verifactu/registros/.
ruta_registro
ID de la factura.
Número oficial de la factura (p. ej.
"FACT-2026-0001").Path a ~/.lefa/verifactu/registros/{factura_id}_{numero_factura}.json.
calcular_hash_registro — hash.py
|, construida en el siguiente orden:
DD-MM-YYYY. El importe se formatea con exactamente dos decimales. El hash_anterior puede ser una cadena vacía para la primera factura del sistema.
NIF/CIF del emisor en mayúsculas (p. ej.
"12345678A"). Se normaliza internamente.Número oficial de la factura ya asignado.
Fecha de emisión de la factura.
Total neto de la factura (subtotal + IVA − IRPF), redondeado a 2 decimales.
Hash SHA-256 hexadecimal (64 caracteres) del registro inmediatamente anterior en la cadena. Cadena vacía
"" para la primera factura. Por defecto "".Módulo qr.py
Constantes
| Constante | Valor | Descripción |
|---|---|---|
QR_PX | 100 | Resolución del PNG intermedio en píxeles (≈85–113 px a 72 dpi). |
QR_MM | 35.0 | Tamaño físico del QR en el PDF en milímetros (rango permitido AEAT: 30–40 mm). |
TEXTO_LEGAL_VERIFACTU | "VERI*FACTU" | Leyenda obligatoria en modo VeriFactu. |
TEXTO_LEGAL_NO_VERIFACTU | "SISTEMA INFORMÁTICO NO VERIFICADO" | Leyenda en modo no-VeriFactu. |
texto_legal_qr
Si es
None (valor por defecto), se lee la constante VERIFACTU_MODO_VERIFACTU de lefa.config."VERI*FACTU" o "SISTEMA INFORMÁTICO NO VERIFICADO".
url_verificacion
- VeriFactu:
…/wlpl/TIKE-CONT/ValidarQR?… - No-VeriFactu:
…/wlpl/TIKE-CONT/ValidarQRNoVerifactu?…
NIF/CIF del emisor. Se convierte a mayúsculas y se recortan espacios.
Número oficial de la factura.
Fecha de emisión de la factura.
Total neto de la factura con punto decimal y dos decimales.
Hash SHA-256 del registro VeriFactu (64 hex en minúsculas). Solo se incluye en la URL en modo VeriFactu y si no es
None ni vacío.Si es
None, se lee de VERIFACTU_MODO_VERIFACTU en lefa.config.urllib.parse.quote.
generar_qr_png
qrcode. El directorio destino se crea automáticamente si no existe.
URL de verificación AEAT a codificar en el QR.
Ruta completa del archivo PNG de salida.
Tamaño de la imagen resultante en píxeles (ancho y alto). Por defecto
100.Path del archivo PNG generado.
hash_para_url
hash_registro es None o vacío. Centraliza el ajuste del formato del hash si la AEAT modificara la especificación.
VerifactuExport — export.py
exportar_zip
~/.lefa/verifactu/registros/ en un archivo ZIP comprimido (deflate) legible por máquinas. Incluye además un archivo indice.json en la raíz del ZIP con el contenido de todos los registros en un array JSON.
Ruta completa del archivo ZIP de salida. Si es
None, se genera automáticamente como verifactu_export_{fecha_hoy}.zip en el directorio padre de registros/ (normalmente ~/.lefa/verifactu/). Si la ruta no termina en .zip, la extensión se añade automáticamente.Path del archivo ZIP generado.
Estructura del ZIP:
Formato del registro JSON
Cada archivo JSON en~/.lefa/verifactu/registros/ corresponde a una RegistroVerifactu serializada con dataclasses.asdict. La estructura completa es la siguiente:
| Campo | Tipo | Descripción |
|---|---|---|
factura_id | int | Clave primaria de la factura en SQLite. |
numero_factura | str | Número oficial asignado en la emisión. |
serie | str | Serie de la factura ("FACT", "RECT", etc.). |
nif_emisor | str | NIF/CIF del emisor leído de las preferencias. |
fecha_emision | str | Fecha en formato ISO 8601 (YYYY-MM-DD). |
importe_total | float | Total neto de la factura redondeado a 2 decimales. |
hash_registro | str | Hash SHA-256 (64 hex) de esta factura. |
hash_anterior | str | Hash SHA-256 de la factura anterior en la cadena. Vacío para la primera. |
timestamp | str | Instante de generación del registro en ISO 8601 sin microsegundos. |
tipo | str | "alta" para facturas ordinarias; "rectificativa" para facturas de serie RECT. |
factura_rectificada_id | int | null | ID de la factura original rectificada, o null. |
URL AEAT — formato completo
La URL construida porurl_verificacion sigue la estructura siguiente:
| Parámetro | Formato | Obligatorio | Descripción |
|---|---|---|---|
nif | Texto en mayúsculas, URL-encoded | Sí | NIF/CIF del emisor. |
numserie | Texto URL-encoded | Sí | Número de factura completo. |
fecha | DD-MM-AAAA | Sí | Fecha de emisión de la factura. |
importe | Decimal con punto, 2 decimales | Sí | Importe total neto de la factura. |
hash | 64 caracteres hexadecimales en minúsculas | Solo en modo VeriFactu | Hash SHA-256 del registro. |
ValidarQRNoVerifactu y el parámetro hash se omite.
La URL base (
VERIFACTU_URL_BASE) y la activación del modo VeriFactu (VERIFACTU_MODO_VERIFACTU) se configuran en lefa/config.py. El valor por defecto apunta al entorno de preproducción de la AEAT (prewww2.aeat.es).