5.7 KiB
phase, plan, status, completed_at
| phase | plan | status | completed_at |
|---|---|---|---|
| 05-finances-fakturownia-import | 04 | complete | 2026-04-14 |
Plan 05-04 Summary — Bugfix importu faktur kosztowych z Fakturowni
Goal (recap)
Naprawic import faktur kosztowych, ktore nie byly pobierane (zgloszony przyklad: faktura 486639934 = FV 1417/04/2026 z KSeF).
Root cause (2 bugi)
Bug A — FakturowniaApiClient::fetchCostDocuments:
Kod probowal kolejno /costs.json, /expenses.json, /invoices.json?income=no i zwracal wynik pierwszej sciezki, ktora odpowiedziala HTTP 200. Problem: /costs.json na tym koncie Fakturowni zwracal HTTP 200 z PUSTA lista, wiec logika uznawala "done, zwroc puste" i nigdy nie trafiala do /invoices.json?income=no, gdzie lezala faktura 486639934.
Bug B — quirk Fakturowni dla wydatkow z KSeF:
Dla faktur pobranych z KSeF (gov_kind='ksef', approval_status='received') Fakturownia zapisuje dane wlasnej firmy w polach seller_*, a prawdziwego dostawce w buyer_* — odwrotnie niz dla klasycznych faktur kosztowych z innych zrodel. Importer dla documentType=cost bral seller_tax_no jako klucz klienta → trafialo na wlasny NIP → faktura szla do fakturownia_unmapped_queue lub byla mapowana na wlasna firme.
Bonus (drugi raunde): hang crona.
Po naprawie Bug A, ale przed dodaniem filtra dat po stronie API, usuniecie wczesnego przerywania paginacji powodowalo pobieranie calej historii Fakturowni (100 stron x 100 dok x 3 endpointy = potencjalnie 30k requestow). Cron wisial. Rozwiazanie: period=more&date_from=startDate&date_to=today — filtr po stronie API, paginacja konczy sie naturalnie po wyczerpaniu zakresu dat.
Changes
autoload/Domain/Finances/FakturowniaApiClient.php
fetchCostDocumentsprzebudowane: odpytuje wszystkie 3 endpointy i merge'uje wyniki z dedup poid. Pusta odpowiedz z jednego endpointu NIE skraca wyszukiwania.fetchSalesDocuments+fetchCostDocumentsuzywaja nowej metodybuildDateRangeQuery→period=more&date_from=X&date_to=today.- Usunieta dead-code metoda
canUseCurrentMonthPeriod. request()zmieniona zprivatenaprotected— umozliwia subklasowanie w testach.
autoload/Domain/Finances/FakturowniaInvoiceImporter.php
processDocumentType: usuniete wczesne przerywanie paginacji na podstawie dat w liscie (API moze sortowac po updated_at, nie issue_date). Zostawiony twardy cap 100 stron jako safety.- Usunieta dead-code metoda
isDateRelevantForImport. normalizeDocumentdladocumentType='cost': gdyseller_tax_no == FAKTUROWNIA_OWN_TAX_NO(z.env), kontrahent jest pobierany zbuyer_*zamiastseller_*(obsluga odwroconych rol KSeF).- Nowa metoda
taxNoEqualsOwn($taxNo)porownujaca NIP po normalizacji. resolveConfigczyta nowy kluczFAKTUROWNIA_OWN_TAX_NO.- Nowe pole
$ownTaxNoustawiane z configa.
.env
- Dodane
FAKTUROWNIA_OWN_TAX_NO=5170167517.
tests/Domain/Finances/FakturowniaApiClientTest.php (nowy)
- 7 asercji pokrywajacych: merge endpointow, brak short-circuit na pustym /costs.json, dedup po id, obecnosc
period=more+date_from+date_tow query, throw gdy wszystkie 3 sciezki zwracaja HTTP 4xx/5xx, pusta liste gdy wszystkie zwracaja 200+[]. FakeFakturowniaApiClient— subklasa nadpisujacarequest()do testow bez prawdziwego API.
tests/run.php
- Zarejestrowany nowy test suite.
Production cleanup (destrukcyjny, wymagal zgody uzytkownika)
Wczesniejsze buggowate importy wyprodukowaly brudne dane. Po zgodzie uzytkownika:
finance_operations: usunietych 80 rekordow z Fakturowni (sum 7761.43 zl). Wszystkie referencjonowane przezfinance_operation_idswfakturownia_imported_documents. Reczne wpisy (6 szt.) zostaly nietkniete.fakturownia_imported_documents: wyczyszczone (60 rekordow).fakturownia_client_mappings: wyczyszczone (36 rekordow) — uzytkownik poprosil o reset wszystkich mapowan.fakturownia_item_mappings: wyczyszczone (60 rekordow).fakturownia_unmapped_queue: wyczyszczone (112 rekordow).fakturownia_import_state.last_import_summary: usuniete.
Verification
php -lna wszystkich zmienionych plikach: OK.php tests/run.php: 8 test suites, wszystkie zielone (w tym nowyrun_fakturownia_api_client_tests).- Diagnoza na zywym API Fakturowni potwierdzila ze faktura 486639934 jest zwracana przez
fetchCostDocumentsi magov_kind='ksef'+approval_status='received'+ odwrocone role seller/buyer.
Deviations vs plan
-
Task 3 (test regresyjny) zostal zwezony: zamiast testu integracyjnego importera (ktory wymagalby mockowania DB), napisany zostal test jednostkowy dla
FakturowniaApiClient— pokrywa faktyczny root cause bugu (merge endpointow + filtr dat po stronie API). Test fix KSeF wnormalizeDocumentnie zostal dodany, bo importer nie ma injectable dependency. Przeniesione do 05-05 jako wymagany refactor (dependency injection) przy okazji skip-list. -
Pomiedzy T1-T2 a checkpoint pojawil sie hang crona. Drugi raund napraw: dodanie
buildDateRangeQueryzperiod=more&date_from&date_to. Zaktualizowane testy ACto odpowiednio. -
Cleanup bazy poza planem — wymagany poniewaz faktura 486639934 byla juz w
fakturownia_imported_documentsze zlym mapowaniem klienta, a bez wyczyszczeniaisDocumentImportedzwracalo true i fix KSeF nie mial szansy zadzialac.
Follow-ups
- 05-05 (zaplanowany): skip-list pozycji faktury — mozliwosc oznaczenia wybranej pozycji jako pomijanej w imporcie.
- Debt:
FakturowniaInvoiceImporterpowinien pozwalac na wstrzykniecieFakturowniaImportRepositoryiFakturowniaApiClientprzez konstruktor — umozliwi pelne testy integracyjne bez DB. Rozwazyc w ramach 05-05.
Next action
Wdrozenie na serwer (FTP sync) i reczny reimport. Uzytkownik wykonuje samodzielnie — cleanup bazy juz zrobiony.