Objawy
Klient zgłosił problem z fakturą sprzedaży w SubiektGT:
- faktura miała status “Wysłana (w trakcie przetwarzania),
- program nie pobierał numeru KSeF ani UPO mimo odświeżania statusów,
- widget KSeF pokazywał w „Dokumentach do wysłania” – “ogółem 1”.
Na pierwszy rzut oka wyglądało to jak problem z KSeF. Ale po weryfikacji okazało się że : faktura została wysłana i w KSeF poprawnie zaakceptowana – numer i UPO istnieją. To program nie dociągnął wyniku do bazy. Dokument utknął w połowie drogi.
Jak to działa w skrócie
- Program wysyła XML faktury do KSeF – w odpowiedzi dostaje unikalny identyfikator przetwarzania (UUID), zapisywany w bazie w
dok_IdPrzetwarzaniaKSeF. W terminologii API KSeF odpowiada to tzw. referencji elementu - KSeF przetwarza fakturę i nadaje numer KSeF (zwykle w kilka sekund).
- Cykliczne odświeżanie statusów ma pobrać numer i UPO do bazy.
Jeśli krok 3 zawiedzie – wygasły token sesji, chwilowa awaria, restart w złym momencie – dokument zostaje z referencją elementu, ale bez numeru, w stanie “w trakcie przetwarzania”. A faktura w portalu KSeF jest i ma numer. To nie błąd danych po stronie MF – to niedokończony zapis po stronie programu.
Rekonstrukcja awarii (co dokładnie się stało)
Odtworzyłem sekwencję zdarzeń z logów i UPO. Wyglądało to tak:
- 12:13:46.032 – SubiektGT wysyła fakturę do KSeF. Wysyłka dochodzi: KSeF zwraca referencję elementu, XML trafia do bazy.
- 12:13:46.104 – KSeF nadaje numer (72 ms po wysłaniu – widać to w UPO). Po stronie KSeF wszystko przebiega idealnie.
- 12:13:47 – i tu następuje zerwanie: program zapisuje “rozpoczęcie przetwarzania”, ale nigdy nie pobiera wyniku. Brak numeru w rejestrze, brak UPO, brak śladu w historii statusów.
- Dowód, że to awaria jednostkowa, a nie systemowa: tego samego dnia trzy inne faktury (11:12, 11:24, 14:43) przeszły normalnie. Padł tylko ten jeden przebieg o 12:13.
- Od tego momentu dokument wisi w statusie „Wysłana (w trakcie przetwarzania)” cykliczne odświeżanie (raz na 5 minut), ręczne odświeżanie nie rozwiązuje problemu.
Prawdopodobna przyczyna: chwilowa awaria “drugiej nogi” wysyłki – request wyszedł, ale pobranie wyniku (numeru/statusu) nie wykonało się. SubiektGT (prawdopodobnie) nie ma mechanizmu samonaprawy dla takiego przypadku, dlatego potrzebna była ingerencja.
Jak to namierzyłem
Oto zapytania, które rozstrzygnęły sprawę.
1. Stan dokumentu i rejestru (czy dokument w ogóle ma wpis KSeF):
SELECT d.dok_NrPelny, d.dok_StatusKSeF, d.dok_CzekaNaKSeF,
d.dok_IdPrzetwarzaniaKSeF, d.dok_NumerKSeFId, d.dok_SesjaKSeF,
f.ksef_StatusPrzetworzenia, f.ksef_NumerKSeF
FROM dbo.dok__Dokument d
LEFT JOIN dbo.ksef_FakturyHandel h ON h.ksefh_IdDokumentu = d.dok_Id
LEFT JOIN dbo.ksef_Faktury f ON f.ksef_Id = h.ksefh_IdFaktury
WHERE d.dok_NrPelny = '<NUMER_FAKTURY>';
2. Szybki sprawdzian skali problemu (ile wysłanych faktur nie ma numeru):
SELECT COUNT(*) FROM dbo.ksef_Faktury WHERE ksef_Zrodlo = 1 AND ksef_NumerKSeF IS NULL;
3. Rozstrzygający test – portal KSeF (ksef.mf.gov.pl): wyszukałem fakturę po referencji elementu. Jest z numerem. Czyli numer istnieje – trzeba go tylko dopisać w bazie, nie próbować wysyłać faktury ponownie.
Naprawa
Najpierw ścieżka w aplikacji – “Pobierz numer KSeF”, “Pobierz UPO”. Czasem to wystarcza. Tu nie wystarczyło.
Potem baza – ale z pełnym zachowaniem procedur: backup, zamknięte okna Subiekta, zatrzymanie usługi. Dane (numer, daty, UPO) brałem z portalu KSeF. Uzupełniłem ręcznie dane w bazie, rejestr KSeF, rejestr numerów i UPO.
Największy myk: “ghost” w widgecie KSeF
Po naprawie widget nadal pokazywał “Dokumenty do wysłania 1”, choć wszystkie listy (np „Widok: Dokumenty oczekujące na wysłanie do KSeF”) były puste. Okazało się, że widok liczników bierze dokumenty, które nie mają powiązania ID z rejestrem numerów – a moja naprawa wpisała numer tekstowo, ale nie ustawiła tego powiązania:
UPDATE dbo.dok__Dokument
SET dok_NumerKSeFId = (SELECT ksefnr_Id FROM dbo.ksef_NumerKSeF
WHERE ksefnr_NumerKSeF = '<NUMER_KSeF_Z_PORTALU>')
WHERE dok_NrPelny = '<NUMER_FAKTURY>';
Po restarcie Subiekta licznik spadł do zera.
