Wstęp
Problem pojawił się podczas rutynowej pracy w Rewizorze GT. Przy próbie dekretacji faktury program wyświetlał komunikat:
“Nieokreślony błąd”
Ręczne wprowadzenie dekretu również kończyło się błędem zapisu do bazy. Faktura widniała na liście dokumentów do dekretacji, ale każda operacja na niej – automatyczna, ręczna, według schematu – kończyła się tym samym błędem.
Wstępna diagnoza: problem dotyczy konkretnej faktury, inne dokumenty od tego samego kontrahenta dekretowały się bez problemu.

Objawy
- Subiekt GT w wersji 1.88 HF5
- Problem występuje w Rewizorze GT oraz Rachmistrzu GT
- Dotyczy zarówno linii GT jak i NEXO (wg zgłoszeń na forum InsERT)
- Komunikat: “Nieokreślony błąd” (HRESULT: -2147467259)
- Błąd pojawia się przy:
- automatycznej dekretacji
- dekretacji według schematu
- ręcznym dodaniu wpisu KPIR z nr KSeF (“Błąd zapisu do bazy”)
Przyczyna – analiza
1. Profiler
W Rewizorze GT przy dekretacji wykonywane jest zapytanie:
SELECT @P1 = ksefk_IdDokumentuWprowadzonego
FROM ksef_Fakturyksiegowosc
WHERE ksefk_TypDokumentuWprowadzonego IN (6, -2147483648)
AND ksefk_IdFaktury = (
SELECT ksefh_IdFaktury
FROM ksef_FakturyHandel
WHERE ksefh_IdDokumentu = 2511836
)
Podzapytanie „SELECT ksefh_IdFaktury FROM ksef_FakturyHandel WHERE ksefh_IdDokumentu = X” zwraca 2 rekordy, podczas gdy oczekiwany jest 1.

Sprawdziliśmy i faktycznie. Silnik SQL zgłasza błąd, a program aplikacji wyświetla ogólny komunikat “Nieokreślony błąd”.
3. Duble w tabelach KSeF
Czas na powiązanie tajemniczego numeru 2511836 z dokumentem
SELECT dok_Id, dok_NrPelny, dok_DataWyst
FROM dbo.dok__Dokument
WHERE dok_Id = 2511836

i voilà – potwierdzone!
Teraz można było szukać dalej… Dla problematycznej faktury znaleziono zdublowane wpisy w następujących tabelach:
ksef_Faktury – 2 rekordy
SELECT ksef_Id, ksef_DataWystawienia, ksef_NumerKSeF, ksef_StatusPrzetworzenia, ksef_IdPlik FROM dbo.ksef_Faktury WHERE ksef_Numer = '<NUMER_FAKTURY>' ORDER BY ksef_Id

Pierwszy wpis (5661) to nieudana próba wysyłki – brak daty wystawienia, brak numeru KSeF. Drugi (5662) to prawidłowo wysłana faktura z nadanym numerem KSeF i UPO.
ksef_FakturyHandel – 2 rekordy (oba wskazują ten sam dokument)
SELECT ksefh_Id, ksefh_IdFaktury, ksefh_IdDokumentu FROM dbo.ksef_FakturyHandel WHERE ksefh_IdDokumentu = (SELECT dok_Id FROM dbo.dok__Dokument WHERE dok_NrPelny = '<NUMER_FAKTURY>') ORDER BY ksefh_Id

ksef_FakturyKsiegowosc – 2 rekordy
SELECT ksefk_Id, ksefk_IdFaktury, ksefk_SchematZatwierdzony FROM dbo.ksef_FakturyKsiegowosc WHERE ksefk_IdFaktury IN (5661, 5662) ORDER BY ksefk_Id

ksef_Pliki – 2 pliki z identyczną treścią XML
SELECT ksefx_Id, ksefx_Hash FROM dbo.ksef_Pliki WHERE ksefx_Id IN (5654, 5655)

Plik 5654 odpowiada wpisowi 5661, plik 5655 – wpisowi 5662. Oba mają identyczny hash – wygenerowano tę samą treść XML dwukrotnie.
Rozwiązanie
Skrypt SQL do naprawy
Poniższy skrypt działa w dwóch trybach sterowanych zmienną @dryRun:
@dryRun = 1(TRY) – tylko raportuje znalezione duplikaty, nic nie zmienia@dryRun = 0(EXECUTE) – wykonuje kasowanie
Przed uruchomieniem koniecznie zrób backup bazy!
W skrypcie usuwane są tylko te wpisy w ksef_Faktury, które nie mają daty wystawienia (ksef_DataWystawienia IS NULL) i są duplikatami (istnieje drugi wpis z tym samym numerem dokumentu, ale już z datą).
-- 1. TRY (@dryRun = 1) - tylko raportuje co znajdzie
-- 2. EXECUTE (@dryRun = 0) - wykonuje kasowanie
DECLARE @dryRun BIT = 1;
-- Pobranie ID duplikatów (po IdDokumentu)
SELECT kf.ksef_Id INTO #DoUsuniecia
FROM dbo.ksef_FakturyHandel kh
INNER JOIN dbo.ksef_Faktury kf ON kh.ksefh_IdFaktury = kf.ksef_Id
WHERE kf.ksef_DataWystawienia IS NULL
AND kh.ksefh_IdDokumentu IN (
SELECT ksefh_IdDokumentu
FROM dbo.ksef_FakturyHandel
WHERE ksefh_IdDokumentu IS NOT NULL
GROUP BY ksefh_IdDokumentu
HAVING COUNT(*) > 1
);
-- Wykonanie lub podgląd
IF @dryRun = 1
BEGIN
SELECT 'TRYB PODGLĄDU - Rekordy do usunięcia:' AS [Status], * FROM dbo.ksef_Faktury
WHERE ksef_Id IN (SELECT ksef_Id FROM #DoUsuniecia);
END
ELSE
BEGIN
BEGIN TRANSACTION;
-- Usuwanie
DELETE FROM dbo.ksef_FakturyHandel WHERE ksefh_IdFaktury IN (SELECT ksef_Id FROM #DoUsuniecia);
DELETE FROM dbo.ksef_FakturyKsiegowosc WHERE ksefk_IdFaktury IN (SELECT ksef_Id FROM #DoUsuniecia);
DELETE FROM dbo.ksef_Faktury WHERE ksef_Id IN (SELECT ksef_Id FROM #DoUsuniecia);
COMMIT TRANSACTION;
SELECT 'Skasowano duplikaty pomyślnie.' AS [Wynik];
END
DROP TABLE #DoUsuniecia;

Instrukcja krok po kroku
- Zrób backup bazy – skrypt usuwa dane, operacja nieodwracalna
- Uruchom w trybie TRY –
DECLARE @dryRun BIT = 1;(domyślnie) - Przeanalizuj raport – sprawdź które dokumenty są wykryte
- Ustaw
@dryRun = 0i uruchom ponownie aby wykonać kasowanie - Zweryfikuj – po usunięciu duplikatu dekretacja powinna zakończyć się powodzeniem
Uwagi
- Skrypt usuwa TYKO niepełne duplikaty (te bez
ksef_DataWystawieniaiksef_NumerKSeF) - Prawidłowy wpis z nadanym numerem KSeF pozostaje nienaruszony
- Po naprawie nie ma potrzeby ponownego wysyłania faktury do KSeF
Jak dochodzi do duplikacji?
Na podstawie analizy bazy i dyskusji na forum InsERT:
- Użytkownik wystawia fakturę
- Subiekt GT wysyła ją do KSeF – tworzy wpis w
ksef_Faktury(bez daty wystawienia) - Wysyłka kończy się błędem (timeout, błąd sieci, restart aplikacji)
- Użytkownik klika “Wyślij ponownie” lub system automatycznie ponawia
- Subiekt tworzy NOWY wpis zamiast nadpisać stary
- Drugi wpis otrzymuje numer KSeF i UPO
- Stary wpis pozostaje osierocony – i blokuje dekretację
InsERT potwierdził, że analizuje źródło problemu. Podejrzewane są stare zamówienia ZK jako dokumenty źródłowe, ale nie ma 100% potwierdzenia.
O autorze wpisu
Tadeusz Sasnal — informatyk z wieloletnim doświadczeniem w obsłudze firm korzystających z programów InsERT (Subiekt GT, Rewizor GT, Rachmistrz GT) oraz Comarch (ERP Optima), administracji baz danych (SQL Server), integracji KSeF oraz automatyzacji procesów księgowo-magazynowych.
Świadczę usługi IT dla firm:
- wdrożenia i optymalizacje systemów
- diagnozowanie i naprawa problemów z bazami danych
- integracja z KSeF i automatyzacja
- analiza danych, skrypty SQL, backup i bezpieczeństwo
- wsparcie techniczne
Opracowano na podstawie analizy realnej bazy (InsERT GT 1.88 HF5) oraz wątków na forum InsERT. Czerwiec 2026.
