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

12 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 05 execute 2
05-04
autoload/Domain/Finances/FakturowniaImportRepository.php
autoload/Domain/Finances/FakturowniaInvoiceImporter.php
autoload/controls/Finances.php
templates/finances/main_view.php
tests/Domain/Finances/FakturowniaApiClientTest.php
false off
## Goal Umozliwic uzytkownikowi oznaczenie wybranej pozycji faktury z Fakturowni jako "pomijanej" — taka pozycja NIE jest zapisywana do `finance_operations` i nie wplywa na statystyki finansowe, nawet jesli reszta faktury jest prawidlowo zaimportowana.

Purpose

Niektore pozycje faktury (np. koszty transportu przerzucane do klienta, zwrotne opakowania, pozycje techniczne) nie powinny byc ksiegowane jako oddzielne operacje finansowe. Dzisiaj kazda pozycja z mapowaniem trafia do finance_operations — nie ma sposobu, zeby pojedyncza pozycja byla widoczna w Fakturowni, ale nie liczona w statystykach CRM.

Output

  • Nowa kolumna skip w fakturownia_item_mappings (lub pole finance_category_id IS NULL jako sygnal skip-u — decyzja w Task 1).
  • Rozszerzony importer: pozycje z mapowaniem typu "skip" sa pomijane na etapie processSingleDocument, ale liczone w skipped_positions metadanych dokumentu (dla audytu).
  • Rozszerzony panel /finances/main_view/ o przycisk "Pomijaj" przy pozycji w kolejce unmapped + widok listy pozycji oznaczonych jako skip z mozliwoscia cofniecia.
  • Test regresyjny: pozycja oznaczona jako skip nie tworzy finance_operations, ale dokument nadal jest oznaczany jako zaimportowany (jesli pozostale pozycje OK) lub jako fully-skipped (jesli wszystkie pozycje skip).
## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md

Prior Work

@.paul/phases/05-finances-fakturownia-import/05-04-PLAN.md

Source Files

@autoload/Domain/Finances/FakturowniaImportRepository.php @autoload/Domain/Finances/FakturowniaInvoiceImporter.php @autoload/controls/Finances.php @templates/finances/main_view.php

<acceptance_criteria>

AC-1: Oznaczenie pozycji jako skip

Given faktura kosztowa z 3 pozycjami jest w kolejce unmapped (queue_type=item)
When uzytkownik klika przycisk "Pomijaj" obok pozycji w panelu /finances/main_view/
Then rekord `fakturownia_item_mappings` zostaje utworzony ze znacznikiem skip
And pozycja znika z kolejki unmapped (jest rozwiazana)

AC-2: Import faktury ze skip-position

Given istnieje `fakturownia_item_mappings` dla pozycji "Transport" ze znacznikiem skip
And faktura 500000001 ma 3 pozycje: "Produkt A" (kategoria 1), "Produkt B" (kategoria 2), "Transport" (skip)
When uruchomiony jest import z Fakturowni
Then `finance_operations` dostaje 2 rekordy (Produkt A, Produkt B), NIE 3
And `fakturownia_imported_documents` dla id=500000001 zawiera w `meta_json` liste pominietych pozycji (item_key + name)
And summary['imported'] === 1 (dokument zaimportowany jako calosc)

AC-3: Wszystkie pozycje skip

Given faktura 500000002 ma 1 pozycje "Transport" oznaczona jako skip
When uruchomiony jest import
Then faktura zostaje oznaczona jako zaimportowana (document_key wpisany do fakturownia_imported_documents)
And NIE powstaje zaden rekord w finance_operations
And summary['imported'] === 1 (zeby nie powtarzala sie co import)

AC-4: Cofniecie skip

Given pozycja "Transport" jest oznaczona jako skip w fakturownia_item_mappings
When uzytkownik klika "Cofnij pomijanie" w panelu /finances/main_view/
Then znacznik skip jest usuniety
And przy nastepnym imporcie pozycja ponownie trafia do kolejki unmapped (bo nie ma finance_category_id)

AC-5: Idempotencja

Given faktura ze skip-position zostala juz raz zaimportowana
When uruchomiony jest import po raz drugi (bez zmian w danych)
Then summary['skipped'] === 1 dla tej faktury (isDocumentImported=true)
And nie powstaja duplikaty finance_operations

</acceptance_criteria>

Model danych dla skip-flag Jak reprezentowac skip w bazie — nowa kolumna czy konwencja pola juz istniejacego? Dodac kolumne `skip TINYINT(1) NOT NULL DEFAULT 0` do fakturownia_item_mappings Jawne, latwe do query, latwe do indeksowania, mozna miec `finance_category_id` + `skip=1` rownoczesnie (np. "kategoria domyslna ale aktualnie pomijana") Wymaga migracji schematu, dodaje kolumne ktora w 99% przypadkow bedzie 0 Uzyc `finance_category_id IS NULL` jako sygnalu skip (bez migracji schematu) Zero migracji, semantyka "mapowanie istnieje ale bez kategorii = skip" jest naturalna, mniejsze ryzyko Mniej jawne, trudniej odroznic "skip" od "mapowanie niedokonczone"; kod musi sprawdzac NULL specjalnie Select: new-column or null-category Task 1: Rozszerzyc FakturowniaImportRepository o obsluge skip autoload/Domain/Finances/FakturowniaImportRepository.php W zaleznosci od wyboru z checkpointu: - option new-column: dodac migracja w `ensureTables()` — ALTER TABLE fakturownia_item_mappings ADD COLUMN IF NOT EXISTS skip TINYINT(1) NOT NULL DEFAULT 0. Dodac metode `markItemAsSkipped($itemKey, $itemName)` wstawiajaca rekord ze skip=1 i finance_category_id=NULL. Dodac `isItemSkipped($itemKey)` zwracajaca bool. - option null-category: dodac metode `markItemAsSkipped($itemKey, $itemName)` wstawiajaca rekord z finance_category_id=NULL. `getItemMapping` juz zwraca rekord; trzeba dodac helper `isSkipMapping($row)` sprawdzajacy czy finance_category_id jest null. Zmodyfikowac istniejaca metode `getItemMapping` tak, zeby kod konsumujacy mogl odroznic: a) brak mapowania (unmapped), b) skip, c) normalne mapowanie z kategoria. Unikaj: breaking changes w publicznym kontrakcie, zmian w logice mapowan klientow. php -l autoload/Domain/Finances/FakturowniaImportRepository.php; php tests/run.php AC-1 spelnione w warstwie repozytorium Task 2: Dodac obsluge skip w FakturowniaInvoiceImporter autoload/Domain/Finances/FakturowniaInvoiceImporter.php W `processSingleDocument`, pomiedzy resolveItemMapping a insertem do finance_operations: - Dla kazdej pozycji sprawdzic czy `itemMap` jest skip (nowa kolumna LUB null category, zaleznie od decyzji). - Jesli skip: NIE dodawac pozycji do `resolvedPositions`, ale dodac do lokalnej listy `skippedPositions` (dla meta_json). - Jesli po filtrze pozostaje 0 pozycji `resolvedPositions` ALE byly `skippedPositions` → traktowac dokument jako imported (zapisac w fakturownia_imported_documents z pusta lista operation_ids i meta_json zawierajacym skipped_positions). AC-3. - Jesli pozostala co najmniej 1 pozycja → zapis jak dotychczas, ale meta_json dodatkowo zawiera `skipped_positions` dla audytu. Unikaj: zmiany semantyki summary['skipped'] (oznacza "pominiete dokumenty", nie "pominiete pozycje" — dodaj osobny kontener meta). php -l autoload/Domain/Finances/FakturowniaInvoiceImporter.php; php tests/run.php AC-2, AC-3, AC-5 spelnione Task 3: Przycisk "Pomijaj" i widok pominietych w panelu finances/main_view autoload/controls/Finances.php, templates/finances/main_view.php W `controls\Finances`: - Dodac akcje `fakturownia_skip_item($item_key, $item_name)` wywolujaca repo->markItemAsSkipped + oznaczajaca rekord w kolejce unmapped jako resolved. - Dodac akcje `fakturownia_unskip_item($item_key)` usuwajaca skip-mapping (lub ustawiajaca skip=0 w wariancie new-column). - Dodac widok `fakturownia_skipped_items_list()` zwracajacy tablice aktywnych skip-mapowan. W `templates/finances/main_view.php`: - W sekcji unmapped queue, przy kazdej pozycji (queue_type=item) dodac przycisk "Pomijaj w imporcie" obok istniejacego selecta kategorii. - Dodac osobna sekcje "Pozycje pomijane" pokazujaca liste z przyciskiem "Cofnij pomijanie". - UI w jezyku polskim, spojne z obecnym stylem Bootstrap. Unikaj: duplikowania logiki mapowania, zmian w mapowaniach klientow (client queue pozostaje bez zmian). php -l dla obu plikow. Recznie: otworzyc /finances/main_view/, kliknac "Pomijaj" na pozycji — rekord pojawia sie w sekcji pomijanych. AC-1, AC-4 spelnione w warstwie UI Task 4: Test regresyjny skip-position tests/Domain/Finances/FakturowniaApiClientTest.php (lub nowy test osobny dla importera, jesli wymaga DB-less mocka) Dodac test case `skip_position_is_excluded_from_finance_operations`: - Stworzyc in-memory mock FakturowniaImportRepository (stub) implementujacy getItemMapping zwracajacy skip-mapping dla "Transport". - Stworzyc mock FakturowniaApiClient z faktura zawierajaca 3 pozycje: Produkt A, Produkt B, Transport. - Uruchomic FakturowniaInvoiceImporter z tymi mockami (dependency injection przez setter lub konstruktor — moze wymagac drobnego refactoru importera, zeby mozna bylo wstrzyknac repo). - Oczekiwac: 2 pozycje w resolvedPositions (A, B), 1 w skippedPositions (Transport), summary['imported'] === 1. Dodatkowy test: wszystkie pozycje skip → imported=1, 0 finance_operations. Unikaj: zaleznosci od prawdziwej bazy; mockowanie tylko tego, co niezbedne. php tests/run.php — nowy test zielony. AC-2, AC-3 pokryte testami Mechanizm skip-list dla pozycji faktur Fakturownia. 1. Otworz /finances/main_view/ — zobacz kolejke unmapped. 2. Przy dowolnej pozycji (np. "Transport") kliknij "Pomijaj w imporcie". 3. Pozycja znika z kolejki i pojawia sie w sekcji "Pozycje pomijane". 4. Uruchom ponownie import. Faktura ktora miala te pozycje importuje sie BEZ niej (sprawdz `finance_operations` po `description LIKE '%Transport%'` — brak). 5. Kliknij "Cofnij pomijanie" — pozycja wraca do kolejki unmapped przy nastepnym imporcie. Napisz "approved" lub opisz problem.

DO NOT CHANGE

  • Logika filtra proforma (05-03).
  • Logika mapowania klientow po NIP (05-02).
  • Fix KSeF taxNoEqualsOwn (05-04).
  • FakturowniaApiClient (sciezki API) — skip jest czysta logika po stronie importera.
  • Publiczny kontrakt FakturowniaInvoiceImporter::import() (zwracany shape summary).

SCOPE LIMITS

  • Nie dodawac skip-list dla klientow (tylko pozycje).
  • Nie dodawac masowego oznaczania (pojedyncze pozycje tylko).
  • Nie ruszac eksportu/raportow finansowych — skip dziala na etapie importu, nie przy wyswietlaniu.
  • Nie dodawac historii zmian skip-list (simple on/off wystarczy).
- [ ] php -l dla wszystkich zmienionych plikow - [ ] php tests/run.php — wszystkie testy zielone - [ ] Manualny flow: oznacz pozycje jako skip, uruchom import, sprawdz brak w finance_operations - [ ] Cofniecie skip dziala i pozycja wraca do kolejki - [ ] Wszystkie AC zaspokojone

<success_criteria>

  • Uzytkownik moze pojedynczym klikiem pominac pozycje w imporcie.
  • Pominiete pozycje nie wplywaja na statystyki finansowe.
  • Skip jest odwracalny.
  • Audit trail: meta_json zaimportowanej faktury zawiera liste pominietych pozycji.
  • Zaden istniejacy test nie regresuje. </success_criteria>
Po zakonczeniu utworz `.paul/phases/05-finances-fakturownia-import/05-05-SUMMARY.md` z: - wybranym wariantem modelu danych (new-column vs null-category) i uzasadnieniem, - opisem zmian w UI, - screenshotami lub krotkim opisem flow "oznacz → import → odtworz", - wynikami UAT.