Portal akceptacji e-faktur dla biur rachunkowych
Klient biura rachunkowego loguje się przez przeglądarkę i akceptuje lub wyklucza e-faktury zakupowe z KSeF — zanim biuro je zaksięguje.
Opublikowano
Po co to
W KSeF klient nie ma kontroli nad tym, jakie faktury do niego trafiają — sprzedawca wystawia, system publikuje, biuro ściąga. Część dokumentów to normalne koszty, część to pomyłki: prywatne zakupy wystawione na firmowy NIP, duplikaty, faktury skierowane na wspólnika zamiast na firmę. Bez akceptacji biuro musiałoby księgować wszystko, a potem żmudnie korygować — albo wymieniać z klientem maile w stylu "akceptujesz fakturę X?" / "tak" / "a pozycję 3 z tej drugiej?".
Portal eliminuje ten ping-pong. Biuro pobiera batch e-faktur klienta z KSeF i otwiera miesiąc akceptacji. Klient dostaje maila z linkiem auto-login, w przeglądarce przegląda dokumenty i klika Akceptuj lub Wyklucz — także dla pojedynczych pozycji w fakturze. Decyzje synchronizują się z bazą TaxMachine, a biuro księguje gotową dyspozycję jednym kliknięciem.
Workflow
(1) Biuro pobiera e-faktury klienta z KSeF (klient KSeF w TaxMachine)
↓
(2) Biuro otwiera "miesiąc akceptacji" — TaxMachine generuje
wizualizacje HTML faktur i zapisuje do bazy
↓
(3) Biuro uruchamia masową wysyłkę zaproszeń — outbox kolejkuje
maile, worker wysyła z SMTP biura
↓
(4) Klient klika link auto-login → /auto-login?token=...
↓
(5) Klient widzi listę miesięcy, wchodzi w batch, widzi listę faktur
↓
(6) Klient akceptuje / wyklucza dokument lub pojedyncze pozycje
↓
(7) Klient klika "Zamknij miesiąc" — decyzje wracają do TaxMachine
↓
(8) Biuro w TaxMachine księguje faktury zgodnie z dyspozycją
Co widzi klient w portalu
Auto-login z maila. Link w mailu prowadzi pod
/auto-login?token=.... Token zawiera identyfikator użytkownika,
datę ważności i podpis HMAC-SHA256 — generowany identycznym
algorytmem po stronie portalu i TaxMachine. Domyślna ważność
linku — 168 h (7 dni; konfigurowalne przez
InvitationLinkLifetimeHours). Alternatywnie klient loguje się
hasłem na /Account/Login (tym samym, którego używa w głównym
TaxMachine).
Lista miesięcy do akceptacji (/Approvals). Klient z trzema
firmami widzi trzy oddzielne batche na miesiąc. W każdym wierszu:
firma, rok/miesiąc, status (open, submitted_by_client,
accepted_by_office, closed, reopened), liczba dokumentów,
ile pozostało do decyzji, ewentualny deadline. Na górze sekcja
Wymaga uwagi — batche z dokumentami w stanie pending
lub partial.
Szczegół batcha (/Approvals/Batch/{id}). Lista faktur
miesiąca: numer, kontrahent, kwoty, status. Akceptacja lub
wykluczenie wprost z listy, edytowalny komentarz do batcha,
historia powiadomień (kiedy poszło zaproszenie, kiedy
przypomnienie, czy dotarło).
Szczegół dokumentu (/Approvals/Document/{id}). Po lewej —
metadane; po prawej — pełna wizualizacja HTML, taka sama jak
widzi księgowy w TaxMachine. Wizualizacja jest renderowana po
stronie programu Delphi, gzip-skompresowana i zapisywana do bazy.
Portal tylko dekompresuje i wyświetla — bez ryzyka rozjazdu między
widokiem klienta a widokiem biura. Niżej tabela pozycji z
przełącznikiem wyklucz/przywróć i komentarzem. Główne przyciski:
Akceptuj dokument, Wyklucz dokument, Zapisz komentarz.
Decyzje per pozycja. Przykład: trzy pozycje, jedna to
prywatny krem, dwie to tonery do biura. Klient wyklucza
pozycję nr 2, dokument przechodzi w stan partial, TaxMachine
zaksięguje tylko pozostałe linie. Kliknięcie Akceptuj
dokument nie przywraca wcześniej wykluczonych pozycji — trzeba
je przywrócić ręcznie.
Read-only po zamknięciu. W stanach submitted_by_client,
accepted_by_office, closed oraz po upływie deadline-u portal
blokuje edycję — zarówno w interfejsie, jak i po stronie
serwerowej, niezależnie od tego, czy worker zdążył zamknąć batch.
Automatyczne zamknięcie po deadline. Worker w tle dla batchy
open/reopened po upływie deadline-u traktuje wszystkie
dokumenty pending jako zaakceptowane i zamyka miesiąc.
Polityka "milcząca zgoda" — klient ma X dni na zgłoszenie
zastrzeżeń, inaczej księgujemy całość.
Co robi biuro w TaxMachine
Otwarcie batcha. Z UI Delphi albo komendą CLI
--command prepare-approvals --year YYYY --month M. Dla każdego
aktywnego klienta z e-fakturami w miesiącu TaxMachine tworzy
rekord akceptacji miesiąca wraz z rekordami akceptacji dokumentów
i pozycji, renderuje wizualizacje HTML i ustawia batch w stanie
open. Opcjonalnie --approval-deadline YYYY-MM-DD ustawia
termin milczącej zgody.
Masowa wysyłka. /Approvals/Bulk albo CLI
--command queue-invitations/queue-reminders. Preview w
gridzie pokazuje firmę, biuro, liczbę e-faktur, status batcha
(new/existing-editable/existing-locked/missing) i flagi
problemów (brak biura, brak odbiorcy, brak SMTP). Eksport do CSV
przed wysłaniem. Przypomnienia tylko dla batchy
open/reopened.
Monitoring. Widok batcha pokazuje historię powiadomień
(queued/sent/failed/cancelled) z liczbą prób. Failed
można ręcznie ponowić.
Integracja z księgowaniem. Po zamknięciu miesiąca przez klienta lub po auto-close portal zapisuje na rekordzie e-faktury: listę pozycji wyłączonych z księgowania, sumę do księgowania (netto dla VAT/OSS, brutto w pozostałych), znacznik zatwierdzenia księgowania, datę zatwierdzenia oraz uwagi klienta. Biuro w TaxMachine ma gotową decyzję — księguje jednym kliknięciem.
Reopen. Jeśli klient pominął coś istotnego, biuro cofa
zamknięcie (submitted_by_client/accepted_by_office →
reopened). Batch closed nie podlega reopenowi — korekty robi
się normalnym wpisem księgowym.
API + integracje
Backend Delphi wystawia REST API. Główne endpointy:
GET /client/ksef-approvals/firma/{firmaId}— lista batchyPOST /client/ksef-approvals/open— otwarcie/pobranie batcha dla(firmaId, rok, miesiąc)GET /client/ksef-approvals/batch/{batchId}— szczegółyGET /client/ksef-approvals/document/{id}— pozycje i sumyPOST /client/ksef-approvals/document/{id}/accept— akceptacja dokumentuPOST /client/ksef-approvals/document/{id}/exclude— wykluczenie dokumentu (z komentarzem)POST /client/ksef-approvals/document/{id}/line/{nrPozycji}— decyzja per pozycja:{"decision": "excluded", "comment": "..."}POST /client/ksef-approvals/batch/{batchId}/submit— zatwierdzenie miesiąca
Backend Delphi i portal webowy korzystają z tej samej bazy MySQL/MariaDB.
Komendy CLI
Portal ma tryb konsolowy do automatyzacji (cron):
| Komenda | Kiedy używać |
|---|---|
--command prepare-approvals --year Y --month M [--approval-deadline D] | Otwarcie batchy dla miesiąca po imporcie e-faktur z KSeF |
--command queue-invitations --year Y --month M | Wysłanie zaproszeń do klientów z otwartymi batchami |
--command queue-reminders --year Y --month M | Przypomnienia dla batchy wciąż open / reopened |
--command process-expired-auto-approvals | Wymuszone sprawdzenie deadline-ów (one-shot zamiast workera w tle) |
Dodatkowe przełączniki: --office-id N (filtr po biurze), oraz
parametry bazy (--db-server, --db-port, --db-name,
--db-user, --db-password, --db-sqlite-file), portu
(--urls) i HTTPS-redirectu (--db-https-redirect).
Po stronie Delphi te same operacje uruchamiane są z UI TaxMachine — startując CLI portalu jako proces zewnętrzny. Typowy harmonogram: prepare-approvals 1-go każdego miesiąca z deadlinem na 10-tego, queue-invitations 2-go, queue-reminders 7-go.
Notyfikacje
Każdy mail jest wierszem w outboksie powiadomień, wysyłanym asynchronicznie przez worker w tle (domyślnie co 10 s). Próby są logowane, a w razie błędu worker retryuje zgodnie z konfiguracją (limit prób i opóźnienie między próbami).
Nadawcą jest biuro rachunkowe, nie portal. SMTP pobierany jest z konfiguracji biura rachunkowego klienta. Fallback — globalny SMTP serwera webowego. Adresatem jest zawsze aktywny użytkownik klienta — biura rachunkowe nie dostają tych maili.
Typy: invitation (pierwsza informacja) i reminder
(przypomnienie dla batchy open/reopened). W widoku batcha
biuro może ręcznie ponowić każdy failed/cancelled rekord,
jeśli typ powiadomienia jest nadal dozwolony dla bieżącego
statusu batcha.
Wymagania techniczne
Backend Delphi. Serwer HTTP hostuje kontroler akceptacji (domyślny port 8080).
Portal webowy. Razor Pages + htmx, .NET SDK 10, dostęp
do bazy MySQL/MariaDB (ta sama instancja co główny TaxMachine).
Konfiguracja w appsettings.json.
Baza danych. Tabele akceptacji e-faktur w głównej bazie TaxMachine — schemat zarządzany po stronie programu Delphi. W dev opcjonalnie SQLite.
Hosting. PublicBaseUrl to publiczny adres portalu wstawiany
w linki auto-login. Portal może być hostowany przez biuro
(np. pod subdomenę) albo udostępniony przez dostawcę TaxMachine.
Dostęp do firm. Portal weryfikuje uprawnienia użytkownika
i jego role (Admin/PowerUser/Manager/Owner). Zwykły
klient widzi tylko swoje firmy.
Bezpieczeństwo
Auto-login token. Podpis HMAC-SHA256 z sekretem identycznym po stronie programu Delphi i portalu webowego, bez szyfrowania — każdy, kto zna sekret i ma identyfikator użytkownika, może wygenerować ważny token. Walidator linków logowania odrzuca tokeny z błędnym podpisem lub po terminie ważności. Sekret jest obecnie zaszyty w kodzie; przed wdrożeniem produkcyjnym zaleca się wyciągnięcie do konfiguracji i rotację.
HTTPS. Konfigurowalny redirect HTTPS. Produkcyjnie portal powinien stać za reverse proxy z certyfikatem TLS.
Kontrola dostępu — portal sprawdza na każdym żądaniu, czy zalogowany użytkownik ma dostęp do firmy z batcha. Globalny handler błędów blokuje swap dla odpowiedzi 400+ i pokazuje alert.
Niemutowalność KSeF. XML faktury w KSeF nigdy nie jest modyfikowany. Decyzje klienta to overlay księgowy w tabelach akceptacji; do rekordu e-faktury synchronizowane są tylko pola wynikowe potrzebne do księgowania.
Status wdrożenia
Portal istnieje w dwóch równoległych implementacjach UI:
Portal Razor Pages + htmx — działa. Pełny pionowy slice: otwieranie batchy, lista, widok batcha, widok dokumentu z podglądem HTML, decyzje per dokument i per pozycja, sekcja księgowania, wysyłka zaproszeń i przypomnień (pojedyncza i masowa), monitoring outboksu, auto-close po deadline. Testy integracyjne pokrywają flow od otwarcia batcha przez akceptację, wykluczenie pozycji, zatwierdzenie miesiąca, po blokadę edycji.
Portal Blazor Web App + DevExpress v25.2.6 — w trakcie. Nowa implementacja od zera, spójność z resztą platformy webowej TaxMachine. Aktualnie zakończony Milestone 1: szkielet uruchamia się, workery startują, podstawowa nawigacja (sidebar, topbar), tryb CLI. Roadmapa: M2 — auth end-to-end, M3 — lista batchy z gridem, M4 — szczegół batcha, M4.5 — prerender HTML w Delphi, M5 — szczegół dokumentu, M6 — masowa wysyłka, M7 — utwardzenie i deploy. Po osiągnięciu parity stary portal zostanie wygaszony.
Czego jeszcze nie ma w żadnej wersji. UI biura w portalu
do przejść submitted_by_client → accepted_by_office →
closed / reopened (obecnie tylko w Delphi); audyt zmian
("kto, kiedy, z jakiego IP"); 2FA i polityka silnych haseł;
lokalizacja inna niż polska; załączniki do decyzji.