feat(98-order-imported-first-only): gate order.imported na pierwszy import + backfill statusow

- AllegroOrderImportService / ShopproOrdersSyncService: trigger order.imported tylko gdy $wasCreated
- bin/backfill_shipped_status_98.php: jednorazowy CLI, w_realizacji + shipment -> wyslane (przez OrdersRepository::updateOrderStatus)
- backfill: 4 zamowienia naprawione (#275, #340, #396, #422), idempotentny

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 10:56:03 +02:00
parent 423829889e
commit 7eefd1af61
9 changed files with 431 additions and 9 deletions

View File

@@ -0,0 +1,141 @@
---
phase: 98-order-imported-first-only
plan: 01
subsystem: automation
tags: [automation, order-import, allegro, shoppro, backfill]
requires:
- phase: 84-order-imported-automation-event
provides: order.imported event + AutomationService trigger plumbing
provides:
- First-import-only gating for order.imported automation event
- One-shot CLI backfill: orders w_realizacji + shipment -> wyslane
affects: [automation rules, allegro import, shoppro sync]
tech-stack:
added: []
patterns: ["Producer-side gating of automation events using $wasCreated flag"]
key-files:
created:
- bin/backfill_shipped_status_98.php
modified:
- src/Modules/Settings/AllegroOrderImportService.php
- src/Modules/Settings/ShopproOrdersSyncService.php
key-decisions:
- "Gate order.imported na producencie, bez nowego eventu order.first_imported"
- "Backfill jednorazowy w bin/, idempotentny, przez OrdersRepository::updateOrderStatus"
patterns-established:
- "Pre-existing $wasCreated flag jest jedynym zrodlem prawdy o pierwszym imporcie"
duration: ~25min
started: 2026-04-13
completed: 2026-04-13
---
# Phase 98 Plan 01: Order Imported First-Only + Status Backfill
**Event automatyzacji `order.imported` ogranicza sie do pierwszego importu zamowienia, a uszkodzone historyczne zamowienia (w realizacji + posiadana przesylka) zostaly przywrocone do statusu "wyslane".**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~25 min |
| Tasks | 2/2 completed |
| Files modified | 3 (2 src + 1 new bin) |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Allegro re-import nie odpala order.imported | Pass | Warunek `$wasCreated && ...` w AllegroOrderImportService.php |
| AC-2: ShopPRO re-import nie odpala order.imported | Pass | Warunek `$wasCreated &&` dodany w ShopproOrdersSyncService.php |
| AC-3: Pierwszy import nadal triggeruje event | Pass | Logika niezmieniona dla `$wasCreated === true` |
| AC-4: Backfill statusow | Pass | 4/4 zamowien (#275, #340, #396, #422) zaktualizowano; drugi run = 0 (idempotentny) |
## Accomplishments
- Producer-side gating eliminuje regresje statusu "wyslane" -> "w realizacji" przy ponownych importach
- Skrypt `bin/backfill_shipped_status_98.php` napisany defensywnie: uzywa `OrdersRepository::updateOrderStatus`, dzieki czemu kazda zmiana ma wpis w `order_status_history` i `order_activity_log`
- Dry-run/apply/--use-remote zgodne z konwencja innych skryptow w `bin/`
- Backfill na produkcyjnej (lokalnie, przez DB_HOST_REMOTE) bazie wykonany: 4 zamowienia naprawione
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Settings/AllegroOrderImportService.php` | Modified | Gate trigger `order.imported` na `$wasCreated` |
| `src/Modules/Settings/ShopproOrdersSyncService.php` | Modified | Gate trigger `order.imported` na `$wasCreated` (zachowane `!$wasPaymentTransition`) |
| `bin/backfill_shipped_status_98.php` | Created | Jednorazowy backfill statusow z pelnym audit trail |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Gating po stronie producenta zamiast nowego eventu `order.first_imported` | Najmniejsza zmiana, bez wplywu na konfiguracje regul ani UI; semantyka eventu pozostaje zgodna z phase 84 | Reguly pobrania zamowienia automatycznie staja sie "first import only" |
| Backfill wykonywany przez `OrdersRepository::updateOrderStatus`, nie bezposrednim UPDATE | Zachowanie historii statusow i activity logu | Pelny audit trail dla recznej naprawy danych |
| Skrypt obsluguje `--use-remote` (DB_HOST_REMOTE) | Zgodnie z CLAUDE.md: DB_HOST_REMOTE dla operacji recznych agenta | Mozliwosc uruchomienia z lokalnego srodowiska bez zmiany runtime |
## Deviations from Plan
| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 0 | - |
| Scope additions | 0 | - |
| Deferred | 0 | - |
Plan wykonany dokladnie wg specyfikacji.
## Issues Encountered
| Issue | Resolution |
|-------|------------|
| Lokalne MySQL niedostepne przy weryfikacji | Uzyto `--use-remote` (DB_HOST_REMOTE) zgodnie z konwencja CLAUDE.md |
## Verification Results
```
$ php -l src/Modules/Settings/AllegroOrderImportService.php
No syntax errors detected
$ php -l src/Modules/Settings/ShopproOrdersSyncService.php
No syntax errors detected
$ php -l bin/backfill_shipped_status_98.php
No syntax errors detected
$ php bin/backfill_shipped_status_98.php --dry-run --use-remote
[scan] candidates: 4
[dry-run] order #275 -> wyslane
[dry-run] order #340 -> wyslane
[dry-run] order #396 -> wyslane
[dry-run] order #422 -> wyslane
$ php bin/backfill_shipped_status_98.php --use-remote
[scan] candidates: 4
[ok] order #275 -> wyslane
[ok] order #340 -> wyslane
[ok] order #396 -> wyslane
[ok] order #422 -> wyslane
Backfill 98: total=4 updated=4 skipped=0
$ php bin/backfill_shipped_status_98.php --dry-run --use-remote
[scan] candidates: 0 # idempotency confirmed
```
## Next Phase Readiness
**Ready:**
- Reguly automatyzacji "Pobranie zamowienia" sa bezpieczne dla zamowien w obrocie
- Mechanizm `OrdersRepository::updateOrderStatus` potwierdzony dla skryptow CLI
**Concerns:**
- Manualny test przez uzytkownika (wymuszony re-import) nie jest jeszcze zarejestrowany w czasie tego Unify
**Blockers:** None
---
*Phase: 98-order-imported-first-only, Plan: 01*
*Completed: 2026-04-13*