Proposals & Invoices · Article 5.9
Numeracja faktur — sekwencyjna per rok per typ, atomowa, bez luk
Każda faktura otrzymuje numer sekwencyjny z atomowego licznika z zakresem per freelancer per rok per typ dokumentu. Żadnych luk niedopuszczalnych zgodnie z Art. 226(2) Dyrektywy VAT UE; egzekwowane przez blokadę bazy danych na poziomie wiersza, żeby równoczesne operacje nie mogły kolidować.
Numeracja faktur wydaje się trywialna, dopóki nie rozważysz: dwie faktury w locie w tym samym momencie nie mogą kolidować na numerze; usunięte faktury nie mogą zwolnić swojego numeru do ponownego użycia; granica roku musi resetować się czysto; luki w sekwencji są czerwonymi flagami w audytach. Projekt licznika rozwiązuje to wszystko w jednym mechanizmie — zaimplementowanym w apps/proposals/models.py:DocumentCounter i używanym wszędzie tam, gdzie dokument otrzymuje numer.
Why this works this way
Dlaczego zgodnie z prawem UE nie są dozwolone luki. Art. 226(2) Dyrektywy VAT UE wymaga, żeby numery faktur były "oparte na jednej lub kilku seriach, jednoznacznie identyfikujących fakturę". Krajowe implementacje (§14 UStG w DE, BTW Art. 35a w NL, Art. 106e ust. 1 pkt 2 Ustawy o VAT w PL) wyraźnie wymagają ciągłej sekwencji bez luk. Audytorzy traktują luki w sekwencji jako sygnał, że faktury zostały wystawione, a następnie ukryte (powszechny wzorzec unikania podatków: wydrukuj fakturę za gotówkę, zniszcz ją, nikt nie zauważy luki). Standard audytu: każdy numer od 0001 wzwyż w danym roku musi istnieć w Twoich aktach.
Projekt licznika (apps/proposals/models.py:DocumentCounter):
``python
class DocumentCounter(BaseModel):
freelancer = ForeignKey(User) # zakres: per freelancer
document_type = CharField() # zakres: per typ (PROPOSAL, DEPOSIT, FINAL, …)
year = IntegerField() # zakres: per rok
next_number = IntegerField(default=1) # wartość
class Meta:
unique_together = [('freelancer', 'document_type', 'year')]
``
Wzorzec atomowego przyrostu:
``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() wydaje zapytanie SQL SELECT … FOR UPDATE, które zajmuje blokadę na poziomie wiersza dla wiersza licznika przez czas trwania transakcji. Równoczesne transakcje dla tego samego wiersza licznika blokują się na blokadzie; gdy pierwsza transakcja zatwierdzi, druga widzi next_number = 2 i kontynuuje. Kolizja niemożliwa.
Dlaczego ma to znaczenie dla aneksów i storno. Gdy aneks generuje Storno (STR-) i nowy INV (wersja 2), każdy otrzymuje własny numer sekwencyjny z własnego licznika:
- STR-2026-0001 (pierwsze storno roku)
- INV-2026-0067 (następny dostępny INV w Twoim roku, różny od wcześniejszych INV)
Nowy INV to revision=2 tej samej logicznej faktury, ale otrzymuje świeży numer. Oryginalny INV (wersja 1) zachowuje swój oryginalny numer; oba są zachowane (oryginał jest oznaczony jako zastąpiony, nigdy usunięty). W ten sposób sekwencja INV nie pokazuje luki — każdy wystawiony INV pozostaje, tylko z flagą zastąpiony dla tych, które zostały zastąpione.
Reset granicy roku. 1 stycznia pole year zmienia się; nowe faktury wyszukują (freelancer, typ, 2027) — ten wiersz jeszcze nie istnieje, więc get_or_create tworzy go z next_number=1. Wiersz licznika z poprzedniego roku pozostaje bez zmian (nie usuwaj; przydatny dla audytu). Pierwsza faktura nowego roku to INV-2027-0001.
Brak ponownego użycia, brak wypełniania luk. Jeśli faktura jest unieważniona (Storno), jej numer pozostaje w sekwencji — Storno to nowy dokument się do niej odwołujący; nie zwalnia oryginalnego numeru. Jeśli faktura jest błędnie wystawiona (np. dane testowe w produkcji — nie powinno się zdarzyć, ale), nadal zajmuje swoje miejsce. Ścieżka audytu jest zachowana.
Niezależność per typ dokumentu. Twój licznik DEP jest niezależny od licznika INV. Więc możesz mieć:
- DEP-2026-0042 + INV-2026-0042 (projekt, gdzie DEP i INV przypadkowo trafiły na ten sam numer seryjny — zbieg okoliczności, nie wymuszone). - DEP-2026-0099 + INV-2026-0017 (DEP wyzwala się częściej, jeśli masz wielu małych klientów z zaliczkami, ale nieliczne zakończenia projektów w roku).
To jest celowe — różne typy dokumentów obsługują różny czas zdarzeń prawnych, więc ich sekwencje są niezwiązane.
Co się dzieje, gdy wiersz licznika desynchronizuje się? Niezwykle rzadkie (wymagałoby błędu integralności bazy danych); jeśli tak się dzieje, następna faktura używa ponownie istniejącego numeru → IntegrityError przy wstawieniu ze względu na unikalne ograniczenie na (freelancer, typ, rok, numer) w modelu dokumentu. Clozo to przechwytuje i ponawia z następnym dostępnym numerem. Wpływ widoczny dla użytkownika końcowego: dodatkowe ~50ms przy rzadkim kolidującym zapisie.
Niestandardowe prefiksy numeracji per firma. Obecnie nie są konfigurowalne — każdy użytkownik Clozo ma te same prefiksy INV- / DEP- / STR- / DCR- / CRN- / REC- / PRO- / AGR-. Niektóre starsze systemy księgowe preferują prefiksy tylko numeryczne lub specyficzne dla firmy (np. „RE-2026-0042" dla niemieckiego „Rechnung" lub „FV-2026-0042" dla polskiej „Faktury VAT"). W planie; na razie standardowe prefiksy są uznawane w UE i akceptowane przez każdy urząd skarbowy, z którym przeprowadziliśmy testy.
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.