Proposals & Invoices · Article 5.9
Factuurnummering — opeenvolgend per jaar per type, atomisch, geen hiaten
Elke factuur krijgt een opeenvolgend nummer van een atomische teller die is begrensd per freelancer per jaar per documenttype. Geen hiaten toegestaan conform EU-BTW-Richtlijn Art. 226(2); afgedwongen door een rij-niveau databasevergrendeling zodat gelijktijdige bewerkingen niet kunnen botsen.
Factuurnummering lijkt triviaal totdat u bedenkt: twee facturen die op exact hetzelfde moment worden verwerkt mogen niet botsen op een nummer; verwijderde facturen kunnen hun nummer niet vrijgeven voor hergebruik; een jaargrens moet schoon resetten; hiaten in de reeks zijn rode vlaggen in audits. Het tellerontwerp lost al deze problemen op in één mechanisme — geïmplementeerd in apps/proposals/models.py:DocumentCounter en overal gebruikt waar een document wordt genummerd.
Why this works this way
Waarom geen hiaten zijn toegestaan onder EU-recht. EU-BTW-Richtlijn Art. 226(2) vereist dat factuurnummers "gebaseerd zijn op één of meer reeksen, die de factuur uniek identificeren". Nationale implementaties (§14 UStG in DE, BTW Art. 35a in NL) vereisen expliciet een ononderbroken reeks zonder hiaten. Accountants beschouwen reeksgaten als een signaal dat facturen zijn uitgerekt en vervolgens achtergehouden (een gebruikelijk ontduikingspatroon: een factuur printen voor contante betaling, hem vernietigen, niemand ziet het gat). De auditstandaard: elk nummer van 0001 opwaarts in een bepaald jaar moet in uw administratie aanwezig zijn.
Het tellerontwerp (apps/proposals/models.py:DocumentCounter):
``python
class DocumentCounter(BaseModel):
freelancer = ForeignKey(User) # bereik: per freelancer
document_type = CharField() # bereik: per type (PROPOSAL, DEPOSIT, FINAL, …)
year = IntegerField() # bereik: per jaar
next_number = IntegerField(default=1) # de waarde
class Meta:
unique_together = [('freelancer', 'document_type', 'year')]
``
Het atomische ophoogpatroon:
``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() geeft een SELECT … FOR UPDATE SQL-query uit die een rij-niveau vergrendeling neemt op de tellerrij voor de duur van de transactie. Gelijktijdige transacties voor dezelfde tellerrij blokkeren op de vergrendeling; zodra de eerste transactie commit, ziet de tweede next_number = 2 en gaat verder. Geen botsing mogelijk.
Waarom dit belangrijk is voor addenda en storno's. Wanneer een addendum een Storno (STR-) genereert en een nieuwe INV (revisie 2), krijgt elk zijn eigen opeenvolgend nummer van zijn eigen teller:
- STR-2026-0001 (eerste storno van het jaar)
- INV-2026-0067 (volgende beschikbare INV in uw jaar, anders dan eventuele eerdere INV's)
De nieuwe INV is revisie=2 van dezelfde logische factuur maar krijgt een nieuw nummer. De originele INV (revisie 1) behoudt zijn oorspronkelijke nummer; beide worden bewaard (het origineel is gemarkeerd als vervangen, nooit verwijderd). Zo toont de INV-reeks geen gat — elke uitgereichte INV blijft aanwezig, slechts met een vervangen-vlag voor vervangen exemplaren.
Reset op jaargrens. Op 1 januari verandert het jaar-veld; nieuwe facturen zoeken (freelancer, type, 2027) op — die rij bestaat nog niet, dus get_or_create maakt hem aan met next_number=1. De tellerrij van vorig jaar blijft ongewijzigd (niet verwijderen; nuttig voor audit). De eerste factuur van het nieuwe jaar is INV-2027-0001.
Geen hergebruik, geen hiaat-opvulling. Als een factuur wordt nietig verklaard (Storno), blijft zijn nummer in de reeks — de Storno is een nieuw document dat ernaar verwijst; het geeft het originele nummer niet vrij. Als een factuur per ongeluk is uitgerekt (bijv. testgegevens in productie — mag nooit gebeuren, maar), neemt het nog steeds zijn slot in. Het audittraject is bewaard.
Onafhankelijkheid per documenttype. Uw DEP-teller is onafhankelijk van uw INV-teller. U kunt dus hebben:
- DEP-2026-0042 + INV-2026-0042 (een project waarbij DEP en INV toevallig op hetzelfde serienummer uitkwamen — toeval, niet afgedwongen). - DEP-2026-0099 + INV-2026-0017 (DEP wordt vaker verstuurd als u veel kleine klanten heeft met voorschotten maar weinig projectvoltooiingen in een jaar).
Dit is opzettelijk — verschillende documenttypen dienen verschillende juridische gebeurtenistiming, dus hun reeksen zijn onafhankelijk.
Wat gebeurt er als de tellerrij niet gesynchroniseerd raakt? Uiterst zeldzaam (zou een database-integriteitsfout vereisen); als het toch gebeurt, hergebruikt de volgende factuur een bestaand nummer → IntegrityError bij invoeging vanwege de unieke beperking op (freelancer, type, jaar, nummer) op het documentmodel. Clozo vangt dit op en probeert het volgende beschikbare nummer. Zichtbaar effect voor de eindgebruiker: een extra ~50ms bij de zeldzame conflicterende opslag.
Aangepaste nummerprefixes per bedrijf. Momenteel niet configureerbaar — elke Clozo-gebruiker heeft dezelfde INV- / DEP- / STR- / DCR- / CRN- / BON- / PRO- / SOV- prefixes. Sommige legacy-boekhoudingsystemen geven de voorkeur aan nummeriek of bedrijfsspecifieke prefixes (bijv. "RE-2026-0042" voor een Duitse "Rechnung"). Op de roadmap; voor nu zijn de gestandaardiseerde prefixes EU-erkend en worden ze geaccepteerd door elke belastingautoriteit waartegen we hebben getest.
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.