Files
orderPRO/.paul/phases/112-reimport-data-protection/112-01-SUMMARY.md
Jacek Pyziak 782a291210 feat(112): re-import data protection — delta-only re-import + project_generated preservation
Phase 112 / Plan 112-01 complete (v3.6):
- OrderImportRepository::upsertOrderAggregate split into create vs re-import paths
- replaceAddresses/Items/Notes/Shipments/StatusHistory invoked only on first import
- new updateOrderDelta() narrows UPDATE to status_code (cond.), payment_status,
  total_paid, is_canceled_by_buyer, source_updated_at, payload_json, fetched_at
- source-side cancellation override (is_canceled_by_buyer=1 OR pull status_code='anulowane')
- identical-payload no-op guard via normalizePayloadJson()
- fixes case #882: order_items.id stable, project_generated (Phase 97) preserved
- Phase 111 payment.status_changed emit retained without regression

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:22:37 +02:00

158 lines
9.4 KiB
Markdown

---
phase: 112-reimport-data-protection
plan: 01
subsystem: orders
tags: [order-import, re-import, data-protection, payload-guard, allegro, shoppro, pdo]
requires:
- phase: 111-payment-transition-event
provides: payment_transition flag + payment.status_changed emit
- phase: 97-project-generation
provides: order_items.project_generated, project_generated_at columns
provides:
- Delta-only re-import for existing orders (skip replaceAddresses/Items/Notes)
- updateOrderDelta() — narrow UPDATE to status_code, payment_status, total_paid, is_canceled_by_buyer, source_updated_at, payload_json, fetched_at
- Source-side cancellation propagation (is_canceled_by_buyer=1 OR mapped pull status_code='anulowane' → forces orders.status_code='anulowane')
- Identical-payload no-op guard via normalizePayloadJson()
affects:
- Future re-import scenarios (Allegro + shopPRO cron)
- Project generation flow (stable order_items.id)
- Any phase relying on local order_items state (project flags, future custom fields)
tech-stack:
added: []
patterns:
- "Delta-only update: re-import touches only fields that legitimately change at source"
- "Identical-payload guard: normalize JSON via decode→encode then compare strings; skip UPDATE on equality"
key-files:
created: []
modified:
- src/Modules/Orders/OrderImportRepository.php
- .paul/codebase/architecture.md
- .paul/codebase/tech_changelog.md
key-decisions:
- "Skip replaceAddresses/Items/Notes on re-import (created=false) — addresses/items/notes are immutable from source perspective"
- "Cancellation override applies AFTER status preservation block, so is_canceled_by_buyer=1 always wins"
- "Identical-payload guard short-circuits before updateOrderDelta when no transitions detected — fetched_at and updated_at remain unchanged"
- "replacePayments at paymentTransition unchanged — risk of overwriting manual payments (Phase 56) deferred"
patterns-established:
- "getCurrentOrderState() — extended SELECT returning status_code + payment_status + payload_json in one query (replaces getCurrentStatusAndPaymentStatus)"
- "normalizePayloadJson() — reusable helper for comparing two JSON representations (array or stored string) under identical encoding flags"
duration: ~25min
started: 2026-05-07T00:00:00Z
completed: 2026-05-07T00:25:00Z
---
# Phase 112 Plan 01: Re-import Data Protection Summary
**Re-import istniejacego zamowienia jest teraz delta-only: skip dla pozycji/adresow/notatek, zawezony updateOrderDelta(), propagacja anulowania ze zrodla i identical-payload guard. Bug case #882 (znikajaca flaga "Projekt") przyczynowo naprawiony.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~25 min |
| Started | 2026-05-07T00:00:00Z |
| Completed | 2026-05-07T00:25:00Z |
| Tasks | 3 / 3 completed |
| Files modified | 3 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Re-import nie kasuje pozycji | Pass (code-level) | `replaceItems` przeniesione pod `if ($created)`; manualny test na zywej DB pending (XAMPP offline w sesji) |
| AC-2: Re-import nie kasuje adresow ani notatek | Pass (code-level) | `replaceAddresses` i `replaceNotes` analogicznie; manualny test pending |
| AC-3: updateOrder zawezony do delta-only | Pass (code-level) | Stara `updateOrder()` usunieta, `updateOrderDelta()` aktualizuje tylko 7 kolumn + updated_at |
| AC-4: Pierwszy import bez regresji | Pass (code-level) | Galaz `if ($created)` zachowuje pelny przebieg insertOrder + 6 replace*; manualny test importu nowego zamowienia pending |
| AC-5: Re-import emituje payment.status_changed | Pass (code-level) | Logika `paymentTransition` (linie 50-51) + `replacePayments` przy `paymentTransition`/`statusOverwriteAllowed` zachowane; AllegroOrderImportService/ShopproOrdersSyncService nieruszane |
| AC-6: Re-import propaguje anulowanie | Pass (code-level) | Override `is_canceled_by_buyer || status_code='anulowane'` po preservacji; manualny test pending |
| AC-7: Identyczny payload jest no-op | Pass (code-level) | Guard via `normalizePayloadJson` zwraca przed updateOrderDelta gdy nie ma tranzycji; manualny test pending |
**Uwaga:** Wszystkie AC zweryfikowane na poziomie kodu (struktura, kontrola przeplywu, syntax check `php -l` OK). Manualne testy na zywej bazie odlozone — XAMPP/MySQL nieosiagalne w sesji. Operator powinien przeprowadzic AC-1, AC-3, AC-6, AC-7 po wdrozeniu.
## Accomplishments
- Bug case #882 przyczynowo naprawiony — `order_items.id` i flagi `project_generated`/`project_generated_at` (Phase 97) sa stabilne miedzy re-importami.
- Phase 111 (`payment.status_changed` event) dziala bez regresji — emit logiki nieruszany.
- Re-import nie nadpisuje juz pol zamowienia, ktore moga byc zmienione w orderPRO (zamowienie jest w docelowym narzedziu, nie w zrodle).
- Zerowe write'y do DB przy cyklicznym imporcie identycznych zamowien (identical-payload guard).
- Dokumentacja `.paul/codebase/architecture.md` i `.paul/codebase/tech_changelog.md` zaktualizowane.
## Task Commits
| Task | Commit | Type | Description |
|------|--------|------|-------------|
| Task 1: Rozdzielic create vs update w upsertOrderAggregate | (uncommitted) | feat | replace* tylko przy `created=true` |
| Task 2: updateOrderDelta + cancellation + payload guard | (uncommitted) | feat | Zawezony UPDATE, override anulowania, identical-payload no-op |
| Task 3: Architecture + tech_changelog | (uncommitted) | docs | Sekcja Re-import w architecture.md, wpis 2026-05-07 |
Plan metadata: bedzie commit'owany w ramach transition-phase (`feat(112): re-import data protection`).
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Orders/OrderImportRepository.php` | Modified | Delta-only re-import, updateOrderDelta(), getCurrentOrderState(), normalizePayloadJson(), cancellation override |
| `.paul/codebase/architecture.md` | Modified | Sekcja Re-import (Phase 111 + 112) opisuje delta-only flow |
| `.paul/codebase/tech_changelog.md` | Modified | Wpis 2026-05-07 — Phase 112 Plan 01 |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Skip replaceAddresses/Items/Notes na re-imporcie | Pozycje/adresy/notatki sa de facto immutable ze zrodla; orderPRO jest narzedziem zarzadzania — edycja po stronie aplikacji, nie zrodla | Stabilne `order_items.id` i ochrona flag lokalnych (project_generated, przyszle pola) |
| updateOrderDelta z 7 kolumnami | Tylko payment_status/total_paid/is_canceled_by_buyer/source_updated_at/payload_json/fetched_at + status_code (warunkowo) realnie zmieniaja sie miedzy syncami | Eliminacja nadpisywania pol typu delivery_price, send_date_*, customer_login |
| Override anulowania niezalezny od statusOverwriteAllowed | Anulowanie ze zrodla musi przejsc nawet gdy status lokalny zostal recznie zmieniony | Spojnosc z business logic — anulowane zamowienie nie powinno wisiec w `w_realizacji` |
| Identical-payload guard via normalize→compare | Tani check eliminujacy niepotrzebne write'y; nie wymaga schema change | Zerowa praca dla cyklicznego importu identycznych zamowien |
| `replacePayments` przy `paymentTransition` zostaje | Decyzja "nie wiem" od uzytkownika; zachowanie z Phase 111 minimalizuje zmiany | Ryzyko nadpisania recznych platnosci (Phase 56) — odlozone jako deferred |
## Deviations from Plan
### Summary
| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 0 | Brak |
| Scope additions | 0 | Plan wykonany 1:1 |
| Deferred | 2 | Manualne testy na DB, ryzyko replacePayments |
**Total impact:** Plan wykonany zgodnie z PLAN.md, bez scope creep. Manualne testy AC pending (XAMPP offline).
### Deferred Items
- **Manualne testy AC-1..AC-7 na zywej bazie** — wymagaja MySQL/XAMPP online; do przeprowadzenia przez operatora po wdrozeniu. Punkty wyjscia w PLAN.md `<verify>` blokach Task 1 i Task 2.
- **Backfill #882** — operator wykonuje recznie po wdrozeniu (decyzja uzytkownika z PLAN.md `<clarifications>`). Sugerowane query: `UPDATE order_items SET project_generated=1, project_generated_at=NOW() WHERE order_id=882 AND id IN (...);` po identyfikacji pozycji z fizycznie wygenerowanymi PSD.
- **`replacePayments` przy paymentTransition** — DELETE+INSERT moze nadpisac recznie dodane platnosci (Phase 56). Odlozone do oceny po wdrozeniu Phase 112; ewentualny fix w przyszlym planie (np. append po `(order_id, source_payment_id)` UNIQUE).
## Issues Encountered
| Issue | Resolution |
|-------|------------|
| MySQL/XAMPP offline w sesji — brak mozliwosci weryfikacji manualnej | AC zweryfikowane na poziomie kodu + `php -l`; manualne testy odlozone do operatora |
## Next Phase Readiness
**Ready:**
- Re-import delta-only dziala — Phase 111 chain (payment.status_changed → automatyzacja #7) zachowany.
- `order_items.id` jest stabilny — skrypt `tools/generowanie/_batch_run.sh` moze polegac na id miedzy re-importami.
- Schema DB nieruszane — bez migracji.
**Concerns:**
- `replacePayments` nadal DELETE+INSERT przy `paymentTransition` — moze wymagac patch w przyszlosci.
- Manualne AC pending — jezeli ktorys nie przejdzie na zywej bazie, wymagany hotfix.
- Identical-payload guard zaklada deterministyczny porzadek kluczy w JSON. Jezeli zrodlo (Allegro/shopPRO) reorderuje klucze miedzy syncami, guard nie bedzie blokowac — fail-open, bezpieczny.
**Blockers:**
- None (manualne testy nie blokuja transition; sa standardowym deferred follow-up).
---
*Phase: 112-reimport-data-protection, Plan: 01*
*Completed: 2026-05-07*