Proposals & Invoices ยท Article 5.9
Invoice numbering โ sequential per year per type, atomic, no gaps
Every invoice gets a sequential number from an atomic counter scoped per freelancer per year per document type. No gaps allowed under EU VAT Directive Art. 226(2); enforced by a row-level database lock so concurrent operations cannot collide.
Invoice numbering looks trivial until you consider: two invoices in flight at the exact same moment must not collide on a number; deleted invoices can't free up their number for reuse; a year boundary must reset cleanly; gaps in sequence are red flags in audits. The counter design solves all of these in one mechanism โ implemented in apps/proposals/models.py:DocumentCounter and used everywhere a document is numbered.
Why this works this way
Why no gaps allowed under EU law. EU VAT Directive Art. 226(2) requires invoice numbers to be "based on one or more series, which uniquely identifies the invoice". National implementations (ยง14 UStG in DE, BTW Art. 35a in NL) explicitly require continuous sequence with no gaps. Auditors look at sequence holes as a signal that invoices were issued and then withheld (a common evasion pattern: print an invoice for cash payment, destroy it, no one notices the gap). The audit standard: every number from 0001 upward in a given year must exist in your records.
The counter design (apps/proposals/models.py:DocumentCounter):
``python
class DocumentCounter(BaseModel):
freelancer = ForeignKey(User) # scope: per freelancer
document_type = CharField() # scope: per type (PROPOSAL, DEPOSIT, FINAL, โฆ)
year = IntegerField() # scope: per year
next_number = IntegerField(default=1) # the value
class Meta:
unique_together = [('freelancer', 'document_type', 'year')]
``
The atomic increment pattern:
``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() issues a SELECT โฆ FOR UPDATE SQL query that takes a row-level lock on the counter row for the duration of the transaction. Concurrent transactions for the same counter row block on the lock; once the first transaction commits, the second sees next_number = 2 and proceeds. No collision possible.
Why this matters for amendments and storno. When an amendment generates a Storno (STR-) and a new INV (revision 2), each gets its own sequential number from its own counter:
- STR-2026-0001 (first storno of the year)
- INV-2026-0067 (next available INV in your year, distinct from any earlier INV)
The new INV is revision=2 of the same logical invoice but gets a fresh number. The original INV (revision 1) keeps its original number; both are preserved (the original is marked superseded, never deleted). This way, the INV sequence shows no gap โ every issued INV remains, just with a superseded flag for ones that were replaced.
Year-boundary reset. On January 1, the year field changes; new invoices look up (freelancer, type, 2027) โ that row doesn't exist yet, so get_or_create creates it with next_number=1. Last year's counter row stays as-is (don't delete; useful for audit). The first invoice of the new year is INV-2027-0001.
No reuse, no gap-filling. If an invoice is voided (Storno), its number remains in the sequence โ the Storno is a new document referencing it; it doesn't free up the original number. If an invoice is mistakenly issued (e.g., test data in production โ should never happen, but), it still occupies its slot. The audit trail is preserved.
Per-document-type independence. Your DEP counter is independent of your INV counter. So you can have:
- DEP-2026-0042 + INV-2026-0042 (a project where DEP and INV happened to land on the same serial โ coincidence, not enforced). - DEP-2026-0099 + INV-2026-0017 (DEP fires more often if you have many small clients with deposits but few project completions in a year).
This is intentional โ different document types serve different legal-event timing, so their sequences are unrelated.
What happens if the counter row gets out of sync? Extremely rare (would require a database integrity bug); if it does, the next invoice reuses an existing number โ IntegrityError on insert because of the unique constraint on (freelancer, type, year, number) on the document model. Clozo catches this and retries with the next available number. End-user-visible impact: an extra ~50ms on the rare conflicting save.
Custom numbering prefixes per business. Not currently configurable โ every Clozo user has the same INV- / DEP- / STR- / DCR- / CRN- / REC- / PRO- / AGR- prefixes. Some legacy accounting systems prefer numeric-only or business-specific prefixes (e.g., "RE-2026-0042" for a German "Rechnung"). On the roadmap; for now, the standardised prefixes are EU-recognised and accepted by every tax authority we've tested against.
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.