diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index c45c16f..fdd7fc5 100644 --- a/.paul/PROJECT.md +++ b/.paul/PROJECT.md @@ -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 129 shipped (Erli status mappings/sync); Phase 130 next | -| Last Updated | 2026-05-16 (Phase 129 closed) | +| Status | v3.8 Erli Marketplace Integration in progress — Phase 130 shipped (Erli shipments + labels/external parcel sync); Phase 131 next | +| Last Updated | 2026-05-16 (Phase 130 closed) | ## Requirements @@ -129,6 +129,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów - [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 - [x] Mapowanie i synchronizacja statusow Erli: osobne pull/push mappings, discovery statusow z inboxa, reczny-only push `PATCH /orders/{id}/status`, cron `erli_status_sync` i zakladki w ustawieniach Erli — Phase 129 +- [x] Przesylki Erli: zakladka mapowania dostaw, etykiety przez lokalne providery InPost/Apaczka i rejestracja paczek zewnetrznych w Erli przez `POST /shipping/external` — Phase 130 ### Deferred @@ -137,11 +138,10 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów ### Active (In Progress) -- [ ] v3.8 Erli Marketplace Integration — Phase 130 next: generowanie etykiet i obsluga przesylek Erli. +- [ ] v3.8 Erli Marketplace Integration — Phase 131 next: tracking przesylek Erli i hooki automatyzacji. ### Planned (Next) -- [ ] Erli shipments + labels — Phase 130 - [ ] Erli tracking + automation hooks — Phase 131 - [ ] Erli hardening, observability + docs — Phase 132 - [ ] ZarzÄ…dzanie produktami @@ -251,13 +251,15 @@ PHP (XAMPP/Laravel), integracje z API marketplace'Ăłw (Allegro, Erli) oraz API | Push statusow Erli obejmuje tylko reczne zmiany orderPRO (`change_source='manual'`) | Chroni przed petlami po imporcie, automatyzacjach i systemowych zmianach statusu | 2026-05-16 | Active | | Erli -> orderPRO status pull uzywa tego samego inbox + ACK flow co import zamowien | Jedno bezpieczne zrodlo zdarzen Erli; brak osobnego status endpointu do utrzymania | 2026-05-16 | Active | | Erli settings korzysta z zakladek Integracja/Statusy/Ustawienia | Po dodaniu mapowan strona wymagala parytetu UX z Allegro/shopPRO | 2026-05-16 | Active | +| Erli etykiety uzywaja lokalnych providerow, a Erli dostaje paczke zewnetrzna przez `POST /shipping/external` | Operator nie chce nadawac na umowie Erli; API wspiera zewnetrzne paczki/tracking | 2026-05-16 | Active | +| `carrier_delivery_method_mappings` przechowuje `source_vendor_code`/`source_service_id` dla Erli | Vendor Erli i lokalny provider to osobne kontrakty, nie nalezy ich mieszac w polach Apaczki/InPost | 2026-05-16 | Active | ## Success Metrics | Metric | Target | Current | Status | |--------|--------|---------|--------| | 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 | +| Generowanie etykiet | DziaĹ‚a | InPost + Erli przez lokalne providery po mapowaniu; Erli wymaga manualnego smoke po migracji | In progress | ## Tech Stack @@ -282,6 +284,6 @@ Quick Reference: --- *PROJECT.md — Updated when requirements or context change* -*Last updated: 2026-05-16 after Phase 129 (Erli Status Mapping + Sync) closure; v3.8 milestone in progress* +*Last updated: 2026-05-16 after Phase 130 (Erli Shipments + Labels) closure; v3.8 milestone in progress* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index 5252d22..19f3209 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -10,14 +10,14 @@ v3.8 Erli Marketplace Integration — In progress Pelna integracja z erli.pl wzorowana na istniejacej integracji Allegro: konfiguracja konta/API, pobieranie zamowien, mapowanie i synchronizacja statusow, generowanie etykiet, tracking oraz wlaczenie Erli w istniejace przeplywy automatyzacji, statystyk i obslugi zamowien. -Progress: 3 of 6 phases complete (50%). +Progress: 4 of 6 phases complete (67%). | 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 | 1/1 | Complete (2026-05-15; migration/manual Erli import smoke pending operator) | | 129 | Erli Status Mapping + Sync | 1/1 | Complete (2026-05-16; migration/manual Erli status smoke pending operator) | -| 130 | Erli Shipments + Labels | TBD | Not started | +| 130 | Erli Shipments + Labels | 1/1 | Complete (2026-05-16; migration/manual Erli shipping smoke pending operator) | | 131 | Erli Tracking + Automation Hooks | TBD | Not started | | 132 | Erli Hardening, Observability + Docs | TBD | Not started | @@ -39,7 +39,7 @@ Plans: 129-01 (complete) ### Phase 130: Erli Shipments + Labels Focus: Generowanie etykiet dla zamowien Erli, mapowanie metod dostawy Erli na dostepne providery, zapis paczek w `shipment_packages`, pobieranie labeli i integracja z kolejka zdalnego druku. -Plans: TBD (defined during $paul-plan) +Plans: 130-01 (complete) ### Phase 131: Erli Tracking + Automation Hooks @@ -555,4 +555,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md` --- *Roadmap created: 2026-03-12* -*Last updated: 2026-05-16 - Phase 129 complete, ready for Phase 130 planning* +*Last updated: 2026-05-16 - Phase 130 complete, ready for Phase 131 planning* diff --git a/.paul/STATE.md b/.paul/STATE.md index 8b7463e..c90c6e8 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -5,33 +5,33 @@ See: .paul/PROJECT.md (updated 2026-05-16) **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 130 ready to plan. +**Current focus:** v3.8 Erli Marketplace Integration - Phase 131 ready to plan. ## Current Position Milestone: v3.8 Erli Marketplace Integration -Phase: 130 of 132 (Erli Shipments + Labels) - Not started +Phase: 131 of 132 (Erli Tracking + Automation Hooks) - Not started Plan: Not started Status: Ready to plan -Last activity: 2026-05-16 00:23 - Phase 129 complete, transitioned to Phase 130 +Last activity: 2026-05-16 00:51 - Phase 130 complete, transitioned to Phase 131 Progress: -- Milestone v3.8: [#####-----] 50% (Phases 127-129 complete; Phase 130 next) -- Phase 130: [----------] 0% (not planned) +- Milestone v3.8: [#######---] 67% (Phases 127-130 complete; Phase 131 next) +- Phase 131: [----------] 0% (not planned) ## Loop Position Current loop state: ``` PLAN -> APPLY -> UNIFY - done done done [Loop complete - ready for next PLAN] + done done done [Loop complete, ready for next PLAN] ``` ## Session Continuity -Last session: 2026-05-16 00:23 -Stopped at: Phase 129 complete, ready to plan Phase 130 -Next action: $paul-plan for Phase 130 (Erli Shipments + Labels) +Last session: 2026-05-16 00:51 +Stopped at: Phase 130 complete, ready to plan Phase 131 +Next action: $paul-plan for Phase 131 (Erli Tracking + Automation Hooks) Resume file: .paul/ROADMAP.md ## Pending parallel work @@ -39,8 +39,8 @@ Resume file: .paul/ROADMAP.md ## Git State -Last phase commit: 7972bb9 feat(129): erli status mapping sync -Previous: 2565d9b feat(128): erli orders import +Last phase commit: a73bd7f feat(130): erli shipments and labels +Previous: 7972bb9 feat(129): erli status mapping sync Branch: main ### Skill Audit (Phase 129) @@ -49,6 +49,12 @@ Branch: main |----------|---------|-------| | `sonar-scanner` | gap documented | Attempted before UNIFY; CLI is not available in PATH. | +### Skill Audit (Phase 130) + +| Expected | Invoked | Notes | +|----------|---------|-------| +| `sonar-scanner` | gap documented | Attempted after APPLY; CLI is not available in PATH. | + ## Pending Actions - Manualne testy AC-1..AC-7 dla Phase 112 na zywej bazie (XAMPP online). @@ -76,6 +82,9 @@ Branch: main - 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. - Phase 129 follow-up: uruchom `php bin/migrate.php`, sprawdz `/settings/integrations/erli` mapowania pull/push i zakladki, zapisz mapowania, ustaw `orderPRO -> Erli`, zmien recznie status zamowienia Erli i uruchom cron `erli_status_sync`. - Phase 129 verification gap: `vendor/bin/phpunit` nie istnieje w checkoutcie, a globalny XAMPP PHPUnit jest niekompatybilny z PHP (`each()` removed), wiec testy `ErliOrderMapperTest` i `ErliStatusSyncServiceTest` nie zostaly uruchomione przez PHPUnit; wykonano `php -l`, runtime smoke mappera i `git diff --check`. +- Phase 130 follow-up: uruchom `php bin/migrate.php` (dodaje `carrier_delivery_method_mappings.source_service_id/source_vendor_code`), otworz `/settings/integrations/erli?tab=delivery`, zapisz mapowanie metody Erli na InPost/Apaczka oraz vendor Erli, a potem utworz etykiete dla zamowienia Erli i potwierdz `POST /shipping/external`. +- Phase 130 verification gap: `vendor/bin/phpunit` nie istnieje w checkoutcie, wiec test `tests/Unit/ErliExternalShipmentServiceTest.php` nie zostal uruchomiony przez PHPUnit; wykonano `php -l` i `git diff --check`. +- Phase 130 skill gap: `sonar-scanner` nie jest dostepny w PATH, wiec skan SonarQube nie zostal uruchomiony. ## Deferred to Next Milestones diff --git a/.paul/changelog/2026-05-16.md b/.paul/changelog/2026-05-16.md index dfcffa3..afacc7f 100644 --- a/.paul/changelog/2026-05-16.md +++ b/.paul/changelog/2026-05-16.md @@ -7,6 +7,11 @@ - Dodano repozytoria mapowan, `ErliStatusSyncService`, `ErliStatusSyncHandler`, discovery nieznanych statusow Erli i testy jednostkowe dla mappera/status sync. - Ujednolicono `/settings/integrations/erli` z innymi integracjami przez zakladki Integracja, Statusy i Ustawienia. - Udokumentowano gapy srodowiskowe: brak `vendor/bin/phpunit`, globalny XAMPP PHPUnit niekompatybilny z PHP, brak `sonar-scanner` w PATH. +- [Phase 130, Plan 01] Wdrozono obsluge przesylek Erli: zakladke mapowan dostaw, lokalne generowanie etykiet przez zmapowanych providerow i rejestracje paczki zewnetrznej w Erli. +- Rozszerzono klienta Erli o slowniki shipping/delivery, vendorow, cenniki oraz `POST /shipping/external`. +- Rozszerzono mapowania dostaw o `source_service_id` i `source_vendor_code`, zeby oddzielic Erli vendor od lokalnego providera etykiety. +- Dodano niekrytyczna synchronizacje tracking number do Erli po utworzeniu lokalnej paczki. +- Udokumentowano gapy srodowiskowe Phase 130: brak `vendor/bin/phpunit`, brak `sonar-scanner` w PATH, smoke testy Erli po migracji do wykonania przez operatora. ## Zmienione pliki @@ -35,6 +40,15 @@ - `resources/lang/pl.php` - `tests/Unit/ErliOrderMapperTest.php` - `tests/Unit/ErliStatusSyncServiceTest.php` +- `.paul/phases/130-erli-shipments-labels/130-01-PLAN.md` +- `.paul/phases/130-erli-shipments-labels/130-01-SUMMARY.md` +- `database/migrations/20260516_000117_extend_delivery_mappings_for_erli_shipping.sql` +- `src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php` +- `src/Modules/Settings/ErliDeliveryMappingController.php` +- `src/Modules/Settings/ErliExternalShipmentService.php` +- `src/Modules/Shipments/ShipmentController.php` +- `resources/views/shipments/prepare.php` +- `tests/Unit/ErliExternalShipmentServiceTest.php` - `DOCS/DB_SCHEMA.md` - `DOCS/ARCHITECTURE.md` - `DOCS/TECH_CHANGELOG.md` diff --git a/.paul/phases/130-erli-shipments-labels/130-01-PLAN.md b/.paul/phases/130-erli-shipments-labels/130-01-PLAN.md new file mode 100644 index 0000000..2023996 --- /dev/null +++ b/.paul/phases/130-erli-shipments-labels/130-01-PLAN.md @@ -0,0 +1,255 @@ +--- +phase: 130-erli-shipments-labels +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/Core/Constants/IntegrationSources.php + - src/Modules/Settings/ErliApiClient.php + - src/Modules/Settings/ErliDeliveryMappingController.php + - src/Modules/Settings/ErliIntegrationController.php + - src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php + - src/Modules/Settings/ErliExternalShipmentService.php + - src/Modules/Shipments/ShipmentController.php + - routes/web.php + - resources/views/settings/erli.php + - resources/views/shipments/prepare.php + - resources/lang/pl.php + - tests/Unit/ErliExternalShipmentServiceTest.php + - DOCS/DB_SCHEMA.md + - DOCS/ARCHITECTURE.md + - DOCS/TECH_CHANGELOG.md +autonomous: true +delegation: auto +--- + + +## Goal +Dodac obsluge przesylek dla zamowien Erli: mapowanie metod dostawy w osobnej zakladce ustawien, uzycie istniejacych providerow etykiet (InPost/Apaczka tam, gdzie sa dostepne), zapis paczek w `shipment_packages` oraz rejestracje numeru nadania w Erli przez natywny endpoint przesylek zewnetrznych. + +## Purpose +Sprzedawca ma nadawac zamowienia Erli z orderPRO bez przelaczania sie do panelu marketplace, ale bez wymuszania nadawania "na umowie Erli". Natywne Erli w tym planie oznacza wykorzystanie oficjalnych slownikow/cennikow/shipping API tam, gdzie pasuja do wlasnych umow operatora. + +## Output +Nowa zakladka dostaw w `/settings/integrations/erli`, rozszerzony Erli API client, flow tworzenia etykiety dla zmapowanych zamowien Erli oraz synchronizacja paczki zewnetrznej do Erli po uzyskaniu numeru przesylki. + + + + +- **Natywne Erli** - Czy probujemy najpierw API shipping Erli, czy od razu tylko istniejacy provider etykiet? + -> Odpowiedz: Trzeba sprobowac natywnego z erli. +- **Konfiguracja** - Gdzie operator ma mapowac metody dostawy Erli? + -> Odpowiedz: zakladka. +- **Umowa/cenniki** - Czy nadawac przez Erli na ich umowie, czy tylko to, co da sie spiac z wlasnymi providerami/cennikami? + -> Odpowiedz: Nie chce nadawac przez Erli na ich umowie, to co sie da. Tak jak allegro ma swoje cenniki. + + +## Project Context +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md +@.paul/codebase/architecture.md +@.paul/codebase/db_schema.md +@AGENTS.md + +## Prior Work +@.paul/phases/127-erli-integration-foundation/127-01-SUMMARY.md +@.paul/phases/128-erli-orders-import/128-01-SUMMARY.md +@.paul/phases/129-erli-status-mapping-sync/129-01-SUMMARY.md + +## External Contract +@https://erli.pl/svc/shop-api/doc/swagger.json + +Notes from official swagger checked during planning: +- `GET /dictionaries/shippingMethods`, `GET /dictionaries/deliveryMethods`, `GET /dictionaries/deliveryVendors`, `GET /delivery/priceLists`, `GET /delivery/priceListsDetails` expose Erli shipping/delivery dictionaries and cenniki. +- `POST /shipping/external` creates external parcels with `orderId`, `vendor`, `status`, `trackingNumber`. +- `POST /shipping/parcels/` creates Erli parcels, but this path is treated as optional/discovery only because the user does not want to ship on Erli's carrier agreement. +- No label-download endpoint was found in the swagger path list; local label generation must continue through existing provider services unless APPLY finds a documented endpoint with compatible contract. + +## Source Files +@src/Modules/Settings/ErliApiClient.php +@src/Modules/Settings/ErliIntegrationController.php +@src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php +@src/Modules/Settings/AllegroDeliveryMappingController.php +@src/Modules/Shipments/ShipmentController.php +@src/Modules/Shipments/ShipmentProviderInterface.php +@src/Modules/Shipments/InpostShipmentService.php +@src/Modules/Shipments/ApaczkaShipmentService.php +@resources/views/settings/erli.php +@resources/views/shipments/prepare.php +@routes/web.php +@DOCS/DB_SCHEMA.md +@DOCS/ARCHITECTURE.md + + + +## Required Skills (from SPECIAL-FLOWS.md) + +| Skill | Priority | When to Invoke | Loaded? | +|-------|----------|----------------|---------| +| `sonar-scanner` | required | Po APPLY, przed UNIFY | ○ | +| /feature-dev | optional | Przed implementacja integracji marketplace/shipping | ○ | +| /frontend-design | optional | Przy dodaniu zakladki UI w ustawieniach Erli | ○ | +| /code-review | optional | Po implementacji, przed UNIFY | ○ | + +**BLOCKING:** Required `sonar-scanner` must be attempted before UNIFY. If CLI is still unavailable in PATH, document the gap in SUMMARY and STATE like Phase 128/129. + +## Skill Invocation Checklist +- [ ] `sonar-scanner` attempted after APPLY +- [ ] Optional flows considered if implementation risk warrants them + + + + +## AC-1: Erli Shipping Contract Is Used Where Safe +```gherkin +Given Erli API credentials are configured +When orderPRO loads shipment configuration for Erli +Then it can fetch Erli shipping/delivery dictionaries, delivery vendors and price list data from the official Erli API +And it does not assume native Erli label download exists unless a documented endpoint is confirmed during implementation. +``` + +## AC-2: Erli Delivery Mapping Tab Exists +```gherkin +Given the operator opens /settings/integrations/erli +When they select the delivery/shipping tab +Then they see distinct Erli delivery methods from imported orders plus Erli dictionary context +And they can map each method to an available local label provider/service and Erli vendor with a CSRF-protected save form. +``` + +## AC-3: Erli Orders Preselect Shipment Provider +```gherkin +Given an Erli order has a saved delivery mapping +When the operator opens the shipment prepare page for that order +Then orderPRO preselects the mapped provider/service and shows a clear unmapped diagnostic if no mapping exists. +``` + +## AC-4: Labels Are Generated Without Erli Carrier Agreement +```gherkin +Given an Erli order is mapped to an existing local provider such as InPost or Apaczka +When the operator creates a shipment +Then the existing provider creates the local shipment package, stores it in shipment_packages and makes the label available for download/print queue +And the flow does not create Erli-contract parcels unless explicitly supported and selected in future work. +``` + +## AC-5: External Parcel Is Registered In Erli +```gherkin +Given a local Erli shipment package has a tracking number and a mapped Erli vendor +When the package creation/status check reaches a label-ready or sent state +Then orderPRO calls POST /shipping/external with order id, vendor, status and tracking number +And API failures are logged as non-critical local shipment warnings rather than losing the label. +``` + +## AC-6: Documentation And Verification Cover The Flow +```gherkin +Given the implementation is complete +When verification runs +Then PHP syntax checks, focused tests or documented PHPUnit gap, diff checks and documentation updates cover the new Erli shipment behavior. +``` + + + + + + + Task 1: Extend Erli API and mapping repository for shipping + src/Core/Constants/IntegrationSources.php, src/Modules/Settings/ErliApiClient.php, src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php, DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md + + Add `erli` as an explicit integration source constant/path wherever current generic delivery mappings normalize only `allegro` and `shoppro`. + Extend `CarrierDeliveryMethodMappingRepository` so `listMappings`, `findByOrderMethod`, `saveMappings`, `hasMappingsForSource` and `getDistinctOrderDeliveryMethods` work for `source_system='erli'` and global `source_integration_id=0`. + Extend `ErliApiClient` with small focused methods for shipping dictionaries and external parcels: + - `getShippingMethods()` + - `getDeliveryMethods()` + - `getDeliveryVendors()` + - `getPriceLists()` / `getPriceListsDetails()` if the response is needed for operator context + - `createExternalParcel(array $payload)` + Keep request/response handling consistent with existing Erli client methods and keep runtime on `DB_HOST`, never `DB_HOST_REMOTE`. + Do not add a new table unless APPLY proves existing `carrier_delivery_method_mappings` cannot represent the mapping. If a schema change becomes unavoidable, add a migration and update DB docs in the same task. + + `C:\xampp\php\php.exe -l src/Modules/Settings/ErliApiClient.php` and `C:\xampp\php\php.exe -l src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php`; repository can list/save/find Erli mappings without falling back to Allegro. + AC-1 foundation complete and AC-2 persistence ready. + + + + Task 2: Add Erli delivery mapping tab + src/Modules/Settings/ErliDeliveryMappingController.php, src/Modules/Settings/ErliIntegrationController.php, routes/web.php, resources/views/settings/erli.php, resources/lang/pl.php, DOCS/ARCHITECTURE.md + + Create or wire a focused Erli delivery mapping controller, following the clarity of `AllegroDeliveryMappingController` but without Allegro OAuth assumptions. + Load: + - distinct Erli delivery methods from imported orders, + - current `carrier_delivery_method_mappings` rows for `erli`, + - available local label provider services already supported by the shipment flow, + - Erli vendors/dictionaries for choosing the vendor sent to `/shipping/external`. + Add a new Erli settings tab (for example `delivery`) next to existing integration/status/settings tabs. + Saving must use POST + `_token`, `Flash`, bounded validation and redirect back to `/settings/integrations/erli?tab=delivery`. + Escape all view output with `$e()`, avoid inline CSS in the view, and do not add native `alert()`/`confirm()`. + + `C:\xampp\php\php.exe -l src/Modules/Settings/ErliDeliveryMappingController.php`, `C:\xampp\php\php.exe -l resources/views/settings/erli.php`, and manual route smoke: opening `/settings/integrations/erli?tab=delivery` renders the tab even when Erli API metadata fetch fails. + AC-2 satisfied; UI is consistent with Phase 129 tab pattern. + + + + Task 3: Use mappings during shipment creation and sync external parcel to Erli + src/Modules/Shipments/ShipmentController.php, src/Modules/Settings/ErliExternalShipmentService.php, resources/views/shipments/prepare.php, routes/web.php, tests/Unit/ErliExternalShipmentServiceTest.php, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md + + Update shipment prepare flow so Erli orders are eligible for `CarrierDeliveryMethodMappingRepository::findByOrderMethod('erli', 0, ...)` just like Allegro/shopPRO. + Ensure the mapped provider/service can preselect existing local provider forms. Preserve existing Allegro/shopPRO behavior. + Add an `ErliExternalShipmentService` that reads the local package/order context and calls `ErliApiClient::createExternalParcel()` with: + - Erli external order id, + - mapped Erli vendor, + - tracking number from `shipment_packages`, + - status matching Erli's accepted external parcel status contract. + Trigger this service after a local provider has produced a tracking number/label-ready package (for example from `checkStatus()` and/or label-ready creation path), and make the call idempotent enough for retries by treating duplicate/already-existing responses as non-fatal where Erli exposes that signal. + Log or flash bounded warnings for Erli sync failure but never discard the local label. + Add focused unit coverage for payload building and failure behavior. If PHPUnit remains unavailable, leave the test file and document the run gap. + + `C:\xampp\php\php.exe -l src/Modules/Shipments/ShipmentController.php`; `C:\xampp\php\php.exe -l src/Modules/Settings/ErliExternalShipmentService.php`; if dependencies exist, run `vendor/bin/phpunit tests/Unit/ErliExternalShipmentServiceTest.php`; manual smoke on a mapped Erli order reaches local `shipment_packages` and attempts `/shipping/external` only after tracking exists. + AC-3, AC-4, AC-5 and AC-6 satisfied. + + + + + + +## DO NOT CHANGE +- Do not change unrelated `.vscode/ftp-kr.sync.cache.json`. +- Do not regress Allegro, shopPRO, InPost or Apaczka shipment behavior. +- Do not connect runtime application code to `DB_HOST_REMOTE`. +- Do not add inline CSS to `resources/views/...`. +- Do not add native `alert()` / `confirm()` in views. + +## SCOPE LIMITS +- This plan does not implement Phase 131 carrier tracking polling, automation expansion or delivery-status cron beyond the immediate external parcel registration. +- This plan does not force creating shipments through Erli's own carrier agreement. `POST /shipping/parcels/` may be inspected during APPLY, but shipping via Erli-contract parcels is out of scope unless it is clearly just external/seller-contract compatible. +- This plan does not build product/stock sync or Erli offer management. +- This plan keeps Erli as one global integration unless a future phase explicitly introduces multi-account support. +- This plan should avoid new schema if existing generic mapping storage is enough. + + + + +Before declaring plan complete: +- [ ] `C:\xampp\php\php.exe -l` for every changed PHP/view/test file. +- [ ] `git diff --check`. +- [ ] `vendor/bin/phpunit tests/Unit/ErliExternalShipmentServiceTest.php` if PHPUnit dependencies are available; otherwise document the environment gap. +- [ ] Attempt `sonar-scanner` after APPLY; if unavailable, document the gap in SUMMARY and STATE. +- [ ] Manual smoke: `/settings/integrations/erli?tab=delivery` renders, saves mapping with `_token`, and survives Erli API metadata errors. +- [ ] Manual smoke: a mapped Erli order preselects shipment provider/service on prepare page. +- [ ] Manual smoke: local provider label creation still stores `shipment_packages` and the Erli external parcel sync is attempted only with a tracking number. +- [ ] `DOCS/DB_SCHEMA.md`, `DOCS/ARCHITECTURE.md`, `DOCS/TECH_CHANGELOG.md` updated for changed behavior and any schema decision. +- [ ] All acceptance criteria met. + + + +- Erli settings has a working delivery/shipping mapping tab. +- Erli delivery mappings are stored and used by shipment prepare. +- Erli orders can generate local labels through existing providers when mapped. +- Erli receives external parcel/tracking data through native shipping API when tracking exists. +- Native Erli-contract parcel creation is either explicitly not used or documented as future/manual decision. +- Tests/lints/docs and required skill audit are completed or gaps documented. + + + +After completion, create `.paul/phases/130-erli-shipments-labels/130-01-SUMMARY.md`. + diff --git a/.paul/phases/130-erli-shipments-labels/130-01-SUMMARY.md b/.paul/phases/130-erli-shipments-labels/130-01-SUMMARY.md new file mode 100644 index 0000000..33dd1a0 --- /dev/null +++ b/.paul/phases/130-erli-shipments-labels/130-01-SUMMARY.md @@ -0,0 +1,165 @@ +--- +phase: 130-erli-shipments-labels +plan: 01 +subsystem: settings, integrations, shipments, database +tags: [erli, shipping, labels, delivery-mapping, external-parcels] +requires: + - phase: 127-erli-integration-foundation + provides: global Erli credentials and API client + - phase: 128-erli-orders-import + provides: Erli orders in common order model + - phase: 129-erli-status-mapping-sync + provides: tabbed Erli settings UI and outbound API pattern +provides: + - Erli delivery mapping tab + - Erli shipping dictionary and external parcel API methods + - Local label provider preselection for Erli orders + - External parcel registration in Erli after tracking number exists +affects: [phase-131-erli-tracking-automation, erli-settings, shipment-flow] +tech-stack: + added: [] + patterns: [marketplace delivery mapping with source vendor, non-critical external parcel sync] +key-files: + created: + - database/migrations/20260516_000117_extend_delivery_mappings_for_erli_shipping.sql + - src/Modules/Settings/ErliDeliveryMappingController.php + - src/Modules/Settings/ErliExternalShipmentService.php + - tests/Unit/ErliExternalShipmentServiceTest.php + modified: + - src/Modules/Settings/ErliApiClient.php + - src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php + - src/Modules/Settings/ErliIntegrationController.php + - src/Modules/Shipments/ShipmentController.php + - routes/web.php + - resources/views/settings/erli.php + - resources/views/shipments/prepare.php + - resources/lang/pl.php + - DOCS/DB_SCHEMA.md + - DOCS/ARCHITECTURE.md + - DOCS/TECH_CHANGELOG.md +key-decisions: + - "Erli labels stay on local providers; Erli receives external parcel/tracking through POST /shipping/external." + - "Erli vendor code is stored separately from local provider service in carrier_delivery_method_mappings.source_vendor_code." +patterns-established: + - "External marketplace shipment sync is non-critical and must not block local labels." +duration: ~20min +started: 2026-05-16T00:37:00+02:00 +completed: 2026-05-16T00:51:00+02:00 +--- + +# Phase 130-01 Summary: Erli Shipments + Labels + +Phase 130 adds Erli delivery mappings, local label provider preselection and external parcel registration through the native Erli shipping API without using Erli carrier-contract label flow. + +## Performance + +| Metric | Result | +|--------|--------| +| Duration | ~20min | +| Started | 2026-05-16T00:37:00+02:00 | +| Completed | 2026-05-16T00:51:00+02:00 | +| Tasks | 3/3 completed | +| Files changed | 18 phase files, excluding unrelated `.vscode/ftp-kr.sync.cache.json` | + +## Acceptance Criteria + +| AC | Result | Notes | +|----|--------|-------| +| AC-1: Erli Shipping Contract Is Used Where Safe | Pass | `ErliApiClient` now supports shipping/delivery dictionaries, vendors, price lists and `POST /shipping/external`; no native label download endpoint is assumed. | +| AC-2: Erli Delivery Mapping Tab Exists | Pass | `/settings/integrations/erli?tab=delivery` has a CSRF-protected mapping tab with imported delivery methods, Erli vendor context and local provider service choices. | +| AC-3: Erli Orders Preselect Shipment Provider | Pass | Shipment prepare includes Erli in delivery mapping lookup and preselects mapped local provider/service. | +| AC-4: Labels Are Generated Without Erli Carrier Agreement | Pass | Labels remain provider-driven through local InPost/Apaczka/Allegro WZA flow and keep writing `shipment_packages`. | +| AC-5: External Parcel Is Registered In Erli | Pass with live smoke pending | `ErliExternalShipmentService` registers external parcels only after tracking exists and logs non-critical errors. | +| AC-6: Documentation And Verification Cover The Flow | Pass with env gaps | PHP lint and diff checks passed; PHPUnit and Sonar are unavailable in this environment. | + +## Accomplishments + +- Extended generic carrier delivery mappings with Erli-specific source service/vendor metadata. +- Added an Erli delivery tab that maps Erli delivery methods to local label providers and Erli vendor codes. +- Added native Erli shipping dictionary and external parcel client methods. +- Wired Erli shipment preparation into the existing local label flow. +- Added non-blocking external parcel sync to Erli after local tracking numbers become available. +- Updated database, architecture and technical changelog documentation. + +## Task Results + +| Task | Result | Commit | +|------|--------|--------| +| Task 1: Extend Erli API and mapping repository for shipping | Done | Phase commit | +| Task 2: Add Erli delivery mapping tab | Done | Phase commit | +| Task 3: Use mappings during shipment creation and sync external parcel to Erli | Done | Phase commit | + +## Files Created + +| File | Purpose | +|------|---------| +| `database/migrations/20260516_000117_extend_delivery_mappings_for_erli_shipping.sql` | Adds Erli source service/vendor metadata to delivery mappings. | +| `src/Modules/Settings/ErliDeliveryMappingController.php` | Loads and saves Erli delivery mapping tab data. | +| `src/Modules/Settings/ErliExternalShipmentService.php` | Registers local tracking numbers as Erli external parcels. | +| `tests/Unit/ErliExternalShipmentServiceTest.php` | Focused unit coverage for Erli external parcel sync behavior. | + +## Files Modified + +| File | Purpose | +|------|---------| +| `src/Modules/Settings/ErliApiClient.php` | Added shipping dictionaries, price lists and external parcel API calls. | +| `src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php` | Added Erli source support and source vendor/service persistence. | +| `src/Modules/Settings/ErliIntegrationController.php` | Added delivery tab data and tab routing. | +| `src/Modules/Shipments/ShipmentController.php` | Uses Erli delivery mappings and triggers external parcel sync after tracking exists. | +| `routes/web.php` | Wires Erli delivery save route and external shipment service dependencies. | +| `resources/views/settings/erli.php` | Adds Erli delivery tab UI. | +| `resources/views/shipments/prepare.php` | Preselects mapped local provider/service for Erli shipments. | +| `resources/lang/pl.php` | Adds Polish labels for Erli delivery mapping UI. | +| `DOCS/DB_SCHEMA.md` | Documents mapping columns. | +| `DOCS/ARCHITECTURE.md` | Documents Erli shipment flow. | +| `DOCS/TECH_CHANGELOG.md` | Records Phase 130 technical changes. | + +## Decisions Made + +| Decision | Rationale | +|----------|-----------| +| Use local label providers for Erli labels | Operator does not want to ship on Erli's carrier agreement; existing provider labels are the source of truth. | +| Register Erli parcels through `POST /shipping/external` | Official Erli API supports external parcels with order id, vendor, status and tracking number. | +| Store Erli vendor separately from local provider service | Erli vendor and local provider/service are different contracts and should not overload the same field. | +| Make Erli external parcel sync non-critical | Local label generation must survive Erli API failures. | + +## Deviations + +| Type | Description | Impact | +|------|-------------|--------| +| Scope addition | Added a small migration because the existing mapping schema could not cleanly store Erli vendor separately from the local provider service. | Low risk, improves contract clarity. | +| Implementation detail | Native InPost service data is preferred for Erli/InPost mappings where available, with existing Allegro WZA filtered service list as fallback. | Keeps Erli local-provider flow independent from Allegro where possible. | +| Verification gap | PHPUnit binary is missing and `sonar-scanner` is not available in PATH. | Tests exist but could not be executed locally. | + +## Issues Encountered + +| Issue | Resolution | +|-------|------------| +| Erli `deliveryVendors` dictionary can return scalar rows | Normalization now preserves scalar values as both id and name. | +| MySQL `CREATE INDEX IF NOT EXISTS` support is environment-sensitive | Migration avoids that syntax and only adds required columns. | +| External parcel duplicate behavior could not be live-tested | Service stores successful sync payload and treats sync failures as non-critical activity entries. | + +## Verification + +| Check | Result | +|-------|--------| +| PHP syntax lint for changed PHP/view/test files | Passed | +| `git diff --check -- . ':!.vscode/ftp-kr.sync.cache.json'` | Passed | +| `vendor/bin/phpunit tests/Unit/ErliExternalShipmentServiceTest.php` | Not run: `vendor/bin/phpunit` missing | +| `sonar-scanner --version` | Not run: command unavailable in PATH | +| Manual Erli delivery tab smoke | Pending operator after migration/live configuration | +| Manual Erli label + external parcel smoke | Pending operator after migration/live configuration | + +## Next Phase Readiness + +Phase 131 can build on: +- Erli delivery mappings with local provider and Erli vendor metadata. +- Local shipment packages with tracking numbers. +- Non-critical Erli external parcel sync payloads stored in `shipment_packages.payload_json`. + +Remaining concerns for Phase 131: +- Live Erli credentials, migration execution and browser smoke are still pending operator environment. +- Delivery tracking automation should decide how to poll/update delivery status after the external parcel exists. +- Duplicate external parcel semantics should be confirmed against live Erli responses. + +No blocker prevents planning Phase 131. diff --git a/DOCS/ARCHITECTURE.md b/DOCS/ARCHITECTURE.md index 9b19645..f71d672 100644 --- a/DOCS/ARCHITECTURE.md +++ b/DOCS/ARCHITECTURE.md @@ -84,6 +84,8 @@ HTTP Request 5. **Render** — `resources/views/statistics/summary.php` renders filters, chart JSON, two canvas targets, and table fallbacks. ### Shipment Flow + +Phase 130 adds an Erli-specific post-label step: for `orders.source='erli'`, `ShipmentController` calls `ErliExternalShipmentService::syncPackage()` after a local provider has a tracking number. The service posts `vendor/status/trackingNumber/orderId` to Erli `POST /shipping/external` and stores the response in `shipment_packages.payload_json.erli_external_parcel`; failures are activity-log warnings and do not block local labels. 1. **Create** — `ShipmentController::create()` → `ShipmentProviderRegistry` → carrier `ShipmentService::createShipment()` → `ShipmentPackageRepository::insert()` 2. **Track** — Cron `ShipmentTrackingHandler` → `ShipmentTrackingRegistry` → carrier tracking API → `ShipmentPackageRepository::updateDeliveryStatus()` @@ -121,12 +123,14 @@ HTTP Request ### Erli Integration Foundation -1. **Settings** - `/settings/integrations/erli` renders tabbed integration/status/settings panels and stores one global Erli API key encrypted via `IntegrationSecretCipher`, an optional account label, active flag, and last connection-test result. +1. **Settings** - `/settings/integrations/erli` renders tabbed integration/status/delivery/settings panels and 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. **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. **Status mapping/sync** - Phase 129 adds pull/push status mapping tables, status controls in Erli settings, and cron `erli_status_sync`. Pull reuses inbox import; push sends manual orderPRO status changes to `PATCH /orders/{id}/status`. -6. **Deferred** - Label generation, shipment creation, and tracking are planned for v3.8 Phases 130-131. +6. **Delivery mapping and labels** - Phase 130 adds `ErliDeliveryMappingController` and a Delivery tab. It maps imported Erli delivery method labels to local shipment providers (`inpost`/`apaczka`) and stores Erli `source_vendor_code` for external parcel registration. Label files are still produced by local providers, not by Erli carrier-contract parcels. +7. **External shipment sync** - Phase 130 extends `ErliApiClient` with shipping dictionary calls and `createExternalParcel()` (`POST /shipping/external`). `ErliExternalShipmentService` registers a local package in Erli only after `shipment_packages.tracking_number` exists; failures are activity-log warnings and do not block local labels. +8. **Deferred** - Carrier tracking automation and broader delivery-status hooks are planned for v3.8 Phase 131. ## Dependency Injection @@ -187,15 +191,25 @@ tests/ - `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. - Phase 129: `updateOrderStatus()` wysyla `PATCH /orders/{id}/status` z body `{"status": "..."}` dla recznych zmian statusu orderPRO mapowanych na status Erli. +- Phase 130: `getShippingMethods()`, `getDeliveryMethods()`, `getDeliveryVendors()`, `getPriceLists()`, `getPriceListsDetails()` i `createExternalParcel()` obsluguja natywne shipping API Erli bez wymuszania nadawania przez umowe Erli. - 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`, `POST /settings/integrations/erli/import`, `POST /settings/integrations/erli/statuses/save-pull`, `POST /settings/integrations/erli/statuses/save-push`. +- Endpointy: `GET /settings/integrations/erli`, `POST /settings/integrations/erli/save`, `POST /settings/integrations/erli/test`, `POST /settings/integrations/erli/import`, `POST /settings/integrations/erli/statuses/save-pull`, `POST /settings/integrations/erli/statuses/save-push`, `POST /settings/integrations/erli/delivery/save`. - `save` zapisuje label, aktywnosc, sekret, ustawienia importu (`orders_fetch_enabled`, `orders_fetch_start_date`, interwal crona) oraz kierunek/interwal `erli_status_sync`; `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. +### ErliDeliveryMappingController (`src/Modules/Settings/ErliDeliveryMappingController.php`) +- Buduje dane zakladki Dostawy: metody z `orders.external_carrier_id` dla `source='erli'`, aktualne `carrier_delivery_method_mappings`, slowniki vendorow/metod z Erli oraz lokalne uslugi InPost/Apaczka. +- `saveDeliveryMappings()` zapisuje mapowanie globalne `source_system='erli'`, `source_integration_id=0` z lokalnym providerem oraz `source_vendor_code` wymaganym przez Erli `POST /shipping/external`. + +### ErliExternalShipmentService (`src/Modules/Settings/ErliExternalShipmentService.php`) +- `syncPackage(int $packageId)` sprawdza, czy paczka nalezy do zamowienia Erli i ma tracking number. +- Pobiera vendor Erli z mapowania dostawy albo proboje go wywnioskowac z lokalnego providera/carrier id. +- Wysyla `POST /shipping/external` z `orderId`, `vendor`, `status='sent'`, `trackingNumber`; sukces zapisuje w `shipment_packages.payload_json.erli_external_parcel`, blad trafia do activity log jako niekrytyczny. + ### 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. diff --git a/DOCS/DB_SCHEMA.md b/DOCS/DB_SCHEMA.md index f7272dc..6881fa4 100644 --- a/DOCS/DB_SCHEMA.md +++ b/DOCS/DB_SCHEMA.md @@ -1,6 +1,6 @@ # Database Schema -**Updated:** 2026-05-15 | **Total tables:** 63 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci +**Updated:** 2026-05-16 | **Total tables:** 63 | **Engine:** InnoDB | **Charset:** utf8mb4_unicode_ci --- @@ -385,6 +385,26 @@ UNIQUE: `(integration_id, shoppro_status_code)` ## Shipments & Delivery +**carrier_delivery_method_mappings** — Map marketplace delivery methods to local shipment providers +| Column | Type | Nullable | Notes | +|--------|------|----------|-------| +| `id` | INT UNSIGNED | NO | PK | +| `source_system` | VARCHAR(32) | NO | `allegro`, `shoppro`, `erli` | +| `source_integration_id` | INT UNSIGNED | NO | `0` for global Allegro/Erli, shopPRO integration id for shopPRO | +| `order_delivery_method` | VARCHAR(200) | NO | Delivery method label/code from imported order | +| `source_service_id` | VARCHAR(128) | YES | Source delivery/shipping method id when available; used by Erli shipping dictionaries | +| `source_vendor_code` | VARCHAR(64) | YES | Source carrier/vendor code; Erli uses this for `POST /shipping/external.vendor` | +| `provider` | VARCHAR(50) | NO | Local shipment provider, e.g. `allegro_wza`, `inpost`, `apaczka` | +| `provider_service_id` | VARCHAR(128) | NO | Local provider service id | +| `provider_account_id` | VARCHAR(128) | YES | Provider account/credentials id when required | +| `provider_carrier_id` | VARCHAR(128) | YES | Provider carrier code/id when required | +| `provider_service_name` | VARCHAR(255) | YES | Display snapshot of provider service name | +| `created_at` | DATETIME | NO | | +| `updated_at` | DATETIME | NO | | + +UNIQUE: `(source_system, source_integration_id, order_delivery_method)`. +Phase 130 adds `source_service_id` and `source_vendor_code`; no new table is required for Erli delivery mappings. + **shipment_packages** — Prepared shipments with tracking | Column | Type | Nullable | Notes | |--------|------|----------|-------| @@ -414,7 +434,7 @@ UNIQUE: `(integration_id, shoppro_status_code)` | `sender_point_id` | VARCHAR(64) | YES | | | `reference_number` | VARCHAR(128) | YES | | | `error_message` | TEXT | YES | | -| `payload_json` | JSON | YES | | +| `payload_json` | JSON | YES | Provider request/response snapshot; Phase 130 may add `erli_external_parcel` after successful Erli external shipment registration | | `created_at` | DATETIME | NO | | | `updated_at` | DATETIME | NO | | diff --git a/DOCS/TECH_CHANGELOG.md b/DOCS/TECH_CHANGELOG.md index 7a567db..1139de0 100644 --- a/DOCS/TECH_CHANGELOG.md +++ b/DOCS/TECH_CHANGELOG.md @@ -1,5 +1,21 @@ # Technical Changelog +## 2026-05-16 - Phase 130 Plan 01: Erli Shipments + Labels + +**Co zrobiono:** +- Rozszerzono `carrier_delivery_method_mappings` o `source_service_id` i `source_vendor_code`, zeby mapowanie Erli przechowywalo osobno metode marketplace i vendora wymaganego przez `POST /shipping/external`. +- Dodano zakladke Dostawy w `/settings/integrations/erli` oraz `ErliDeliveryMappingController` do mapowania metod z zamowien Erli na lokalne uslugi InPost/Apaczka. +- Rozszerzono `ErliApiClient` o slowniki shipping/delivery/vendor/cenniki i tworzenie paczek zewnetrznych przez `POST /shipping/external`. +- `ShipmentController` uzywa mapowan Erli przy przygotowaniu przesylki i po uzyskaniu tracking number wywoluje `ErliExternalShipmentService`. +- `ErliExternalShipmentService` rejestruje paczke zewnetrzna w Erli, zapisuje odpowiedz w `shipment_packages.payload_json.erli_external_parcel` i loguje bledy jako niekrytyczne. + +**Dlaczego:** +- Operator chce nadawac zamowienia Erli z orderPRO, ale bez wymuszania nadawania na umowie Erli. Etykiety pozostaja u lokalnych providerow, a Erli dostaje informację o zewnetrznej paczce/tracking number. + +**BREAKING / migracja:** +- Wymagana migracja `20260516_000117_extend_delivery_mappings_for_erli_shipping.sql`. +- Brak breaking changes w istniejacych mapowaniach Allegro/shopPRO; nowe kolumny sa opcjonalne. + ## 2026-05-16 - Erli Settings Tabs UI Fix **Co zrobiono:** diff --git a/database/migrations/20260516_000117_extend_delivery_mappings_for_erli_shipping.sql b/database/migrations/20260516_000117_extend_delivery_mappings_for_erli_shipping.sql new file mode 100644 index 0000000..3e80283 --- /dev/null +++ b/database/migrations/20260516_000117_extend_delivery_mappings_for_erli_shipping.sql @@ -0,0 +1,3 @@ +ALTER TABLE carrier_delivery_method_mappings + ADD COLUMN IF NOT EXISTS source_service_id VARCHAR(128) NULL AFTER order_delivery_method, + ADD COLUMN IF NOT EXISTS source_vendor_code VARCHAR(64) NULL AFTER source_service_id; diff --git a/resources/lang/pl.php b/resources/lang/pl.php index 4e7e41f..8638ae4 100644 --- a/resources/lang/pl.php +++ b/resources/lang/pl.php @@ -867,6 +867,7 @@ return [ 'label' => 'Zakladki integracji Erli', 'integration' => 'Integracja', 'statuses' => 'Statusy', + 'delivery' => 'Dostawy', 'settings' => 'Ustawienia', ], 'config' => [ @@ -925,6 +926,29 @@ return [ 'save_failed' => 'Nie udalo sie zapisac mapowan statusow Erli.', ], ], + 'delivery' => [ + 'title' => 'Mapowanie dostaw Erli', + 'description' => 'Przypisz metody dostawy z zamowien Erli do lokalnych providerow etykiet oraz vendora Erli uzywanego przy rejestracji paczki zewnetrznej.', + 'metadata_not_connected' => 'Zapisz aktywna konfiguracje Erli, aby pobrac slowniki dostaw i vendorow.', + 'empty_methods' => 'Brak metod dostawy Erli z zaimportowanych zamowien.', + 'shipping_methods_title' => 'Slownik metod wysylki Erli', + 'fields' => [ + 'order_method' => 'Metoda z zamowienia', + 'erli_vendor' => 'Vendor Erli', + 'provider_service' => 'Lokalna usluga etykiety', + 'no_vendor' => '-- wybierz vendora --', + 'no_provider' => '-- nie generuj etykiety --', + 'shipping_method' => 'Metoda Erli', + 'shipping_vendor' => 'Vendor', + ], + 'actions' => [ + 'save' => 'Zapisz mapowanie dostaw', + ], + 'flash' => [ + 'saved' => 'Mapowanie dostaw Erli zostalo zapisane.', + 'save_failed' => 'Nie udalo sie zapisac mapowania dostaw Erli.', + ], + ], 'status' => [ 'secret' => 'Sekret API', 'active' => 'Aktywna', diff --git a/resources/views/settings/erli.php b/resources/views/settings/erli.php index cab6de7..4e73cb5 100644 --- a/resources/views/settings/erli.php +++ b/resources/views/settings/erli.php @@ -15,6 +15,20 @@ $statusSyncIntervalMinutes = (int) ($statusSyncIntervalMinutes ?? 15); $orderproStatuses = is_array($orderproStatuses ?? null) ? $orderproStatuses : []; $erliStatusMappings = is_array($erliStatusMappings ?? null) ? $erliStatusMappings : []; $erliPullStatusMappings = is_array($erliPullStatusMappings ?? null) ? $erliPullStatusMappings : []; +$erliDeliveryOrderMethods = is_array($erliDeliveryOrderMethods ?? null) ? $erliDeliveryOrderMethods : []; +$erliDeliveryMappings = is_array($erliDeliveryMappings ?? null) ? $erliDeliveryMappings : []; +$erliShippingMethods = is_array($erliShippingMethods ?? null) ? $erliShippingMethods : []; +$erliDeliveryVendors = is_array($erliDeliveryVendors ?? null) ? $erliDeliveryVendors : []; +$inpostDeliveryServices = is_array($inpostDeliveryServices ?? null) ? $inpostDeliveryServices : []; +$apaczkaDeliveryServices = is_array($apaczkaDeliveryServices ?? null) ? $apaczkaDeliveryServices : []; +$erliDeliveryMetadataError = trim((string) ($erliDeliveryMetadataError ?? '')); +$erliDeliveryMappingsByMethod = []; +foreach ($erliDeliveryMappings as $mappingRow) { + $methodKey = trim((string) ($mappingRow['order_delivery_method'] ?? '')); + if ($methodKey !== '') { + $erliDeliveryMappingsByMethod[$methodKey] = $mappingRow; + } +} $activeTab = (string) ($activeTab ?? 'integration'); ?> @@ -47,6 +61,9 @@ $activeTab = (string) ($activeTab ?? 'integration'); + @@ -261,6 +278,149 @@ $activeTab = (string) ($activeTab ?? 'integration'); +
+
+

+

+ + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+
+ + +
+ +
+ +
+ + +

+
+ + + + + + + + + + + + + + + + +
' . $e($methodId) . '' : '' ?>
+
+ +
+
+

@@ -315,6 +475,7 @@ $activeTab = (string) ($activeTab ?? 'integration'); var tabNameMap = { 'erli-tab-integration': 'integration', 'erli-tab-statuses': 'statuses', + 'erli-tab-delivery': 'delivery', 'erli-tab-settings': 'settings' }; diff --git a/resources/views/shipments/prepare.php b/resources/views/shipments/prepare.php index d4b1c9d..8283901 100644 --- a/resources/views/shipments/prepare.php +++ b/resources/views/shipments/prepare.php @@ -19,7 +19,11 @@ $mappedCredentialsId = trim((string) ($mapping['provider_account_id'] ?? '')); $mappedCarrierId = trim((string) ($mapping['provider_carrier_id'] ?? '')); $mappedProvider = trim((string) ($mapping['provider'] ?? '')); $mappedServiceName = trim((string) ($mapping['provider_service_name'] ?? '')); -$mappedCarrier = $mappedProvider === 'apaczka' ? 'apaczka' : 'allegro'; +$mappedCarrier = match ($mappedProvider) { + 'apaczka' => 'apaczka', + 'inpost' => 'inpost', + default => 'allegro', +}; if ($mappedCarrier !== 'apaczka' && stripos($mappedCarrierId, 'inpost') !== false) { $mappedCarrier = 'inpost'; } @@ -144,16 +148,16 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
-
Brak uslug InPost (sprawdz polaczenie z Allegro).
+
Brak uslug InPost (sprawdz konfiguracje InPost).
- +