feat(125): invoice_requested import fix + drop legacy is_invoice column

- shopPRO: ShopproOrderMapper jako jedyne zrodlo heurystyki detekcji faktury;
  mapOrderAggregate() zwraca top-level invoice_detected (transient).
- ShopproOrdersSyncService: usunieta wlasna shouldRequestInvoice(); propagacja
  aggregate['invoice_detected'] do setInvoiceRequested() tylko przy created=true.
- Allegro: nowa shouldRequestInvoice(payload) z 4 wzorcami (invoice.required,
  naturalPerson=false, address.taxId, companyName/address.company.name).
  Wczesniej tylko invoice.required -> analogiczna luka jak shopPRO.
- Migracja 20260513_000113: idempotentny backfill (UPDATE invoice_requested=1
  WHERE is_invoice=1 AND invoice_requested=0) + DROP COLUMN orders.is_invoice.
  Guard przez information_schema.COLUMNS + PREPARE/EXECUTE z ALTER TABLE COMMENT
  no-op fallbackiem (portable MySQL/MariaDB).
- Cleanup is_invoice z OrderImportRepository (INSERT cols/values/params,
  docstring Phase 112) i OrdersRepository (paginate SELECT, transformOrderRow
  hydrate). AllegroOrderImportService mapping w mapCheckoutFormPayload tez
  usuniety (wymuszone konsekwencja DROP COLUMN).
- Bugfix #1089: zamowienie shopPRO z firm_nip (bez wants_invoice/invoice.required)
  ustawia teraz invoice_requested=1 -> UI w zakladce Platnosci zaznacza checkbox,
  przycisk "Wystaw fakture" widoczny.

Pending operator: php bin/migrate.php (XAMPP MySQL online) -> backfill 7 zamowien.
Smoke test: re-import shopPRO + nowe Allegro z NIP.
This commit is contained in:
2026-05-12 22:11:49 +02:00
parent e7a417bc22
commit 2ab461aaae
15 changed files with 619 additions and 67 deletions

View File

@@ -1,5 +1,28 @@
# Technical Changelog
## 2026-05-13 - Phase 125 Plan 01: invoice_requested Import Fix
**Co zrobiono:**
- Bugfix #1089: shopPRO order z `firm_nip` (bez kluczy z 5-elementowej listy `shouldRequestInvoice`) nie ustawial `invoice_requested=1` przy imporcie. Mapper wykrywal poprawnie (`is_invoice` przez heurystyke NIP), ale `ShopproOrdersSyncService::shouldRequestInvoice` mial wezsza liste kluczy -> UI w zakladce Platnosci wyswietlal odznaczony checkbox.
- `ShopproOrderMapper::mapOrderAggregate()` zwraca teraz top-level klucz `invoice_detected` (wynik `resolveInvoiceRequested($payload)`). Klucz `is_invoice` usuniety z tablicy `order` (nie odpowiada juz zadnej kolumnie DB).
- `ShopproOrdersSyncService::importOne()` propaguje `!empty($aggregate['invoice_detected'])` do `setInvoiceRequested(true)` zamiast wlasnej heurystyki. Stara metoda `shouldRequestInvoice` usunieta (zastapiona heurystyka mappera — zero duplikacji).
- `AllegroOrderImportService::shouldRequestInvoice($payload)` (nowa prywatna metoda) — rozszerza detekcje o `invoice.naturalPerson === false`, `invoice.address.taxId`, `invoice.companyName`/`invoice.address.company.name`. Wczesniej tylko `invoice.required` -> analogiczna luka jak shopPRO dla klientow Allegro z NIP bez `required=true`.
- Migracja `20260513_000113_drop_orders_is_invoice_and_backfill_invoice_requested.sql`:
- Idempotentny guard przez `information_schema.COLUMNS` + prepared statements (DDL no-op gdy kolumna juz nie istnieje, pattern z Key Decision 2026-05-10).
- Backfill: `UPDATE orders SET invoice_requested=1 WHERE is_invoice=1 AND invoice_requested=0` (7 zamowien na produkcji, w tym #1089).
- DROP COLUMN `orders.is_invoice` (legacy z Phase 115, dryft wzgledem `invoice_requested`).
- `OrderImportRepository::insertOrder()` SQL — usuniety `is_invoice` z kolumn INSERT i `:is_invoice` z VALUES. `orderParams()` — usunieta linia mapowania. Docstring `updateOrderDelta()` (Phase 112) — usunieta wzmianka.
- `OrdersRepository` — usuniety `o.is_invoice` z SELECT (`paginate` query) i `transformOrderRow()` hydrate (klucz `is_invoice` nie wystepuje juz w zwracanych row'ach).
**Dlaczego:**
- Bug #1089: zamowienie shopPRO z fakturowymi danymi firmowymi mialo `is_invoice=1` (mapper) ale `invoice_requested=0` (sync service). UI pokazywal odznaczony checkbox -> przycisk "Wystaw fakture" niedostepny -> operator musial recznie klikac toggle.
- Dryft: Phase 115 zostawila dwie kolumny dla tej samej semantyki (`is_invoice` legacy + `invoice_requested` nowy). Dwie sciezki detekcji (mapper vs. sync service) mialy rozna szerokosc heurystyki -> systematyczny rozjazd dla shopPRO orders z `firm_name`/`firm_nip`.
- Fix architekturalny: jedno zrodlo prawdy (`invoice_requested`), jedna heurystyka per zrodlo (mapper dla shopPRO, prywatna metoda dla Allegro).
**BREAKING:**
- Kolumna `orders.is_invoice` przestaje istniec po migracji `20260513_000113_*`. Wewnetrzny kontrakt — nie wystepuje w API ani odpowiedziach JSON. Jezeli ktokolwiek (skrypt operatora, raport custom) czytal `is_invoice` z DB -> przelaczyc na `invoice_requested`.
- `ShopproOrderMapper::mapOrderAggregate()` zwraca teraz dodatkowy top-level klucz `invoice_detected` (boolean). Klucz `is_invoice` znika z podtablicy `order` (nie odpowiada juz kolumnie DB).
## 2026-05-12 - Phase 124 Plan 01: SMS Templates
**Co zrobiono:**