Files
crmPRO/.paul/phases/05-finances-fakturownia-import/05-04-SUMMARY.md
2026-04-15 01:24:42 +02:00

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

  • fetchCostDocuments przebudowane: odpytuje wszystkie 3 endpointy i merge'uje wyniki z dedup po id. Pusta odpowiedz z jednego endpointu NIE skraca wyszukiwania.
  • fetchSalesDocuments + fetchCostDocuments uzywaja nowej metody buildDateRangeQueryperiod=more&date_from=X&date_to=today.
  • Usunieta dead-code metoda canUseCurrentMonthPeriod.
  • request() zmieniona z private na protected — 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.
  • normalizeDocument dla documentType='cost': gdy seller_tax_no == FAKTUROWNIA_OWN_TAX_NO (z .env), kontrahent jest pobierany z buyer_* zamiast seller_* (obsluga odwroconych rol KSeF).
  • Nowa metoda taxNoEqualsOwn($taxNo) porownujaca NIP po normalizacji.
  • resolveConfig czyta nowy klucz FAKTUROWNIA_OWN_TAX_NO.
  • Nowe pole $ownTaxNo ustawiane 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_to w query, throw gdy wszystkie 3 sciezki zwracaja HTTP 4xx/5xx, pusta liste gdy wszystkie zwracaja 200+[].
  • FakeFakturowniaApiClient — subklasa nadpisujaca request() 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 przez finance_operation_ids w fakturownia_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 -l na wszystkich zmienionych plikach: OK.
  • php tests/run.php: 8 test suites, wszystkie zielone (w tym nowy run_fakturownia_api_client_tests).
  • Diagnoza na zywym API Fakturowni potwierdzila ze faktura 486639934 jest zwracana przez fetchCostDocuments i ma gov_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 w normalizeDocument nie 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 buildDateRangeQuery z period=more&date_from&date_to. Zaktualizowane testy ACto odpowiednio.

  • Cleanup bazy poza planem — wymagany poniewaz faktura 486639934 byla juz w fakturownia_imported_documents ze zlym mapowaniem klienta, a bez wyczyszczenia isDocumentImported zwracalo 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: FakturowniaInvoiceImporter powinien pozwalac na wstrzykniecie FakturowniaImportRepository i FakturowniaApiClient przez 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.