update
This commit is contained in:
196
.paul/phases/05-finances-fakturownia-import/05-04-PLAN.md
Normal file
196
.paul/phases/05-finances-fakturownia-import/05-04-PLAN.md
Normal file
@@ -0,0 +1,196 @@
|
||||
---
|
||||
phase: 05-finances-fakturownia-import
|
||||
plan: 04
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- autoload/Domain/Finances/FakturowniaApiClient.php
|
||||
- autoload/Domain/Finances/FakturowniaInvoiceImporter.php
|
||||
- tests/Domain/Finances/FakturowniaInvoiceImporterTest.php
|
||||
autonomous: false
|
||||
delegation: off
|
||||
---
|
||||
|
||||
<objective>
|
||||
## 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.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## 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
|
||||
</context>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Koszty pobierane zawsze z /invoices.json?income=no
|
||||
```gherkin
|
||||
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
|
||||
```gherkin
|
||||
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
|
||||
```gherkin
|
||||
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
|
||||
```gherkin
|
||||
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>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Napraw fetchCostDocuments w FakturowniaApiClient</name>
|
||||
<files>autoload/Domain/Finances/FakturowniaApiClient.php</files>
|
||||
<action>
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
php -l autoload/Domain/Finances/FakturowniaApiClient.php
|
||||
Manualne wywolanie z tokenem testowym: var_dump($client->fetchCostDocuments('2026-04-01', 1)) zawiera faktura 486639934.
|
||||
</verify>
|
||||
<done>AC-1, AC-2 spelnione</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Popraw paginacje i filtr dat w FakturowniaInvoiceImporter</name>
|
||||
<files>autoload/Domain/Finances/FakturowniaInvoiceImporter.php</files>
|
||||
<action>
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
php -l autoload/Domain/Finances/FakturowniaInvoiceImporter.php
|
||||
php tests/run.php (istniejace testy przechodza).
|
||||
</verify>
|
||||
<done>AC-3 spelnione</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Test regresyjny dla faktury kosztowej typu invoice</name>
|
||||
<files>tests/Domain/Finances/FakturowniaInvoiceImporterTest.php</files>
|
||||
<action>
|
||||
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' => [[ 'name' => 'Uslugi IT', 'total_price_net' => 1230.00, 'quantity' => 1 ]]
|
||||
]].
|
||||
- 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.
|
||||
</action>
|
||||
<verify>php tests/run.php — oba nowe testy zielone.</verify>
|
||||
<done>AC-4 spelnione</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<what-built>Poprawiony import kosztow z Fakturowni + test regresyjny.</what-built>
|
||||
<how-to-verify>
|
||||
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).
|
||||
</how-to-verify>
|
||||
<resume-signal>Napisz "approved" lub opisz problem do naprawy.</resume-signal>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## 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.
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
- [ ] php -l dla wszystkich zmienionych plikow
|
||||
- [ ] php tests/run.php — wszystkie testy zielone
|
||||
- [ ] Manualny import pobieral faktura 486639934 (checkpoint human-verify)
|
||||
- [ ] Wszystkie AC zaspokojone
|
||||
</verification>
|
||||
|
||||
<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>
|
||||
|
||||
<output>
|
||||
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.
|
||||
</output>
|
||||
Reference in New Issue
Block a user