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:
@@ -111,6 +111,7 @@ HTTP Request
|
||||
| `AllegroStatusSyncHandler` | Push status changes to Allegro |
|
||||
| `AllegroTokenRefreshHandler` | OAuth token refresh (24h expiry) |
|
||||
| `ShopproOrdersImportHandler` | Fetch new shopPRO orders |
|
||||
| `ErliOrdersImportHandler` | Fetch unread Erli inbox order events |
|
||||
| `ShopproStatusSyncHandler` | Push status to shopPRO |
|
||||
| `ShopproPaymentStatusSyncHandler` | Sync payment statuses |
|
||||
| `ShipmentTrackingHandler` | Poll carrier tracking APIs |
|
||||
@@ -122,7 +123,8 @@ HTTP Request
|
||||
1. **Settings** - `/settings/integrations/erli` stores one global Erli API key encrypted via `IntegrationSecretCipher`, an optional account label, active flag, and last connection-test result.
|
||||
2. **Connection test** - `ErliIntegrationController::test()` loads active credentials, calls `ErliApiClient::testConnection()`, performs a real authenticated `GET https://erli.pl/svc/shop-api/inbox`, and stores the result in `integrations.last_test_*`.
|
||||
3. **Hub** - `IntegrationsHubController::buildErliRow()` adds Erli to `/settings/integrations` with configured/missing secret status, active status, last test timestamp, and configure URL.
|
||||
4. **Deferred** - Phase 127 does not import orders, sync statuses, create labels, or track shipments. Those flows are planned for v3.8 Phases 128-131.
|
||||
4. **Order import** - Phase 128 adds `/settings/integrations/erli/import` and cron `erli_orders_import`. Both call `ErliOrdersSyncService`, which fetches unread `/inbox` messages, maps supported order events through `ErliOrderMapper`, persists via `OrderImportRepository::upsertOrderAggregate()`, emits existing automation events, and acknowledges `POST /inbox/mark-read` only after a zero-failure batch.
|
||||
5. **Deferred** - Phase 128 does not implement status push mappings, label generation, shipment creation, or tracking. Those flows are planned for v3.8 Phases 129-131.
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
@@ -181,13 +183,25 @@ tests/
|
||||
|
||||
### ErliApiClient (`src/Modules/Settings/ErliApiClient.php`)
|
||||
- `testConnection()` wykonuje realny `GET /inbox` do Erli z naglowkiem `Authorization: Bearer ...`.
|
||||
- Phase 128: `fetchInbox()` pobiera do 500 nieprzeczytanych wiadomosci; `markInboxRead()` potwierdza `POST /inbox/mark-read` z `lastMessageId` dopiero po udanym batchu.
|
||||
- Wysyla `Accept: application/json` i `User-Agent: orderPRO/1.0 (erli-integration)`.
|
||||
- Traktuje HTTP 2xx jako sukces; 401/403 jako blad autoryzacji, 429 jako limit zapytan, pozostale bledy jako czytelny komunikat z odpowiedzi.
|
||||
- Uzywa `SslCertificateResolver` i nie wywoluje `curl_close()` (PHP 8.5 compatible).
|
||||
|
||||
### ErliIntegrationController (`src/Modules/Settings/ErliIntegrationController.php`)
|
||||
- Endpointy: `GET /settings/integrations/erli`, `POST /settings/integrations/erli/save`, `POST /settings/integrations/erli/test`.
|
||||
- `save` zapisuje label, aktywnosc i sekret; `test` wykonuje realny test API i zapisuje wynik przez `IntegrationsRepository::updateTestResult()`.
|
||||
- Endpointy: `GET /settings/integrations/erli`, `POST /settings/integrations/erli/save`, `POST /settings/integrations/erli/test`, `POST /settings/integrations/erli/import`.
|
||||
- `save` zapisuje label, aktywnosc, sekret i ustawienia importu (`orders_fetch_enabled`, `orders_fetch_start_date`, interwal crona); `test` wykonuje realny test API i zapisuje wynik przez `IntegrationsRepository::updateTestResult()`.
|
||||
- `importNow()` uruchamia reczny import Erli z pominieciem flagi cron enable, ale nadal wymaga aktywnych credentials.
|
||||
|
||||
### ErliOrdersSyncService / ErliOrderMapper (`src/Modules/Settings/`)
|
||||
- `ErliOrdersSyncService::sync()` jest wspolnym entrypointem dla crona i importu recznego. Zwraca liczniki `processed`, `imported_created`, `imported_updated`, `failed`, `skipped`, `acknowledged`.
|
||||
- Obsluguje tylko zdarzenia order inbox (`orderCreated`, `orderStatusChanged`, `orderSellerStatusChanged`); wiadomosci produktowe sa pomijane do przyszlych faz.
|
||||
- `ErliOrderMapper` mapuje statusy bazowe: `pending -> nieoplacone`, `purchased -> nowe`, `cancelled/returned -> anulowane`. Konfigurowalne pull/push status mappings sa odlozone do Phase 129.
|
||||
- Nowe zamowienia z invoice/company/tax id ustawiają `orders.invoice_requested=1`; re-import korzysta z istniejacego delta-only kontraktu `OrderImportRepository`.
|
||||
- Automatyzacje: `order.imported` dla nowych zamowien i `payment.status_changed` przy tranzycji platnosci na re-imporcie.
|
||||
|
||||
### ErliOrdersImportHandler (`src/Modules/Cron/ErliOrdersImportHandler.php`)
|
||||
- Handler crona `erli_orders_import`, domyslnie seedowany jako disabled. Operator wlacza go z ustawien Erli.
|
||||
|
||||
### IntegrationsHubController
|
||||
- Dodaje wiersz Erli do `/settings/integrations` ze statusem konfiguracji, sekretu, aktywnosci i ostatniego testu.
|
||||
|
||||
@@ -366,6 +366,17 @@ UNIQUE: `(order_id, source_payment_id)`
|
||||
UNIQUE: `(integration_id, shoppro_status_code)`
|
||||
|
||||
**integration_order_sync_state** — Track order fetch progress per integration
|
||||
| Column | Type | Nullable | Notes |
|
||||
|--------|------|----------|-------|
|
||||
| `integration_id` | INT UNSIGNED | NO | PK, FK → integrations(id) CASCADE |
|
||||
| `last_synced_order_updated_at` | DATETIME | YES | Used by Allegro/Erli cursors |
|
||||
| `last_synced_source_order_id` | VARCHAR(64) | YES | Erli stores last acknowledged inbox message id here |
|
||||
| `last_synced_external_order_id` | VARCHAR(128) | YES | Legacy/source-specific cursor |
|
||||
| `last_run_at` | DATETIME | YES | |
|
||||
| `last_success_at` | DATETIME | YES | |
|
||||
| `last_error` | VARCHAR(500) | YES | |
|
||||
| `created_at` | DATETIME | NO | |
|
||||
| `updated_at` | DATETIME | NO | |
|
||||
|
||||
**integration_order_status_sync_state** — Track status sync progress per integration and direction
|
||||
|
||||
@@ -941,6 +952,8 @@ Index: `(status, priority, scheduled_at)`
|
||||
| `created_at` | DATETIME | NO | |
|
||||
| `updated_at` | DATETIME | NO | |
|
||||
|
||||
Seeded recurring jobs include `shoppro_orders_import`, `allegro_orders_import`, `shoppro_order_status_sync`, `shoppro_payment_status_sync`, `allegro_status_sync`, `shipment_tracking_sync`, `automation_history_cleanup`, `order_status_aged`, and `erli_orders_import` (Phase 128; default disabled until Erli order import is enabled).
|
||||
|
||||
---
|
||||
|
||||
## Settings & Configuration
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# Technical Changelog
|
||||
|
||||
## 2026-05-15 - Phase 128 Plan 01: Erli Orders Import
|
||||
|
||||
**Co zrobiono:**
|
||||
- Dodano migracje `20260515_000115_add_erli_orders_import_schedule.sql`, ktora zapewnia kolumny kursora w `integration_order_sync_state` i seeduje `cron_schedules.job_type='erli_orders_import'` jako disabled.
|
||||
- Rozszerzono ustawienia Erli o wlaczenie importu zamowien, date startu, interwal crona oraz reczna akcje `POST /settings/integrations/erli/import`.
|
||||
- Rozszerzono `ErliApiClient` o `fetchInbox()` (`GET /inbox`) oraz bezpieczny ACK `markInboxRead()` (`POST /inbox/mark-read`, body `lastMessageId`) potwierdzony z oficjalnego swaggera Erli.
|
||||
- Dodano `ErliOrderMapper`, `ErliOrderSyncStateRepository`, `ErliOrdersSyncService` i `ErliOrdersImportHandler`.
|
||||
- Import wspiera zdarzenia `orderCreated`, `orderStatusChanged`, `orderSellerStatusChanged`, zapisuje order aggregate przez `OrderImportRepository`, ustawia `invoice_requested` przy danych firmowych/NIP, zapisuje activity log i emituje `order.imported` oraz `payment.status_changed`.
|
||||
- Dodano testy jednostkowe `tests/Unit/ErliOrderMapperTest.php`.
|
||||
|
||||
**Dlaczego:**
|
||||
- Erli ma zaczac realnie dostarczac zamowienia do orderPRO po fundamencie konfiguracji z Phase 127.
|
||||
- `/inbox` jest rekomendowanym zrodlem zdarzen Erli; ACK jest wykonywany dopiero po bezblednym batchu, zeby nie zgubic zamowien przy czesciowej awarii.
|
||||
|
||||
**BREAKING / migracja:**
|
||||
- Brak breaking changes. Nowy cron jest domyslnie wylaczony do czasu wlaczenia importu w ustawieniach Erli.
|
||||
- Manual smoke po wdrozeniu: `php bin/migrate.php`, zapis aktywnej konfiguracji Erli, wlaczenie importu, klik `Importuj zamowienia teraz`, kontrola `orders.source='erli'` i licznikow importu.
|
||||
|
||||
## 2026-05-15 - Phase 127 Plan 01: Erli Integration Foundation
|
||||
|
||||
**Co zrobiono:**
|
||||
|
||||
Reference in New Issue
Block a user