Proposals & Invoices · Article 5.9
Numérotation des factures — séquentielle par année et par type, atomique, sans interruption
Chaque facture reçoit un numéro séquentiel d'un compteur atomique délimité par freelancer, par année et par type de document. Aucune interruption autorisée en vertu de l'art. 226(2) de la directive TVA UE ; appliqué par un verrou de base de données au niveau de la ligne afin que les opérations simultanées ne puissent pas entrer en collision.
La numérotation des factures semble triviale jusqu'à ce que vous considériez : deux factures en cours d'émission au même instant ne doivent pas entrer en collision sur un numéro ; les factures supprimées ne peuvent pas libérer leur numéro pour réutilisation ; une limite d'année doit être réinitialisée proprement ; les trous dans la séquence sont des signaux d'alarme lors des audits. La conception du compteur résout tous ces problèmes en un seul mécanisme — implémenté dans apps/proposals/models.py:DocumentCounter et utilisé partout où un document est numéroté.
Why this works this way
Pourquoi aucune interruption n'est autorisée en vertu du droit européen. L'art. 226(2) de la directive TVA UE exige que les numéros de factures soient « basés sur une ou plusieurs séries qui identifient la facture de façon unique ». Les mises en œuvre nationales (§14 UStG en DE, BTW art. 35a en NL) exigent explicitement une séquence continue sans interruption. Les auditeurs considèrent les trous dans la séquence comme un signal que des factures ont été émises puis dissimulées (un schéma d'évasion courant : imprimer une facture pour un paiement en espèces, la détruire, personne ne remarque le trou). La norme d'audit : chaque numéro de 0001 en avant dans une année donnée doit exister dans vos dossiers.
La conception du compteur (apps/proposals/models.py:DocumentCounter) :
``python
class DocumentCounter(BaseModel):
freelancer = ForeignKey(User) # périmètre : par freelancer
document_type = CharField() # périmètre : par type (PROPOSAL, DEPOSIT, FINAL, …)
year = IntegerField() # périmètre : par année
next_number = IntegerField(default=1) # la valeur
class Meta:
unique_together = [('freelancer', 'document_type', 'year')]
``
Le modèle d'incrémentation atomique :
``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() émet une requête SQL SELECT … FOR UPDATE qui prend un verrou au niveau de la ligne sur la ligne du compteur pour la durée de la transaction. Les transactions simultanées pour la même ligne de compteur se bloquent sur le verrou ; une fois la première transaction validée, la deuxième voit next_number = 2 et procède. Aucune collision possible.
Pourquoi cela est important pour les avenants et les storno. Lorsqu'un avenant génère un Storno (STR-) et un nouveau INV (révision 2), chacun reçoit son propre numéro séquentiel de son propre compteur :
- STR-2026-0001 (premier storno de l'année)
- INV-2026-0067 (prochain INV disponible dans votre année, distinct de tout INV précédent)
Le nouveau INV est la revision=2 de la même facture logique mais reçoit un nouveau numéro. Le INV original (révision 1) conserve son numéro original ; les deux sont préservés (l'original est marqué superseded, jamais supprimé). Ainsi, la séquence INV ne présente aucune interruption — chaque INV émis reste présent, simplement avec un marqueur superseded pour ceux qui ont été remplacés.
Réinitialisation à la limite de l'année. Le 1er janvier, le champ year change ; les nouvelles factures recherchent (freelancer, type, 2027) — cette ligne n'existe pas encore, donc get_or_create la crée avec next_number=1. La ligne de compteur de l'année précédente reste telle quelle (ne pas supprimer ; utile pour l'audit). La première facture de la nouvelle année est INV-2027-0001.
Pas de réutilisation, pas de comblement des interruptions. Si une facture est annulée (Storno), son numéro reste dans la séquence — le Storno est un nouveau document y faisant référence ; il ne libère pas le numéro original. Si une facture a été émise par erreur (p. ex. données de test en production — ne devrait jamais arriver, mais), elle occupe quand même son emplacement. La piste d'audit est préservée.
Indépendance par type de document. Votre compteur DEP est indépendant de votre compteur INV. Vous pouvez donc avoir :
- DEP-2026-0042 + INV-2026-0042 (un projet où DEP et INV ont par coïncidence le même numéro de série — coïncidence, pas imposé). - DEP-2026-0099 + INV-2026-0017 (la DEP se déclenche plus souvent si vous avez de nombreux petits clients avec des acomptes mais peu d'achèvements de projets dans une année).
C'est intentionnel — les différents types de documents servent différents calendriers d'événements juridiques, donc leurs séquences ne sont pas liées.
Que se passe-t-il si la ligne de compteur se désynchronise ? Extrêmement rare (nécessiterait un bug d'intégrité de base de données) ; si c'est le cas, la prochaine facture réutilise un numéro existant → IntegrityError à l'insertion en raison de la contrainte d'unicité sur (freelancer, type, année, numéro) sur le modèle de document. Clozo capture cela et réessaie avec le prochain numéro disponible. Impact visible par l'utilisateur final : ~50ms supplémentaires sur la sauvegarde conflictuelle rare.
Préfixes de numérotation personnalisés par entreprise. Pas actuellement configurable — chaque utilisateur Clozo a les mêmes préfixes INV- / DEP- / STR- / DCR- / CRN- / REC- / PRO- / AGR-. Certains systèmes comptables hérités préfèrent les préfixes numériques uniquement ou spécifiques à l'entreprise (p. ex. « RE-2026-0042 » pour un « Rechnung » allemand). Sur la feuille de route ; pour l'instant, les préfixes standardisés sont reconnus dans l'UE et acceptés par chaque autorité fiscale que nous avons testée.
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.