---
phase: 05-finances-fakturownia-import
plan: 02
type: execute
wave: 1
depends_on: ["05-01"]
files_modified:
  - autoload/Domain/Finances/FakturowniaInvoiceImporter.php
  - templates/finances/fakturownia-import-panel.php
autonomous: true
---

<objective>
## Goal
Usprawnic mapowanie klienta w imporcie Fakturownia tak, aby priorytetowo mapowac po NIP i ograniczyc reczne mapowanie tej samej firmy przy kolejnych fakturach kosztowych.

## Purpose
W aktualnym imporcie czesc dokumentow kluczuje klienta po `client_id`, co moze powodowac tworzenie kolejnych rekordow "brak mapowania" dla tego samego kontrahenta. Zmiana ma zapewnic stabilny klucz po NIP.

## Output
- Zmieniony algorytm `buildClientKey()` z priorytetem NIP
- Normalizacja NIP do wspolnego formatu klucza
- Kompatybilnosc wsteczna: fallback do starego klucza `id:...` podczas importu
- Widoczny NIP przy brakujacych mapowaniach klienta w panelu finansow
</objective>

<context>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@.paul/phases/05-finances-fakturownia-import/05-01-PLAN.md
@.paul/phases/05-finances-fakturownia-import/05-01-SUMMARY.md

## Source Files
@autoload/Domain/Finances/FakturowniaInvoiceImporter.php
@templates/finances/fakturownia-import-panel.php
@autoload/Controllers/FinancesController.php
@autoload/Domain/Finances/FakturowniaImportRepository.php
</context>

<acceptance_criteria>

## AC-1: Priorytet mapowania klienta po NIP
```gherkin
Given dokument z Fakturowni zawiera NIP kontrahenta
When importer buduje klucz klienta
Then klucz jest oparty o NIP (prefiks `tax:`) niezaleznie od obecnosci `client_id`
```

## AC-2: Stabilna normalizacja NIP
```gherkin
Given NIP wystepuje w roznych formatach (spacje, myslniki, inne separatory)
When importer normalizuje NIP
Then wszystkie formy daja ten sam klucz mapowania klienta
```

## AC-3: Kompatybilnosc wsteczna mapowan
```gherkin
Given istnieje historyczne mapowanie klienta zapisane po kluczu `id:...`
When importer nie znajdzie mapowania po nowym kluczu `tax:...`
Then wykona fallback do starego klucza `id:...` i zaimportuje dokument bez ponownego recznego mapowania
```

## AC-4: NIP widoczny w panelu brakow mapowania
```gherkin
Given klient trafia do listy "Brakujace mapowania klientow"
When uzytkownik otwiera panel w `/finances/main_view/`
Then przy rekordzie widzi NIP z payloadu (jesli dostepny), co ulatwia wybor klienta CRM
```

</acceptance_criteria>

<tasks>

<task type="auto">
  <name>Task 1: Zmienic algorytm klucza klienta na NIP-first z normalizacja</name>
  <files>autoload/Domain/Finances/FakturowniaInvoiceImporter.php</files>
  <action>
    1. Zmienic `buildClientKey()` tak, aby kolejnosc byla:
       - `tax:{normalized_tax_no}`
       - `id:{client_id}`
       - `name:{normalized_name}`
    2. Dodac pomocnicza normalizacje NIP usuwajaca znaki nienumeryczne i biale znaki.
    3. Gdy normalizacja da pusty wynik, traktowac NIP jako niedostepny i przejsc do fallbacku.

    Unikac: zmiany semantyki mapowania pozycji (`buildItemKey`) i modyfikacji niezwiązanych z klientem.
  </action>
  <verify>
    Odczyt kodu potwierdza, ze `buildClientKey()` sprawdza najpierw NIP, a NIP jest normalizowany do stalego formatu.
  </verify>
  <done>AC-1 i AC-2 satisfied</done>
</task>

<task type="auto">
  <name>Task 2: Dodac fallback odczytu mapowania po historycznym kluczu id</name>
  <files>autoload/Domain/Finances/FakturowniaInvoiceImporter.php</files>
  <action>
    1. W `processSingleDocument()` po braku mapowania po nowym `client_key` wykonac probe odczytu mapowania po starym kluczu `id:{client_id}`, o ile `client_id` istnieje i nowy klucz jest inny.
    2. Jesli fallback znajdzie mapowanie, kontynuowac import bez queue dla klienta.
    3. Jesli fallback nie znajdzie mapowania, zachowac obecne zachowanie queue `client`.

    Unikac: zapisu nowego mapowania automatycznie bez decyzji uzytkownika.
  </action>
  <verify>
    Sciezka warunkowa importera zawiera probe fallbacku `id:` przed `queueUnmapped('client', ...)`.
  </verify>
  <done>AC-3 satisfied</done>
</task>

<task type="auto">
  <name>Task 3: Pokazac NIP w panelu brakujacych mapowan klientow</name>
  <files>templates/finances/fakturownia-import-panel.php</files>
  <action>
    1. W tabeli "Brakujace mapowania klientow" wyswietlic NIP z payloadu (`tax_no`) przy danym rekordzie, z escapowaniem.
    2. Zachowac dotychczasowe informacje o kluczu i liczbie wystapien.
    3. Nie zmieniac endpointow zapisu mapowania i CSRF.
  </action>
  <verify>
    Widok panelu renderuje dodatkowa linie z NIP (gdy payload ma `tax_no`) i pozostaje bezpieczny pod XSS.
  </verify>
  <done>AC-4 satisfied</done>
</task>

</tasks>

<boundaries>

## DO NOT CHANGE
- mechanizm importu pozycji i mapowania kategorii
- struktura tabel SQL w `FakturowniaImportRepository` (bez migracji w tym planie)
- endpointy i routing niezwiązane z finansami

## SCOPE LIMITS
- Tylko mapowanie klienta i prezentacja NIP w panelu
- Bez tworzenia klientow CRM automatycznie
- Bez zmian w harmonogramie cron

</boundaries>

<verification>
Before declaring plan complete:
- [ ] `buildClientKey()` ma priorytet `tax -> id -> name`
- [ ] NIP jest normalizowany do stabilnego formatu klucza
- [ ] Importer ma fallback odczytu mapowania po historycznym `id:...`
- [ ] Panel brakow mapowan klientow wyswietla NIP (jesli dostępny)
- [ ] All acceptance criteria met
</verification>

<success_criteria>
- Brak ponownego mapowania tej samej firmy, gdy dokumenty roznia sie `client_id`, ale maja ten sam NIP
- Istniejace mapowania po `id:` nie przestaja dzialac po wdrozeniu zmiany
- Uzytkownik widzi NIP w panelu i szybciej mapuje klienta
</success_criteria>

<output>
After completion, create `.paul/phases/05-finances-fakturownia-import/05-02-SUMMARY.md`
</output>
