--- 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 `` blokach Task 1 i Task 2. - **Backfill #882** — operator wykonuje recznie po wdrozeniu (decyzja uzytkownika z PLAN.md ``). 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*