From 7fd88038e4cff75358d2c81309e111aed918263f Mon Sep 17 00:00:00 2001 From: Jacek Pyziak Date: Mon, 18 May 2026 09:59:51 +0200 Subject: [PATCH] feat(140): shoppro polkurier delivery mapping Phase 140 complete: - add Polkurier as shopPRO delivery mapping provider - reuse PolkurierShipmentService delivery services - update PAUL state, docs, and changelog --- .paul/PROJECT.md | 15 +- .paul/ROADMAP.md | 24 +-- .paul/STATE.md | 46 +++-- .paul/changelog/2026-05-18.md | 24 +++ .../140-01-PLAN.md | 185 ++++++++++++++++++ .../140-01-SUMMARY.md | 130 ++++++++++++ DOCS/ARCHITECTURE.md | 1 + DOCS/TECH_CHANGELOG.md | 14 ++ resources/lang/pl.php | 5 +- resources/views/settings/shoppro.php | 57 +++++- routes/web.php | 29 +-- .../ShopproIntegrationsController.php | 50 ++++- 12 files changed, 509 insertions(+), 71 deletions(-) create mode 100644 .paul/changelog/2026-05-18.md create mode 100644 .paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md create mode 100644 .paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md diff --git a/.paul/PROJECT.md b/.paul/PROJECT.md index cc0ef33..a5437bf 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.9.0-dev | -| Status | v3.9 Stabilizacja i splata dlugu technicznego in progress - Phase 139 Sonar Critical/Major Cleanup complete; Phase 140 ready to plan | -| Last Updated | 2026-05-17 (Phase 139 closed) | +| Status | v3.9 Stabilizacja i splata dlugu technicznego complete - Phase 140 shopPRO Polkurier Delivery Mapping closed | +| Last Updated | 2026-05-18 (Phase 140 unified) | ## Requirements @@ -133,12 +133,13 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów - [x] Tracking i automatyzacje Erli: lokalny provider tracking jak w Allegro, retry niekrytycznej rejestracji paczki zewnetrznej Erli z `shipment_tracking_sync`, wspolny kontekst `shipment.created`/`shipment.status_changed` dla regul e-mail/SMS/statystyk — Phase 131 - [x] Hardening Erli: spojna diagnostyka importu/ACK w `integration_order_sync_state.last_error`, brak ACK po blednym batchu, testy jednostkowe import/status sync i dokumentacja obserwowalnosci bez nowej migracji — Phase 132 - [x] Parytet Erli w powierzchniach wspolnych: filtr zrodla zamowien, kanaly statystyk dziennych/podsumowania, warunek integracji automatyzacji, menu integracji i etykiety `zrodlo` uzywaja wspolnego rejestru zrodel — Phase 133 -- [x] Backlog Reality Check: `.paul/codebase/todo.md` i `.paul/codebase/concerns.md` sklasyfikowane przeciw aktualnemu kodowi/docs, z dowodami w `BACKLOG-AUDIT.md` i routingiem do faz 135-142 — Phase 134 +- [x] Backlog Reality Check: `.paul/codebase/todo.md` i `.paul/codebase/concerns.md` sklasyfikowane przeciw aktualnemu kodowi/docs, z dowodami w `BACKLOG-AUDIT.md` i pierwotnym routingiem do kolejnych faz dlugu; nieaktualne fazy 140+ usuniete 2026-05-18 decyzja operatora — Phase 134 - [x] Accounting Net Correctness: nowe paragony zapisuja VAT-aware `receipts.total_net`, a statystyki dzienne preferuja source-level net, potem `order_items` VAT fallback, z gross `/1.23` tylko jako legacy fallback — Phase 135 - [x] Fakturownia Invoice Idempotency: delegowane faktury uzywaja stabilnego `oid=orders.internal_order_number`, lookup-first `GET /invoices.json?oid=...`, lokalnego stanu `pending_external`/`failed_retryable` i auto-attach po timeoutach — Phase 136 - [x] Delivery Status Backlog Verification: `DELIVERY-STATUS-MGMT` zamkniete jako wdrozone; runtime korzysta z DB-driven statusow, a read-only DB check nie wykazal starych ani niepoprawnych kluczy automatyzacji — Phase 137 - [x] Security and Legacy Hardening: test SMTP ma strict TLS by default z lokalnym `SMTP_ALLOW_SELF_SIGNED_DEV`, szablony e-mail/SMS blokuja nieznane placeholdery, raw `$_SESSION` jest izolowany w `Session`, a wskazane widoki uzywaja `$component()` zamiast hard `require` — Phase 138 - [x] Sonar Critical/Major Cleanup: Phase 139 odswiezyla baseline Sonar i zmniejszyla OPEN BLOCKER/CRITICAL/MAJOR z 648 do 495 przez delivery-status/statistics cleanup, typowane wyjatki oraz szeroka migracje alert include/import patterns — Phase 139 +- [x] shopPRO Polkurier Delivery Mapping: zakladka `Dostawy` integracji shopPRO pozwala mapowac forme dostawy na Polkurier, laduje uslugi z `PolkurierShipmentService::getDeliveryServices()` i zapisuje `provider='polkurier'` w `carrier_delivery_method_mappings` bez migracji DB — Phase 140 - [x] Integracja polkurier.pl (fundament): pojedyncza globalna konfiguracja w `/settings/integrations/polkurier`, szyfrowany Token API + login, karta w hubie integracji obok Apaczki i realny test polaczenia przez `apimetod=test_auth_api` zweryfikowany na zywym koncie operatora; `ShipmentProviderRegistry` netkniety — `PolkurierShipmentService/TrackingService` w kolejnych fazach — Phase 127 - [x] polkurier ShipmentService + TrackingService + UI prepare panel: pelen kontrakt API (createShipment/getLabel/getStatus/cancelOrder/getAvailableCarriers), `PolkurierShipmentService` implementujacy `ShipmentProviderInterface` z normalizacja shipmenttype (lowercase) i splitem ulicy na street/housenumber/flatnumber, `PolkurierTrackingService` mapujacy statusy O/P/A/WP/D/Z/W na znormalizowane, panel "polkurier" w `prepare.php` z dynamiczna lista uslug z `available_carriers`, seed migracja `delivery_status_mappings(provider='polkurier')` z 7 wpisami z PDF v1.11; live test na #114/#115 zakonczony sukcesem po 4 iteracjach (ReferenceError → uppercase shipmenttype → orderno parsing → A4/A6); rozmiar etykiety sterowany w panelu klienta polkurier.pl (Ustawienia konta → Preferencje etykiet), NIE przez API — Phase 128 - [x] Order User Notes module (Phase 129): pelen CRUD notatek autorskich operatora per zamowienie. Reuse `order_notes` przez nowy `note_type='user'` z `user_id` (FK→users SET NULL) + `author_name` (snapshot) + indeks `idx_order_notes_type_order`. `OrderNotesService` z autoryzacja DB-level (`WHERE user_id = :user_id`, rowCount=0 ⇒ 403). Sekcja `#notes` w "Wiadomosci i zalaczniki" w `/orders/{id}` z inline edit form + delete przez `OrderProAlerts.confirm`. Badge `[N]` (indigo neutralny) przy nr zamowienia na `/orders/list` (subquery `user_notes_count` w paginate). Brak admin override (brak systemu rol w aplikacji) — edit/delete tylko dla autora — Phase 129 @@ -151,7 +152,7 @@ Sprzedawca moĹĽe obsĹ‚ugiwać zamĂłwienia ze wszystkich kanałów ### Active (In Progress) -- [ ] v3.9 Stabilizacja i splata dlugu technicznego — Phase 140 Performance Safeguards ready to plan after Phase 139. +- None - v3.9 current milestone is complete. ### Planned (Next) @@ -267,13 +268,13 @@ PHP (XAMPP/Laravel), integracje z API marketplace'Ăłw (Allegro, Erli) oraz API | `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 | | Erli hardening uzywa istniejacych powierzchni obserwowalnosci zamiast nowej tabeli logow | Operator wybral ujednolicenie istniejacych miejsc; `integration_order_sync_state.last_error`, wynik crona i activity log wystarczaja dla Phase 132 | 2026-05-16 | Active | | Zrodla zamowien marketplace maja wspolny `OrderSourceRegistry` | Parytet Erli ma byc utrzymany wszedzie tam, gdzie kod potrzebuje listy lub etykiety zrodla; lokalne pary Allegro/shopPRO prowadzily do pominiec Erli | 2026-05-16 | Active | -| v3.9 debt phases start from evidence-backed backlog audit | Phase 134 rozdzielil wpisy aktywne, wdrozone, stale i decyzyjne; kolejne fazy 135-142 maja naprawiac tylko potwierdzone problemy | 2026-05-16 | Active | +| v3.9 debt phases start from evidence-backed backlog audit | Phase 134 rozdzielil wpisy aktywne, wdrozone, stale i decyzyjne. 2026-05-18 operator usunal nieaktualne fazy 140+ i zastapil je pilna faza mapowania shopPRO -> Polkurier. | 2026-05-16 | Active | | Existing receipt `total_net` rows are not backfilled | Operator wybral zakres Phase 135 tylko dla nowych paragonow; historia pozostaje bez migracji/UPDATE | 2026-05-16 | Active | | Accounting net fallbacks prefer explicit source data before assumptions | Phase 135: source-level net > item net/gross+VAT > legacy gross `/1.23`; dostawa fallback jako 23% VAT | 2026-05-16 | Active | | SMTP mailbox TLS is strict by default | Phase 138: `ssl` and STARTTLS verify peer and host name; self-signed/unverified certificates require `SMTP_ALLOW_SELF_SIGNED_DEV=true` and local/dev/testing env. | 2026-05-17 | Active | | Unknown e-mail/SMS template placeholders are blocked on save | Phase 138: `TemplateVariableCatalog` is the shared catalog; create/edit rejects unknown `{{group.variable}}` keys while existing DB rows are not migrated. | 2026-05-17 | Active | | Raw session access belongs only in `App\Core\Support\Session` | Phase 138 moved auth, CSRF, flash and Allegro OAuth state access behind `Session::get/set/has/forget/pull`. | 2026-05-17 | Active | -| Phase 139 cleanup slices must stay behavior-preserving and leave god-class splits to Phase 141 | Phase 139 reduced Sonar BLOCKER/CRITICAL/MAJOR from 648 to 495 without DB/schema/business-flow changes; `php:S1448` remains a dedicated architecture concern. | 2026-05-17 | Active | +| Phase 139 cleanup slices must stay behavior-preserving and leave god-class splits to a future refactor | Phase 139 reduced Sonar BLOCKER/CRITICAL/MAJOR from 648 to 495 without DB/schema/business-flow changes; `php:S1448` remains a dedicated architecture concern. Former Phase 141 was removed from the active roadmap on 2026-05-18. | 2026-05-17 | Active | | polkurier startuje jako jedna globalna konfiguracja (single-instance, mirror Apaczka/HostedSMS/SMSPLANET) z realnym testowym wywolaniem `apimetod=test_auth_api` | Operator ma jedno konto polkurier; fundament musi byc zweryfikowany na zywym API zanim dolozymy `PolkurierShipmentService` | 2026-05-14 | Active | | polkurier wymaga `login + token` razem w body `authorization` (nie samego tokena) | Zweryfikowane w SDK polkurier-sdk (`Auth.php`/`Request.php`); kolumna `login VARCHAR(190)` w `polkurier_integration_settings` mimo ze PLAN tego nie wymagal — kontrakt API to dyktuje | 2026-05-14 | Active | | polkurier API: top-level `status` === `'success'` (nie `'ok'`), tresc bledu w polu `response` envelope'a | `ResponseStatus::SUCCESS = 'success'` z `src/Type/ResponseStatus.php` SDK; bledy rzucane przez `ErrorException($response->get('response'))` w `PolkurierWebService.php`. Pattern dla wszystkich przyszlych metod polkurier API (`createShipment`, `getLabel`, `getStatus`, `cancelOrder`, etc.) | 2026-05-14 | Active | @@ -321,6 +322,6 @@ Quick Reference: --- *PROJECT.md — Updated when requirements or context change* -*Last updated: 2026-05-17 after Phase 139 (Sonar Critical/Major Cleanup) closure* +*Last updated: 2026-05-18 after Phase 140 (shopPRO Polkurier Delivery Mapping) closure* diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index 42c17a2..c505823 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -12,7 +12,7 @@ Milestone porzadkujacy zbudowany z `.paul/codebase/todo.md` i `.paul/codebase/co Rule for every phase/plan: przed implementacja sprawdzic w kodzie i dokumentacji, czy wpis nadal jest aktualny i czy nie zostal juz wdrozony; nastepnie przedstawic krotki plan operatorowi i zapytac o potwierdzenie. Dopiero po akceptacji wolno wprowadzac zmiany i uruchamiac testy. Jezeli wpis jest nieaktualny albo juz zrealizowany, faza/planu ma zamknac go dokumentacyjnie bez niepotrzebnej zmiany kodu. -Progress: 6 of 9 phases complete (67%). +Progress: 7 of 7 phases complete (100%). | Phase | Name | Plans | Status | |-------|------|-------|--------| @@ -22,9 +22,7 @@ Progress: 6 of 9 phases complete (67%). | 137 | Delivery Status Backlog Verification | 1/1 | Complete (2026-05-17; verification-only closure, no stale automation keys found) | | 138 | Security and Legacy Hardening | 1/1 | Complete (2026-05-17; SMTP TLS/template/session/view hardening, PHPUnit/Sonar env gaps documented) | | 139 | Sonar Critical/Major Cleanup | 2/2 | Complete (2026-05-17; Sonar BLOCKER/CRITICAL/MAJOR reduced 648 -> 495 across two cleanup slices) | -| 140 | Performance Safeguards | TBD | Not started | -| 141 | God Classes and Duplication Refactor | TBD | Not started | -| 142 | Architecture Guardrails | TBD | Not started | +| 140 | shopPRO Polkurier Delivery Mapping | 1/1 | Complete (2026-05-18; shopPRO delivery mapping supports Polkurier, manual UI/Sonar follow-up pending) | ### Phase 134: Backlog Reality Check @@ -56,20 +54,10 @@ Plans: 138-01 (complete; `.paul/phases/138-security-and-legacy-hardening/138-01- Focus: Zmniejszyc potwierdzone problemy SonarQube z `concerns.md`: generic exceptions, zbyt wiele returnow, powtarzajace sie literaly, cognitive complexity, unused parameters, use-namespace-import oraz accessibility (`aria-label`, ``). Przed kazda grupa zmian odswiezyc stan skanu albo lokalnie potwierdzic wystepowanie problemu. Plans: 139-01 (complete; `.paul/phases/139-sonar-critical-major-cleanup/139-01-SUMMARY.md`); 139-02 (complete; `.paul/phases/139-sonar-critical-major-cleanup/139-02-SUMMARY.md`) -### Phase 140: Performance Safeguards +### Phase 140: shopPRO Polkurier Delivery Mapping -Focus: Zweryfikowac i wdrozyc potwierdzone zabezpieczenia wydajnosciowe: deferred indexes `INDEX-106-01`, potencjalne N+1 w szczegolach zamowienia oraz ryzyko wzrostu kolejki cron bez backoffu. Indeksy i migracje wykonywac zgodnie z obecnym progiem danych i po potwierdzeniu operatora. -Plans: TBD (defined during $paul-plan) - -### Phase 141: God Classes and Duplication Refactor - -Focus: Wrocic do odlozonego Phase 68 i potwierdzonych `S1448`: `OrdersRepository`, `OrdersController`, `AutomationService`, `ShopproOrderMapper`, `ApaczkaShipmentService`, `ShopproIntegrationsController`, plus duplikacje `SslCertificateResolver`, `ToggleableRepositoryTrait`, `RedirectPathResolver` oraz overlap `ReceiptService`/accounting. -Plans: TBD (defined during $paul-plan) - -### Phase 142: Architecture Guardrails - -Focus: Po pilniejszych poprawkach zdecydowac, ktore guardraile sa warte wdrozenia teraz: interfejsy repozytoriow do testow, typowane event/action names, wspolna warstwa walidacji, ewentualne naglowki cache i lokalne query caching. Kazdy element wymaga osobnej decyzji, bo czesc ma niski impact. -Plans: TBD (defined during $paul-plan) +Focus: Dodac Polkurier do zakladki Dostawy w ustawieniach integracji shopPRO, aby formy dostawy z zamowien shopPRO mogly byc mapowane na lokalna usluge Polkurier i pozniej automatycznie preselectowane przy przygotowaniu przesylki. +Plans: 140-01 (complete; `.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md`) ## Previous Milestone @@ -633,4 +621,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md` --- *Roadmap created: 2026-03-12* -*Last updated: 2026-05-17 - Phase 139 complete; Phase 140 ready to plan* +*Last updated: 2026-05-18 - Phase 140 complete; v3.9 milestone complete; obsolete phases 140+ removed* diff --git a/.paul/STATE.md b/.paul/STATE.md index c8014b5..07dcd20 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -2,45 +2,46 @@ ## Project Reference -See: .paul/PROJECT.md (updated 2026-05-17) +See: .paul/PROJECT.md (updated 2026-05-18) **Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami. -**Current focus:** v3.9 Stabilizacja i splata dlugu technicznego; Phase 139 Sonar Critical/Major Cleanup complete, Phase 140 Performance Safeguards ready to plan. +**Current focus:** v3.9 Stabilizacja i splata dlugu technicznego complete; Phase 140 shopPRO Polkurier Delivery Mapping unified. ## Current Position Milestone: v3.9 Stabilizacja i splata dlugu technicznego -Phase: 140 of 142 (Performance Safeguards) -Plan: Not started -Status: Ready to plan -Last activity: 2026-05-17 23:21 - Phase 139 complete; transitioned to Phase 140 +Phase: 140 of 140 (shopPRO Polkurier Delivery Mapping) - Complete +Plan: 140-01 complete +Status: Milestone complete, ready for next milestone or release decision +Last activity: 2026-05-18 00:00 - Unified .paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md Progress: -- Milestone v3.9: [#######---] 67% (6 of 9 phases complete) -- Phase 140: [----------] 0% (ready to plan) +- Milestone v3.9: [##########] 100% (7 of 7 phases complete) +- Phase 140: [##########] 100% (complete) ## Loop Position Current loop state: ``` PLAN -> APPLY -> UNIFY - done done done [Phase 139 loop complete; ready for Phase 140 PLAN] + done done done [Loop complete - milestone complete] ``` ## Session Continuity -Last session: 2026-05-17 23:21 -Stopped at: Phase 139 complete, ready to plan Phase 140 -Next action: $paul-plan for Phase 140 Performance Safeguards -Resume file: .paul/ROADMAP.md +Last session: 2026-05-18 00:00 +Stopped at: Phase 140 complete; v3.9 milestone complete +Next action: Run $paul-complete-milestone or start next milestone planning +Resume file: .paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md ## Pending parallel work - None — Phase 118, 121, 122 wszystkie zacommitowane (8f14851, 360eef1). ## Git State -Last phase commit: HEAD feat(139): sonar critical major cleanup -Previous: feat(136): fakturownia invoice idempotency +Last commit: HEAD feat(140): shoppro polkurier delivery mapping +Last phase commit: HEAD feat(140): shoppro polkurier delivery mapping +Previous: feat(139): sonar critical major cleanup Branch: main ### Skill Audit (Phase 139) @@ -50,6 +51,12 @@ Branch: main | `sonar-scanner` | invoked | Local PATH did not contain the scanner, but the official Windows x64 scanner was downloaded to `%TEMP%` and used successfully before and after cleanup. | | `sonar-scanner` 139-02 | invoked | Reused the official Windows x64 scanner from `%TEMP%`; final scan succeeded with analysis `2c18a5b3-40b4-41d8-b826-df88615749db` and 495 OPEN BLOCKER/CRITICAL/MAJOR issues. | +### Skill Audit (Phase 140) + +| Expected | Invoked | Notes | +|----------|---------|-------| +| `sonar-scanner` | gap documented | `sonar-project.properties` exists, but `sonar-scanner` is not available in PATH and the Phase 139 `%TEMP%` fallback scanner is not present. | + ### Skill Audit (Phase 129) | Expected | Invoked | Notes | @@ -131,17 +138,20 @@ Branch: main - Phase 136 APPLY: `php bin/migrate.php` could not run because local MySQL refused connection; `vendor/bin/phpunit` is missing; `sonar-scanner` is unavailable in PATH. PHP lint, documentation grep, git diff check and ad-hoc SQLite repository smoke passed. - Phase 138 APPLY: `vendor/bin/phpunit` is missing, so new unit tests were linted but not run; `sonar-scanner` is unavailable in PATH. PHP lint, targeted `rg` checks and `git diff --check` passed. - Phase 139 APPLY: local PATH still does not contain `sonar-scanner`, but the official Windows x64 scanner was downloaded to `%TEMP%` and used successfully. `vendor/bin/phpunit` remains unavailable because `vendor/` is missing and Composer is not installed in PATH. -- Phase 140: deferred indexes should be applied only after operator confirms dataset size/prod timing. +- Phase 140 APPLY: manual UI smoke was not run because local app/DB session was not started; Sonar scan could not run because `sonar-scanner` is unavailable. +- Obsolete Phase 140+ debt plans were removed from the active roadmap on 2026-05-18 by operator decision; performance/debt items can be reintroduced later only if still relevant. ### Deferred Issues -- Backlog items and concern groups classified in `.paul/phases/134-backlog-reality-check/BACKLOG-AUDIT.md`; remaining implementation deferred to phases 136-142. +- Backlog items and concern groups classified in `.paul/phases/134-backlog-reality-check/BACKLOG-AUDIT.md`; obsolete Phase 140+ debt work removed from active roadmap by operator decision on 2026-05-18. ## Pending Actions - Phase 138 follow-up: run `vendor/bin/phpunit tests/Unit/SmtpSecurityContextFactoryTest.php tests/Unit/TemplateVariableCatalogTest.php` after dependencies are installed. -- Phase 139 follow-up: split `OrdersStatisticsRepository` (`php:S1448`, 43 methods) or include it in Phase 141 god-class refactor. +- Phase 139 follow-up: split `OrdersStatisticsRepository` (`php:S1448`, 43 methods) in a future god-class refactor if still relevant. - Phase 139 follow-up: continue with confirmed groups `php:S1142`, `php:S3776`, `php:S1172`, `php:S1192`, `php:S112`, plus Web table/accessibility issues. `php:S4833` is now only 3 core framework require issues. +- Phase 140 follow-up: manual smoke `/settings/integrations/shoppro?tab=delivery` -> wybierz Polkurier -> zapisz -> odswiez -> mapowanie pozostaje; potem przygotuj przesylke shopPRO i potwierdz preselect `provider='polkurier'`. +- Phase 140 follow-up: uruchom SonarQube scan po przywroceniu `sonar-scanner` w PATH albo ponownym pobraniu oficjalnego scanner fallback. - Phase 138 manual smoke: test a real SMTP SSL/STARTTLS mailbox in strict mode; test invalid and valid e-mail/SMS template saves in UI. - Manualne testy AC-1..AC-7 dla Phase 112 na zywej bazie (XAMPP online). - Backfill zamowienia #882 - operator robi recznie po wdrozeniu (poza zakresem planu). diff --git a/.paul/changelog/2026-05-18.md b/.paul/changelog/2026-05-18.md new file mode 100644 index 0000000..68d1823 --- /dev/null +++ b/.paul/changelog/2026-05-18.md @@ -0,0 +1,24 @@ +# 2026-05-18 + +## Co zrobiono + +- [Phase 140, Plan 01] Dodano mapowanie form dostawy shopPRO na uslugi Polkurier. +- Rozszerzono zakladke `Dostawy` integracji shopPRO o przewoznika Polkurier i wyszukiwalna liste uslug. +- Zapis mapowan shopPRO obsluguje `provider='polkurier'` oraz zapis service code i nazwy uslugi w `carrier_delivery_method_mappings`. +- Zaktualizowano dokumentacje architektury, techniczny changelog oraz stan PAUL; stare nieaktualne fazy 140+ usunieto z aktywnej roadmapy. +- Gap: manualny smoke UI i SonarQube scan pozostaja do wykonania po uruchomieniu app/DB i przywroceniu `sonar-scanner`. + +## Zmienione pliki + +- `.paul/PROJECT.md` +- `.paul/ROADMAP.md` +- `.paul/STATE.md` +- `.paul/changelog/2026-05-18.md` +- `.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md` +- `.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md` +- `DOCS/ARCHITECTURE.md` +- `DOCS/TECH_CHANGELOG.md` +- `resources/lang/pl.php` +- `resources/views/settings/shoppro.php` +- `routes/web.php` +- `src/Modules/Settings/ShopproIntegrationsController.php` diff --git a/.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md b/.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md new file mode 100644 index 0000000..4986c11 --- /dev/null +++ b/.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md @@ -0,0 +1,185 @@ +--- +phase: 140-shoppro-polkurier-delivery-mapping +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - routes/web.php + - src/Modules/Settings/ShopproIntegrationsController.php + - resources/views/settings/shoppro.php + - resources/lang/pl.php + - DOCS/ARCHITECTURE.md + - DOCS/TECH_CHANGELOG.md +autonomous: true +delegation: off +--- + + +## Goal +Dodac Polkurier jako dostepnego lokalnego providera w mapowaniu form dostawy shopPRO, tak aby operator mogl przypisac forme dostawy z zamowienia shopPRO do uslugi Polkurier i zeby przygotowanie przesylki pozniej korzystalo z zapisanego mapowania. + +## Purpose +Sprzedawca ma nadawac przesylki z orderPRO bez recznego przelaczania providera przy kazdym zamowieniu. shopPRO ma miec parytet z istniejacym flow przygotowania przesylek, gdzie `carrier_delivery_method_mappings` wskazuje provider, usluge i nazwe uslugi. + +## Output +Zakladka `/settings/integrations/shoppro?tab=delivery` pokazuje Polkurier obok Allegro/InPost/Apaczki, pobiera uslugi z istniejacego `PolkurierShipmentService::getDeliveryServices()` i zapisuje mapowanie jako `provider='polkurier'`, `provider_service_id=`, `provider_service_name=`. + + + + +- **Zakres fazy** - Czy potraktowac to jako pilna nowa faze PAUL, czy jako hotfix poza roadmapowym nurtem? + -> Odpowiedz: Jako nowa faza. Stare fazy od 140 w gore sa do usuniecia (nieaktualne). +- **Zakres funkcji** - Czy shopPRO ma dostac Polkurier jako kolejnego providera obok Allegro/InPost/Apaczka z lista uslug z `PolkurierShipmentService::getDeliveryServices()` i zapisem `provider='polkurier'`, `provider_service_id=servicecode`, `provider_service_name=name`? + -> Odpowiedz: Tak. + + +## Project Context +@AGENTS.md +@.paul/PROJECT.md +@.paul/ROADMAP.md +@.paul/STATE.md +@DOCS/DB_SCHEMA.md +@DOCS/ARCHITECTURE.md + +## Source Files +@routes/web.php +@src/Modules/Settings/ShopproIntegrationsController.php +@src/Modules/Settings/CarrierDeliveryMethodMappingRepository.php +@src/Modules/Shipments/PolkurierShipmentService.php +@resources/views/settings/shoppro.php +@resources/lang/pl.php +@resources/views/shipments/prepare.php + + + +## Required Skills (from SPECIAL-FLOWS.md) + +| Skill | Priority | When to Invoke | Loaded? | +|-------|----------|----------------|---------| +| sonar-scanner | required | Po APPLY, przed UNIFY | ○ | +| /feature-dev | optional | Przy implementacji nowej funkcji integracyjnej | ○ | +| /frontend-design | optional | Przy korekcie formularza mapowan dostawy | ○ | +| /code-review | optional | Po implementacji, przed UNIFY | ○ | + +**BLOCKING:** `sonar-scanner` jest wymagany przez `.paul/SPECIAL-FLOWS.md` po APPLY. Jezeli lokalny PATH nadal go nie ma, uzyc sprawdzonego fallbacku z Phase 139 albo zapisac gap w SUMMARY. + + + + +## AC-1: Polkurier Widoczny W Mapowaniu shopPRO +```gherkin +Given istnieje zapisana integracja shopPRO oraz wykryte formy dostawy z zamowien tej integracji +When operator otwiera /settings/integrations/shoppro?tab=delivery +Then w kolumnie przewoznika moze wybrac Polkurier, a w kolumnie uslugi moze wybrac usluge Polkurier z listy dostepnych uslug +``` + +## AC-2: Zapis Mapowania Polkurier +```gherkin +Given operator wybral Polkurier i konkretna usluge dla formy dostawy shopPRO +When zapisuje formularz mapowania dostaw +Then `carrier_delivery_method_mappings` dla tej formy dostawy zapisuje `source_system='shoppro'`, `provider='polkurier'`, `provider_service_id` jako kod uslugi Polkurier i `provider_service_name` jako jej nazwe +``` + +## AC-3: Wczytanie Istniejacego Mapowania +```gherkin +Given forma dostawy shopPRO ma zapisane mapowanie na Polkurier +When operator ponownie otwiera zakladke Dostawy shopPRO +Then wiersz pokazuje wybranego przewoznika Polkurier i zaznaczona poprzednio usluge bez utraty zapisanych mapowan dla Allegro, InPost i Apaczki +``` + +## AC-4: Przygotowanie Przesylki Korzysta Z Mapowania +```gherkin +Given zamowienie shopPRO ma forme dostawy zmapowana na Polkurier +When operator przechodzi do przygotowania przesylki dla tego zamowienia +Then istniejacy flow preselectu providera otrzymuje `provider='polkurier'` oraz `delivery_method_id` rowny zapisanej usludze Polkurier +``` + + + + + + + Task 1: Podlaczyc uslugi Polkurier do shopPRO delivery tab + routes/web.php, src/Modules/Settings/ShopproIntegrationsController.php + + Rozszerz `ShopproIntegrationsController` o opcjonalna zaleznosc `PolkurierShipmentService`. + - W `index()` przekaz do widoku `polkurierDeliveryServices`. + - W `loadDeliveryServices()` albo osobnej malej metodzie doladuj uslugi Polkurier przez `getDeliveryServices()`; bledy traktuj jak brak listy i pokaz czytelny komunikat tylko jesli jest sensowny, bez blokowania Allegro/Apaczka. + - W `saveDeliveryMappings()` obsluz `carrier[] = polkurier`, pobierz `polkurier_delivery_method_id[]` i zapisz `provider='polkurier'`, `provider_service_id`, pusty `provider_account_id`, `provider_carrier_id` opcjonalnie pusty/kod, oraz `provider_service_name`. + - W `routes/web.php` ustaw DI tak, by ten sam `PolkurierShipmentService` byl przekazany do kontrolera shopPRO i do `ShipmentProviderRegistry`. + Unikaj duplikowania wywolan `PolkurierApiClient` bezposrednio w kontrolerze, bo istniejacy provider juz normalizuje service list. + + C:\xampp\php\php.exe -l src/Modules/Settings/ShopproIntegrationsController.php; C:\xampp\php\php.exe -l routes/web.php + AC-1 i AC-2 sa spelnione po stronie kontrolera i DI. + + + + Task 2: Dodac Polkurier do UI mapowan dostawy shopPRO + resources/views/settings/shoppro.php, resources/lang/pl.php + + Rozszerz istniejaca tabele mapowan bez tworzenia nowego widoku. + - Dodaj opcje `Polkurier` w select przewoznika. + - Dodaj panel wyboru uslugi Polkurier analogiczny do Apaczki: wyszukiwalna lista z `data-value=` i `data-label=`. + - Dodaj hidden input `polkurier_delivery_method_id[]` oraz wykorzystaj istniejacy hidden service-name, zeby zapis dostal nazwe uslugi. + - Rozszerz JS `showPanel`, reset pol oraz `selectOption()` tak, by Polkurier czyscil pola Allegro/Apaczka i zapisywal poprawny provider service id. + - Rozpoznawaj istniejace mapowanie `provider='polkurier'` jako aktualny carrier. + - Zaktualizuj polskie etykiety/opisy: opis ma wspominac Allegro WZA/InPost/Apaczka/Polkurier, placeholder ma byc neutralny (`Szukaj uslugi...`), dodaj komunikat braku uslug Polkurier. + Nie dodawaj inline CSS poza istniejacymi prostymi `style` uzytymi juz w tym widoku. + + C:\xampp\php\php.exe -l resources/views/settings/shoppro.php; rg -n "polkurier|polkurierDeliveryServices|polkurier_delivery_method_id" resources/views/settings/shoppro.php resources/lang/pl.php + AC-1 i AC-3 sa spelnione w UI. + + + + Task 3: Udokumentowac kontrakt bez migracji + DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md + + Zaktualizuj dokumentacje techniczna. + - W `DOCS/ARCHITECTURE.md` dopisz, ze shopPRO delivery mapping obsluguje takze Polkurier przez `provider='polkurier'` i liste z `PolkurierShipmentService`. + - W `DOCS/TECH_CHANGELOG.md` dodaj wpis z data 2026-05-18 opisujacy, co i dlaczego zmieniono. + - Nie aktualizuj `DOCS/DB_SCHEMA.md`, bo plan nie zmienia tabel, kolumn, indeksow ani FK; istnieje juz `carrier_delivery_method_mappings`. + + rg -n "shopPRO.*Polkurier|Polkurier.*shopPRO|2026-05-18" DOCS/ARCHITECTURE.md DOCS/TECH_CHANGELOG.md + Dokumentacja odzwierciedla AC-1..AC-4 i jasno wskazuje brak migracji. + + + + + + +## DO NOT CHANGE +- Nie zmieniac schematu bazy danych ani migracji; `carrier_delivery_method_mappings` juz ma potrzebne pola. +- Nie zmieniac kontraktu tworzenia przesylek Polkurier (`PolkurierShipmentService::createShipment()` i API payload) poza ewentualnym reuse listy uslug. +- Nie przebudowywac calego widoku shopPRO ani systemu zakladek. +- Nie usuwac obslugi Allegro, InPost ani Apaczki w mapowaniach shopPRO. + +## SCOPE LIMITS +- Zakres dotyczy tylko mapowania form dostawy shopPRO na Polkurier. +- Brak nowego selektora punktow odbioru Polkurier; przygotowanie przesylki nadal uzywa istniejacych pol `receiver_point_id`/`sender_point_id`. +- Brak zmian w imporcie zamowien shopPRO. +- Brak zmian w Erli, Allegro delivery mapping i statusach dostaw. + + + +Before declaring plan complete: +- [ ] `C:\xampp\php\php.exe -l routes/web.php` +- [ ] `C:\xampp\php\php.exe -l src/Modules/Settings/ShopproIntegrationsController.php` +- [ ] `C:\xampp\php\php.exe -l resources/views/settings/shoppro.php` +- [ ] `rg -n "polkurier|polkurierDeliveryServices|polkurier_delivery_method_id" src/Modules/Settings/ShopproIntegrationsController.php resources/views/settings/shoppro.php resources/lang/pl.php` +- [ ] Manual smoke, jesli aplikacja i DB sa dostepne: `/settings/integrations/shoppro?tab=delivery` -> wybierz Polkurier -> zapisz -> odswiez -> mapowanie pozostaje. +- [ ] SonarQube scan zgodnie z `.paul/SPECIAL-FLOWS.md` albo udokumentowany gap/fallback. +- [ ] Wszystkie acceptance criteria spelnione. + + + +- Polkurier jest dostepny w UI mapowania dostaw shopPRO. +- Zapis mapowania tworzy rekord uzywany pozniej przez przygotowanie przesylki (`provider='polkurier'`, `provider_service_id`). +- Istniejace mapowania Allegro/InPost/Apaczka pozostaja kompatybilne. +- Dokumentacja techniczna opisuje nowy wariant bez sugerowania zmian schematu. +- Weryfikacje z sekcji `` przeszly albo gap jest jasno opisany. + + + +After completion, create `.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md` + diff --git a/.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md b/.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md new file mode 100644 index 0000000..ec171cd --- /dev/null +++ b/.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md @@ -0,0 +1,130 @@ +--- +phase: 140-shoppro-polkurier-delivery-mapping +plan: 01 +subsystem: settings +tags: [shoppro, polkurier, delivery-mapping, shipments] +requires: + - phase: 128-polkurier-shipment-service + provides: PolkurierShipmentService and delivery service list from polkurier available_carriers +provides: + - shopPRO delivery methods can be mapped to Polkurier services + - carrier_delivery_method_mappings rows can store provider='polkurier' for shopPRO +affects: [shoppro, shipments, carrier_delivery_method_mappings] +tech-stack: + added: [] + patterns: [reuse existing ShipmentProviderInterface service list for settings mapping] +key-files: + created: + - .paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md + modified: + - routes/web.php + - src/Modules/Settings/ShopproIntegrationsController.php + - resources/views/settings/shoppro.php + - resources/lang/pl.php + - DOCS/ARCHITECTURE.md + - DOCS/TECH_CHANGELOG.md +key-decisions: + - "Use existing carrier_delivery_method_mappings; no schema change." + - "Load Polkurier services via PolkurierShipmentService instead of duplicating API calls in settings." +patterns-established: + - "shopPRO delivery mapping can add local providers by extending provider-specific hidden field + shared provider_service_name snapshot." +duration: 1h +started: 2026-05-18T00:00:00+02:00 +completed: 2026-05-18T00:00:00+02:00 +--- + +# Phase 140 Plan 01 Summary: shopPRO Polkurier Delivery Mapping + +shopPRO delivery forms can now be mapped directly to Polkurier services and later reused by the existing shipment prepare flow. + +## Status +UNIFY complete. Phase complete. + +## Performance + +| Metric | Value | +|--------|-------| +| Duration | ~1h | +| Started | 2026-05-18T00:00:00+02:00 | +| Completed | 2026-05-18T00:00:00+02:00 | +| Tasks | 3 completed | +| Files modified | 11 | + +## Tasks Completed + +### Task 1: Podlaczyc uslugi Polkurier do shopPRO delivery tab +- `ShopproIntegrationsController` dostal opcjonalna zaleznosc `PolkurierShipmentService`. +- Zakladka `delivery` przekazuje do widoku `polkurierDeliveryServices`. +- `saveDeliveryMappings()` obsluguje `carrier[]=polkurier` i zapisuje `provider='polkurier'` z `provider_service_id` z `polkurier_delivery_method_id[]`. +- `routes/web.php` przekazuje ten sam `PolkurierShipmentService` do kontrolera shopPRO i do `ShipmentProviderRegistry`. + +### Task 2: Dodac Polkurier do UI mapowan dostawy shopPRO +- W `resources/views/settings/shoppro.php` dodano opcje `Polkurier`, panel wyszukiwalnej listy uslug i hidden input `polkurier_delivery_method_id[]`. +- Istniejace mapowanie `provider='polkurier'` jest rozpoznawane i odtwarzane po odswiezeniu. +- JS czysci i synchronizuje pola Allegro/InPost/Apaczka/Polkurier bez zmiany schematu formularza. +- Tlumaczenia opisow i placeholderow w `resources/lang/pl.php` zostaly zaktualizowane. + +### Task 3: Udokumentowac kontrakt bez migracji +- `DOCS/ARCHITECTURE.md` opisuje mapowanie shopPRO -> Polkurier przez `carrier_delivery_method_mappings`. +- `DOCS/TECH_CHANGELOG.md` ma wpis z 2026-05-18. +- `DOCS/DB_SCHEMA.md` bez zmian, bo tabela juz miala potrzebne pola. + +## Verification +- PASS: `C:\xampp\php\php.exe -l routes/web.php` +- PASS: `C:\xampp\php\php.exe -l src/Modules/Settings/ShopproIntegrationsController.php` +- PASS: `C:\xampp\php\php.exe -l resources/views/settings/shoppro.php` +- PASS: `rg -n "polkurier|polkurierDeliveryServices|polkurier_delivery_method_id" src/Modules/Settings/ShopproIntegrationsController.php resources/views/settings/shoppro.php resources/lang/pl.php` +- PASS: `rg -n "shopPRO.*Polkurier|Polkurier.*shopPRO|2026-05-18" DOCS/ARCHITECTURE.md DOCS/TECH_CHANGELOG.md` +- PASS: `git diff --check` (only Git CRLF warnings, no whitespace errors) + +## Gaps / Not Run +- Manual UI smoke was not run because the local app/DB session was not started during APPLY. +- SonarQube scan was not run: `sonar-project.properties` exists, but `sonar-scanner` is not available in PATH and the Phase 139 `%TEMP%` fallback scanner is not present. + +## Files Modified +- `routes/web.php` +- `src/Modules/Settings/ShopproIntegrationsController.php` +- `resources/views/settings/shoppro.php` +- `resources/lang/pl.php` +- `DOCS/ARCHITECTURE.md` +- `DOCS/TECH_CHANGELOG.md` +- `.paul/PROJECT.md` +- `.paul/ROADMAP.md` +- `.paul/STATE.md` +- `.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md` +- `.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-SUMMARY.md` + +## Acceptance Criteria + +| Criterion | Status | Notes | +|-----------|--------|-------| +| AC-1: Polkurier Widoczny W Mapowaniu shopPRO | Pass | UI includes Polkurier and lists services from `PolkurierShipmentService::getDeliveryServices()`. | +| AC-2: Zapis Mapowania Polkurier | Pass | Save handler writes `provider='polkurier'`, selected service code and service name snapshot. | +| AC-3: Wczytanie Istniejacego Mapowania | Pass | Existing `provider='polkurier'` rows rehydrate the selected carrier and service. | +| AC-4: Przygotowanie Przesylki Korzysta Z Mapowania | Pass | Existing prepare flow reads shared mapping and receives `provider='polkurier'` plus mapped method id. | + +## Decisions Made + +| Decision | Rationale | Impact | +|----------|-----------|--------| +| Reuse `carrier_delivery_method_mappings` | Existing table already stores source, provider, service id and service name. | No migration required. | +| Reuse `PolkurierShipmentService::getDeliveryServices()` | Provider service already normalizes Polkurier available carriers. | Avoids a duplicate settings-only Polkurier API path. | + +## Deviations from Plan + +| Type | Count | Impact | +|------|-------|--------| +| Deferred verification | 2 | Manual UI smoke and Sonar scan documented as gaps. | + +## Next Phase Readiness + +**Ready:** +- Phase 140 is complete in code and documentation. +- The active v3.9 roadmap has no remaining phases after obsolete 140+ debt phases were removed by operator decision. + +**Concerns:** +- Manual UI smoke should be run when local app/DB are available. +- Sonar scan should be run once `sonar-scanner` is restored or downloaded again. + +**Blockers:** +- None for phase closure. diff --git a/DOCS/ARCHITECTURE.md b/DOCS/ARCHITECTURE.md index c00f69c..8e975f3 100644 --- a/DOCS/ARCHITECTURE.md +++ b/DOCS/ARCHITECTURE.md @@ -139,6 +139,7 @@ Phase 135 fixes daily net totals: `OrdersStatisticsRepository::netAmountSql()` p ### 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. Phase 131 extends the same Allegro-like contract into cron tracking: `ShipmentTrackingHandler` retries the Erli external parcel sync after a provider returns tracking status, but the retry is non-critical and never blocks local `delivery_status` updates. 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. +Phase 140 extends shopPRO delivery mapping with Polkurier. `/settings/integrations/shoppro?tab=delivery` now lists Polkurier services from `PolkurierShipmentService::getDeliveryServices()` and stores selected rows in `carrier_delivery_method_mappings` as `source_system='shoppro'`, `provider='polkurier'`, `provider_service_id=`, and `provider_service_name=`. No schema change is required; the existing shipment prepare flow already reads the shared mapping and preselects `provider='polkurier'` with the stored delivery method id. 1. **Create** — `ShipmentController::create()` → `ShipmentProviderRegistry` → carrier `ShipmentService::createShipment()` → `ShipmentPackageRepository::insert()` 2. **Track** — Cron `ShipmentTrackingHandler` → `ShipmentTrackingRegistry` → carrier tracking API → optional Erli external parcel retry → `ShipmentPackageRepository::updateDeliveryStatus()` → shared `shipment.status_changed` automation event when normalized status really changes. diff --git a/DOCS/TECH_CHANGELOG.md b/DOCS/TECH_CHANGELOG.md index 2333bc6..218671a 100644 --- a/DOCS/TECH_CHANGELOG.md +++ b/DOCS/TECH_CHANGELOG.md @@ -1,5 +1,19 @@ # Technical Changelog +## 2026-05-18 - Phase 140 Plan 01: shopPRO Polkurier Delivery Mapping + +**Co zrobiono:** +- Dodano Polkurier jako lokalnego providera w zakladce `Dostawy` ustawien integracji shopPRO. +- Lista uslug Polkurier w mapowaniu shopPRO korzysta z istniejacego `PolkurierShipmentService::getDeliveryServices()`, bez duplikowania klienta API w kontrolerze ustawien. +- Zapis mapowania formy dostawy shopPRO obsluguje `provider='polkurier'`, `provider_service_id=` i snapshot `provider_service_name`. +- Zachowano dotychczasowe mapowania Allegro WZA/InPost/Apaczka oraz istniejacy kontrakt tabeli `carrier_delivery_method_mappings`. + +**Dlaczego:** +- Operator musi mapowac formy dostawy shopPRO na Polkurier, aby pozniej przygotowanie przesylki automatycznie wybieralo wlasciwego providera i usluge bez recznego przelaczania. + +**BREAKING / migracja:** +- Brak migracji DB i brak zmian breaking; wykorzystano istniejaca tabele `carrier_delivery_method_mappings`. + ## 2026-05-17 - Phase 139 Plan 02: Sonar Critical/Major Cleanup **Co zrobiono:** diff --git a/resources/lang/pl.php b/resources/lang/pl.php index 788be8d..68f8d35 100644 --- a/resources/lang/pl.php +++ b/resources/lang/pl.php @@ -1289,17 +1289,18 @@ return [ ], 'delivery' => [ 'title' => 'Formy dostawy', - 'description' => 'Mapowanie form dostawy shopPRO do uslug nadawczych Allegro WZA/InPost.', + 'description' => 'Mapowanie form dostawy shopPRO do uslug nadawczych Allegro WZA/InPost/Apaczka/Polkurier.', 'select_integration_first' => 'Najpierw wybierz lub zapisz integracje w zakladce Integracja.', 'empty_orders' => 'Brak form dostawy shopPRO wykrytych w zamowieniach tej integracji.', 'not_connected' => 'Brak aktywnego polaczenia Allegro. Podlacz konto Allegro, aby pobrac liste uslug dostawy.', 'no_inpost_services' => 'Brak uslug InPost (sprawdz polaczenie z Allegro).', + 'no_polkurier_services' => 'Brak uslug Polkurier (sprawdz konfiguracje w Ustawienia > Integracje > polkurier).', 'fields' => [ 'order_method' => 'Forma dostawy shopPRO', 'carrier' => 'Przewoznik', 'allegro_service' => 'Usluga dostawy', 'no_mapping' => 'brak mapowania', - 'search_placeholder' => 'Szukaj uslugi Allegro...', + 'search_placeholder' => 'Szukaj uslugi...', 'select_carrier_first' => 'Najpierw wybierz przewoznika.', ], 'actions' => [ diff --git a/resources/views/settings/shoppro.php b/resources/views/settings/shoppro.php index bb8c6f6..8377431 100644 --- a/resources/views/settings/shoppro.php +++ b/resources/views/settings/shoppro.php @@ -16,6 +16,7 @@ $dmMappings = is_array($deliveryMappings ?? null) ? $deliveryMappings : []; $dmOrderMethods = is_array($orderDeliveryMethods ?? null) ? $orderDeliveryMethods : []; $dmAllegroServices = is_array($allegroDeliveryServices ?? null) ? $allegroDeliveryServices : []; $dmApaczkaServices = is_array($apaczkaDeliveryServices ?? null) ? $apaczkaDeliveryServices : []; +$dmPolkurierServices = is_array($polkurierDeliveryServices ?? null) ? $polkurierDeliveryServices : []; $dmInpostServices = is_array($inpostDeliveryServices ?? null) ? $inpostDeliveryServices : []; $dmServicesError = (string) ($allegroDeliveryServicesError ?? ''); $dmMappingsByMethod = []; @@ -480,7 +481,9 @@ foreach ($dmMappings as $dm) { $currentServiceName = $currentMapping !== null ? trim((string) ($currentMapping['provider_service_name'] ?? '')) : ''; $currentProviderCarrierId = $currentMapping !== null ? trim((string) ($currentMapping['provider_carrier_id'] ?? '')) : ''; $currentCarrier = ''; - if ($currentProvider === 'apaczka') { + if ($currentProvider === 'polkurier') { + $currentCarrier = 'polkurier'; + } elseif ($currentProvider === 'apaczka') { $currentCarrier = 'apaczka'; } elseif (stripos($currentProviderCarrierId, 'inpost') !== false) { $currentCarrier = 'inpost'; @@ -499,12 +502,14 @@ foreach ($dmMappings as $dm) { +
- + + @@ -602,6 +607,39 @@ foreach ($dmMappings as $dm) {
+
+ +
+ + +
+
+ -- -- +
+ + +
+ +
+ +
+ +
+
@@ -690,9 +728,11 @@ foreach ($dmMappings as $dm) { var allegroPanel = serviceWrap.querySelector('.dm-allegro-panel'); var inpostPanel = serviceWrap.querySelector('.dm-inpost-panel'); var apaczkaPanel = serviceWrap.querySelector('.dm-apaczka-panel'); + var polkurierPanel = serviceWrap.querySelector('.dm-polkurier-panel'); var emptyPanel = serviceWrap.querySelector('.dm-empty-panel'); var hiddenMethodId = serviceWrap.querySelector('.dm-hidden-method-id'); var hiddenApaczkaMethodId = serviceWrap.querySelector('.dm-hidden-apaczka-method-id'); + var hiddenPolkurierMethodId = serviceWrap.querySelector('.dm-hidden-polkurier-method-id'); var hiddenCredentialsId = serviceWrap.querySelector('.dm-hidden-credentials-id'); var hiddenCarrierId = serviceWrap.querySelector('.dm-hidden-carrier-id'); var hiddenServiceName = serviceWrap.querySelector('.dm-hidden-service-name'); @@ -701,6 +741,7 @@ foreach ($dmMappings as $dm) { if (allegroPanel) allegroPanel.style.display = carrier === 'allegro' ? '' : 'none'; if (inpostPanel) inpostPanel.style.display = carrier === 'inpost' ? '' : 'none'; if (apaczkaPanel) apaczkaPanel.style.display = carrier === 'apaczka' ? '' : 'none'; + if (polkurierPanel) polkurierPanel.style.display = carrier === 'polkurier' ? '' : 'none'; if (emptyPanel) emptyPanel.style.display = carrier === '' ? '' : 'none'; } @@ -711,6 +752,7 @@ foreach ($dmMappings as $dm) { showPanel(carrier); if (hiddenMethodId) hiddenMethodId.value = ''; if (hiddenApaczkaMethodId) hiddenApaczkaMethodId.value = ''; + if (hiddenPolkurierMethodId) hiddenPolkurierMethodId.value = ''; if (hiddenCredentialsId) hiddenCredentialsId.value = ''; if (hiddenCarrierId) hiddenCarrierId.value = ''; if (hiddenServiceName) hiddenServiceName.value = ''; @@ -723,7 +765,7 @@ foreach ($dmMappings as $dm) { if (allegroDropdown) { allegroDropdown.classList.remove('is-open'); } - [inpostPanel, apaczkaPanel].forEach(function (panel) { + [inpostPanel, apaczkaPanel, polkurierPanel].forEach(function (panel) { if (!panel) return; var inp = panel.querySelector('.dm-search-input'); if (inp) { inp.value = ''; inp.blur(); } @@ -742,6 +784,7 @@ foreach ($dmMappings as $dm) { var hiddenMethodId = serviceWrap.querySelector('.dm-hidden-method-id'); var hiddenApaczkaMethodId = serviceWrap.querySelector('.dm-hidden-apaczka-method-id'); + var hiddenPolkurierMethodId = serviceWrap.querySelector('.dm-hidden-polkurier-method-id'); var hiddenCredentialsId = serviceWrap.querySelector('.dm-hidden-credentials-id'); var hiddenCarrierId = serviceWrap.querySelector('.dm-hidden-carrier-id'); var hiddenServiceName = serviceWrap.querySelector('.dm-hidden-service-name'); @@ -751,16 +794,24 @@ foreach ($dmMappings as $dm) { var provider = wrapper.getAttribute('data-provider') || ''; var isApaczka = provider === 'apaczka'; + var isPolkurier = provider === 'polkurier'; function selectOption(opt) { var val = opt.getAttribute('data-value') || ''; if (isApaczka) { if (hiddenMethodId) hiddenMethodId.value = ''; if (hiddenApaczkaMethodId) hiddenApaczkaMethodId.value = val; + if (hiddenPolkurierMethodId) hiddenPolkurierMethodId.value = ''; + if (hiddenCredentialsId) hiddenCredentialsId.value = ''; + } else if (isPolkurier) { + if (hiddenMethodId) hiddenMethodId.value = ''; + if (hiddenApaczkaMethodId) hiddenApaczkaMethodId.value = ''; + if (hiddenPolkurierMethodId) hiddenPolkurierMethodId.value = val; if (hiddenCredentialsId) hiddenCredentialsId.value = ''; } else { if (hiddenMethodId) hiddenMethodId.value = val; if (hiddenApaczkaMethodId) hiddenApaczkaMethodId.value = ''; + if (hiddenPolkurierMethodId) hiddenPolkurierMethodId.value = ''; if (hiddenCredentialsId) hiddenCredentialsId.value = opt.getAttribute('data-credentials-id') || ''; } if (hiddenCarrierId) hiddenCarrierId.value = opt.getAttribute('data-carrier-id') || ''; diff --git a/routes/web.php b/routes/web.php index 910d97a..3b78535 100644 --- a/routes/web.php +++ b/routes/web.php @@ -188,6 +188,19 @@ return static function (Application $app): void { $auth, $inpostIntegrationRepository ); + $companySettingsRepository = new CompanySettingsRepository($app->db()); + $shipmentPackageRepository = new ShipmentPackageRepository($app->db()); + $polkurierIntegrationRepository = new PolkurierIntegrationRepository( + $app->db(), + (string) $app->config('app.integrations.secret', '') + ); + $polkurierShipmentService = new PolkurierShipmentService( + $polkurierIntegrationRepository, + new PolkurierApiClient(), + $shipmentPackageRepository, + $companySettingsRepository, + new OrdersRepository($app->db()) + ); $shopproIntegrationsRepository = new ShopproIntegrationsRepository( $app->db(), (string) $app->config('app.integrations.secret', '') @@ -206,7 +219,8 @@ return static function (Application $app): void { $allegroOAuthClient, new AllegroApiClient(), $apaczkaIntegrationRepository, - $apaczkaApiClient + $apaczkaApiClient, + $polkurierShipmentService ); $fakturowniaIntegrationRepository = new FakturowniaIntegrationRepository( $app->db(), @@ -233,10 +247,6 @@ return static function (Application $app): void { new HostedSmsApiClient(), new IntegrationsRepository($app->db()) ); - $polkurierIntegrationRepository = new PolkurierIntegrationRepository( - $app->db(), - (string) $app->config('app.integrations.secret', '') - ); $polkurierIntegrationController = new PolkurierIntegrationController( $template, $translator, @@ -314,7 +324,6 @@ return static function (Application $app): void { $deliveryStatusMappingRepository, $deliveryStatusRepository ); - $companySettingsRepository = new CompanySettingsRepository($app->db()); $companySettingsController = new CompanySettingsController( $template, $translator, @@ -482,7 +491,6 @@ return static function (Application $app): void { new MfWhitelistApiClient() ); $allegroApiClient = new AllegroApiClient(); - $shipmentPackageRepository = new ShipmentPackageRepository($app->db()); $shipmentService = new AllegroShipmentService( $allegroTokenManager, $allegroApiClient, @@ -503,13 +511,6 @@ return static function (Application $app): void { $companySettingsRepository, new OrdersRepository($app->db()) ); - $polkurierShipmentService = new PolkurierShipmentService( - $polkurierIntegrationRepository, - new PolkurierApiClient(), - $shipmentPackageRepository, - $companySettingsRepository, - new OrdersRepository($app->db()) - ); $shipmentProviderRegistry = new ShipmentProviderRegistry([ $shipmentService, $apaczkaShipmentService, diff --git a/src/Modules/Settings/ShopproIntegrationsController.php b/src/Modules/Settings/ShopproIntegrationsController.php index 9f16d98..cf75c0e 100644 --- a/src/Modules/Settings/ShopproIntegrationsController.php +++ b/src/Modules/Settings/ShopproIntegrationsController.php @@ -15,6 +15,7 @@ use DateInterval; use DateTimeImmutable; use App\Core\Constants\IntegrationSources; use App\Core\Constants\RedirectPaths; +use App\Modules\Shipments\PolkurierShipmentService; use RuntimeException; use Throwable; @@ -47,7 +48,8 @@ final class ShopproIntegrationsController private readonly AllegroOAuthClient $allegroOAuthClient, private readonly AllegroApiClient $allegroApiClient, private readonly ?ApaczkaIntegrationRepository $apaczkaRepository = null, - private readonly ?ApaczkaApiClient $apaczkaApiClient = null + private readonly ?ApaczkaApiClient $apaczkaApiClient = null, + private readonly ?PolkurierShipmentService $polkurierShipmentService = null ) { } @@ -80,7 +82,7 @@ final class ShopproIntegrationsController : []; $deliveryServicesData = $activeTab === 'delivery' ? $this->loadDeliveryServices() - : [[], [], '']; + : [[], [], [], '']; $deliveryMappings = $selectedIntegration !== null ? $this->deliveryMappings->listMappings(IntegrationSources::SHOPPRO, (int) ($selectedIntegration['id'] ?? 0)) : []; @@ -109,7 +111,8 @@ final class ShopproIntegrationsController 'orderDeliveryMethods' => $orderDeliveryMethods, 'allegroDeliveryServices' => $deliveryServicesData[0], 'apaczkaDeliveryServices' => $deliveryServicesData[1], - 'allegroDeliveryServicesError' => $deliveryServicesData[2], + 'polkurierDeliveryServices' => $deliveryServicesData[2], + 'allegroDeliveryServicesError' => $deliveryServicesData[3], 'inpostDeliveryServices' => array_values(array_filter( $deliveryServicesData[0], static fn (array $svc): bool => stripos((string) ($svc['carrierId'] ?? ''), 'inpost') !== false @@ -383,6 +386,7 @@ final class ShopproIntegrationsController $carriers = (array) $request->input('carrier', []); $allegroMethodIds = (array) $request->input('allegro_delivery_method_id', []); $apaczkaMethodIds = (array) $request->input('apaczka_delivery_method_id', []); + $polkurierMethodIds = (array) $request->input('polkurier_delivery_method_id', []); $credentialsIds = (array) $request->input('allegro_credentials_id', []); $carrierIds = (array) $request->input('allegro_carrier_id', []); $serviceNames = (array) $request->input('allegro_service_name', []); @@ -392,10 +396,12 @@ final class ShopproIntegrationsController foreach ($orderMethods as $index => $orderMethod) { $orderMethodValue = trim((string) $orderMethod); $carrier = trim((string) ($carriers[$index] ?? 'allegro')); - $provider = $carrier === 'apaczka' ? 'apaczka' : 'allegro_wza'; - $providerServiceId = $provider === 'apaczka' - ? trim((string) ($apaczkaMethodIds[$index] ?? '')) - : trim((string) ($allegroMethodIds[$index] ?? '')); + $provider = $this->resolveDeliveryProvider($carrier); + $providerServiceId = match ($provider) { + 'apaczka' => trim((string) ($apaczkaMethodIds[$index] ?? '')), + 'polkurier' => trim((string) ($polkurierMethodIds[$index] ?? '')), + default => trim((string) ($allegroMethodIds[$index] ?? '')), + }; if ($orderMethodValue === '' || $providerServiceId === '') { continue; } @@ -423,6 +429,15 @@ final class ShopproIntegrationsController return Response::redirect($redirectTo); } + private function resolveDeliveryProvider(string $carrier): string + { + return match (trim($carrier)) { + 'apaczka' => 'apaczka', + 'polkurier' => 'polkurier', + default => 'allegro_wza', + }; + } + /** * @param array|null $integration * @return array @@ -920,18 +935,35 @@ final class ShopproIntegrationsController } /** - * @return array{0: array>, 1: array>, 2: string} + * @return array{0: array>, 1: array>, 2: array>, 3: string} */ private function loadDeliveryServices(): array { [$allegroServices, $errorMessage] = $this->loadAllegroDeliveryServices(); [$apaczkaServices, $apaczkaError] = $this->loadApaczkaServices(); + $polkurierServices = $this->loadPolkurierServices(); if ($errorMessage === '' && $apaczkaError !== '') { $errorMessage = $apaczkaError; } - return [$allegroServices, $apaczkaServices, $errorMessage]; + return [$allegroServices, $apaczkaServices, $polkurierServices, $errorMessage]; + } + + /** + * @return array> + */ + private function loadPolkurierServices(): array + { + if ($this->polkurierShipmentService === null) { + return []; + } + + try { + return $this->polkurierShipmentService->getDeliveryServices(); + } catch (Throwable) { + return []; + } } /**