- 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.
323 lines
19 KiB
Markdown
323 lines
19 KiB
Markdown
---
|
|
phase: 125-invoice-requested-import-fix
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- src/Modules/Settings/ShopproOrdersSyncService.php
|
|
- src/Modules/Settings/ShopproOrderMapper.php
|
|
- src/Modules/Settings/AllegroOrderImportService.php
|
|
- src/Modules/Orders/OrderImportRepository.php
|
|
- src/Modules/Orders/OrdersRepository.php
|
|
- database/migrations/20260513_000113_drop_orders_is_invoice_and_backfill_invoice_requested.sql
|
|
- .paul/codebase/db_schema.md
|
|
- .paul/codebase/architecture.md
|
|
- .paul/codebase/tech_changelog.md
|
|
autonomous: true
|
|
delegation: off
|
|
---
|
|
|
|
<objective>
|
|
## Goal
|
|
Naprawić rozjazd między mapperem shopPRO a auto-set `orders.invoice_requested` przy imporcie, tak aby zamówienie z fakturą poprawnie pokazywało zaznaczony checkbox w zakładce Płatności i odblokowywało przycisk „Wystaw fakturę". Przy okazji usunąć duplikującą się kolumnę `orders.is_invoice` (legacy z Phase 115), bo to ona była źródłem dryftu między mapperem a sync service'em.
|
|
|
|
## Purpose
|
|
- Bugfix #1089: shopPRO order z `firm_nip` nie ustawia `invoice_requested=1` (operator musi ręcznie klikać toggle).
|
|
- Analogiczna luka w Allegro: import nie wykrywa `invoice.address.taxId` bez `invoice.required=true`.
|
|
- Eliminacja struktury źródłowej buga: dwie kolumny dla tej samej semantyki (`is_invoice` ustawiany przez importer, `invoice_requested` czytany przez UI). Jedyne źródło prawdy → `invoice_requested`.
|
|
|
|
## Output
|
|
- ShopproOrdersSyncService i AllegroOrderImportService używają tej samej heurystyki co mapper, propagując wynik z `$aggregate['order']['_invoice_detected']` (lub bezpośrednio z mappera) do `setInvoiceRequested()`.
|
|
- Migracja idempotentna: backfill `invoice_requested=1` dla zamówień gdzie poprzednio detekcja zadziałała na poziomie mappera, potem DROP COLUMN `orders.is_invoice`.
|
|
- Kod oczyszczony z odniesień do `is_invoice` (mapper, OrderImportRepository INSERT, OrdersRepository SELECT/hydrate).
|
|
- Dokumentacja zaktualizowana (`db_schema.md`, `architecture.md`, `tech_changelog.md`).
|
|
</objective>
|
|
|
|
<context>
|
|
<clarifications>
|
|
- **[Detekcja shopPRO]** — Jak szeroko rozszerzyć auto-detekcję faktury przy imporcie shopPRO?
|
|
→ Odpowiedź: Propaguj wynik mappera (is_invoice → invoice_requested) — najprościej, zero duplikacji, mapper już sprawdza firm_name/firm_nip/invoice.required/is_invoice/invoice (top-level).
|
|
- **[Allegro fix]** — Czy przy okazji naprawić analogiczną lukę dla Allegro?
|
|
→ Odpowiedź: Tak — rozszerz Allegro o detekcję NIP/firmy (`invoice.address.taxId`, `invoice.naturalPerson=false`, `invoice.companyName`).
|
|
- **[Backfill]** — Backfill istniejących zamówień: jak wykonać?
|
|
→ Odpowiedź: Migracja SQL idempotentna (UPDATE … WHERE is_invoice=1 AND invoice_requested=0) — pipeline `php bin/migrate.php`, idempotentne (po backfillu DROP COLUMN i tak czyni operację jednorazową).
|
|
- **[is_invoice fate]** — Co zrobić z kolumną orders.is_invoice?
|
|
→ Odpowiedź: Usunąć kolumnę w tej fazie — migracja DROP COLUMN po backfillu, usunięcie z `OrderImportRepository` (INSERT, params, docstring Phase 112), z `OrdersRepository` (SELECT, hydrate), z `ShopproOrderMapper` (zwraca flagę jako transient w aggregate'cie zamiast pisać do DB), z `AllegroOrderImportService` (analogicznie).
|
|
|
|
**Stan w bazie produkcyjnej (2026-05-13):**
|
|
- 7 zamówień `is_invoice=1 AND invoice_requested=0` (w tym #1089, source=shoppro).
|
|
- Kolumna `orders.is_invoice TINYINT(1) NOT NULL DEFAULT 0` istnieje, nie ma indexu.
|
|
- `db_schema.md` (linia 244+) NIE wymienia kolumny `is_invoice` — dokumentacja była już niespójna z DB.
|
|
</clarifications>
|
|
|
|
## Project Context
|
|
@.paul/PROJECT.md
|
|
@.paul/ROADMAP.md
|
|
@.paul/STATE.md
|
|
|
|
## Prior Work
|
|
@.paul/phases/115-invoice-from-order/115-01-SUMMARY.md
|
|
# Phase 115 wprowadziła dwutorową detekcję: mapper → is_invoice, sync service → invoice_requested.
|
|
# Ta faza koryguje rozjazd przez propagację z mappera i eliminację is_invoice.
|
|
|
|
## Source Files
|
|
@src/Modules/Settings/ShopproOrderMapper.php
|
|
@src/Modules/Settings/ShopproOrdersSyncService.php
|
|
@src/Modules/Settings/AllegroOrderImportService.php
|
|
@src/Modules/Orders/OrderImportRepository.php
|
|
@src/Modules/Orders/OrdersRepository.php
|
|
@.paul/codebase/db_schema.md
|
|
@.paul/codebase/architecture.md
|
|
</context>
|
|
|
|
<acceptance_criteria>
|
|
|
|
## AC-1: Import shopPRO z firm_nip ustawia invoice_requested
|
|
```gherkin
|
|
Given zamówienie shopPRO z payloadem zawierającym `firm_name`+`firm_nip` (bez kluczy `wants_invoice`/`invoice_required`/`invoice.required`/`buyer.wants_invoice`/`buyer.invoice`)
|
|
When ShopproOrdersSyncService importuje to zamówienie jako nowe (wasCreated=true)
|
|
Then `orders.invoice_requested = 1`
|
|
And UI w zakładce Płatności (`/orders/{id}`) ma zaznaczony checkbox „Klient prosi o fakturę"
|
|
And przycisk „Wystaw fakturę" jest widoczny
|
|
```
|
|
|
|
## AC-2: Import Allegro z NIP ustawia invoice_requested
|
|
```gherkin
|
|
Given zamówienie Allegro z payloadem `invoice.address.taxId` lub `invoice.naturalPerson=false`, ale BEZ `invoice.required=true`
|
|
When AllegroOrderImportService importuje to zamówienie jako nowe (wasCreated=true)
|
|
Then `orders.invoice_requested = 1`
|
|
```
|
|
|
|
## AC-3: Re-import nie nadpisuje manualnego toggla
|
|
```gherkin
|
|
Given zamówienie z payload zawierającym firm_nip oraz manualnie ustawionym `invoice_requested=0` (operator odznaczył)
|
|
When importer re-importuje to zamówienie (wasCreated=false, delta-only)
|
|
Then `orders.invoice_requested` pozostaje `0`
|
|
And kontrakt Phase 115 (auto-set tylko przy `created=true`) jest zachowany
|
|
```
|
|
|
|
## AC-4: Backfill istniejących zamówień
|
|
```gherkin
|
|
Given migracja `20260513_000113_drop_orders_is_invoice_and_backfill_invoice_requested.sql` zostaje uruchomiona
|
|
When `php bin/migrate.php` wykonuje ją na bazie gdzie 7 zamówień ma `is_invoice=1 AND invoice_requested=0`
|
|
Then `UPDATE orders SET invoice_requested=1 WHERE is_invoice=1 AND invoice_requested=0` wykonuje się PRZED `DROP COLUMN`
|
|
And po migracji `orders.is_invoice` nie istnieje
|
|
And dla każdego z 7 dotkniętych zamówień `invoice_requested=1`
|
|
And ponowne uruchomienie migracji jest no-op (kolumna już nie istnieje — `DROP COLUMN IF EXISTS` lub idempotentny SQL przez `information_schema` check)
|
|
```
|
|
|
|
## AC-5: Kolumna is_invoice nie istnieje w runtime
|
|
```gherkin
|
|
Given migracja została wykonana
|
|
When aplikacja importuje nowe zamówienie lub wyświetla szczegóły zamówienia
|
|
Then żaden SELECT/INSERT/UPDATE nie referencuje `orders.is_invoice`
|
|
And testy PHPUnit (`OrderImportRepositoryTest`) przechodzą bez modyfikacji asercji powiązanych z is_invoice (albo asercje zostały usunięte wraz z fixture)
|
|
And ręczny `SELECT id, invoice_requested FROM orders WHERE id=1089` zwraca `invoice_requested=1`
|
|
```
|
|
|
|
</acceptance_criteria>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Mapper exposes detection result, importers propagate it</name>
|
|
<files>
|
|
src/Modules/Settings/ShopproOrderMapper.php,
|
|
src/Modules/Settings/ShopproOrdersSyncService.php,
|
|
src/Modules/Settings/AllegroOrderImportService.php
|
|
</files>
|
|
<action>
|
|
**ShopproOrderMapper.php:**
|
|
- Usuń klucz `'is_invoice'` z tablicy `$order` (linia 148).
|
|
- Zachowaj metodę `resolveInvoiceRequested(array $payload): bool` jako jedyne źródło heurystyki.
|
|
- W `mapOrderAggregate()` dodaj do zwracanego array klucz top-level `'invoice_detected' => $this->resolveInvoiceRequested($payload)` (poza `order`, na poziomie aggregate'u — analogicznie do `addresses`/`items`/`payments`). Powód: nie zaśmiecać kontraktu `order` (który mapuje 1:1 na kolumny tabeli) flagą transient'ową.
|
|
|
|
**ShopproOrdersSyncService.php:**
|
|
- W bloku po `upsertOrderAggregate` (okolice linii 273-277) zamień warunek `if ($this->shouldRequestInvoice($rawOrder))` na `if (!empty($aggregate['invoice_detected']))`.
|
|
- USUŃ prywatną metodę `shouldRequestInvoice(array $rawOrder): bool` (linie 316-338) — zastąpiona heurystyką mappera.
|
|
- Zachowaj guard `wasCreated=true` (kontrakt Phase 115 z AC-3).
|
|
|
|
**AllegroOrderImportService.php:**
|
|
- W bloku auto-set (linie 99-103) rozszerz warunek: `if (!empty($invoiceFlag['required']))` → wydziel do nowej prywatnej metody `private function shouldRequestInvoice(array $payload): bool` która sprawdza:
|
|
1. `!empty($payload['invoice']['required'])` (istniejące zachowanie)
|
|
2. `!empty($payload['invoice']['naturalPerson']) === false && isset($payload['invoice'])` → klient firmowy
|
|
3. `!empty($payload['invoice']['address']['taxId'])` — NIP w adresie faktury
|
|
4. `!empty($payload['invoice']['companyName'])`
|
|
- Zwracaj `true` gdy któryś z warunków spełniony.
|
|
- Wywołanie: `if ($wasCreated && $this->shouldRequestInvoice($payload)) { $this->ordersRepository->setInvoiceRequested($savedOrderId, true); }`
|
|
|
|
Avoid:
|
|
- NIE zmieniać sygnatury `OrdersRepository::setInvoiceRequested()` ani `recordActivity()`.
|
|
- NIE dodawać kolumny `invoice_detected` do DB — to wartość transient w pamięci między mapperem a syncem.
|
|
</action>
|
|
<verify>
|
|
- `php -l src/Modules/Settings/ShopproOrderMapper.php` (lint pass).
|
|
- `php -l src/Modules/Settings/ShopproOrdersSyncService.php`.
|
|
- `php -l src/Modules/Settings/AllegroOrderImportService.php`.
|
|
- Grep: `grep -n "is_invoice" src/Modules/Settings/` zwraca tylko pozostałości w komentarzach (jeśli są) — żadnych aktywnych odwołań.
|
|
- Grep: `grep -n "shouldRequestInvoice" src/Modules/Settings/ShopproOrdersSyncService.php` → 0 trafień.
|
|
</verify>
|
|
<done>AC-1, AC-2, AC-3 satisfied: mapper jest jedynym źródłem detekcji shopPRO, Allegro ma rozszerzoną detekcję NIP/firmy, oba importery propagują flagę tylko przy created=true.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Migration — backfill invoice_requested + DROP COLUMN is_invoice</name>
|
|
<files>
|
|
database/migrations/20260513_000113_drop_orders_is_invoice_and_backfill_invoice_requested.sql
|
|
</files>
|
|
<action>
|
|
Utwórz migrację z idempotentnym DDL+DML:
|
|
|
|
```sql
|
|
-- Phase 125-01: backfill invoice_requested z is_invoice + DROP is_invoice
|
|
-- Idempotentna: DML w bloku IF (kolumna istnieje), DROP w bloku IF (kolumna istnieje).
|
|
-- Pattern z `.paul` Key Decision (2026-05-10): migracje no-op zawsze jako DDL.
|
|
|
|
SET @col_exists := (
|
|
SELECT COUNT(*) FROM information_schema.COLUMNS
|
|
WHERE TABLE_SCHEMA = DATABASE()
|
|
AND TABLE_NAME = 'orders'
|
|
AND COLUMN_NAME = 'is_invoice'
|
|
);
|
|
|
|
SET @sql_backfill := IF(@col_exists > 0,
|
|
'UPDATE orders SET invoice_requested = 1 WHERE is_invoice = 1 AND invoice_requested = 0',
|
|
'ALTER TABLE orders COMMENT = ''phase-125 backfill no-op'''
|
|
);
|
|
PREPARE stmt_backfill FROM @sql_backfill;
|
|
EXECUTE stmt_backfill;
|
|
DEALLOCATE PREPARE stmt_backfill;
|
|
|
|
SET @sql_drop := IF(@col_exists > 0,
|
|
'ALTER TABLE orders DROP COLUMN is_invoice',
|
|
'ALTER TABLE orders COMMENT = ''phase-125 drop no-op'''
|
|
);
|
|
PREPARE stmt_drop FROM @sql_drop;
|
|
EXECUTE stmt_drop;
|
|
DEALLOCATE PREPARE stmt_drop;
|
|
```
|
|
|
|
Avoid:
|
|
- NIE używać `SELECT 1;` jako no-op (Key Decision 2026-05-10: powoduje SQLSTATE 2014 z PDO unbuffered).
|
|
- NIE używać `DROP COLUMN IF EXISTS` (MariaDB only — produkcja może być na czystym MySQL).
|
|
</action>
|
|
<verify>
|
|
- Plik istnieje w `database/migrations/`.
|
|
- Składnia SQL waliduje: `mysql --help` test dry-run niemożliwy bez DB; alternatywa: `mysql -h … -e "$(cat migration.sql)" --dry-run` — XAMPP nie wspiera; zostawiamy weryfikację na operatora przy `php bin/migrate.php`.
|
|
- Po wykonaniu na bazie: `SELECT COUNT(*) FROM orders WHERE invoice_requested=1;` rośnie o 7 vs. pre-migration baseline.
|
|
- `SHOW COLUMNS FROM orders LIKE 'is_invoice';` → empty set.
|
|
- Re-run migracji → no-op (ALTER TABLE COMMENT).
|
|
</verify>
|
|
<done>AC-4 satisfied: migracja idempotentna, backfill 7 zamówień przed DROP COLUMN, ponowne uruchomienie bezpieczne.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Remove is_invoice from PHP code (repository, hydrate)</name>
|
|
<files>
|
|
src/Modules/Orders/OrderImportRepository.php,
|
|
src/Modules/Orders/OrdersRepository.php
|
|
</files>
|
|
<action>
|
|
**OrderImportRepository.php:**
|
|
- W `insertOrder()` SQL (linie 161-175) usuń `is_invoice` z listy kolumn INSERT oraz `:is_invoice` z VALUES.
|
|
- W `orderParams()` (linia 258) usuń linię `'is_invoice' => !empty($orderData['is_invoice']) ? 1 : 0,`.
|
|
- W docstring `updateOrderDelta()` (linia 190) usuń wzmiankę o `is_invoice` z listy pól nie nadpisywanych przy delta-only (kolumna już nie istnieje, wzmianka jest dezinformująca).
|
|
|
|
**OrdersRepository.php:**
|
|
- Linia 172: usuń `o.is_invoice,` z SELECT (`findById()` / pokrewne — zweryfikować, że to ten sam zapytanie).
|
|
- Linia 235: usuń `'is_invoice' => (int) ($row['is_invoice'] ?? 0) === 1,` z hydrate / mapowania zwracanego row'a.
|
|
- Jeśli kontroler/view referencjuje `$order['is_invoice']` — sprawdź `grep -rn "\\['is_invoice'\\]" src/ resources/views/` i usuń odwołania (lub zamień na `$order['invoice_requested']` jeśli kontekst tego wymaga).
|
|
|
|
Avoid:
|
|
- NIE zmieniać kontraktu `OrderImportRepository::upsertOrderAggregate()` poza usunięciem klucza is_invoice (sygnatura, return value bez zmian).
|
|
- NIE dotykać `payment_status` ani `total_paid` (chronione przez Phase 119).
|
|
</action>
|
|
<verify>
|
|
- `php -l src/Modules/Orders/OrderImportRepository.php`.
|
|
- `php -l src/Modules/Orders/OrdersRepository.php`.
|
|
- `grep -rn "is_invoice" src/ resources/views/` → 0 trafień (poza ewentualnymi historycznymi komentarzami w `.paul/`).
|
|
- Manual: po wdrożeniu importu zamówienie #1089 ma `invoice_requested=1` po re-imporcie (delta-only nie nadpisze, ale przed migracją można też ręcznie ustawić toggle aby zweryfikować że runtime nie próbuje pisać do is_invoice).
|
|
</verify>
|
|
<done>AC-5 satisfied: żaden runtime SELECT/INSERT nie odwołuje się do `is_invoice`; aplikacja działa po DROP COLUMN.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 4: Update docs (db_schema, architecture, tech_changelog)</name>
|
|
<files>
|
|
.paul/codebase/db_schema.md,
|
|
.paul/codebase/architecture.md,
|
|
.paul/codebase/tech_changelog.md
|
|
</files>
|
|
<action>
|
|
**db_schema.md:**
|
|
- Sekcja `orders` (linia 244+) — pozostaje bez `is_invoice` (i tak już nieobecna, tylko potwierdzenie spójności).
|
|
- W komentarzu pod tabelą `orders` dodaj wzmiankę: „`invoice_requested` (Phase 113-01) jest jedynym znacznikiem żądania faktury. Legacy `is_invoice` usunięte w Phase 125-01."
|
|
- Phase footer: zaktualizuj `Updated: 2026-05-13` i `Total tables: 61` (bez zmian; kolumna usunięta to nie tabela).
|
|
|
|
**architecture.md:**
|
|
- W sekcji „### Auto-import flagi invoice_requested" (linia 261+) zaktualizuj opis:
|
|
- shopPRO: `ShopproOrderMapper::resolveInvoiceRequested()` jest jedynym źródłem heurystyki; sprawdza: `is_invoice` w payload (top-level z legacy źródeł zewnętrznych — payload, nie kolumna), `invoice.required`, top-level `invoice` jako bool, `firm_name`/`firm_nip`/`invoice.company_name`/`invoice.tax_id`. Sync service propaguje wynik z `$aggregate['invoice_detected']`.
|
|
- Allegro: `AllegroOrderImportService::shouldRequestInvoice($payload)` sprawdza `invoice.required`, `invoice.naturalPerson=false`, `invoice.address.taxId`, `invoice.companyName`. Tylko przy `wasCreated=true`.
|
|
|
|
**tech_changelog.md:**
|
|
- Dodaj wpis dla Phase 125-01:
|
|
```
|
|
## Phase 125-01 — invoice_requested import fix (2026-05-13)
|
|
- Bug: zamówienia shopPRO z `firm_nip` (bez `invoice.required`) nie ustawiały `invoice_requested=1` (mapper wykrywał, sync service nie).
|
|
- Fix: ShopproOrderMapper eksponuje `invoice_detected` w aggregate. ShopproOrdersSyncService propaguje zamiast duplikować heurystykę. Usunięta metoda `shouldRequestInvoice` ze sync service.
|
|
- Allegro: rozszerzenie detekcji o `invoice.naturalPerson=false`, `invoice.address.taxId`, `invoice.companyName`.
|
|
- Migracja 20260513_000113 — backfill 7 zamówień + DROP COLUMN `orders.is_invoice` (legacy z Phase 115, dryft względem `invoice_requested`).
|
|
- Files: ShopproOrderMapper.php, ShopproOrdersSyncService.php, AllegroOrderImportService.php, OrderImportRepository.php, OrdersRepository.php.
|
|
```
|
|
</action>
|
|
<verify>
|
|
- Grep `grep -n "is_invoice" .paul/codebase/db_schema.md .paul/codebase/architecture.md` — tylko historyczne wzmianki w kontekście Phase 125.
|
|
- Sekcja Phase 125 istnieje w `tech_changelog.md`.
|
|
</verify>
|
|
<done>Dokumentacja spójna z kodem; przyszli czytelnicy widzą że `invoice_requested` to jedyne źródło prawdy.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<boundaries>
|
|
|
|
## DO NOT CHANGE
|
|
- `orders.invoice_requested` schema (Phase 113-01 zostaje, index `idx_orders_invoice_requested` zostaje).
|
|
- `OrdersRepository::setInvoiceRequested()` sygnatura i `recordActivity('invoice_requested_changed')` event type.
|
|
- Kontrakt Phase 115: auto-set tylko przy `wasCreated=true`, delta-only re-import nie nadpisuje manualnej flagi.
|
|
- Kontrakt Phase 119: `updateOrderDelta()` zachowuje ochronę `total_paid` i `is_canceled_by_buyer` — ta faza nie dotyka logiki delta.
|
|
- Kontrakt Phase 112: `replaceAddresses/replaceItems/replaceNotes` wywoływane tylko przy `created=true`.
|
|
- `payload_json` — nie filtrujemy, surowy payload zostaje (mapper-tylko detekcja).
|
|
- Allegro `invoice.required` jako warunek wystarczający — pozostaje (rozszerzenie, nie zamiana).
|
|
|
|
## SCOPE LIMITS
|
|
- NIE robimy nowego eventu automatyzacji `invoice.created` (zostaje na future plan zgodnie z Key Decision 2026-05-10).
|
|
- NIE dotykamy INVOICE-IDEMP-115 (double-POST Fakturownia) — to osobny todo.
|
|
- NIE refaktorujemy `OrderImportRepository::orderParams()` poza usunięciem klucza is_invoice (tylko minimalna delta).
|
|
- NIE migrujemy stałych Allegro do wspólnego helpera — `shouldRequestInvoice` zostaje prywatną metodą per importer (shopPRO ma to w mapperze, Allegro nie ma analogicznego mappera klasowego; ujednolicenie poza zakresem).
|
|
- NIE dodajemy testów PHPUnit dla detekcji shopPRO/Allegro (możliwe w follow-up; weryfikacja przez ręczny smoke test operatora na zamówieniu #1089).
|
|
|
|
</boundaries>
|
|
|
|
<verification>
|
|
Przed zamknięciem planu:
|
|
- [ ] `php -l` na 5 zmodyfikowanych plikach PHP — bez błędów składni.
|
|
- [ ] `grep -rn "is_invoice" src/` zwraca 0 trafień w aktywnym kodzie.
|
|
- [ ] Migracja przygotowana, idempotentna (`@col_exists` guard + ALTER TABLE COMMENT no-op).
|
|
- [ ] Dokumentacja zaktualizowana (db_schema, architecture, tech_changelog).
|
|
- [ ] STATE.md pokazuje pending action: operator uruchamia `php bin/migrate.php` + ręczna weryfikacja na #1089.
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- 5 plików PHP zmodyfikowanych zgodnie z zadaniami 1+3.
|
|
- Nowa migracja idempotentna.
|
|
- 3 pliki dokumentacji zaktualizowane.
|
|
- AC-1..AC-5 spełnione (manualna weryfikacja AC-1/AC-4 przez operatora na żywej bazie po uruchomieniu migracji).
|
|
- Order #1089 po backfillu ma `invoice_requested=1` i checkbox w UI zaznaczony.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Po zakończeniu utworzyć `.paul/phases/125-invoice-requested-import-fix/125-01-SUMMARY.md`.
|
|
</output>
|