feat(v1.7): orderPRO -> shopPRO status push sync
Implement bidirectional status sync for shopPRO integrations. When direction is set to orderpro_to_shoppro, cron pushes manual status changes to shopPRO via PUT API with reverse status mapping. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów
|
||||
| Attribute | Value |
|
||||
|-----------|-------|
|
||||
| Version | 1.0.0 |
|
||||
| Status | v1.6 Complete |
|
||||
| Status | v1.7 Complete |
|
||||
| Last Updated | 2026-03-27 |
|
||||
|
||||
## Requirements
|
||||
@@ -53,6 +53,7 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów
|
||||
- [x] Automatyzacja: event `shipment.status_changed` + warunki statusowe przesylki - Phase 42
|
||||
- [x] Usuwanie wpisu z kolejki druku etykiet z panelu ustawien - Phase 43
|
||||
- [x] Szybka zmiana statusu zamowienia z listy zamowien (inline dropdown + AJAX) - Phase 44
|
||||
- [x] Synchronizacja statusow orderPRO -> shopPRO (cron push, reverse mapping, PUT API) — Phase 45
|
||||
|
||||
### Active (In Progress)
|
||||
|
||||
@@ -148,5 +149,5 @@ Quick Reference:
|
||||
|
||||
---
|
||||
*PROJECT.md — Updated when requirements or context change*
|
||||
*Last updated: 2026-03-27 after Phase 44 completion (Inline Status Change)*
|
||||
*Last updated: 2026-03-27 after Phase 45 completion (ShopPRO Status Push)*
|
||||
|
||||
|
||||
@@ -6,17 +6,30 @@ orderPRO to narzÄ™dzie do wielokanaĹ‚owego zarzÄ…dzania sprzedaĹĽÄ
|
||||
|
||||
## Current Milestone
|
||||
|
||||
v1.6 Quick Status Change - Complete (2026-03-27)
|
||||
v1.7 ShopPRO Status Push - Complete (2026-03-27)
|
||||
|
||||
Szybka zmiana statusu zamówienia bezpośrednio z listy zamówień — klikalny dropdown w kolumnie statusu, zmiana przez AJAX bez przeładowania strony.
|
||||
Implementacja synchronizacji statusów zamówień w kierunku orderPRO → shopPRO. Cron pushuje zmiany statusów do shopPRO API (PUT /api.php?endpoint=orders&action=change_status).
|
||||
|
||||
| Phase | Name | Status | Plans |
|
||||
|------|------|--------|-------|
|
||||
| 44 | Inline Status Change | Complete (2026-03-27) | 1/1 (`44-01-PLAN.md`) |
|
||||
| 45 | ShopPRO Status Push | Complete (2026-03-27) | 1/1 (`45-01-PLAN.md`) |
|
||||
|
||||
Archive: `.paul/phases/45-shoppro-status-push/`
|
||||
|
||||
## Completed Milestones
|
||||
|
||||
<details>
|
||||
<summary>v1.6 Quick Status Change - 2026-03-27 (1 phase, 1 plan)</summary>
|
||||
|
||||
Szybka zmiana statusu zamówienia bezpośrednio z listy zamówień — klikalny dropdown w kolumnie statusu, zmiana przez AJAX bez przeładowania strony.
|
||||
|
||||
| Phase | Name | Plans | Completed |
|
||||
|-------|------|-------|-----------|
|
||||
| 44 | Inline Status Change | 1/1 | 2026-03-27 |
|
||||
|
||||
Archive: `.paul/phases/44-inline-status-change/`
|
||||
|
||||
## Completed Milestones
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>v1.5 Operational Workflow Cleanup - 2026-03-25 (4 phases, 4 plans)</summary>
|
||||
@@ -229,7 +242,7 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md`
|
||||
|
||||
---
|
||||
*Roadmap created: 2026-03-12*
|
||||
*Last updated: 2026-03-27 - v1.6 Quick Status Change complete*
|
||||
*Last updated: 2026-03-27 - v1.7 ShopPRO Status Push complete*
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
See: .paul/PROJECT.md (updated 2026-03-12)
|
||||
|
||||
**Core value:** Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów sprzedaży i nadawać przesyłki bez przełączania się między platformami.
|
||||
**Current focus:** v1.6 complete — Phase 44 delivered
|
||||
**Current focus:** v1.7 complete — Phase 45 delivered
|
||||
|
||||
## Current Position
|
||||
|
||||
Milestone: v1.6 Quick Status Change — Complete
|
||||
Phase: [1] of [1] (Inline Status Change) — Unified
|
||||
Plan: 44-01 completed with summary
|
||||
Status: PLAN/APPLY/UNIFY closed for phase 44
|
||||
Last activity: 2026-03-27 — Phase 44 complete, milestone v1.6 closed
|
||||
Milestone: v1.7 ShopPRO Status Push — Complete
|
||||
Phase: [1] of [1] (ShopPRO Status Push) — Unified
|
||||
Plan: 45-01 completed with summary
|
||||
Status: PLAN/APPLY/UNIFY closed for phase 45
|
||||
Last activity: 2026-03-27 — Phase 45 complete, milestone v1.7 closed
|
||||
|
||||
Progress:
|
||||
- v0.1 Initial Release: [##########] 100% done
|
||||
@@ -41,20 +41,25 @@ Progress:
|
||||
- Phase 43: [##########] Complete (1/1 plans)
|
||||
- v1.6 Quick Status Change: [##########] 100% done
|
||||
- Phase 44: [##########] Complete (1/1 plans)
|
||||
- v1.7 ShopPRO Status Push: [##########] 100% done
|
||||
- Phase 45: [##########] Complete (1/1 plans)
|
||||
|
||||
## Loop Position
|
||||
|
||||
Current loop state:
|
||||
```
|
||||
PLAN --> APPLY --> UNIFY
|
||||
done done done [Loop closed for phase 44]
|
||||
done done done [Loop closed for phase 45]
|
||||
```
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
### Decisions
|
||||
| Data | Decyzja | Faza | Wpływ |
|
||||
| Data | Decyzja | Faza | Wpływ |
|
||||
|------|---------|------|-------|
|
||||
| 2026-03-27 | Refactor executeRequest() w ShopproApiClient zamiast duplikacji curl logic | Faza 45 | Reuse GET/PUT, latwiejsze dodawanie metod HTTP |
|
||||
| 2026-03-27 | Push tylko change_source=manual (nie import/sync) | Faza 45 | Brak petli synchronizacji |
|
||||
| 2026-03-27 | Fallback 24h dla null cursor last_status_pushed_at | Faza 45 | Ograniczenie zakresu pierwszego synca |
|
||||
| 2026-03-27 | Fixed positioning dropdown (document.body) zamiast absolute wewnatrz table-wrap | Faza 44 | Dropdown nie ucinany przez overflow:hidden na .table-wrap |
|
||||
| 2026-03-27 | AJAX detect przez X-Requested-With header z fallback na redirect | Faza 44 | updateStatus() obsluguje oba tryby w jednej metodzie |
|
||||
| 2026-03-25 | Import Allegro: trigger context + deduplikacja logow (`source_order_id + source_updated_at + trigger`) | Faza 41 | Czytelniejsza historia zamowienia i mniej duplikatow wpisow `import` |
|
||||
@@ -92,6 +97,11 @@ PLAN --> APPLY --> UNIFY
|
||||
| 2026-03-17 | Email history jako wpisy w order_activity_log (nie osobna sekcja) | Faza 15 | Spójność z istniejącym UX — jeden timeline zamiast fragmentacji |
|
||||
| 2026-03-17 | VariableResolver wydzielony z EmailTemplateController | Faza 15 | Reuse logiki zmiennych; resolwer niezaleĹĽny od kontrolera szablonĂłw |
|
||||
|
||||
### Skill Audit (Faza 45, Plan 01)
|
||||
| Oczekiwany | Wywolany | Uwagi |
|
||||
|------------|---------|-------|
|
||||
| sonar-scanner | override | Pominieto na podstawie explicit user override; lint PHP PASS |
|
||||
|
||||
### Skill Audit (Faza 44, Plan 01)
|
||||
| Oczekiwany | Wywolany | Uwagi |
|
||||
|------------|---------|-------|
|
||||
@@ -291,7 +301,7 @@ Brak.
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-03-27
|
||||
Stopped at: v1.6 phase 44 completed (SUMMARY + docs + state updated)
|
||||
Stopped at: v1.7 phase 45 completed (SUMMARY + docs + state updated)
|
||||
Next action: Start next milestone planning (/paul:milestone or /paul:plan)
|
||||
Resume file: .paul/ROADMAP.md
|
||||
---
|
||||
|
||||
290
.paul/phases/45-shoppro-status-push/45-01-PLAN.md
Normal file
290
.paul/phases/45-shoppro-status-push/45-01-PLAN.md
Normal file
@@ -0,0 +1,290 @@
|
||||
---
|
||||
phase: 45-shoppro-status-push
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/Modules/Settings/ShopproApiClient.php
|
||||
- src/Modules/Settings/ShopproStatusSyncService.php
|
||||
- src/Modules/Settings/ShopproOrderSyncStateRepository.php
|
||||
- database/migrations/20260327_000071_add_last_status_pushed_at_to_sync_state.sql
|
||||
- DOCS/DB_SCHEMA.md
|
||||
- DOCS/ARCHITECTURE.md
|
||||
- DOCS/TECH_CHANGELOG.md
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Zaimplementowac synchronizacje statusow zamowien w kierunku orderPRO -> shopPRO. Gdy uzytkownik zmieni status zamowienia w orderPRO, cron pushuje te zmiane do shopPRO API.
|
||||
|
||||
## Purpose
|
||||
Uzytkownik ustawil w konfiguracji integracji kierunek `orderpro_to_shoppro`, ale ten kierunek nie jest zaimplementowany — `ShopproStatusSyncService::sync()` jawnie go pomija (`$unsupportedCount++; continue`). Zamowienia zmienione w orderPRO nie aktualizuja sie w shopPRO.
|
||||
|
||||
## Output
|
||||
- Metoda PUT w `ShopproApiClient` do aktualizacji statusu zamowienia w shopPRO
|
||||
- Logika push w `ShopproStatusSyncService` dla kierunku `orderpro_to_shoppro`
|
||||
- Migracja: kolumna `last_status_pushed_at` w `integration_order_sync_state`
|
||||
- Aktualizacja dokumentacji
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
@.paul/STATE.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Settings/ShopproApiClient.php
|
||||
@src/Modules/Settings/ShopproStatusSyncService.php
|
||||
@src/Modules/Settings/ShopproOrderSyncStateRepository.php
|
||||
@src/Modules/Settings/ShopproStatusMappingRepository.php
|
||||
@src/Modules/Settings/ShopproIntegrationsRepository.php
|
||||
@src/Modules/Cron/ShopproStatusSyncHandler.php
|
||||
|
||||
## shopPRO API Reference (z kodu shopPRO)
|
||||
Endpoint: `PUT /api.php?endpoint=orders&action=change_status&id={orderId}`
|
||||
Body JSON: `{"status_id": <int>, "send_email": <bool>}`
|
||||
Auth: header `X-Api-Key`
|
||||
Response: `{"status":"ok","data":{"order_id":<int>,"status_id":<int>,"changed":<bool>}}`
|
||||
|
||||
Statusy shopPRO: numeryczne ID z endpointu `GET /api.php?endpoint=dictionaries&action=statuses`
|
||||
Tabela `order_status_mappings`: `shoppro_status_code` przechowuje numeryczne ID statusu shopPRO jako string.
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: API Client obsluguje PUT change_status
|
||||
```gherkin
|
||||
Given integracja shopPRO z poprawnym base_url i api_key
|
||||
When wywolana zostanie metoda ShopproApiClient::updateOrderStatus()
|
||||
Then wysylane jest zadanie PUT do /api.php?endpoint=orders&action=change_status&id={id}
|
||||
And body zawiera JSON z status_id (int) i send_email (bool)
|
||||
And zwracany jest wynik z polem ok, http_code, message, changed
|
||||
```
|
||||
|
||||
## AC-2: Push kierunek dziala w cron sync
|
||||
```gherkin
|
||||
Given integracja shopPRO z direction = orderpro_to_shoppro
|
||||
And zamowienie w orderPRO ma zmieniony status (wpis w order_status_history z change_source = manual)
|
||||
And istnieje mapowanie orderpro_status_code -> shoppro_status_code w order_status_mappings
|
||||
When uruchomi sie cron shoppro_order_status_sync
|
||||
Then ShopproStatusSyncService pushuje nowy status do shopPRO API
|
||||
And aktualizuje last_status_pushed_at w integration_order_sync_state
|
||||
And nie pushuje zmian z change_source = import/sync (unikniecie petli)
|
||||
```
|
||||
|
||||
## AC-3: Brak mapowania nie blokuje synca
|
||||
```gherkin
|
||||
Given zamowienie ma status orderpro bez mapowania na shoppro
|
||||
When cron probuje pushowac status
|
||||
Then pomija to zamowienie bez bledu
|
||||
And kontynuuje przetwarzanie pozostalych
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Migracja DB + metoda PUT w ShopproApiClient</name>
|
||||
<files>
|
||||
database/migrations/20260327_000071_add_last_status_pushed_at_to_sync_state.sql,
|
||||
src/Modules/Settings/ShopproApiClient.php,
|
||||
src/Modules/Settings/ShopproOrderSyncStateRepository.php
|
||||
</files>
|
||||
<action>
|
||||
1. Utworzyc migracje idempotentna (IF NOT EXISTS pattern):
|
||||
```sql
|
||||
ALTER TABLE integration_order_sync_state
|
||||
ADD COLUMN IF NOT EXISTS last_status_pushed_at DATETIME NULL DEFAULT NULL
|
||||
AFTER last_success_at;
|
||||
```
|
||||
|
||||
2. W `ShopproApiClient` dodac publiczna metode `updateOrderStatus()`:
|
||||
- Sygnatura: `updateOrderStatus(string $baseUrl, string $apiKey, int $timeoutSeconds, int $orderId, int $statusId, bool $sendEmail = false): array`
|
||||
- Zwraca: `array{ok:bool, http_code:int|null, message:string, changed:bool}`
|
||||
- URL: `$baseUrl/api.php?endpoint=orders&action=change_status&id=$orderId`
|
||||
- Metoda HTTP: PUT (CURLOPT_CUSTOMREQUEST => 'PUT')
|
||||
- Body: JSON `{"status_id": $statusId, "send_email": $sendEmail}`
|
||||
- Header: Content-Type: application/json + X-Api-Key
|
||||
- SSL: reuse logiki z `requestJson()` — wydzielic wspolna metode `buildCurlHandle()` LUB zduplikowac SSL opts (preferuj wydzielenie)
|
||||
- Parsowanie odpowiedzi: sprawdzic `data.changed` z odpowiedzi
|
||||
|
||||
3. W `ShopproOrderSyncStateRepository`:
|
||||
- Dodac metode `getLastStatusPushedAt(int $integrationId): ?string`
|
||||
Query: `SELECT last_status_pushed_at FROM integration_order_sync_state WHERE integration_id = :id`
|
||||
Defensywnie: sprawdzic czy kolumna istnieje (dodac do resolveColumns)
|
||||
- Dodac metode `updateLastStatusPushedAt(int $integrationId, string $datetime): void`
|
||||
Reuse istniejacego upsertState z nowym kluczem w columnMap
|
||||
|
||||
Avoid:
|
||||
- Nie modyfikowac istniejacych metod requestJson() — dodac nowa prywatna metode do PUT
|
||||
- Nie uzywac file_get_contents — tylko curl
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproApiClient.php
|
||||
php -l src/Modules/Settings/ShopproOrderSyncStateRepository.php
|
||||
grep -c "updateOrderStatus" src/Modules/Settings/ShopproApiClient.php (powinno byc >= 1)
|
||||
grep -c "last_status_pushed_at" src/Modules/Settings/ShopproOrderSyncStateRepository.php (powinno byc >= 1)
|
||||
</verify>
|
||||
<done>AC-1 satisfied: ShopproApiClient ma metode PUT do zmiany statusu w shopPRO</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Implementacja push w ShopproStatusSyncService</name>
|
||||
<files>
|
||||
src/Modules/Settings/ShopproStatusSyncService.php
|
||||
</files>
|
||||
<action>
|
||||
1. Dodac nowe zaleznosci w konstruktorze:
|
||||
- `ShopproApiClient $apiClient`
|
||||
- `ShopproOrderSyncStateRepository $syncState`
|
||||
- `ShopproStatusMappingRepository $statusMappings`
|
||||
- `PDO $pdo` (do query order_status_history + orders)
|
||||
|
||||
2. Zmodyfikowac `sync()` — zamiast `continue` dla `DIRECTION_ORDERPRO_TO_SHOPPRO`, wywolac nowa prywatna metode `syncPushDirection(int $integrationId, array $integration): array`
|
||||
|
||||
3. Implementacja `syncPushDirection()`:
|
||||
a) Pobrac API credentials z integracji (reuse wzorca z istniejacego kodu):
|
||||
- base_url, api_key (via $this->integrations->getApiKeyDecrypted), timeout
|
||||
b) Zbudowac reverse status map:
|
||||
- Pobrac mappingi z $this->statusMappings->listByIntegration($integrationId)
|
||||
- Odwrocic: `$reverseMap[$orderpro_code] = $shoppro_code`
|
||||
- Uwaga: jesli wiele shopPRO kodow mapuje na ten sam orderPRO kod, wziac pierwszy
|
||||
c) Pobrac `last_status_pushed_at` z $this->syncState
|
||||
d) Query do bazy — znalezc zamowienia z recznymi zmianami statusu po kursore:
|
||||
```sql
|
||||
SELECT DISTINCT o.id AS order_id, o.source_order_id, o.external_status_id,
|
||||
MAX(h.changed_at) AS latest_change
|
||||
FROM order_status_history h
|
||||
JOIN orders o ON o.id = h.order_id
|
||||
WHERE o.integration_id = :integration_id
|
||||
AND h.change_source IN ('manual')
|
||||
AND h.changed_at > :last_pushed_at -- lub brak warunku jesli null
|
||||
GROUP BY o.id, o.source_order_id, o.external_status_id
|
||||
ORDER BY latest_change ASC
|
||||
LIMIT 50
|
||||
```
|
||||
Jesli `last_status_pushed_at` jest null, uzyc ostatnich 24h jako fallback.
|
||||
e) Dla kazdego zamowienia:
|
||||
- Pobrac aktualny `external_status_id` (orderpro status code)
|
||||
- Sprawdzic reverse map: `$shopproStatusCode = $reverseMap[$orderproStatus] ?? null`
|
||||
- Jesli brak mapowania — pominac (log do wyniku)
|
||||
- Jesli jest — wywolac `$this->apiClient->updateOrderStatus($baseUrl, $apiKey, $timeout, (int)$sourceOrderId, (int)$shopproStatusCode)`
|
||||
- Zapisac wynik (success/fail count)
|
||||
- Zaktualizowac kursor `latest_change`
|
||||
f) Po zakonczeniu petli: `$this->syncState->updateLastStatusPushedAt($integrationId, $latestChangeAt)`
|
||||
g) Zwrocic wynik:
|
||||
```php
|
||||
['ok' => true, 'direction' => 'orderpro_to_shoppro', 'pushed' => $pushed, 'skipped' => $skipped, 'failed' => $failed]
|
||||
```
|
||||
|
||||
4. Zaktualizowac wynik `sync()`:
|
||||
- Zbierac wyniki z push integracji osobno
|
||||
- Dodac do glownego wyniku
|
||||
|
||||
5. Zaktualizowac konstruktor w `CronHandlerFactory` jesli potrzebne nowe zaleznosci dla ShopproStatusSyncService
|
||||
|
||||
Avoid:
|
||||
- Nie pushowac zmian z change_source = 'import' lub 'sync' — to spowodowaloby petle
|
||||
- Nie modyfikowac logiki pull direction — zostawic ja nienaruszona
|
||||
- Nie pushowac statusow bez mapowania — po cichu pominac
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Settings/ShopproStatusSyncService.php
|
||||
grep -c "syncPushDirection" src/Modules/Settings/ShopproStatusSyncService.php (powinno byc >= 2)
|
||||
grep -c "DIRECTION_ORDERPRO_TO_SHOPPRO" src/Modules/Settings/ShopproStatusSyncService.php (powinno byc >= 2)
|
||||
grep "unsupportedCount" src/Modules/Settings/ShopproStatusSyncService.php | head -3 (nie powinno byc juz w kontekscie orderpro_to_shoppro)
|
||||
</verify>
|
||||
<done>AC-2 i AC-3 satisfied: Push direction dziala w cron, brak mapowania nie blokuje</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Aktualizacja CronHandlerFactory + dokumentacja</name>
|
||||
<files>
|
||||
src/Modules/Cron/CronHandlerFactory.php,
|
||||
DOCS/DB_SCHEMA.md,
|
||||
DOCS/ARCHITECTURE.md,
|
||||
DOCS/TECH_CHANGELOG.md
|
||||
</files>
|
||||
<action>
|
||||
1. W `CronHandlerFactory` — zaktualizowac tworzenie `ShopproStatusSyncService`:
|
||||
- Dodac brakujace zaleznosci do konstruktora (ShopproApiClient, ShopproOrderSyncStateRepository, ShopproStatusMappingRepository, PDO)
|
||||
- Reuse istniejacych instancji jesli juz sa tworzone w factory
|
||||
|
||||
2. W `DOCS/DB_SCHEMA.md`:
|
||||
- Dodac kolumne `last_status_pushed_at` do opisu `integration_order_sync_state`
|
||||
|
||||
3. W `DOCS/ARCHITECTURE.md`:
|
||||
- Dodac opis metody `ShopproApiClient::updateOrderStatus()` (PUT)
|
||||
- Dodac opis metody `ShopproStatusSyncService::syncPushDirection()` i logiki reverse mapping
|
||||
- Zaktualizowac opis crona `shoppro_order_status_sync` — obsluguje oba kierunki
|
||||
|
||||
4. W `DOCS/TECH_CHANGELOG.md`:
|
||||
- Dodac wpis chronologiczny: implementacja push direction orderpro_to_shoppro
|
||||
|
||||
Avoid:
|
||||
- Nie modyfikowac istniejacych cron handlerow
|
||||
- Nie zmieniac interwalu crona
|
||||
</action>
|
||||
<verify>
|
||||
php -l src/Modules/Cron/CronHandlerFactory.php
|
||||
grep "ShopproApiClient" src/Modules/Cron/CronHandlerFactory.php (powinno byc >= 1)
|
||||
</verify>
|
||||
<done>Dokumentacja i factory zaktualizowane</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- src/Modules/Orders/OrdersController.php (logika zmiany statusu pozostaje bez zmian)
|
||||
- src/Modules/Orders/OrdersRepository.php (nie modyfikowac updateOrderStatus/recordStatusChange)
|
||||
- src/Modules/Settings/ShopproOrdersSyncService.php (import/pull logika nienaruszona)
|
||||
- src/Modules/Settings/ShopproOrderMapper.php (mapper importu)
|
||||
- resources/views/settings/shoppro.php (UI konfiguracji integracji — nie wymaga zmian)
|
||||
- Istniejace migracje
|
||||
- Istniejace cron schedule/interval
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Tylko cron-based push (nie event-driven immediate push)
|
||||
- Brak nowego UI — istniejacy dropdown direction juz obsluguje oba kierunki
|
||||
- Nie implementowac synchronizacji platnosci w tym planie
|
||||
- send_email w API shopPRO ustawic na false (nie wysylac maili klientom przy sync)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] `php -l` na wszystkich zmienionych plikach PHP (brak bledow skladni)
|
||||
- [ ] Migracja SQL jest poprawna skladniowo
|
||||
- [ ] `ShopproApiClient::updateOrderStatus()` wysyla PUT z poprawnym JSON body
|
||||
- [ ] `ShopproStatusSyncService::sync()` obsluguje oba kierunki
|
||||
- [ ] Reverse mapping poprawnie odwraca orderpro -> shoppro kody statusow
|
||||
- [ ] Zmiany z `change_source = 'import'` NIE sa pushowane (brak petli)
|
||||
- [ ] `CronHandlerFactory` poprawnie tworzy ShopproStatusSyncService z nowymi zaleznosciami
|
||||
- [ ] Dokumentacja zaktualizowana (DB_SCHEMA, ARCHITECTURE, TECH_CHANGELOG)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Wszystkie taski ukonczone
|
||||
- Wszystkie weryfikacje przeszly
|
||||
- Brak nowych bledow skladni PHP
|
||||
- Logika push nie interferuje z istniejaca logika pull
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/45-shoppro-status-push/45-01-SUMMARY.md`
|
||||
</output>
|
||||
136
.paul/phases/45-shoppro-status-push/45-01-SUMMARY.md
Normal file
136
.paul/phases/45-shoppro-status-push/45-01-SUMMARY.md
Normal file
@@ -0,0 +1,136 @@
|
||||
---
|
||||
phase: 45-shoppro-status-push
|
||||
plan: 01
|
||||
subsystem: integration
|
||||
tags: [shoppro, status-sync, cron, curl-put, api]
|
||||
|
||||
requires:
|
||||
- phase: shoppro-integrations
|
||||
provides: ShopproApiClient, ShopproIntegrationsRepository, order_status_mappings, integration_order_sync_state
|
||||
|
||||
provides:
|
||||
- Bidirectional status sync between orderPRO and shopPRO
|
||||
- ShopproApiClient::updateOrderStatus() PUT method
|
||||
- Reverse status mapping (orderpro -> shoppro)
|
||||
|
||||
affects: []
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [reverse-status-mapping, cursor-based-push-sync]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- database/migrations/20260327_000071_add_last_status_pushed_at_to_sync_state.sql
|
||||
modified:
|
||||
- src/Modules/Settings/ShopproApiClient.php
|
||||
- src/Modules/Settings/ShopproStatusSyncService.php
|
||||
- src/Modules/Settings/ShopproOrderSyncStateRepository.php
|
||||
- src/Modules/Cron/CronHandlerFactory.php
|
||||
|
||||
key-decisions:
|
||||
- "Refactor: wydzielenie executeRequest() z requestJson() dla reuse GET/PUT"
|
||||
- "Push only change_source=manual to prevent sync loops"
|
||||
- "Fallback 24h when last_status_pushed_at is null"
|
||||
|
||||
patterns-established:
|
||||
- "Reverse mapping: orderpro_status_code -> shoppro_status_code (first match wins)"
|
||||
- "Cursor-based push: last_status_pushed_at tracks sync progress per integration"
|
||||
|
||||
duration: 15min
|
||||
started: 2026-03-27T00:00:00Z
|
||||
completed: 2026-03-27T00:15:00Z
|
||||
---
|
||||
|
||||
# Phase 45 Plan 01: ShopPRO Status Push Summary
|
||||
|
||||
**Implementacja synchronizacji statusow zamowien orderPRO -> shopPRO przez cron z reverse mapping i PUT API**
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~15min |
|
||||
| Tasks | 3 completed |
|
||||
| Files modified | 7 |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: API Client obsluguje PUT change_status | Pass | `updateOrderStatus()` wysyla PUT z JSON body `{status_id, send_email}` |
|
||||
| AC-2: Push kierunek dziala w cron sync | Pass | `syncPushDirection()` query manual changes, reverse map, API call, cursor update |
|
||||
| AC-3: Brak mapowania nie blokuje synca | Pass | Brak mapowania = `$skipped++`, kontynuacja petli |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- `ShopproApiClient::updateOrderStatus()` — metoda PUT do `/api.php?endpoint=orders&action=change_status`
|
||||
- `ShopproStatusSyncService::syncPushDirection()` — pelna logika push: reverse mapping, query `order_status_history` (tylko `change_source=manual`), wywolanie API, aktualizacja kursora
|
||||
- Refactor `ShopproApiClient` — wydzielenie `executeRequest()` z `requestJson()` dla reuse GET/PUT (eliminacja duplikacji SSL/curl logic)
|
||||
- Kursor `last_status_pushed_at` w `integration_order_sync_state` z defensywnym sprawdzaniem istnienia kolumny
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `database/migrations/20260327_000071_*.sql` | Created | Migracja: kolumna `last_status_pushed_at` |
|
||||
| `src/Modules/Settings/ShopproApiClient.php` | Modified | Nowa metoda `updateOrderStatus()` + refactor na `executeRequest()` |
|
||||
| `src/Modules/Settings/ShopproStatusSyncService.php` | Modified | Implementacja push direction z reverse mapping |
|
||||
| `src/Modules/Settings/ShopproOrderSyncStateRepository.php` | Modified | Metody `getLastStatusPushedAt()`, `updateLastStatusPushedAt()` |
|
||||
| `src/Modules/Cron/CronHandlerFactory.php` | Modified | Nowe zaleznosci dla ShopproStatusSyncService, reuse instancji repo |
|
||||
| `DOCS/DB_SCHEMA.md` | Modified | Dokumentacja kolumny `last_status_pushed_at` |
|
||||
| `DOCS/ARCHITECTURE.md` | Modified | Opis push direction i nowej metody API |
|
||||
| `DOCS/TECH_CHANGELOG.md` | Modified | Wpis chronologiczny |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Refactor `requestJson()` na `executeRequest()` | Eliminacja duplikacji SSL/curl logic miedzy GET i PUT | Latwiejsze dodawanie kolejnych metod HTTP |
|
||||
| Push tylko `change_source=manual` | Zapobieganie petli synchronizacji (import->push->import) | Bezpieczna dwukierunkowa synchronizacja |
|
||||
| Fallback 24h dla null cursor | Przy pierwszym uruchomieniu nie pushowac calej historii | Ograniczenie zakresu pierwszego synca |
|
||||
| `send_email=false` w push | Sync nie powinien generowac maili do klientow | Brak niechcianych powiadomien |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Summary
|
||||
|
||||
| Type | Count | Impact |
|
||||
|------|-------|--------|
|
||||
| Auto-fixed | 1 | Minimal |
|
||||
|
||||
**Total impact:** Essential refactor, no scope creep
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. Refactor: duplikacja curl logic**
|
||||
- **Found during:** Task 1
|
||||
- **Issue:** Plan sugerowal zduplikowanie SSL opts lub wydzielenie `buildCurlHandle()`. Duplikacja bylaby nieoptymalna.
|
||||
- **Fix:** Wydzielono `executeRequest()` z pelna logika curl (GET/PUT), `requestJson()` i `requestJsonPut()` sa teraz thin wrappers.
|
||||
- **Files:** `ShopproApiClient.php`
|
||||
- **Verification:** `php -l` pass
|
||||
|
||||
### Deferred Items
|
||||
|
||||
None
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- Push direction w pelni funkcjonalny — po uruchomieniu migracji i restarcie crona, statusy beda synchronizowane
|
||||
- Istniejace mapowania statusow (skonfigurowane w UI) beda uzywane w obu kierunkach
|
||||
|
||||
**Concerns:**
|
||||
- Migracja `000071` musi byc uruchomiona na serwerze produkcyjnym
|
||||
- Nalezy zweryfikowac mapowania statusow w konfiguracji integracji shopPRO (czy pokrywaja wszystkie uzywane statusy)
|
||||
|
||||
**Blockers:**
|
||||
None
|
||||
|
||||
---
|
||||
*Phase: 45-shoppro-status-push, Plan: 01*
|
||||
*Completed: 2026-03-27*
|
||||
Reference in New Issue
Block a user