„AN26000001” mówi więcej niż „S00001”: to oferta, pochodzi z 2026 roku i jest pierwsza. Wiele firm, zwłaszcza tych, które przechodzą ze starszego systemu na Odoo, chce zachować swoje numery dokumentów właśnie w takiej postaci. Samo Odoo numeruje oferty, zamówienia i dowody dostawy własnymi ciągami (S00001, WH/OUT/00001, P00001), a faktury prefiksem dziennika i rokiem (INV/2026/00001).
Napisaliśmy w tym celu moduł Document Numbering by Prefix and Year (document_number_prefix_year) dla Odoo 19. Jest dostępny jako wolne oprogramowanie na licencji LGPL-3 na GitHubie:
github.com/Alex0176/odoo-document-number-prefix-year
Najpierw uczciwa uwaga: W Biricon IT Services nie używamy tego modułu. Publikujemy go, ponieważ jest gotowy, udokumentowany i wyposażony w testy, i może innym zaoszczędzić pracy. Kto go używa, powinien przeczytać sekcje o ograniczeniach i Testy .
Schemat numeracji
Każdy numer składa się z trzech części: prefiksu dla danego rodzaju dokumentu, roku i licznika o stałej liczbie cyfr. Prefiks, format roku (26 lub 2026) i liczbę cyfr ustawiają Państwo dla każdej firmy w Ustawienia → Numeracja dokumentów.
Obsługiwane są oferty, zamówienia klientów, faktury i noty kredytowe klientów, dowody dostawy, przyjęcia towarów i zamówienia zakupu. Prefiksy na ilustracji są tylko przykładami: AN, AU, RE, GU, LI, WE, BE. Kto pozostawi prefiks pusty, zachowuje dla tego rodzaju dokumentu standardową numerację Odoo. Moduł nie robi więc nic, dopóki go Państwo nie skonfigurują.
Jak zachowują się numery
- Co roku od nowa. Licznik zaczyna znów od 1 wraz ze zmianą roku.
- Dalej po zaimportowanych numerach. Moduł szuka najwyższego istniejącego numeru z tym samym prefiksem i rokiem, bez względu na jego długość. Jeśli w bazie danych znajduje się ze starego systemu
AN26119, następna oferta otrzyma numerAN26000120. Dlatego moduł nadaje się przy zmianie systemu: stare dokumenty są importowane z oryginalnymi numerami, a nowe dokumenty płynnie do nich nawiązują. - Nowy numer zamówienia przy potwierdzeniu. Potwierdzona oferta otrzymuje na życzenie numer z ciągu zamówień. Numer oferty pozostaje zachowany w polu Numer oferty przy zamówieniu i jest widoczny w formularzu, na liście i w wyszukiwarce.
- Faktury przy księgowaniu. Faktury i noty kredytowe klientów otrzymują numer dopiero przy księgowaniu, a nie przy zakładaniu. Usunięte wersje robocze nie pozostawiają więc luki. Rok pochodzi z daty faktury: faktura z 30.12.2025, zaksięgowana 2.1.2026, nosi numer
RE25…. - Cała reszta pozostaje. Faktury dostawców, płatności, zapisy księgowe i zlecenia produkcyjne zachowują standardowe ciągi Odoo. Istniejące nazwy nigdy nie są przepisywane, także wtedy, gdy moduł zostanie ponownie wyłączony.
Newralgiczna część: dwóch użytkowników naraz
Własne nadawanie numerów wygląda prosto: znaleźć najwyższy numer i dodać jeden. Takie nie jest, gdy tylko dwóch użytkowników w tej samej chwili zakłada ofertę. Obaj odczytują „najwyższy numer = 0”, obaj nadają AN26000001. Odoo ma w tym celu dla własnych ciągów sekwencje bazy danych. Przy samodzielnie zbudowanym numerze tego brakuje, a dla ofert i zamówień zakupu Odoo nie ma ponadto żadnej kontroli unikalności nazwy: dwa dokumenty o tym samym numerze są po prostu zapisywane.
Oczywistym zabezpieczeniem jest blokada. Moduł zakłada dla każdej firmy, prefiksu i roku blokadę bazy danych (PostgreSQL Advisory Lock), która trwa do końca transakcji. Drugi użytkownik czeka, aż pierwszy skończy. To jednak nie wystarcza, co odkryliśmy podczas próby na kopii bazy produkcyjnej:
Odoo pracuje na poziomie izolacji REPEATABLE READ. Stan bazy danych widziany przez transakcję zostaje zamrożony przy jej pierwszym zapytaniu. Użytkownik B ma już ten stan, zanim A skończy. Gdy B następnie czeka na blokadę i ją otrzymuje, odczytuje ze swoim starym stanem „najwyższy numer = 0” i nadaje ten numer po raz drugi. Blokada uregulowała kolejność, ale nie odświeżyła wiedzy.
Rozwiązaniem jest drugi odczyt przez własne, krótkotrwałe połączenie z bazą danych, które widzi wszystkie już zatwierdzone wiersze. Wygrywa większa z dwóch wartości. Pierwszy odczyt pozostaje potrzebny, ponieważ tylko on zna numery, które ta sama transakcja już nadała, ale jeszcze nie zatwierdziła, na przykład przy imporcie kilku dokumentów naraz.
Sprawdziliśmy to na dwóch transakcjach, z których druga, co zostało potwierdzone, pobrała swój stan przed zatwierdzeniem (commit) pierwszej, a następnie czekała na blokadę. Bez drugiego odczytu oba zamówienia otrzymały ten sam numer, z nim numery 1 i 2.
Ważne dla oceny: Ta próba jest sprawdzeniem ręcznym. Nie wchodzi w skład testów automatycznych, ponieważ wymaga dwóch prawdziwych połączeń z bazą danych, których środowisko testowe Odoo (jedna transakcja na test) nie zapewnia.
Realizacja techniczna
| Dokument | Punkt zaczepienia |
|---|---|
| Oferta | sale.order.create, gdy nazwa jest pusta, / lub New |
| Zamówienie klienta | sale.order.action_confirm, przed standardowym potwierdzeniem |
| Faktura, nota kredytowa | account.move._set_next_sequence, wywoływane przy księgowaniu |
| Dowód dostawy, przyjęcie towarów | stock.picking.create według typu operacji |
| Zamówienie zakupu | purchase.order.create |
- Licznik. Najwyższy numer znajduje wyrażenie regularne (
^<rdzeń>([0-9]{1,15})$, rdzeń jest maskowany) dla każdej firmy, wraz z nazwami bez firmy. - Faktury.
_set_next_sequencezapisuje nazwę i wywołuje_compute_split_sequence, aby logika sekwencji Odoo (prefiks, numer, rozpoznawanie roku dla następnej faktury dziennika) pozostała spójna. - Ustawienia. Pola firmy
document_number_*są odzwierciedlane wres.config.settings. Ustawienia odrzucają prefiksy ze spacją lub cyfrą na końcu. - Tłumaczenie. Niemieckie tłumaczenie jest dołączone.
Instalacja i konfiguracja
- Umieścić folder
document_number_prefix_yearw ścieżce addonów. - Odświeżyć listę aplikacji, zainstalować moduł. Wymagane są Sprzedaż, Zakupy, Magazyn i Księgowość.
- W Ustawienia → Numeracja dokumentów wpisać prefiksy, format roku i liczbę cyfr.
- Najpierw wypróbować na kopii. Numeru dokumentu nie da się później automatycznie cofnąć, a w przypadku faktur z numerem wiążą się obowiązki archiwizacji i kontroli.
ograniczeniach
- Oferty są numerowane przy zakładaniu. Usunięte lub anulowane oferty pozostawiają luki. To samo dotyczy każdego zamówienia klienta, które zakłada inny moduł: koszyki sklepu internetowego (
website_sale) to zamówienia w statusie Oferta i zużywają po jednym numerze. Bez luk są tylko faktury i noty kredytowe, ponieważ są numerowane przy księgowaniu. - Nie zmieniać formatu roku w trakcie pracy. Przy rdzeniu
AN26moduł odczytuje istniejącyAN2026000001jako licznik26000001. Format należy ustalić przed pierwszym dokumentem. - Licznik najwyżej 15 cyfr. Dłuższe ciągi cyfr po rdzeniu są pomijane przy wyszukiwaniu najwyższego numeru.
- Brak oddzielnych serii dla dziennika lub magazynu. Licznik obowiązuje dla firmy, prefiksu i roku. Kilka dzienników sprzedaży dzieli licznik faktur.
- Prefiksy nie mogą zawierać spacji ani kończyć się cyfrą, w przeciwnym razie prefiksu, roku i licznika nie da się już rozdzielić.
- Obsługiwane są tylko wymienione rodzaje dokumentów.
Testy
Moduł zawiera dziesięć testów automatycznych. Sprawdzają one:
- Oferta i potwierdzenie: numer oferty i zamówienia, zachowanie numeru oferty
- Liczenie dalej po zaimportowanym numerze (
AN26119→AN26000120) - brak późniejszej zmiany numeracji istniejących dokumentów
- Faktura, nota kredytowa i zmiana roku według daty faktury
- Zamówienie zakupu i dowody dostawy
- pusty prefiks: standardowy numer Odoo pozostaje
- czterocyfrowy rok
- Prefiks ze znakami specjalnymi
- kilka numerów w jednej transakcji
- bardzo długie ciągi cyfr są pomijane
Wywołanie:
odoo-bin -d <Testdatenbank> -i document_number_prefix_year --test-enable --test-tags=/document_number_prefix_year --stop-after-init
Testy działają na zwykłych transakcjach. Zachowanie przy równoczesnym zakładaniu przez dwóch użytkowników do nich nie należy, zostało sprawdzone ręcznie na kopii bazy danych, jak opisano powyżej. Kto używa modułu w systemie z wieloma równoczesnymi użytkownikami, powinien powtórzyć tę próbę na własnej bazie danych.
Uwaga prawna dotycząca numeru faktury
Faktury muszą według § 11 UStG nosić kolejny numer, nadawany jednokrotnie w celu identyfikacji faktury. Moduł numeruje faktury przy księgowaniu i z własnym licznikiem dla każdego prefiksu i roku, co do tego pasuje. To, czy Państwa konkretne ustawienie (kilka dzienników, noty kredytowe z własnym prefiksem, zmiana roku) spełnia wymagania Państwa doradcy podatkowego, muszą Państwo wyjaśnić z nim. Ten wpis nie stanowi porady prawnej.
Najczęstsze pytania
Dlaczego po prostu nie dostosować sekwencji Odoo?
W przypadku faktur jest to możliwe przez prefiks dziennika. Dla ofert, zamówień, dowodów dostawy i zamówień zakupu nie ma jednak wspólnego schematu z prefiksu, roku i licznika ze zmianą roku, a licznik nie zna zaimportowanych starych numerów. Tu właśnie wkracza moduł.
Czy istniejąca numeracja jest nadpisywana?
Nie. Moduł nadaje tylko nowe numery. Już zapisane nazwy pozostają bez zmian, także po wyłączeniu.
Jak go ponownie wyłączyć?
Proszę wyczyścić prefiks danego rodzaju dokumentu. Wtedy Odoo znów numeruje je samo. Także odinstalowanie nie zmienia nadanych numerów.
Czy Państwo sami go używają?
Nie. U nas działają standardowe numery Odoo. Sprawdziliśmy moduł za pomocą testów automatycznych i opisanej próby ręcznej, ale nie w działającym systemie z wieloma użytkownikami.
Czy działa z Odoo 17 lub 18?
Testowaliśmy go tylko z Odoo 19.0 Community. Dla innych wersji może pasować lub nie, nie sprawdzaliśmy tego.
Na jakiej licencji jest udostępniony?
Na licencji LGPL-3. Błędy i ulepszenia są mile widziane jako issue w repozytorium GitHub .
Wsparcie ze strony Biricon IT Services
Opiekujemy się instalacjami Odoo dla małych i średnich firm: od wdrożenia, przez dostosowania i migracje, aż po bieżącą eksploatację. Jeśli chcą Państwo zachować numery dokumentów przy zmianie systemu, sprawdzić nadawanie numerów pod obciążeniem lub bezpiecznie wdrożyć taki moduł na instancji produkcyjnej, chętnie pomożemy. Kolejne własne rozwiązania: Firmenbuch i weryfikacja adresów dla austriackich klientów, Zestawy produktów w ofercie jako sekcja i Web RBL, lista blokad dla ruchu atakującego.
Stan na 3 listopada 2026 r. Wersja modułu 19.0.1.0.0. Wszystkie numery w przykładach i na ilustracjach zostały dobrane dowolnie.