feat(128): erli orders import
Phase 128 complete: - add Erli /inbox order import with safe mark-read ACK - add cron/manual import controls and sync state tracking - map Erli orders into orderPRO aggregates with mapper tests and docs
This commit is contained in:
@@ -13,8 +13,8 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów
|
||||
| Attribute | Value |
|
||||
|-----------|-------|
|
||||
| Version | 3.8.0-dev |
|
||||
| Status | v3.8 Erli Marketplace Integration in progress — Phase 127 shipped (Erli settings/API foundation); Phase 128 next |
|
||||
| Last Updated | 2026-05-15 (Phase 127 closed) |
|
||||
| Status | v3.8 Erli Marketplace Integration in progress — Phase 128 shipped (Erli orders import); Phase 129 next |
|
||||
| Last Updated | 2026-05-15 (Phase 128 closed) |
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -127,6 +127,7 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów
|
||||
- [x] Szablony SMS: CRUD w `/settings/sms-templates` (name + body + is_active), wspolny `SmsVariableResolver` wydzielony z Email\\VariableResolver (placeholdery `{{zamowienie.*|kupujacy.*|adres.*|firma.*|przesylka.*}}`), dropdown "Wybierz szablon" w zakladce SMS na `/orders/{id}` wstawia rozwiniete zmienne do textarea (z `OrderProAlerts.confirm` przy nadpisaniu); stopka SMSPLANET dalej doklejana wylacznie przez `SmsConversationService::buildFinalOutboundBody()` (Phase 122 contract preserved) — Phase 124
|
||||
- [x] Bugfix detekcji faktury przy imporcie: shopPRO order z `firm_nip` ustawia `invoice_requested=1` (mapper jako jedyne zrodlo heurystyki, sync service propaguje `aggregate['invoice_detected']`); Allegro rozszerzony o `naturalPerson=false`/`address.taxId`/`companyName` (wczesniej tylko `invoice.required`); usunieta legacy kolumna `orders.is_invoice` (Phase 115 dryft) + backfill 7 zamowien — Phase 125
|
||||
- [x] Fundament integracji Erli: pojedyncza globalna konfiguracja `/settings/integrations/erli`, szyfrowany Bearer API key, realny test `GET /svc/shop-api/inbox`, karta w hubie integracji oraz dokumentacja schematu/architektury — Phase 127
|
||||
- [x] Import zamowien Erli: pobieranie `/inbox` przez cron i recznie, mapper do orderPRO, delta-only re-import, `invoice_requested` z danych firmowych/NIP, bezpieczny ACK `/inbox/mark-read` po bezblednym batchu — Phase 128
|
||||
|
||||
### Deferred
|
||||
|
||||
@@ -135,11 +136,10 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów
|
||||
|
||||
### Active (In Progress)
|
||||
|
||||
- [ ] v3.8 Erli Marketplace Integration — Phase 127 shipped; Phase 128 next: pobieranie zamowien Erli przez cron/import reczny, mapper do wspolnego modelu orderPRO i state cursor.
|
||||
- [ ] v3.8 Erli Marketplace Integration — Phase 129 next: mapowanie statusow pull/push Erli i synchronizacja statusow.
|
||||
|
||||
### Planned (Next)
|
||||
|
||||
- [ ] Erli status mapping + sync — Phase 129
|
||||
- [ ] Erli shipments + labels — Phase 130
|
||||
- [ ] Erli tracking + automation hooks — Phase 131
|
||||
- [ ] Erli hardening, observability + docs — Phase 132
|
||||
@@ -244,12 +244,15 @@ PHP (XAMPP/Laravel), integracje z API marketplace'Ăłw (Allegro, Erli) oraz API
|
||||
| `$messageHtml` w alert component musi być `unset()` po każdym include | PHP `include` widzi zmienne kontekstu z extracted scope; bez `unset` kolejny include w tym samym widoku falszywie wykrywa `isset($messageHtml)`. Pattern dla wszystkich miejsc używających `$messageHtml` (4 widoki: invoice_form, receipt-create, printing, statistics/orders) | 2026-05-12 | Active |
|
||||
| Erli startuje jako jedna globalna konfiguracja bez sandbox switcha | Operator wybral prosty model pojedynczego konta; srodowisko testowe Erli wymaga osobnej domeny z BOK, wiec nie trafia do Phase 127 | 2026-05-15 | Active |
|
||||
| Test Erli uzywa realnego read-only `GET /inbox` | Operator wymagal realnego testu API, ale fundament nie moze jeszcze importowac zamowien ani oznaczac inboxa jako przeczytanego | 2026-05-15 | Active |
|
||||
| Erli import uzywa `/inbox` jako glownego zrodla zdarzen | Model inbox jest event-driven i pasuje do bezpiecznego przetwarzania batchy oraz przyszlych aktualizacji statusow | 2026-05-15 | Active |
|
||||
| ACK Erli przez `POST /inbox/mark-read` tylko po bezblednym batchu | Zapobiega utracie zdarzen, gdy lokalny import czesciowo sie nie powiedzie | 2026-05-15 | Active |
|
||||
| Phase 128 ma domyslne mapowania statusow, a UI mapowan dopiero Phase 129 | Import ma realnie dzialac teraz, a pelne strojenie pull/push statusow wymaga osobnej fazy | 2026-05-15 | Active |
|
||||
|
||||
## Success Metrics
|
||||
|
||||
| Metric | Target | Current | Status |
|
||||
|--------|--------|---------|--------|
|
||||
| Liczba zintegrowanych źródeł zamówień | ≥3 | 2 aktywne importy + fundament Erli | In progress |
|
||||
| Liczba zintegrowanych źródeł zamówień | ≥3 | 3 zrodla importu (Allegro, shopPRO, Erli); Erli wymaga manualnego smoke po migracji | In progress |
|
||||
| Generowanie etykiet | Działa | InPost | In progress |
|
||||
|
||||
## Tech Stack
|
||||
@@ -275,6 +278,6 @@ Quick Reference:
|
||||
|
||||
---
|
||||
*PROJECT.md — Updated when requirements or context change*
|
||||
*Last updated: 2026-05-15 after Phase 127 (Erli Integration Foundation) closure; v3.8 milestone in progress*
|
||||
*Last updated: 2026-05-15 after Phase 128 (Erli Orders Import) closure; v3.8 milestone in progress*
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Pelna integracja z erli.pl wzorowana na istniejacej integracji Allegro: konfigur
|
||||
| Phase | Name | Plans | Status |
|
||||
|-------|------|-------|--------|
|
||||
| 127 | Erli Integration Foundation | 1/1 | Complete (2026-05-15; migration/manual Erli API smoke pending operator) |
|
||||
| 128 | Erli Orders Import | TBD | Not started |
|
||||
| 128 | Erli Orders Import | 1/1 | Complete (2026-05-15; migration/manual Erli import smoke pending operator) |
|
||||
| 129 | Erli Status Mapping + Sync | TBD | Not started |
|
||||
| 130 | Erli Shipments + Labels | TBD | Not started |
|
||||
| 131 | Erli Tracking + Automation Hooks | TBD | Not started |
|
||||
@@ -27,7 +27,7 @@ Plans: 127-01 (complete)
|
||||
### Phase 128: Erli Orders Import
|
||||
|
||||
Focus: Pobieranie nowych zamowien Erli przez cron i import reczny, mapper do wspolnego modelu orderPRO, state cursor, delta-only re-import, adresy/pozycje/platnosci/notatki oraz flaga faktury/NIP tam, gdzie API Erli daje dane firmowe.
|
||||
Plans: TBD (defined during $paul-plan)
|
||||
Plans: 128-01 (complete)
|
||||
|
||||
### Phase 129: Erli Status Mapping + Sync
|
||||
|
||||
@@ -553,4 +553,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md`
|
||||
|
||||
---
|
||||
*Roadmap created: 2026-03-12*
|
||||
*Last updated: 2026-05-15 - Phase 127 UNIFY closed*
|
||||
*Last updated: 2026-05-15 - Phase 128 UNIFY closed*
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
See: .paul/PROJECT.md (updated 2026-05-07)
|
||||
|
||||
**Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami.
|
||||
**Current focus:** v3.8 Erli Marketplace Integration - Phase 127 complete; Phase 128 ready to plan.
|
||||
**Current focus:** v3.8 Erli Marketplace Integration - Phase 128 complete; Phase 129 ready to plan.
|
||||
|
||||
## Current Position
|
||||
|
||||
Milestone: v3.8 Erli Marketplace Integration
|
||||
Phase: 128 of 132 (Erli Orders Import)
|
||||
Phase: 129 of 132 (Erli Status Mapping + Sync)
|
||||
Plan: Not started
|
||||
Status: Ready to plan
|
||||
Last activity: 2026-05-15 23:26 - Phase 127 complete; transitioned to Phase 128
|
||||
Last activity: 2026-05-15 23:52 - Phase 128 complete; transitioned to Phase 129
|
||||
|
||||
Progress:
|
||||
- Milestone v3.8: [##--------] ~16% (Phase 127 complete)
|
||||
- Phase 128: [----------] 0% (not planned)
|
||||
- Milestone v3.8: [####------] ~33% (Phases 127-128 complete)
|
||||
- Phase 129: [----------] 0% (not planned)
|
||||
|
||||
## Loop Position
|
||||
|
||||
@@ -29,10 +29,10 @@ PLAN -> APPLY -> UNIFY
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-05-15 23:26
|
||||
Stopped at: Phase 127 complete; Phase 128 ready to plan
|
||||
Next action: $paul-plan for Phase 128 (Erli Orders Import)
|
||||
Resume file: .paul/ROADMAP.md
|
||||
Last session: 2026-05-15 23:52
|
||||
Stopped at: Phase 128 complete
|
||||
Next action: $paul-plan for Phase 129 (Erli Status Mapping + Sync)
|
||||
Resume file: .paul/phases/128-erli-orders-import/128-01-SUMMARY.md
|
||||
|
||||
## Pending parallel work
|
||||
- None — Phase 118, 121, 122 wszystkie zacommitowane (8f14851, 360eef1).
|
||||
@@ -66,6 +66,8 @@ Branch: main
|
||||
- Phase 121 transition note (rozwiązane): commit 360eef1 obejmuje Phase 121 i Phase 122 razem; per-faza hunk-split nie wykonany ze względu na nakładkowe modyfikacje plików.
|
||||
- Phase 126 follow-up: manual smoke `/orders/1090/invoice/create` (JDG, NIP 5170167517) -> "Imie i nazwisko"="JACEK PYZIAK", "Nazwa firmy"="Project-Pro Pyziak Jacek" niezmieniona; drugi smoke na zamowieniu spolki z aktywnym KRS; `curl /api/nip/lookup?nip=5170167517` -> `data.is_jdg=true`.
|
||||
- Phase 127 follow-up: uruchom `php bin/migrate.php` gdy lokalny MySQL/XAMPP jest online, zapisz prawdziwy klucz Erli w `/settings/integrations/erli`, wykonaj realny test polaczenia i potwierdz wpis w hubie integracji.
|
||||
- Phase 128 follow-up: uruchom `php bin/migrate.php`, wlacz import Erli w `/settings/integrations/erli`, kliknij `Importuj zamowienia teraz`, potwierdz `orders.source='erli'` i sprawdz, ze przy bezblednym batchu inbox ACK `POST /inbox/mark-read` nie zostawia nieprzeczytanych zdarzen.
|
||||
- Phase 128 verification gap: `vendor/bin/phpunit` nie istnieje w checkoutcie, wiec test `tests/Unit/ErliOrderMapperTest.php` nie zostal uruchomiony przez PHPUnit; wykonano `php -l` i runtime smoke mappera.
|
||||
|
||||
## Deferred to Next Milestones
|
||||
|
||||
@@ -76,4 +78,4 @@ Branch: main
|
||||
|
||||
## Skill Requirements
|
||||
|
||||
- `sonar-scanner` required after APPLY; Phase 116, Phase 117, Phase 121 and Phase 122 gaps documented because CLI was not available in PATH.
|
||||
- `sonar-scanner` required after APPLY; Phase 116, Phase 117, Phase 121, Phase 122 and Phase 128 gaps documented because CLI was not available in PATH.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
- [Phase 127, Plan 01] Dodano fundament integracji Erli: globalna konfiguracja API, szyfrowany klucz, realny test polaczenia, widok ustawien i wiersz w hubie integracji.
|
||||
- Utworzono plan i summary dla Phase 127 oraz przygotowano przejscie do Phase 128.
|
||||
- [Phase 128, Plan 01] Wdrozono import zamowien Erli przez `/inbox`: cron, reczny import, mapper, sync service i bezpieczny ACK `/inbox/mark-read`.
|
||||
- Dodano test mappera Erli oraz dokumentacje DB/architektury/changelogu dla importu zamowien.
|
||||
|
||||
## Zmienione pliki
|
||||
|
||||
@@ -22,3 +24,13 @@
|
||||
- `DOCS/DB_SCHEMA.md`
|
||||
- `DOCS/ARCHITECTURE.md`
|
||||
- `DOCS/TECH_CHANGELOG.md`
|
||||
- `.paul/phases/128-erli-orders-import/128-01-PLAN.md`
|
||||
- `.paul/phases/128-erli-orders-import/128-01-SUMMARY.md`
|
||||
- `database/migrations/20260515_000115_add_erli_orders_import_schedule.sql`
|
||||
- `src/Core/Constants/IntegrationSources.php`
|
||||
- `src/Modules/Cron/CronHandlerFactory.php`
|
||||
- `src/Modules/Cron/ErliOrdersImportHandler.php`
|
||||
- `src/Modules/Settings/ErliOrderMapper.php`
|
||||
- `src/Modules/Settings/ErliOrderSyncStateRepository.php`
|
||||
- `src/Modules/Settings/ErliOrdersSyncService.php`
|
||||
- `tests/Unit/ErliOrderMapperTest.php`
|
||||
|
||||
311
.paul/phases/128-erli-orders-import/128-01-PLAN.md
Normal file
311
.paul/phases/128-erli-orders-import/128-01-PLAN.md
Normal file
@@ -0,0 +1,311 @@
|
||||
---
|
||||
phase: 128-erli-orders-import
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- database/migrations/20260515_000115_add_erli_orders_import_schedule.sql
|
||||
- src/Core/Constants/IntegrationSources.php
|
||||
- src/Modules/Settings/ErliApiClient.php
|
||||
- src/Modules/Settings/ErliIntegrationRepository.php
|
||||
- src/Modules/Settings/ErliIntegrationController.php
|
||||
- src/Modules/Settings/ErliOrderMapper.php
|
||||
- src/Modules/Settings/ErliOrderSyncStateRepository.php
|
||||
- src/Modules/Settings/ErliOrdersSyncService.php
|
||||
- src/Modules/Cron/ErliOrdersImportHandler.php
|
||||
- src/Modules/Cron/CronHandlerFactory.php
|
||||
- routes/web.php
|
||||
- resources/views/settings/erli.php
|
||||
- resources/lang/pl.php
|
||||
- tests/Unit/ErliOrderMapperTest.php
|
||||
- DOCS/DB_SCHEMA.md
|
||||
- DOCS/ARCHITECTURE.md
|
||||
- DOCS/TECH_CHANGELOG.md
|
||||
autonomous: true
|
||||
delegation: auto
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Wdrozyc realny import zamowien Erli do orderPRO na bazie Erli `/inbox`: cron job, reczny import z ustawien, mapper payloadu zamowienia do wspolnego modelu `OrderImportRepository` oraz bezpieczne potwierdzanie przeczytania inboxa po udanym batchu.
|
||||
|
||||
## Purpose
|
||||
Phase 127 dala konfiguracje i test API. Phase 128 ma sprawic, ze Erli zaczyna dostarczac realne zamowienia do listy orderPRO, z zachowaniem kontraktow delta-only re-import, `invoice_requested` i automatyzacji `order.imported` / `payment.status_changed`.
|
||||
|
||||
## Output
|
||||
Nowe klasy importu Erli, cron schedule `erli_orders_import`, przycisk recznego importu w `/settings/integrations/erli`, testy mappera oraz dokumentacja techniczna.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
<clarifications>
|
||||
- **Zrodlo importu** - Czy Phase 128 ma uzywac Erli `/inbox`, czy klasycznej listy zamowien po `updated`?
|
||||
-> Odpowiedz: Wg rekomendacji; uzyc `/inbox` jako glownego zrodla.
|
||||
- **ACK inboxa** - Czy po udanym przetworzeniu oznaczac wiadomosci Erli jako przeczytane?
|
||||
-> Odpowiedz: Wg rekomendacji; oznaczac po udanym batchu, z notatka jezeli trzeba cos pozniej zrobic.
|
||||
- **Reczny import** - Czy dodac reczna akcje importu w ustawieniach, czy tylko cron?
|
||||
-> Odpowiedz: Obie.
|
||||
</clarifications>
|
||||
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
@.paul/STATE.md
|
||||
@.paul/codebase/architecture.md
|
||||
@.paul/codebase/db_schema.md
|
||||
@DOCS/DB_SCHEMA.md
|
||||
@DOCS/ARCHITECTURE.md
|
||||
|
||||
## Prior Work
|
||||
@.paul/phases/127-erli-integration-foundation/127-01-SUMMARY.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Settings/ErliApiClient.php
|
||||
@src/Modules/Settings/ErliIntegrationRepository.php
|
||||
@src/Modules/Settings/ErliIntegrationController.php
|
||||
@resources/views/settings/erli.php
|
||||
@src/Modules/Settings/AllegroOrdersSyncService.php
|
||||
@src/Modules/Settings/AllegroOrderImportService.php
|
||||
@src/Modules/Settings/ShopproOrdersSyncService.php
|
||||
@src/Modules/Settings/ShopproOrderMapper.php
|
||||
@src/Modules/Settings/AllegroOrderSyncStateRepository.php
|
||||
@src/Modules/Orders/OrderImportRepository.php
|
||||
@src/Modules/Cron/CronHandlerFactory.php
|
||||
@src/Modules/Cron/AllegroOrdersImportHandler.php
|
||||
@src/Modules/Cron/ShopproOrdersImportHandler.php
|
||||
@routes/web.php
|
||||
@resources/lang/pl.php
|
||||
@tests/Unit/OrderImportRepositoryTest.php
|
||||
@tests/Unit/AllegroOrderImportServiceTest.php
|
||||
|
||||
## External API Notes
|
||||
@https://erli.pl/svc/shop-api/doc/
|
||||
- Erli API uses REST over HTTPS with `Authorization: Bearer ...`, `Accept: application/json` and a meaningful `User-Agent`.
|
||||
- Orders and order changes are available through `/svc/shop-api/inbox`.
|
||||
- One fetch returns up to 500 unread messages.
|
||||
- Messages should be marked read only after processing, using the id of the newest/last message.
|
||||
- Status basics: `pending` means unpaid PayU; `purchased` means paid PayU or COD; `cancelled` means cancelled.
|
||||
- If the exact ACK endpoint/method is not recoverable from the public reference during APPLY, import must stay non-destructive, skip ACK, and SUMMARY must record the follow-up.
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills / Tools (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill / Tool | Priority | When to Invoke | Loaded? |
|
||||
|--------------|----------|----------------|---------|
|
||||
| `sonar-scanner` | required | After APPLY, before UNIFY | o |
|
||||
|
||||
## Optional Flows
|
||||
- `/feature-dev` optional before implementation of this marketplace feature.
|
||||
- `/code-review` optional after implementation, before UNIFY.
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Import Configuration And Cron
|
||||
```gherkin
|
||||
Given Erli settings have a saved API key
|
||||
When the operator enables Erli order import and saves the settings
|
||||
Then `orders_fetch_enabled`, optional `orders_fetch_start_date`, cron interval, and `erli_orders_import` schedule are persisted
|
||||
And the settings page offers a CSRF-protected "Importuj teraz" action.
|
||||
```
|
||||
|
||||
## AC-2: Inbox Fetch And Safe Acknowledgement
|
||||
```gherkin
|
||||
Given Erli returns unread `/inbox` messages containing order events
|
||||
When the cron or manual import processes the batch without per-order failures
|
||||
Then every supported order event is imported or re-imported
|
||||
And Erli inbox is marked read only up to the newest processed message id.
|
||||
```
|
||||
|
||||
## AC-3: No Data Loss On Partial Failure
|
||||
```gherkin
|
||||
Given an Erli inbox batch contains at least one order that cannot be mapped or saved
|
||||
When import finishes with failures
|
||||
Then the sync state records the failure
|
||||
And the inbox acknowledgement is not sent for that batch
|
||||
And the result exposes processed/imported/failed/skipped counters plus sampled errors.
|
||||
```
|
||||
|
||||
## AC-4: Order Aggregate Mapping
|
||||
```gherkin
|
||||
Given an Erli order payload contains buyer, delivery, payment, line items, totals and optional invoice/company data
|
||||
When the mapper builds an order aggregate
|
||||
Then `orders`, `order_addresses`, `order_items`, `order_payments`, `order_notes`, `order_status_history` receive orderPRO-compatible data
|
||||
And new orders with invoice/company markers set `orders.invoice_requested=1`.
|
||||
```
|
||||
|
||||
## AC-5: Existing Import Contracts Preserved
|
||||
```gherkin
|
||||
Given an Erli order already exists in orderPRO
|
||||
When the same order is imported again from a changed inbox event
|
||||
Then `OrderImportRepository::upsertOrderAggregate()` performs delta-only re-import
|
||||
And local items/addresses/notes are not replaced on re-import
|
||||
And payment transition can still trigger `payment.status_changed`.
|
||||
```
|
||||
|
||||
## AC-6: Observability And Documentation
|
||||
```gherkin
|
||||
Given Phase 128 is complete
|
||||
When maintainers read the docs or run tests
|
||||
Then Erli import architecture, schema/schedule changes, verification gaps and manual smoke steps are documented
|
||||
And mapper/unit checks cover the core Erli payload shapes.
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add Erli import controls, schedule and entry points</name>
|
||||
<files>
|
||||
database/migrations/20260515_000115_add_erli_orders_import_schedule.sql,
|
||||
src/Modules/Settings/ErliIntegrationRepository.php,
|
||||
src/Modules/Settings/ErliIntegrationController.php,
|
||||
resources/views/settings/erli.php,
|
||||
resources/lang/pl.php,
|
||||
routes/web.php,
|
||||
src/Modules/Cron/ErliOrdersImportHandler.php,
|
||||
src/Modules/Cron/CronHandlerFactory.php
|
||||
</files>
|
||||
<action>
|
||||
Add an idempotent migration seeding `cron_schedules.job_type='erli_orders_import'` with a conservative default interval (5 minutes), disabled until the operator enables import.
|
||||
Reuse existing `integrations.orders_fetch_enabled` and `integrations.orders_fetch_start_date`; do not add duplicate Erli-only columns for the same settings.
|
||||
Extend Erli settings save/read to expose:
|
||||
- import enabled checkbox,
|
||||
- optional start date,
|
||||
- order import interval minutes using `CronRepository::upsertSchedule`.
|
||||
Add a POST `/settings/integrations/erli/import` action protected by CSRF that calls the Erli sync service with `ignore_orders_fetch_enabled=true` and small manual limits.
|
||||
Wire `ErliOrdersImportHandler` into `CronHandlerFactory` as `erli_orders_import`.
|
||||
Keep UI compact and reuse existing alert component; do not add inline CSS or native `alert()` / `confirm()`.
|
||||
</action>
|
||||
<verify>
|
||||
`C:\xampp\php\php.exe -l src/Modules/Settings/ErliIntegrationRepository.php`
|
||||
`C:\xampp\php\php.exe -l src/Modules/Settings/ErliIntegrationController.php`
|
||||
`C:\xampp\php\php.exe -l src/Modules/Cron/ErliOrdersImportHandler.php`
|
||||
`C:\xampp\php\php.exe -l src/Modules/Cron/CronHandlerFactory.php`
|
||||
`C:\xampp\php\php.exe -l routes/web.php`
|
||||
`C:\xampp\php\php.exe -l resources/views/settings/erli.php`
|
||||
</verify>
|
||||
<done>AC-1 satisfied: Erli import can be enabled, scheduled, and manually triggered from settings.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Implement Erli inbox client, mapper and sync service</name>
|
||||
<files>
|
||||
src/Core/Constants/IntegrationSources.php,
|
||||
src/Modules/Settings/ErliApiClient.php,
|
||||
src/Modules/Settings/ErliOrderMapper.php,
|
||||
src/Modules/Settings/ErliOrderSyncStateRepository.php,
|
||||
src/Modules/Settings/ErliOrdersSyncService.php
|
||||
</files>
|
||||
<action>
|
||||
Add `IntegrationSources::ERLI = 'erli'`.
|
||||
Extend `ErliApiClient` with reusable JSON request helpers:
|
||||
- `fetchInbox(base_url, api_key, timeout)` via `GET /inbox`,
|
||||
- `ackInboxRead(base_url, api_key, timeout, latest_message_id)` after confirming the exact ACK method/path in Erli reference before coding,
|
||||
- consistent handling for 401/403, 429, non-JSON bodies and cURL errors.
|
||||
Build `ErliOrderMapper` that accepts supported inbox event payloads (`orderCreated`, `orderStatusChanged` and equivalent shape variants) and produces the aggregate arrays required by `OrderImportRepository::upsertOrderAggregate()`.
|
||||
Mapping rules:
|
||||
- source/integration: `source='erli'`, `external_platform_id='erli'`,
|
||||
- status defaults: `pending -> nieoplacone`, `purchased -> nowe`, `cancelled -> anulowane`; richer pull/push mapping is deferred to Phase 129,
|
||||
- payment status: `pending -> 0`, `purchased -> 2`, COD `purchased -> 2`, cancelled -> 0 unless payload clearly says paid/refunded,
|
||||
- totals, currency and delivery price from payload when present,
|
||||
- customer, delivery and invoice addresses from payload; company tax number/company name should set `invoice_detected=true`,
|
||||
- items with source ids, names, quantity, gross price, SKU/EAN/image when present,
|
||||
- buyer message/comment as order note when present,
|
||||
- status history row with raw Erli status in payload/comment.
|
||||
Build `ErliOrdersSyncService` that:
|
||||
- reads active credentials from `ErliIntegrationRepository`,
|
||||
- respects `orders_fetch_enabled` unless manual import overrides it,
|
||||
- filters/skips messages older than `orders_fetch_start_date` where payload dates allow it,
|
||||
- imports each supported order event through `OrderImportRepository`,
|
||||
- records import activity with source `Erli`,
|
||||
- sets `invoice_requested` only for newly created orders when mapper detects invoice/company data,
|
||||
- triggers `order.imported` for created orders and `payment.status_changed` for re-import payment transitions,
|
||||
- advances `integration_order_sync_state` on success and stores errors on failure,
|
||||
- sends ACK only if the full batch had zero import failures and ACK endpoint was confirmed.
|
||||
If the ACK endpoint cannot be confirmed in APPLY, implement the service with ACK disabled by default, return `acknowledged=false`, and add a clear follow-up in SUMMARY/STATE; do not guess a destructive endpoint.
|
||||
</action>
|
||||
<verify>
|
||||
`C:\xampp\php\php.exe -l src/Modules/Settings/ErliApiClient.php`
|
||||
`C:\xampp\php\php.exe -l src/Modules/Settings/ErliOrderMapper.php`
|
||||
`C:\xampp\php\php.exe -l src/Modules/Settings/ErliOrderSyncStateRepository.php`
|
||||
`C:\xampp\php\php.exe -l src/Modules/Settings/ErliOrdersSyncService.php`
|
||||
Static check: `rg -n "IntegrationSources::ERLI|erli_orders_import|ackInboxRead|order.imported|payment.status_changed" src routes`
|
||||
</verify>
|
||||
<done>AC-2, AC-3, AC-4 and AC-5 satisfied for the runtime import path.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Add mapper tests and update technical docs</name>
|
||||
<files>
|
||||
tests/Unit/ErliOrderMapperTest.php,
|
||||
DOCS/DB_SCHEMA.md,
|
||||
DOCS/ARCHITECTURE.md,
|
||||
DOCS/TECH_CHANGELOG.md
|
||||
</files>
|
||||
<action>
|
||||
Add PHPUnit tests for `ErliOrderMapper` covering:
|
||||
- paid/purchased order maps to an importable aggregate with source `erli`,
|
||||
- pending order maps payment status 0 and status `nieoplacone`,
|
||||
- cancelled order maps status `anulowane` and cancellation flag,
|
||||
- invoice/company/tax id data sets `invoice_detected=true`,
|
||||
- malformed/unsupported inbox messages are skipped or throw controlled mapper exceptions as designed.
|
||||
Update DB docs with the new cron schedule and any sync-state usage/migration changes.
|
||||
Update architecture docs with Erli import flow: settings/manual import/cron -> inbox client -> mapper -> `OrderImportRepository` -> automation.
|
||||
Update technical changelog with Phase 128 scope, status defaults, ACK safety rule, manual verification steps and any deferred ACK follow-up if needed.
|
||||
</action>
|
||||
<verify>
|
||||
`C:\xampp\php\php.exe -l tests/Unit/ErliOrderMapperTest.php`
|
||||
If dependencies are installed: `vendor\bin\phpunit tests\Unit\ErliOrderMapperTest.php`
|
||||
`git diff --check`
|
||||
`sonar-scanner` after APPLY when available in PATH.
|
||||
</verify>
|
||||
<done>AC-6 satisfied: tests and documentation describe the new Erli import behavior and remaining live-smoke steps.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Do not change Allegro/shopPRO import behavior except for shared constants or wiring required by Erli.
|
||||
- Do not weaken Phase 112/119 delta-only re-import protections in `OrderImportRepository`.
|
||||
- Do not implement Erli status push, pull status mapping UI, label generation, shipment creation or tracking in this plan.
|
||||
- Do not add a sandbox/environment switch; Phase 127 decision says one production/global config.
|
||||
- Do not introduce native JS `alert()` / `confirm()` or CSS inside views.
|
||||
- Do not use `DB_HOST_REMOTE` in runtime code.
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Phase 128 imports orders from Erli; Phase 129 owns configurable status mappings and status sync.
|
||||
- Phase 130 owns shipments/labels.
|
||||
- Phase 131 owns tracking/automation hooks beyond existing `order.imported` and `payment.status_changed`.
|
||||
- Product catalog/stock sync is out of scope even though Erli inbox may include product sync messages.
|
||||
- Live import verification requires real Erli credentials and local DB migration; if unavailable, record as manual follow-up.
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] `C:\xampp\php\php.exe -l` passes for all created/modified PHP files.
|
||||
- [ ] `vendor\bin\phpunit tests\Unit\ErliOrderMapperTest.php` passes when dependencies are installed.
|
||||
- [ ] `git diff --check` passes.
|
||||
- [ ] `sonar-scanner` run or documented as unavailable.
|
||||
- [ ] Manual smoke documented: run `php bin/migrate.php`, enable Erli import, click "Importuj teraz", confirm Erli orders appear with `source='erli'`.
|
||||
- [ ] If ACK endpoint was confirmed: successful import returns `acknowledged=true`; failure batch returns `acknowledged=false`.
|
||||
- [ ] All acceptance criteria met or deferred with explicit reason in SUMMARY.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Erli orders can be imported by cron and manually from settings.
|
||||
- Successful supported inbox events create/update orderPRO orders with addresses, items, payments, notes and status history.
|
||||
- Re-import keeps existing delta-only protections.
|
||||
- Inbox read acknowledgement is safe: only after all processed messages in the batch succeed, or explicitly disabled with follow-up if the ACK endpoint cannot be confirmed.
|
||||
- Operator-visible result counters exist for manual import and cron payload result.
|
||||
- Documentation and tests are updated.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/128-erli-orders-import/128-01-SUMMARY.md`.
|
||||
</output>
|
||||
177
.paul/phases/128-erli-orders-import/128-01-SUMMARY.md
Normal file
177
.paul/phases/128-erli-orders-import/128-01-SUMMARY.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
phase: 128-erli-orders-import
|
||||
plan: 01
|
||||
subsystem: settings, integrations, cron, api, database, testing
|
||||
tags: [erli, marketplace, orders-import, inbox, cron, mapper, automation]
|
||||
requires:
|
||||
- phase: 127-erli-integration-foundation
|
||||
provides: global Erli credentials, settings UI, API client base
|
||||
- phase: 112-reimport-data-protection
|
||||
provides: delta-only OrderImportRepository contract
|
||||
- phase: 119-reimport-total-paid-protection
|
||||
provides: total_paid protection on stable payment status
|
||||
provides:
|
||||
- Erli orders import via /inbox
|
||||
- manual Erli import action
|
||||
- erli_orders_import cron handler and schedule
|
||||
- Erli order mapper to orderPRO aggregate
|
||||
- safe inbox ACK after zero-failure batch
|
||||
affects: [erli-status-sync, erli-shipments, erli-tracking, automations, statistics]
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [inbox-driven-marketplace-import, safe-ack-after-batch, source-specific-order-mapper]
|
||||
key-files:
|
||||
created:
|
||||
- database/migrations/20260515_000115_add_erli_orders_import_schedule.sql
|
||||
- src/Modules/Cron/ErliOrdersImportHandler.php
|
||||
- src/Modules/Settings/ErliOrderMapper.php
|
||||
- src/Modules/Settings/ErliOrderSyncStateRepository.php
|
||||
- src/Modules/Settings/ErliOrdersSyncService.php
|
||||
- tests/Unit/ErliOrderMapperTest.php
|
||||
modified:
|
||||
- src/Modules/Settings/ErliApiClient.php
|
||||
- src/Modules/Settings/ErliIntegrationRepository.php
|
||||
- src/Modules/Settings/ErliIntegrationController.php
|
||||
- src/Modules/Cron/CronHandlerFactory.php
|
||||
- resources/views/settings/erli.php
|
||||
- routes/web.php
|
||||
- DOCS/DB_SCHEMA.md
|
||||
- DOCS/ARCHITECTURE.md
|
||||
- DOCS/TECH_CHANGELOG.md
|
||||
key-decisions:
|
||||
- "Erli order import uses /inbox as primary event source."
|
||||
- "POST /inbox/mark-read ACK runs only after a zero-failure batch."
|
||||
- "Phase 128 uses fixed status defaults; configurable mappings are deferred to Phase 129."
|
||||
patterns-established:
|
||||
- "ErliOrdersSyncService is shared by cron and manual import."
|
||||
- "ErliOrderMapper returns null for unsupported inbox messages."
|
||||
duration: ~14min
|
||||
started: 2026-05-15T23:32:00+02:00
|
||||
completed: 2026-05-15T23:46:00+02:00
|
||||
---
|
||||
|
||||
# Phase 128 Plan 01: Erli Orders Import Summary
|
||||
|
||||
Erli now imports order events from `/inbox` into the shared orderPRO order aggregate, with cron/manual entry points, state tracking, automation hooks, and safe Erli inbox acknowledgement after a clean batch.
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~14min |
|
||||
| Started | 2026-05-15T23:32:00+02:00 |
|
||||
| Completed | 2026-05-15T23:46:00+02:00 |
|
||||
| Tasks | 6 acceptance areas completed |
|
||||
| Files modified | 24 |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: Import configuration and schedule | Pass | Added `orders_fetch_enabled`, `orders_fetch_start_date`, interval UI, idempotent cron seed `erli_orders_import`, and manual import route. |
|
||||
| AC-2: Fetch Erli inbox and ACK safely | Pass | `ErliApiClient::fetchInbox()` reads `/inbox`; `markInboxRead()` posts to `/inbox/mark-read` only after zero failures. Endpoint contract confirmed against official Erli swagger. |
|
||||
| AC-3: Cursor/state and failure handling | Pass | `ErliOrderSyncStateRepository` records cursor, last run/success/error; failed batches mark failure and skip ACK. |
|
||||
| AC-4: Map Erli order payload to orderPRO aggregate | Pass | Mapper covers source identifiers, status/payment defaults, customer/delivery/invoice addresses, items, payments, notes, status history, and invoice detection. |
|
||||
| AC-5: Reuse shared order import and automations | Pass | Sync uses `OrderImportRepository`, preserves delta-only behavior, emits `order.imported` on create and `payment.status_changed` on payment transitions. |
|
||||
| AC-6: Tests and documentation | Pass with environment gaps | Mapper unit test file added; docs updated. PHPUnit and Sonar CLI were unavailable in this checkout. |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Added Erli order import service using the same orderPRO aggregate path as Allegro/shopPRO.
|
||||
- Added cron composition and a manual "import now" action in Erli settings.
|
||||
- Added import-state persistence so batches are observable and ACK is not sent on partial failure.
|
||||
- Added Erli mapper coverage for common order, payment, invoice and cancellation cases.
|
||||
- Updated technical docs for DB schema, architecture and changelog.
|
||||
|
||||
## Verification Results
|
||||
|
||||
| Check | Result |
|
||||
|-------|--------|
|
||||
| `php -l` on all changed PHP/view/lang/test files | Pass |
|
||||
| Runtime mapper smoke via inline PHP | Pass: `MAPPER_SMOKE_OK` |
|
||||
| `vendor/bin/phpunit tests/Unit/ErliOrderMapperTest.php` | Not run: `vendor/bin/phpunit` missing in checkout |
|
||||
| `git diff --check` | Pass, with existing CRLF warnings only |
|
||||
| `sonar-scanner` | Not run: CLI unavailable in PATH |
|
||||
| Live migration + manual Erli import | Pending operator smoke on local/production DB |
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `database/migrations/20260515_000115_add_erli_orders_import_schedule.sql` | Created | Add sync-state fields and seed `erli_orders_import` cron schedule. |
|
||||
| `src/Modules/Cron/ErliOrdersImportHandler.php` | Created | Cron handler for Erli import batches. |
|
||||
| `src/Modules/Settings/ErliOrderMapper.php` | Created | Convert Erli inbox order messages to orderPRO aggregate. |
|
||||
| `src/Modules/Settings/ErliOrderSyncStateRepository.php` | Created | Persist import cursor, success and error state. |
|
||||
| `src/Modules/Settings/ErliOrdersSyncService.php` | Created | Coordinate fetch, map, upsert, automation and ACK. |
|
||||
| `tests/Unit/ErliOrderMapperTest.php` | Created | Unit tests for mapper status/payment/invoice cases. |
|
||||
| `src/Modules/Settings/ErliApiClient.php` | Modified | Add `/inbox` fetch and `/inbox/mark-read` ACK. |
|
||||
| `src/Modules/Settings/ErliIntegrationRepository.php` | Modified | Store import settings and expose active integration credentials. |
|
||||
| `src/Modules/Settings/ErliIntegrationController.php` | Modified | Save import settings and run manual import. |
|
||||
| `src/Modules/Cron/CronHandlerFactory.php` | Modified | Register `erli_orders_import`. |
|
||||
| `resources/views/settings/erli.php` | Modified | Add import controls and manual import button. |
|
||||
| `routes/web.php` | Modified | Wire service construction and manual import route. |
|
||||
| `DOCS/DB_SCHEMA.md`, `DOCS/ARCHITECTURE.md`, `DOCS/TECH_CHANGELOG.md` | Modified | Document schema, flow and technical change. |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Use Erli `/inbox` as the primary import source | Inbox is event-driven and aligns with Erli's message processing model. | Phase 129+ can use the same event source for status-related updates. |
|
||||
| ACK only after zero-failure batch | Prevents losing Erli messages when a partial batch fails locally. | Failed messages remain unread for retry. |
|
||||
| Keep status mapping defaults fixed in Phase 128 | User chose recommendation; full configurable mapping belongs to Phase 129. | Import works now, status tuning remains explicit next scope. |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Summary
|
||||
|
||||
| Type | Count | Impact |
|
||||
|------|-------|--------|
|
||||
| Auto-fixed/clarified | 1 | ACK endpoint confirmed and implemented during APPLY. |
|
||||
| Scope additions | 0 | No extra product scope added. |
|
||||
| Deferred | 3 | Environment/live verification only. |
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. Erli ACK endpoint contract**
|
||||
- **Found during:** API client implementation.
|
||||
- **Issue:** Plan intentionally left ACK endpoint verification open.
|
||||
- **Fix:** Confirmed official Erli swagger uses `POST /inbox/mark-read` with `lastMessageId` or `ids`; implemented `lastMessageId`.
|
||||
- **Verification:** API client method and sync path reference checked; live ACK pending real credentials.
|
||||
|
||||
### Deferred Items
|
||||
|
||||
- Run `php bin/migrate.php` and enable Erli import in `/settings/integrations/erli`.
|
||||
- Click `Importuj zamowienia teraz` and confirm `orders.source='erli'` plus no unread messages after clean ACK.
|
||||
- Install/restore PHPUnit tooling and run `tests/Unit/ErliOrderMapperTest.php`; run Sonar when CLI is available.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| `vendor/bin/phpunit` missing | Documented as verification gap; mapper smoke run with PHP runtime. |
|
||||
| `sonar-scanner` missing in PATH | Documented as required-skill gap in STATE. |
|
||||
| Live Erli import not executable without operator DB/API setup | Added explicit follow-up in STATE. |
|
||||
|
||||
## Skill Audit
|
||||
|
||||
| Expected | Invoked | Notes |
|
||||
|----------|---------|-------|
|
||||
| `sonar-scanner` | Gap | CLI unavailable in PATH; gap documented in STATE. |
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- Phase 129 can add configurable Erli pull/push status mapping on top of imported Erli order status fields.
|
||||
- Cron/manual import flow and state cursor are in place.
|
||||
- Payment transition and first-import automation hooks are aligned with existing orderPRO contracts.
|
||||
|
||||
**Concerns:**
|
||||
- Real inbox payload variance may require mapper additions after live smoke.
|
||||
- PHPUnit and Sonar need environment repair for full verification.
|
||||
|
||||
**Blockers:**
|
||||
- None for planning Phase 129.
|
||||
|
||||
---
|
||||
*Phase: 128-erli-orders-import, Plan: 01*
|
||||
*Completed: 2026-05-15*
|
||||
Reference in New Issue
Block a user