This commit is contained in:
2026-03-31 10:56:31 +02:00
parent af48e84449
commit 50507d70a5
13 changed files with 616 additions and 75 deletions

View File

@@ -0,0 +1,176 @@
---
phase: 62-import-reimport-safety
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/Modules/Settings/ShopproOrdersSyncService.php
- src/Modules/Orders/OrderImportRepository.php
autonomous: true
---
<objective>
## Goal
Naprawa dwóch problemów z re-importem zamówień:
1. Rozróżnienie "Import" vs "Aktualizacja" w activity log dla shopPRO (analogicznie do Allegro) + deduplikacja
2. Ochrona danych lokalnych (płatności, historia statusów, przesyłki) przed nadpisaniem przy re-imporcie — dla obu źródeł (shopPRO i Allegro)
## Purpose
Obecnie re-import zamówienia kasuje DELETE+INSERT dane, które mogły zostać dodane lokalnie w orderPRO (ręczna płatność, zmiana statusu, przesyłka). Dodatkowo shopPRO loguje identyczne wpisy "Import zamówienia" przy każdym re-imporcie zamiast rozróżniać import od aktualizacji.
## Output
- shopPRO activity log: "Import zamowienia z shopPRO" vs "Zaktualizowano zamowienie z shopPRO (re-import)" + deduplikacja jak Allegro
- `upsertOrderAggregate` przy UPDATE pomija replace płatności, historii statusów i przesyłek (chroni dane lokalne)
</objective>
<context>
## Source Files
@src/Modules/Settings/ShopproOrdersSyncService.php (linia 205-259: importOneOrder — brak rozróżnienia create/update w activity log)
@src/Modules/Settings/AllegroOrderImportService.php (linia 58-103: wzorcowa implementacja — rozróżnia import/aktualizacja + shouldSkipDuplicate)
@src/Modules/Orders/OrderImportRepository.php (linia 25-64: upsertOrderAggregate — zawsze DELETE+INSERT na wszystkich relacjach)
@src/Modules/Orders/OrdersRepository.php (linia 765-813: shouldSkipDuplicateImportActivity — istniejąca logika deduplikacji)
</context>
<acceptance_criteria>
## AC-1: shopPRO activity log rozróżnia import od aktualizacji
```gherkin
Given zamówienie z shopPRO już istnieje w orderPRO
When cron re-importuje to zamówienie (source_updated_at się zmieniło)
Then w activity log pojawia się "Zaktualizowano zamowienie z shopPRO (re-import)" zamiast "Import zamowienia z shopPRO"
```
## AC-2: shopPRO activity log deduplikuje identyczne wpisy
```gherkin
Given zamówienie z shopPRO zostało właśnie zaimportowane/zaktualizowane
When cron próbuje re-importować z tym samym source_updated_at
Then nowy wpis w activity log NIE jest tworzony (shouldSkipDuplicateImportActivity)
```
## AC-3: Re-import nie kasuje lokalnych płatności
```gherkin
Given zamówienie ma płatność dodaną ręcznie w orderPRO
When cron re-importuje to zamówienie z shopPRO lub Allegro
Then ręcznie dodana płatność nie jest usunięta
And płatności z importu są nadal poprawnie zapisywane przy pierwszym imporcie
```
## AC-4: Re-import nie kasuje lokalnej historii statusów
```gherkin
Given zamówienie ma zmianę statusu wykonaną w orderPRO
When cron re-importuje to zamówienie
Then lokalna historia statusów nie jest usunięta
And historia statusów z importu jest poprawnie zapisywana przy pierwszym imporcie
```
## AC-5: Re-import nie kasuje lokalnych przesyłek importowych
```gherkin
Given zamówienie ma przesyłki zaimportowane lub utworzone w orderPRO
When cron re-importuje to zamówienie
Then przesyłki z order_shipments nie są usunięte
And przesyłki z importu są poprawnie zapisywane przy pierwszym imporcie
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Activity log shopPRO — rozróżnienie import/aktualizacja + deduplikacja</name>
<files>src/Modules/Settings/ShopproOrdersSyncService.php</files>
<action>
W metodzie `importOneOrder()` (linia 239-246) zmienić blok activity log analogicznie do AllegroOrderImportService (linia 71-94):
1. Po linii 234 (po sprawdzeniu `$save['created']`) dodać logikę:
- Ustalić `$wasCreated = !empty($save['created'])`
- Ustalić `$summary`:
- Jeśli `$wasCreated`: `'Import zamowienia z shopPRO'`
- Jeśli nie: `'Zaktualizowano zamowienie z shopPRO (re-import)'`
2. Rozszerzyć `$details` o pola potrzebne do deduplikacji:
- `'source_updated_at' => $sourceUpdatedAt`
- `'created' => $wasCreated`
- `'trigger' => 'orders_sync'`
- `'trigger_label' => 'Synchronizacja zamowien'`
3. Owinąć `recordActivity()` w warunek `shouldSkipDuplicateImportActivity()`:
```php
if (!$this->orders->shouldSkipDuplicateImportActivity((int) ($save['order_id'] ?? 0), $details)) {
$this->orders->recordActivity(...);
}
```
Wzorzec: AllegroOrderImportService linia 71-94.
</action>
<verify>Przegląd kodu: shopPRO importOneOrder używa shouldSkipDuplicateImportActivity i rozróżnia summary</verify>
<done>AC-1 i AC-2 satisfied</done>
</task>
<task type="auto">
<name>Task 2: upsertOrderAggregate — pominięcie replace płatności/historii/przesyłek przy UPDATE</name>
<files>src/Modules/Orders/OrderImportRepository.php</files>
<action>
W metodzie `upsertOrderAggregate()` (linia 25-64):
1. Przenieść wywołania `replacePayments`, `replaceShipments` i `replaceStatusHistory` do bloku warunkowego `if ($created)`:
```php
$this->replaceAddresses($orderId, $addresses);
$this->replaceItems($orderId, $items);
$this->replaceNotes($orderId, $notes);
if ($created) {
$this->replacePayments($orderId, $payments);
$this->replaceShipments($orderId, $shipments);
$this->replaceStatusHistory($orderId, $statusHistory);
}
```
2. Logika:
- Adresy i pozycje (items) — nadpisywane ZAWSZE (dane pochodzą ze źródła, nie są edytowane lokalnie)
- Notatki — nadpisywane ZAWSZE (pochodzą ze źródła)
- Płatności — tylko przy INSERT (ręczne płatności dodane w orderPRO nie zostaną skasowane)
- Przesyłki (order_shipments) — tylko przy INSERT (lokalne przesyłki nie zostaną skasowane)
- Historia statusów — tylko przy INSERT (lokalne zmiany statusów nie zostaną skasowane)
Ta zmiana dotyczy OBIE źródeł (shopPRO i Allegro) bo obie korzystają z tego samego repozytorium.
</action>
<verify>Przegląd kodu: replacePayments, replaceShipments, replaceStatusHistory wywoływane tylko gdy $created === true</verify>
<done>AC-3, AC-4 i AC-5 satisfied</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- AllegroOrderImportService.php — Allegro już ma poprawną logikę activity log, nie modyfikować
- OrdersRepository.php — shouldSkipDuplicateImportActivity() działa poprawnie, reuse bez zmian
- Logika kursora (ShopproOrderMapper, ShopproOrderSyncStateRepository) — nie modyfikować
- Tabele DB — brak migracji
## SCOPE LIMITS
- Brak kolumny `origin` w tabelach (to byłby etap 2, poza zakresem)
- Nie zmieniamy logiki replace dla adresów, pozycji ani notatek (te dane pochodzą wyłącznie ze źródła)
- Nie dodajemy nowego merge/diff — po prostu pomijamy replace przy update
</boundaries>
<verification>
Before declaring plan complete:
- [ ] shopPRO importOneOrder rozróżnia "Import" vs "Zaktualizowano (re-import)" w summary
- [ ] shopPRO importOneOrder używa shouldSkipDuplicateImportActivity
- [ ] upsertOrderAggregate: replacePayments/replaceShipments/replaceStatusHistory wywołane tylko przy $created
- [ ] upsertOrderAggregate: replaceAddresses/replaceItems/replaceNotes wywołane zawsze (bez zmian)
- [ ] Brak zmian w AllegroOrderImportService
</verification>
<success_criteria>
- Activity log shopPRO rozróżnia import od aktualizacji
- Duplikaty activity log eliminowane przez shouldSkipDuplicateImportActivity
- Re-import nie kasuje lokalnych płatności, przesyłek ani historii statusów
- Pierwsze importowanie zapisuje wszystkie dane normalnie
- Brak regresji w imporcie Allegro
</success_criteria>
<output>
After completion, create `.paul/phases/62-import-reimport-safety/62-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,106 @@
---
phase: 62-import-reimport-safety
plan: 01
subsystem: api
tags: [import, activity-log, deduplication, data-protection]
requires:
- phase: 56-order-payments
provides: ręczne płatności w orderPRO które mogą być nadpisane
provides:
- rozróżnienie import vs aktualizacja w activity log shopPRO
- deduplikacja wpisów activity log shopPRO (shouldSkipDuplicateImportActivity)
- ochrona lokalnych płatności, przesyłek i historii statusów przed nadpisaniem przy re-imporcie
affects: []
tech-stack:
added: []
patterns:
- "replacePayments/Shipments/StatusHistory tylko przy INSERT (nie UPDATE) w upsertOrderAggregate"
key-files:
created: []
modified:
- src/Modules/Settings/ShopproOrdersSyncService.php
- src/Modules/Orders/OrderImportRepository.php
key-decisions:
- "Adresy, pozycje i notatki nadpisywane zawsze (dane ze źródła); płatności, przesyłki i historia statusów tylko przy pierwszym imporcie"
- "Reuse shouldSkipDuplicateImportActivity z Allegro zamiast nowej logiki"
patterns-established:
- "Przy re-imporcie chronić dane które mogą pochodzić z lokalnych akcji użytkownika"
duration: 3min
started: 2026-03-31
completed: 2026-03-31
---
# Phase 62 Plan 01: Import Re-import Safety Summary
**Rozróżnienie import/aktualizacja w activity log shopPRO + ochrona lokalnych danych (płatności, przesyłki, historia statusów) przed nadpisaniem przy re-imporcie dla obu źródeł.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~3min |
| Started | 2026-03-31 |
| Completed | 2026-03-31 |
| Tasks | 2 completed |
| Files modified | 2 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: shopPRO rozróżnia import od aktualizacji | Pass | "Import zamowienia z shopPRO" vs "Zaktualizowano zamowienie z shopPRO (re-import)" |
| AC-2: shopPRO deduplikuje identyczne wpisy | Pass | shouldSkipDuplicateImportActivity reuse z Allegro |
| AC-3: Re-import nie kasuje lokalnych płatności | Pass | replacePayments tylko przy $created |
| AC-4: Re-import nie kasuje lokalnej historii statusów | Pass | replaceStatusHistory tylko przy $created |
| AC-5: Re-import nie kasuje lokalnych przesyłek | Pass | replaceShipments tylko przy $created |
## Accomplishments
- shopPRO activity log rozróżnia pierwszy import od re-importu (analogicznie do Allegro)
- Deduplikacja wpisów activity log eliminuje powtórzenia przy tym samym source_updated_at
- Re-import (UPDATE) nie kasuje już płatności, przesyłek ani historii statusów — chroni dane dodane lokalnie w orderPRO
- Zmiana w OrderImportRepository dotyczy obu źródeł (shopPRO i Allegro)
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Settings/ShopproOrdersSyncService.php` | Modified | Rozróżnienie summary import/aktualizacja, dodanie pól deduplikacji, warunek shouldSkipDuplicate |
| `src/Modules/Orders/OrderImportRepository.php` | Modified | replacePayments/Shipments/StatusHistory przeniesione do bloku if ($created) |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Adresy/pozycje/notatki nadpisywane zawsze | Dane pochodzą wyłącznie ze źródła, nie są edytowane lokalnie | Źródło pozostaje autorytatywne dla tych danych |
| Płatności/przesyłki/historia tylko przy INSERT | Mogą być dodawane lokalnie w orderPRO (ręczna płatność, zmiana statusu) | Lokalne dane chronione przed kaskadowym DELETE |
## Deviations from Plan
None - plan executed exactly as written
## Issues Encountered
None
## Next Phase Readiness
**Ready:**
- Import bezpieczny dla danych lokalnych
- Activity log spójny między Allegro i shopPRO
**Concerns:**
- Brak kolumny `origin` (source/local) na tabelach relacyjnych — przy przyszłej potrzebie merge/diff danych z obu źródeł trzeba będzie dodać
**Blockers:**
- None
---
*Phase: 62-import-reimport-safety, Plan: 01*
*Completed: 2026-03-31*