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
15 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
| phase | plan | type | wave | depends_on | files_modified | autonomous | delegation | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 128-erli-orders-import | 01 | execute | 1 |
|
true | auto |
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.
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/jsonand a meaningfulUser-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:
pendingmeans unpaid PayU;purchasedmeans paid PayU or COD;cancelledmeans 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.
| Skill / Tool | Priority | When to Invoke | Loaded? |
|---|---|---|---|
sonar-scanner |
required | After APPLY, before UNIFY | o |
Optional Flows
/feature-devoptional before implementation of this marketplace feature./code-reviewoptional after implementation, before UNIFY.
<acceptance_criteria>
AC-1: Import Configuration And Cron
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
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
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
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
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
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>
Task 1: Add Erli import controls, schedule and entry points 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 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()`. `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` AC-1 satisfied: Erli import can be enabled, scheduled, and manually triggered from settings. Task 2: Implement Erli inbox client, mapper and sync service 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 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. `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` AC-2, AC-3, AC-4 and AC-5 satisfied for the runtime import path. Task 3: Add mapper tests and update technical docs tests/Unit/ErliOrderMapperTest.php, DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md 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. `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. AC-6 satisfied: tests and documentation describe the new Erli import behavior and remaining live-smoke steps.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_REMOTEin 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.importedandpayment.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.
<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>