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

9.4 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
phase plan type wave depends_on files_modified autonomous delegation
05-finances-fakturownia-import 04 execute 1
autoload/Domain/Finances/FakturowniaApiClient.php
autoload/Domain/Finances/FakturowniaInvoiceImporter.php
tests/Domain/Finances/FakturowniaInvoiceImporterTest.php
false off
## Goal Naprawic import faktur kosztowych z Fakturowni tak, by dokumenty typu "invoice" z `income=false` (np. faktura 486639934 pod URL /invoices/486639934) byly niezawodnie pobierane, normalizowane i importowane do finansow.

Purpose

Zgloszony bug: faktura kosztowa 486639934 nie pojawila sie w finansach po imporcie. Phase 5 dostarczyla mechanizm importu, ale obecna logika FakturowniaApiClient::fetchCostDocuments() i FakturowniaInvoiceImporter::processDocumentType() ma trzy potencjalne dziury, przez ktore dokumenty kosztowe typu invoices.json?income=no moga zostac calkowicie pominiete.

Output

  • Poprawiony FakturowniaApiClient zawsze odpytujacy /invoices.json?income=no dla kosztow (z /costs.json i /expenses.json jako uzupelnienie, a nie jako early-exit).
  • Poprawiony FakturowniaInvoiceImporter: usuniete pressie "wczesnego przerwania" na podstawie daty z listy oraz warunkowe period=this_month dla kosztow.
  • Test jednostkowy odtwarzajacy brak faktury 486639934 i potwierdzajacy fix.
  • UAT: ponowny import zwraca faktura 486639934 do panelu mapowan lub do finansow.
## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md

Prior Work

@.paul/phases/05-finances-fakturownia-import/05-01-SUMMARY.md @.paul/phases/05-finances-fakturownia-import/05-03-SUMMARY.md

Source Files

@autoload/Domain/Finances/FakturowniaApiClient.php @autoload/Domain/Finances/FakturowniaInvoiceImporter.php @autoload/Domain/Finances/FakturowniaImportRepository.php @tests/Domain/Finances/FakturowniaInvoiceImporterTest.php

<acceptance_criteria>

AC-1: Koszty pobierane zawsze z /invoices.json?income=no

Given token Fakturowni jest skonfigurowany
And faktura kosztowa istnieje pod /invoices/486639934 (income=false)
When importer wywoluje fetchCostDocuments
Then zapytanie do /invoices.json?income=no jest wykonane niezaleznie od odpowiedzi /costs.json i /expenses.json
And lista zwrocona importerowi zawiera rekord 486639934

AC-2: Brak filtra period=this_month dla kosztow

Given FAKTUROWNIA_START_DATE jest pierwszym dniem biezacego miesiaca
When fetchCostDocuments buduje query
Then parametr period nie jest wysylany
And API zwraca takze faktury z wczesniejszych dni miesiaca wg issue_date

AC-3: Importer nie przerywa paginacji na podstawie dat listy

Given pierwsza strona z API zawiera dokumenty posortowane malejaco po updated_at
And wszystkie dokumenty na stronie maja issue_date starsze niz startDate
When processDocumentType przetwarza strone
Then petla kontynuuje do kolejnej strony dopoki API zwraca pelna strone (per_page)
And faktura 486639934 nie jest pomijana wylacznie z powodu sortowania

AC-4: Test regresyjny

Given test z fake'owym api clientem zwracajacym liste dokumentow z jednym kosztem income=false
When FakturowniaInvoiceImporter::import zostaje wywolany
Then dokument trafia do kolejki unmapped lub do finance_operations (nie jest skipped)

</acceptance_criteria>

Task 1: Napraw fetchCostDocuments w FakturowniaApiClient autoload/Domain/Finances/FakturowniaApiClient.php Przebuduj fetchCostDocuments tak, by: - Zawsze probowal /invoices.json?income=no (to jest primary source — URL faktury to /invoices/ID). - Uzupelniajaco probowal /costs.json i /expenses.json i laczyl wyniki (dedup po id), aby nie gubic dokumentow obecnych pod jednym endpointem a nieobecnych pod innym. - NIE stosowal period=this_month dla kosztow (usun canUseCurrentMonthPeriod z tej sciezki; sales moze zostac bez zmian albo tez ma byc usuniete — zdecyduj w ramach Task 1 spojnie i udokumentuj w komentarzu). - Zachowal softFail dla endpointow pobocznych (/costs.json, /expenses.json zwracajacych 404), ale traktowal 2xx z pusta lista jako "ta sciezka pusta" i szedl dalej zamiast zwracac wynik. - W razie gdy wszystkie trzy sciezki zwroca puste listy BEZ bledu HTTP, zwraca [] (nie rzuca wyjatku). Wyjatek tylko gdy wszystkie trzy rzucily bledy. Unikaj: dodawania nowych zaleznosci, zmiany sygnatur publicznych metod, ukrywania bledow HTTP. php -l autoload/Domain/Finances/FakturowniaApiClient.php Manualne wywolanie z tokenem testowym: var_dump($client->fetchCostDocuments('2026-04-01', 1)) zawiera faktura 486639934. AC-1, AC-2 spelnione Task 2: Popraw paginacje i filtr dat w FakturowniaInvoiceImporter autoload/Domain/Finances/FakturowniaInvoiceImporter.php W processDocumentType: - Usun wczesne przerywanie petli na podstawie !hasRelevantDateInPage. API moze sortowac po updated_at lub created_at, nie po issue_date — wczesne przerwanie gubi faktury z odroznionym issue_date. - Zachowaj twardy limit paginacji ($page > 100) jako safety-valve. - Zostaw filtr "za stare" na poziomie processSingleDocument (tam gdzie porownuje $document['date'] z startDate). Ten filtr dziala per-dokument i jest bezpieczny. Dodatkowo w normalizeDocument: dla dokumentow bez positions w liscie (gdy API zwraca skrocona forme), upewnij sie ze fallback do apiClient->fetchInvoiceDetails dziala i nie konsumuje zbyt wielu requestow (logika juz jest w resolvePositions — zweryfikuj ze nie regresuje przy naprawie). Unikaj: rekurencyjnego pobierania wszystkich stron w nieskonczonosc, cichego polykania wyjatkow API. php -l autoload/Domain/Finances/FakturowniaInvoiceImporter.php php tests/run.php (istniejace testy przechodza). AC-3 spelnione Task 3: Test regresyjny dla faktury kosztowej typu invoice tests/Domain/Finances/FakturowniaInvoiceImporterTest.php Dodaj test case "cost_invoice_from_invoices_endpoint_is_imported": - Zamockuj FakturowniaApiClient (interface lub testowa podklasa) tak, by fetchCostDocuments zwracalo [[ 'id' => 486639934, 'number' => 'FV 100/04/2026', 'kind' => 'vat', 'income' => false, 'issue_date' => '2026-04-05', 'seller_name' => 'Dostawca Sp. z o.o.', 'seller_tax_no' => '5252344567', 'positions' => ]]. - Uruchom importer z czystymi tabelami mapowan. - Oczekuj: summary['unmapped'] === 1 (bo brak mapowania klienta) oraz wpis w kolejce unmapped dla client_key='tax:5252344567'. - Dodatkowy test: z pre-zalozonym mapowaniem klienta i pozycji — oczekuj summary['imported'] === 1 i rekordu w finance_operations z amount = -1230.00. Unikaj: zaleznosci od prawdziwego API, pomijania czyszczenia bazy testowej miedzy testami. php tests/run.php — oba nowe testy zielone. AC-4 spelnione Poprawiony import kosztow z Fakturowni + test regresyjny. 1. Uruchom import recznie: otworz /finances/main_view/ i kliknij "Importuj z Fakturowni" (lub wywolaj cron.php). 2. Sprawdz komunikat podsumowania — powinno byc co najmniej 1 nowy rekord w kategoriach imported/unmapped. 3. W bazie: SELECT * FROM fakturownia_import_documents WHERE external_id = '486639934' — rekord istnieje. 4. Jesli klient niezmapowany: panel mapowan w /finances/main_view/ pokazuje faktura 486639934 w kolejce unmapped. 5. Po zmapowaniu klienta i pozycji: ponowny import tworzy rekord w finance_operations z ujemna kwota (koszt). Napisz "approved" lub opisz problem do naprawy.

DO NOT CHANGE

  • FakturowniaImportRepository.php (schemat tabel zablokowany — zmiany tylko jesli niezbedne do poprawki bugu).
  • Logika mapowania klientow po NIP (05-02) — nie modyfikuj buildClientKey / normalizeTaxNo.
  • Logika filtra proforma (05-03) — isProformaDocument zostaje bez zmian.
  • Publiczny kontrakt FakturowniaInvoiceImporter::import() (zwracany shape summary).

SCOPE LIMITS

  • Nie dodajemy nowych endpointow API Fakturowni (tylko naprawiamy uzycie istniejacych).
  • Nie zmieniamy UI panelu mapowan w /finances/main_view/.
  • Nie wprowadzamy nowego cachingu ani retry-logic — tylko poprawa logiki pobierania/paginacji.
  • Nie refaktoryzujemy importera pod testy E2E z prawdziwym API.
- [ ] php -l dla wszystkich zmienionych plikow - [ ] php tests/run.php — wszystkie testy zielone - [ ] Manualny import pobieral faktura 486639934 (checkpoint human-verify) - [ ] Wszystkie AC zaspokojone

<success_criteria>

  • Faktura 486639934 pojawia sie w wynikach importu (imported lub unmapped, zaleznie od mapowan).
  • Nowy test regresyjny przechodzi i zostaje w suite.
  • Zadne istniejace testy nie regresuja.
  • Brak nowych warningow php -l. </success_criteria>
Po zakonczeniu utworz `.paul/phases/05-finances-fakturownia-import/05-04-SUMMARY.md` z: - opisem zmian w API client i importerze, - root cause bugu, - przyklad payloadu z API Fakturowni dla faktury 486639934, - wynikami UAT.