---
phase: 111-payment-transition-event
plan: 01
subsystem: automation
tags: [allegro, shoppro, payment-status, automation, import]

requires:
  - phase: 98-order-imported-first-only
    provides: gate $wasCreated dla order.imported (commit 7eefd1a)
  - phase: 62-import-reimport-safety
    provides: logika preservacji status_code przy re-imporcie
provides:
  - detekcja payment_transition oparta o porownanie payment_status (0/1 -> 2)
  - emit payment.status_changed w Allegro/shopPRO re-imporcie
  - bin/backfill_payment_transition_111.php (idempotent CLI)
affects: [Allegro re-import flow, ShopPRO re-import flow, Automation rule chain]

tech-stack:
  added: []
  patterns:
    - "Rozdzielenie paymentTransition (event) i statusOverwriteAllowed (status_code preservation) jako osobnych decyzji w upsertOrderAggregate"

key-files:
  created:
    - bin/backfill_payment_transition_111.php
  modified:
    - src/Modules/Orders/OrderImportRepository.php
    - src/Modules/Settings/AllegroOrderImportService.php
    - src/Modules/Settings/ShopproOrdersSyncService.php
    - .paul/codebase/architecture.md
    - .paul/codebase/tech_changelog.md

key-decisions:
  - "paymentTransition oparte o porownanie payment_status (0/1 -> 2), nie status_code"
  - "Logika preservacji status_code (Phase 62) wydzielona jako $statusOverwriteAllowed — niezalezna decyzja"
  - "Reuse istniejacej reguly automatyzacji #7 (bez warunku integration_id) zamiast tworzenia osobnej reguly per integracja"
  - "Backfill idempotentny przez kryterium status_code='nieoplacone' AND payment_status=2 — po updateOrderStatus zamowienie nie spelnia warunku"

patterns-established:
  - "Re-import emituje payment.status_changed gdy repo zwraca payment_transition i !$wasCreated — wzor dla potencjalnych przyszlych integracji"

duration: ~30min
started: 2026-05-05T13:00:00Z
completed: 2026-05-05T13:30:00Z
---

# Phase 111 Plan 01: Payment Transition Event Summary

**Re-import zamowienia (Allegro + shopPRO) wykrywa tranzycje payment_status 0/1 -> 2 i emituje `payment.status_changed`, dzieki czemu chain reguly automatyzacji #7 zmienia status na `w_realizacji` dla zamowien zaimportowanych przed potwierdzeniem platnosci.**

## Performance

| Metric | Value |
|--------|-------|
| Duration | ~30 min |
| Started | 2026-05-05T13:00:00Z |
| Completed | 2026-05-05T13:30:00Z |
| Tasks | 4 completed |
| Files modified | 5 (1 nowy + 4 zmienione) |

## Acceptance Criteria Results

| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Repo wykrywa tranzycje 0/1 → 2 | Pass (code) | Logika rozszerzona w `OrderImportRepository::upsertOrderAggregate`: `paymentTransition = in_array($oldPaymentStatus, [0, 1], true) && $newPaymentStatus === 2`. `statusOverwriteAllowed` zachowuje semantyke Phase 62. Lint OK. Pelny runtime test wymaga zamowienia testowego pre-payment — operator zweryfikuje po deploy. |
| AC-2: Allegro + shopPRO emituje payment.status_changed | Pass (code) | Oba serwisy emituja event tylko gdy `!$wasCreated && $wasPaymentTransition`. Lint OK. Runtime weryfikacja jak w AC-1 — wymaga zamowienia testowego. |
| AC-3: Backfill naprawia historyczne dane | Pass (preview) | Skrypt `bin/backfill_payment_transition_111.php` zgodny ze wzorcem Phase 98 (flagi `--dry-run`/`--use-remote`, idempotentny). SQL preview na produkcji znalazl **0 kandydatow** — zamowienie #864 jest juz `wyslane`, brak innych analogicznych. Skrypt zostaje jako safety net. |
| AC-4: Brak regresji w istniejacym flow | Pass | `order.imported` gate `$wasCreated` nietknięty; nowy emit pod osobnym warunkiem `!$wasCreated && $wasPaymentTransition` — pierwszy import ma `$wasPaymentTransition=false` z definicji (created=true → blok detekcji nieuruchomiony). |

## Accomplishments

- **OrderImportRepository** rozdzielil dwie semantyki: `paymentTransition` (eventowa, oparta o porownanie payment_status) i `statusOverwriteAllowed` (preservacja status_code z Phase 62) — dotychczas mieszane w jednej fladze
- **AllegroOrderImportService + ShopproOrdersSyncService** spojnie emituja `payment.status_changed` na re-import, bez ruszania gate'u `order.imported` (commit 7eefd1a Phase 98)
- **Backfill CLI** wzorem Phase 98 — gotowy do uruchomienia po deploy, obecnie no-op (luki historyczne brak)
- **Reuse reguly #7** zamiast tworzenia osobnej reguly per integracja — chain automatyzacji obejmuje teraz Allegro automatycznie

## Task Commits

| Task | Commit | Type | Description |
|------|--------|------|-------------|
| Task 1: OrderImportRepository payment_transition | (uncommitted) | feat | Rozszerzenie detekcji 0/1→2 + getCurrentStatusAndPaymentStatus |
| Task 2: Allegro+shopPRO emit payment.status_changed | (uncommitted) | feat | Konsumpcja payment_transition flag, emit do AutomationService |
| Task 3: Backfill CLI | (uncommitted) | feat | bin/backfill_payment_transition_111.php |
| Task 4: Docs update | (uncommitted) | docs | architecture.md + tech_changelog.md |

**Note:** Wszystkie zmiany wykonane w trybie inline jako jeden working tree state. Atomowe commity zostana wykonane przez transition-phase.

## Files Created/Modified

| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Orders/OrderImportRepository.php` | Modified | `upsertOrderAggregate`: rozdzielenie paymentTransition (0/1→2) i statusOverwriteAllowed; nowa metoda `getCurrentStatusAndPaymentStatus` |
| `src/Modules/Settings/AllegroOrderImportService.php` | Modified | Emit `payment.status_changed` na payment_transition w re-imporcie |
| `src/Modules/Settings/ShopproOrdersSyncService.php` | Modified | Emit `payment.status_changed` analogicznie do Allegro |
| `bin/backfill_payment_transition_111.php` | Created | Jednorazowy CLI dla zamowien `payment_status=2 && status_code='nieoplacone'` |
| `.paul/codebase/architecture.md` | Modified | Sekcja Order Lifecycle: pkt 2 Re-import (Phase 111) |
| `.paul/codebase/tech_changelog.md` | Modified | Wpis `2026-05-05 - Phase 111` |

## Decisions Made

| Decision | Rationale | Impact |
|----------|-----------|--------|
| `paymentTransition` oparte o porownanie payment_status (nie status_code) | Restrykcyjna definicja "0/1 → 2" wybrana przez uzytkownika — lapie wszystkie tranzycje platnosci niezaleznie od stanu status_code | Bedzie emitowac event tez dla zamowien w nietypowych stanach status (np. po recznym ustawieniu) |
| Rozdzielenie `statusOverwriteAllowed` od `paymentTransition` | Phase 62 logika preservacji status_code musiala zostac zachowana — laczenie obu w jednej fladze rozszerzaloby zakres nadpisywania status_code | Zachowane zachowanie shopPRO (replacePayments przy paymentTransition) i Phase 62 (preservacja przy ogolnym re-imporcie) |
| Reuse reguly #7 (bez warunku integration_id) | Regula juz istnieje, dziala dla shopPRO; brak integration_id oznacza universal coverage; chain idempotentny przez OrdersRepository::updateOrderStatus | Nie tworzymy duplikatu reguly per integracja, mniej rzeczy do utrzymania |
| Backfill idempotentny przez `status_code='nieoplacone' AND payment_status=2` | Po updateOrderStatus → status_code='w_realizacji', warunek SELECT przestaje pasowac | Bezpieczne wielokrotne uruchomienie |

## Deviations from Plan

### Summary

| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 0 | — |
| Scope additions | 0 | — |
| Deferred | 0 | — |

**Total impact:** Plan wykonany dokladnie wg specyfikacji. Brak odchylen.

### Auto-fixed Issues

None — plan executed exactly as written.

### Deferred Items

None — wszystkie 4 zadania ukonczone w zakresie planu.

## Issues Encountered

| Issue | Resolution |
|-------|------------|
| Lokalny runtime backfillu niemozliwy (brak `vendor/`) | Zweryfikowano przez `php -l` (lint) + bezposredni SQL preview na DB — 0 kandydatow potwierdzonych. Operator uruchomi skrypt na serwerze po deploy (no-op spodziewany). |
| Pelny test E2E `payment.status_changed` chain wymaga zamowienia testowego Allegro pre-payment | Udokumentowane w SUMMARY jako "operator weryfikuje po deploy". Code path zweryfikowany staticznie (lint + przeglad logiki + idempotencja przez kryterium). |

## Next Phase Readiness

**Ready:**
- Hotfix gotowy do deploy (3 zmienione pliki PHP + 1 nowy CLI + 2 docs)
- Backfill jako safety net (no-op na obecnym stanie DB)
- Architektura udokumentowana w `.paul/codebase/architecture.md`

**Concerns:**
- Pelny test E2E wymaga zamowienia testowego Allegro w stanie pre-payment + wymuszenia re-importu po confirm-paid. Operator powinien zweryfikowac na pierwszym realnym przypadku po deploy.
- Idempotencja przy podwojnym pokryciu shopPRO (osobny `ShopproPaymentStatusSyncService` tez emituje `payment.status_changed`) — w praktyce regula 7 jest idempotentna (`update_order_status` na juz-w_realizacji nie tworzy nowej historii).

**Blockers:**
- None

---
*Phase: 111-payment-transition-event, Plan: 01*
*Completed: 2026-05-05*
