Proposals & Invoices · Article 5.9
Numeración de facturas — secuencial por año por tipo, atómica, sin huecos
Cada factura recibe un número secuencial de un contador atómico con ámbito por autónomo por año por tipo de documento. No se permiten huecos según el Art. 226(2) de la Directiva del IVA de la UE; se aplica mediante un bloqueo a nivel de fila en la base de datos para que las operaciones concurrentes no puedan colisionar.
La numeración de facturas parece trivial hasta que se considera: dos facturas en vuelo en el mismo momento exacto no deben colisionar en un número; las facturas eliminadas no pueden liberar su número para su reutilización; un límite de año debe restablecerse limpiamente; los huecos en la secuencia son señales de alerta en las auditorías. El diseño del contador resuelve todo esto en un mecanismo — implementado en apps/proposals/models.py:DocumentCounter y usado en todo lugar donde se numera un documento.
Why this works this way
Por qué no se permiten huecos según la ley de la UE. El Art. 226(2) de la Directiva del IVA de la UE exige que los números de factura estén «basados en una o varias series, que identifiquen de forma única la factura». Las implementaciones nacionales (§14 UStG en DE, BTW Art. 35a en NL) exigen explícitamente una secuencia continua sin huecos. Los auditores ven los huecos en la secuencia como una señal de que se emitieron facturas y luego se retuvieron (un patrón de evasión habitual: imprimir una factura para el pago en efectivo, destruirla, nadie nota el hueco). El estándar de auditoría: cada número desde 0001 en adelante en un año dado debe existir en sus registros.
El diseño del contador (apps/proposals/models.py:DocumentCounter):
``python
class DocumentCounter(BaseModel):
freelancer = ForeignKey(User) # ámbito: por autónomo
document_type = CharField() # ámbito: por tipo (PROPOSAL, DEPOSIT, FINAL, …)
year = IntegerField() # ámbito: por año
next_number = IntegerField(default=1) # el valor
class Meta:
unique_together = [('freelancer', 'document_type', 'year')]
``
El patrón de incremento atómico:
``python
with transaction.atomic():
counter, created = DocumentCounter.objects.select_for_update().get_or_create(
freelancer=proposal.freelancer,
document_type='PROPOSAL',
year=2026,
defaults={'next_number': 1}
)
number = counter.next_number
counter.next_number += 1
counter.save()
``
select_for_update() emite una consulta SQL SELECT … FOR UPDATE que toma un bloqueo a nivel de fila en la fila del contador durante la duración de la transacción. Las transacciones concurrentes para la misma fila del contador se bloquean en el bloqueo; una vez que la primera transacción confirma, la segunda ve next_number = 2 y procede. Sin colisión posible.
Por qué esto importa para las enmiendas y el storno. Cuando una enmienda genera un Storno (STR-) y un nuevo INV (revisión 2), cada uno obtiene su propio número secuencial de su propio contador:
- STR-2026-0001 (primer storno del año)
- INV-2026-0067 (siguiente INV disponible en su año, distinto de cualquier INV anterior)
El nuevo INV es revision=2 de la misma factura lógica pero obtiene un número nuevo. El INV original (revisión 1) conserva su número original; ambos se preservan (el original se marca como reemplazado, nunca eliminado). De esta manera, la secuencia de INV no muestra huecos — cada INV emitido permanece, solo con un indicador reemplazado para los que fueron sustituidos.
Restablecimiento del límite de año. El 1 de enero, el campo year cambia; las nuevas facturas buscan (freelancer, tipo, 2027) — esa fila aún no existe, por lo que get_or_create la crea con next_number=1. La fila del contador del año anterior permanece tal cual (no elimine; útil para auditoría). La primera factura del nuevo año es INV-2027-0001.
Sin reutilización, sin relleno de huecos. Si una factura se anula (Storno), su número permanece en la secuencia — el Storno es un nuevo documento que lo referencia; no libera el número original. Si una factura se emite por error (p. ej., datos de prueba en producción — nunca debería ocurrir, pero sí ocurre), sigue ocupando su posición. El registro de auditoría se preserva.
Independencia por tipo de documento. Su contador DEP es independiente de su contador INV. Así puede tener:
- DEP-2026-0042 + INV-2026-0042 (un proyecto donde DEP e INV cayeron en el mismo número de serie — coincidencia, no obligatorio). - DEP-2026-0099 + INV-2026-0017 (DEP se activa con más frecuencia si tiene muchos clientes pequeños con anticipos pero pocas finalizaciones de proyectos en un año).
Esto es intencional — los diferentes tipos de documentos sirven a diferentes temporalizaciones de eventos legales, por lo que sus secuencias no están relacionadas.
¿Qué ocurre si la fila del contador se desincroniza? Extremadamente raro (requeriría un error de integridad de la base de datos); si ocurre, la siguiente factura reutiliza un número existente → IntegrityError al insertar debido a la restricción única en (autónomo, tipo, año, número) en el modelo del documento. Clozo lo detecta y reintenta con el siguiente número disponible. Impacto visible para el usuario final: ~50 ms adicionales en el raro guardado conflictivo.
Prefijos de numeración personalizados por empresa. Actualmente no es configurable — cada usuario de Clozo tiene los mismos prefijos INV- / DEP- / STR- / DCR- / CRN- / REC- / PRO- / AGR-. Algunos sistemas de contabilidad heredados prefieren prefijos solo numéricos o específicos de la empresa (p. ej., «RE-2026-0042» para una «Rechnung» alemana). En la hoja de ruta; por ahora, los prefijos estandarizados son reconocidos en la UE y aceptados por todas las autoridades fiscales que hemos probado.
Troubleshooting
Keep reading
Refunds & Notifications
EU invoice compliance — Art. 226 mandatory fields, sequence numbering, retention
Every invoice Clozo issues complies with EU VAT Directive Art. 226: 14 mandatory fields, sequential numbering with no gaps, immutability after issue, and 10-year retention.
Proposals & Invoices
The deposit invoice (DEP-) — Anzahlungsrechnung, facture d'acompte
The deposit invoice is the legal artefact that records VAT liability on an advance payment. Under EU VAT Directive Art. 65, the deposit becomes chargeable the moment the client pays — the deposit invoice is what the law requires you issue.
Proposals & Invoices
The final invoice (INV-) — Schlussrechnung, facture de solde
The final invoice closes the project. It states the full work value, then explicitly references the deposit invoice and **deducts both the deposit amount and the deposit VAT**, so you don't pay tax twice. This deduction is mandated by §14 UStG and parallel rules across the EU.
Proposals & Invoices
The Clozo invoice family: DEP, INV, STR, DCR, CRN, REC
Six document types make up the full Clozo invoicing chain. Each has a distinct legal role under EU VAT Directive Art. 220 and §14 UStG. This article maps which document fires when and what it references.