Przejdź do treści
[ ← blog ]
// blog · wpis

KSeF: co zrobić, gdy wysyłka faktury utknie i status jest nieznany

· 4 min czytania · Dawid Kuliberda

Drugi klik w KSeF rejestruje drugi dokument. Tego nie da się cofnąć.

KSeF jest obowiązkowym krajowym systemem e-fakturowania. Kiedy wysyłasz fakturę i system nie odpowiada w wyznaczonym czasie, stajesz przed wyborem bez dobrego wyjścia: poczekać i mieć nadzieję, że jednak doszło, albo spróbować ponownie i ryzykować, że pierwsza wysyłka trafiła. Pracownik pod presją wybiera to drugie. Jeśli pierwsza faktura rzeczywiście doszła, właśnie zarejestrowałeś duplikat w systemie państwowym.

Ten wpis serii opisuje szablon, który układa wysyłkę faktur tak, żeby nigdy nie szła w ciemno.

Maszyna stanów na niepewne wyniki

Centralny pomysł jest prosty. Przed każdą próbą wysyłki do systemu zewnętrznego workflow zapisuje ZAMIAR wysyłki w bazie danych. Wiersz z unikalnym kluczem próby trafia do tabeli jeszcze przed wywołaniem API. Jeśli aplikacja padnie w tym wąskim oknie, awaria nie jest niewidzialna. Przy następnym uruchomieniu sweepów wiadomo, że próba miała miejsce, której faktury dotyczyła i na jakim etapie stanęła.

Każda faktura przechodzi walidację dwa razy: na wejściu przez webhook, a potem w sweepie wysyłkowym, który sprawdza między innymi sumę kontrolną NIP i kształt XML. Brakujące albo nieprawidłowe dane kończą się stanem VALIDATION_REJECTED i wpisem do kolejki wyjątków dla człowieka. Żadna z tych faktur nie trafi do systemu zewnętrznego.

Faktury, które przejdą walidację, doczekają się próby wysyłki. Każda próba kończy się jednym z jawnych, nazwanych stanów. Timeout dostaje własny stan UNKNOWN_OUTCOME, odrębny od błędu i od potwierdzenia. Wynik nieznany też jest wynikiem. To rozróżnienie ma twarde konsekwencje przy kolejnym uruchomieniu sweepów.

Jak sweep naprawczy podejmuje decyzje

Co 30 minut sweep naprawczy przegląda nierozwiązane stany. Sweep najpierw pyta system o status konkretnej wysyłki po jej własnym identyfikatorze i dopiero potem rozważa ponowienie. Adapter zwraca jedną z czterech odpowiedzi: zaakceptowano, nie ma takiej wysyłki, nieznane, błąd.

Jedyna odpowiedź, która otwiera drogę do jednej ponownej próby, to autorytatywne "nie ma takiej wysyłki": twarda odpowiedź samego systemu. Brak wpisu w lokalnym rejestrze się nie liczy. Każda inna odpowiedź oznacza, że faktura czeka z zerem dodatkowych wywołań do API. Sweep nie zakłada niczego.

Dwa mechanizmy w tym szablonie zasługują na osobne wymienienie.

Pierwszy to idempotencja na tożsamości prawnej. Kluczem każdej faktury jest skrót SHA-256 z NIP-u sprzedawcy i numeru faktury. Jeśli do systemu trafi faktura z tą samą kombinacją NIP i numer, ale z inną kwotą lub walutą, workflow nie traktuje jej jako ponownej próby pierwszego dokumentu. Kieruje ją do człowieka ze stanem CORRECTION_REQUIRED_SAME_LEGAL_IDENTITY. Duplikat z inną kwotą nigdy nie trafia automatycznie do KSeF.

Drugi to circuit breaker na przeciążenie API. Kaskada odpowiedzi 429 od systemu zewnętrznego otwiera bezpiecznik - pole breaker_open_until w statycznych danych workflow. Dopóki bezpiecznik jest otwarty, kolejne faktury wchodzą do kolejki ze stanem BREAKER_OPEN_QUEUED. Zero dodatkowych wywołań do API, które właśnie powiedziało, że ma za dużo żądań.

Każde przejście między stanami ląduje w dzienniku dowodowym. Wyjątki dostają komunikat po polsku dla operatora: co się stało i co operator ma zrobić.

Co jest w repozytorium

Szablon jest dostępny bezpłatnie: https://github.com/kuliberdalabs/n8n-sme-workflows/tree/main/workflows/07-ksef-exception-desk. To siódmy z ośmiu szablonów w repozytorium.

Kilka rzeczy trzeba powiedzieć wprost.

Szablon nie woła prawdziwego API KSeF. Kroki wysyłki i sprawdzania statusu działają na wbudowanym mocku, który odwzorowuje kształty odpowiedzi systemu: referencje, UPO, odpowiedzi 429, timeouty. Wpięcie produkcyjnego API i kwalifikowanego certyfikatu to praca po stronie integracji. Szablon dostarcza maszynę stanów i logikę decyzyjną.

W środku jest zestaw scenariuszy testowych T01 do T14 z syntetycznymi NIP-ami. Liczby 9999999999 i 1111111111 przechodzą weryfikację sumy kontrolnej, ale nie należą do żadnego rzeczywistego podmiotu. Przed uruchomieniem produkcyjnym zastępujesz ten blok fixtur swoim rzeczywistym źródłem faktur.

Warto zanotować jedno ograniczenie architektoniczne. Sweep używa odczytów z Data Table i statycznych danych workflow do ochrony przed duplikatami, nie atomowej blokady bazy. Dwa równoległe sweepy nie są serializowane. W praktyce uruchamiasz jeden sweep na raz.

W szablonie jest też przygotowany adapter dla przyszłego przejścia na certyfikat kwalifikowany. Dziś konfiguracja certyfikatu kończy się zamkniętym błędem AUTH_ADAPTER_BLOCKED. Przy docelowej integracji wystarczy zmiana konfiguracji zamiast przepisywania całego flow.

Kiedy szablon nie wystarcza

Jeśli twoja księgowość obsługuje KSeF przez gotowy program do fakturowania, który robi to automatycznie w tle, ten szablon nie jest ci potrzebny. Robi się ciekawe, kiedy faktury przechodzą przez własny system - ERP, własny generator dokumentów, integrację z innym narzędziem - i potrzebujesz wiedzieć dokładnie, co trafia do KSeF, kiedy i z jakim wynikiem.

Wtedy do szablonu dochodzi realne API, kwalifikowany certyfikat i procesy księgowe wokół obsługi wyjątków. To praca wdrożeniowa, którą warto zaplanować z wyprzedzeniem.

Jeśli chcesz sprawdzić, czy ta sytuacja dotyczy twoich procesów, zacznij od bezpłatnej diagnozy: /kontakt. Karta z detalami szablonu i wariantami wdrożenia: /automatyzacje/straznik-ksef.

// next

Najprościej zacząć od diagnozy.

W pół godziny rozmowy usłyszysz konkretną odpowiedź: gdzie w Twojej firmie system zdejmie najwięcej ręcznej pracy.

UMÓW BEZPŁATNĄ DIAGNOZĘ →[ ← wróć na bloga ]
KSeF: co zrobić, gdy wysyłka faktury utknie i status jest nieznany | Kuliberda Labs