feat(130): polkurier delivery status mappings UI

Phase 130 complete (1 plan):
- POLKURIER_MAP + POLKURIER_DESCRIPTIONS w DeliveryStatus.php (7 wpisow O/P/A/WP/D/Z/W z dokumentacji v1.11)
- 'polkurier' w PROVIDERS w DeliveryStatusesController + DeliveryStatusMappingController
- countAllUnmappedForBadge() zlicza polkurier
- Defaulty hardcoded w kodzie (spojnie z InPost/Apaczka/Allegro); migracja Phase 128 staje sie no-op
- Zero zmian w widoku (_delivery-status-mappings-content.php auto-iteruje po providerach)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-14 17:17:48 +02:00
parent 48351b5f36
commit 27df08e661
11 changed files with 462 additions and 14 deletions

View File

@@ -13,8 +13,8 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
| Attribute | Value | | Attribute | Value |
|-----------|-------| |-----------|-------|
| Version | 3.7.0-dev | | Version | 3.7.0-dev |
| Status | v3.7 in progress — Phases 113-129 shipped (Fakturownia + HostedSMS/SMSPLANET + Alert unify + receipt VAT + SMS templates + invoice_requested import fix + invoice GUS mapping + polkurier foundation + polkurier shipment service + order user notes) | | Status | v3.7 in progress — Phases 113-130 shipped (Fakturownia + HostedSMS/SMSPLANET + Alert unify + receipt VAT + SMS templates + invoice_requested import fix + invoice GUS mapping + polkurier foundation + polkurier shipment service + order user notes + polkurier delivery status mappings UI) |
| Last Updated | 2026-05-14 (Phase 129 closed) | | Last Updated | 2026-05-14 (Phase 130 closed) |
## Requirements ## Requirements
@@ -129,6 +129,7 @@ Sprzedawca moĹĽe obsĹugiwać zamĂłwienia ze wszystkich kanaĹĂłw
- [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] 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] 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 - [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
- [x] polkurier delivery status mappings UI (Phase 130): polkurier jako 4. provider w dropdownie `/settings/delivery-statuses?tab=mapping`. `POLKURIER_MAP` + `POLKURIER_DESCRIPTIONS` w `DeliveryStatus.php` (7 wpisow O/P/A/WP/D/Z/W z oficjalnej dokumentacji v1.11, identyczne z migracja Phase 128 — DB seed staje sie no-op). `PROVIDERS` rozszerzone w `DeliveryStatusesController` + `DeliveryStatusMappingController`. `countAllUnmappedForBadge()` zlicza polkurier. Zero zmian w widoku (`_delivery-status-mappings-content.php` auto-iteruje po providerach z controllera) — Phase 130
### Deferred ### Deferred
@@ -254,6 +255,8 @@ PHP (XAMPP/Laravel), integracje z API marketplace'Ăłw (Allegro, Erli) oraz API
| Autoryzacja CRUD przez `WHERE user_id = :user_id` + rowCount=0 ⇒ `RuntimeException(403)` (Phase 129) | Eliminacja konieczności osobnego SELECT pre-check'a — atomowy UPDATE/DELETE z filtrem user_id robi to w jednym query. Wzorzec do reuse dla innych zasobow "ownership-based" w aplikacji. | 2026-05-14 | Active | | Autoryzacja CRUD przez `WHERE user_id = :user_id` + rowCount=0 ⇒ `RuntimeException(403)` (Phase 129) | Eliminacja konieczności osobnego SELECT pre-check'a — atomowy UPDATE/DELETE z filtrem user_id robi to w jednym query. Wzorzec do reuse dla innych zasobow "ownership-based" w aplikacji. | 2026-05-14 | Active |
| Brak admin override dla notatek (Phase 129) — tylko autor edit/delete | Aplikacja nie ma systemu rol (`grep is_admin\|role=` zwrocil 0 trafien). Odlozone do osobnej fazy gdy beda role; obecnie operator ktory dodal notatke moze ja modyfikowac, inni widzą ale nie modyfikują. | 2026-05-14 | Deferred | | Brak admin override dla notatek (Phase 129) — tylko autor edit/delete | Aplikacja nie ma systemu rol (`grep is_admin\|role=` zwrocil 0 trafien). Odlozone do osobnej fazy gdy beda role; obecnie operator ktory dodal notatke moze ja modyfikowac, inni widzą ale nie modyfikują. | 2026-05-14 | Deferred |
| Badge `[N]` w `order_ref` przy nr zamowienia (Phase 129) — neutralny indigo, NIE alertowy | Subtelniejszy niz `.risk-return-badge` (czerwony, alertowy) — notatki to informacja, nie ostrzezenie. Klik scrolluje do `#notes` w szczegolach zamowienia. Pattern do reuse dla kolejnych metryk per-order (np. liczba SMS, liczba dokumentow). | 2026-05-14 | Active | | Badge `[N]` w `order_ref` przy nr zamowienia (Phase 129) — neutralny indigo, NIE alertowy | Subtelniejszy niz `.risk-return-badge` (czerwony, alertowy) — notatki to informacja, nie ostrzezenie. Klik scrolluje do `#notes` w szczegolach zamowienia. Pattern do reuse dla kolejnych metryk per-order (np. liczba SMS, liczba dokumentow). | 2026-05-14 | Active |
| Provider-addition recipe dla `/settings/delivery-statuses?tab=mapping` (Phase 130) | 5 punktow edycji w 4 plikach: (1) const definition `XXX_MAP`/`XXX_DESCRIPTIONS` w `DeliveryStatus.php`, (2) rejestracja w `PROVIDER_MAPS`/`PROVIDER_DESCRIPTIONS`, (3) match arms w `normalize()`/`description()`, (4) `PROVIDERS` const w `DeliveryStatusesController` + `DeliveryStatusMappingController`, (5) lista providerow w `DeliveryStatusMappingRepository::countAllUnmappedForBadge()`. Widok `_delivery-status-mappings-content.php` automatycznie iteruje. Pattern do reuse dla kazdego nowego przewoznika. | 2026-05-14 | Active |
| Defaultowe mapowania statusow dostawy hardcoded w kodzie (nie tylko z DB seed) | Spojnosc z InPost/Apaczka/Allegro — wszyscy maja hardcoded fallback w `DeliveryStatus.php`. UI dziala od razu po deploy, niezaleznie czy operator uruchomil migracje seed. DB override (`delivery_status_mappings`) nadal dziala dla kazdego raw statusu — pattern dual-source (kod default + DB override) zachowany. | 2026-05-14 | Active |
## Success Metrics ## Success Metrics
@@ -285,6 +288,6 @@ Quick Reference:
--- ---
*PROJECT.md — Updated when requirements or context change* *PROJECT.md — Updated when requirements or context change*
*Last updated: 2026-05-14 after Phase 128 (polkurier ShipmentService + Tracking + UI prepare) closure; v3.7 milestone in progress* *Last updated: 2026-05-14 after Phase 130 (polkurier delivery status mappings UI) closure; v3.7 milestone in progress*

View File

@@ -29,6 +29,7 @@ Wystawianie faktur dla klientow z NIP poprzez integracje z Fakturownia (app.fakt
| 127 | polkurier Integration Foundation (single-instance settings + Token API + realny test polaczenia; obok Apaczki) | 1/1 | Complete (2026-05-14; live API verified — `Autoryzacja: 1`) | | 127 | polkurier Integration Foundation (single-instance settings + Token API + realny test polaczenia; obok Apaczki) | 1/1 | Complete (2026-05-14; live API verified — `Autoryzacja: 1`) |
| 128 | polkurier ShipmentService + TrackingService + UI prepare panel + delivery_status_mappings seed (live test na #114/#115) | 1/1 | Complete (2026-05-14; live test passed po 4 iteracjach; migracja + cron tracking weryfikacja pending) | | 128 | polkurier ShipmentService + TrackingService + UI prepare panel + delivery_status_mappings seed (live test na #114/#115) | 1/1 | Complete (2026-05-14; live test passed po 4 iteracjach; migracja + cron tracking weryfikacja pending) |
| 129 | Order User Notes module (extend `order_notes` o user_id/author_name/note_type='user' + pelen CRUD restricted to author + badge `[N]` na liscie zamowien) | 1/1 | Complete (2026-05-14; migracja + manualny smoke pending operator) | | 129 | Order User Notes module (extend `order_notes` o user_id/author_name/note_type='user' + pelen CRUD restricted to author + badge `[N]` na liscie zamowien) | 1/1 | Complete (2026-05-14; migracja + manualny smoke pending operator) |
| 130 | polkurier delivery status mappings UI (hardcoded POLKURIER_MAP/DESCRIPTIONS + dropdown w `/settings/delivery-statuses?tab=mapping` + badge counter) | 1/1 | Complete (2026-05-14; manualny smoke pending operator) |
Planowane kolejne fazy v3.7 (kandydaci, do rozplanowania): Planowane kolejne fazy v3.7 (kandydaci, do rozplanowania):
- polkurier TrackingService + `delivery_status_mappings` (provider='polkurier') - polkurier TrackingService + `delivery_status_mappings` (provider='polkurier')
@@ -513,4 +514,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md`
--- ---
*Roadmap created: 2026-03-12* *Roadmap created: 2026-03-12*
*Last updated: 2026-05-14 - Phase 129 UNIFY closed (Order User Notes module; migracja + smoke pending operator)* *Last updated: 2026-05-14 - Phase 130 UNIFY closed (polkurier delivery status mappings UI; manualny smoke pending operator)*

View File

@@ -5,19 +5,19 @@
See: .paul/PROJECT.md (updated 2026-05-07) See: .paul/PROJECT.md (updated 2026-05-07)
**Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami. **Core value:** Sprzedawca moze obslugiwac zamowienia ze wszystkich kanalow sprzedazy i nadawac przesylki bez przelaczania sie miedzy platformami.
**Current focus:** v3.7 Invoices + operational integrations - Phase 128 polkurier ShipmentService loop closed, transition pending (git commit + ROADMAP/PROJECT update). **Current focus:** v3.7 Invoices + operational integrations - Phase 130 polkurier delivery status mappings UI loop closed, transition pending (git commit + PROJECT/ROADMAP update).
## Current Position ## Current Position
Milestone: v3.7 Invoices (Fakturownia integration) - In progress Milestone: v3.7 Invoices (Fakturownia integration) - In progress
Phase: 129 of TBD (Order User Notes module) - Complete Phase: 130 of TBD (polkurier delivery status mappings UI) - Complete
Plan: 129-01 complete (SUMMARY.md created) Plan: 130-01 complete (SUMMARY.md created)
Status: UNIFY complete, transition pending (git commit + Decisions w PROJECT.md + ROADMAP status) Status: UNIFY complete, transition pending (git commit + Decisions w PROJECT.md + ROADMAP status)
Last activity: 2026-05-14 - Phase 129-01 UNIFY zakonczony, SUMMARY + changelog utworzone Last activity: 2026-05-14 - Phase 130-01 UNIFY zakonczony, SUMMARY + tech_changelog + changelog utworzone
Progress: Progress:
- Milestone v3.7: [##########] ~99% (Phase 113-129 complete; transition pending) - Milestone v3.7: [##########] ~99% (Phase 113-130 complete; transition pending)
- Phase 129: [##########] 100% - Phase 130: [##########] 100%
## Loop Position ## Loop Position
@@ -30,9 +30,9 @@ PLAN -> APPLY -> UNIFY
## Session Continuity ## Session Continuity
Last session: 2026-05-14 Last session: 2026-05-14
Stopped at: Phase 129-01 UNIFY closed; SUMMARY.md created Stopped at: Phase 130-01 UNIFY closed; SUMMARY.md created
Next action: Phase transition (git commit `feat(129): order user notes module` + Decisions w PROJECT.md + ROADMAP status update), potem wybor kolejnego kandydata v3.7 (paczkomaty polkurier UI / event automatyzacji note.created / eksport XLSX faktur / invoice.created event / admin override dla notatek po wprowadzeniu rol) Next action: Phase transition (git commit `feat(130): polkurier delivery status mappings UI` + Decisions w PROJECT.md + ROADMAP status update), potem wybor kolejnego kandydata v3.7
Resume file: .paul/phases/129-order-user-notes/129-01-SUMMARY.md Resume file: .paul/phases/130-polkurier-delivery-status-mappings/130-01-SUMMARY.md
## Pending parallel work ## Pending parallel work
- None — Phase 118, 121, 122 wszystkie zacommitowane (8f14851, 360eef1). - None — Phase 118, 121, 122 wszystkie zacommitowane (8f14851, 360eef1).
@@ -74,6 +74,8 @@ Branch: main (7 commits ahead of origin/main)
- Phase 129 follow-up: uruchom migracje gdy XAMPP MySQL online: `php bin/migrate.php` (utworzy `order_notes.user_id` + `author_name` + FK + indeks `idx_order_notes_type_order`). - Phase 129 follow-up: uruchom migracje gdy XAMPP MySQL online: `php bin/migrate.php` (utworzy `order_notes.user_id` + `author_name` + FK + indeks `idx_order_notes_type_order`).
- Phase 129 follow-up: manualny smoke — `/orders/{X}` → sekcja "Notatki" widoczna, dodanie notatki tworzy wiersz + wpis w `order_activity_log`. Drugi user (`session.user_id != note.user_id`) nie widzi przycisków Edytuj/Usuń; POST `/notes/{noteId}/delete` jako inny user → 403 flash. - Phase 129 follow-up: manualny smoke — `/orders/{X}` → sekcja "Notatki" widoczna, dodanie notatki tworzy wiersz + wpis w `order_activity_log`. Drugi user (`session.user_id != note.user_id`) nie widzi przycisków Edytuj/Usuń; POST `/notes/{noteId}/delete` jako inny user → 403 flash.
- Phase 129 follow-up: `/orders/list` → badge `[N]` widoczny przy zamówieniach z notatkami autorskimi; klik scrolluje do `#notes` w szczegółach. Sprawdzić że badge zwrotów (Phase 106) działa równolegle. - Phase 129 follow-up: `/orders/list` → badge `[N]` widoczny przy zamówieniach z notatkami autorskimi; klik scrolluje do `#notes` w szczegółach. Sprawdzić że badge zwrotów (Phase 106) działa równolegle.
- Phase 130 follow-up: manualny smoke `/settings/delivery-statuses?tab=mapping` → dropdown ma 4 pozycje; `?provider=polkurier` → 7 wierszy (O/P/A/WP/D/Z/W) z `is_custom=false`. Override (zapis nowego mapowania) → wiersz przechodzi w `is_custom=true`.
- Phase 130 follow-up: migracja Phase 128 (`20260514_000115_seed_polkurier_delivery_status_mappings.sql`) staje się no-op — można ją uruchomić lub pominąć, defaulty z kodu pokryją tę samą wartość.
## Deferred to Next Milestones ## Deferred to Next Milestones

View File

@@ -82,3 +82,20 @@
- `.paul/STATE.md`, `.paul/ROADMAP.md` - `.paul/STATE.md`, `.paul/ROADMAP.md`
- `.paul/phases/129-order-user-notes/129-01-PLAN.md` (nowy plik) - `.paul/phases/129-order-user-notes/129-01-PLAN.md` (nowy plik)
- `.paul/phases/129-order-user-notes/129-01-SUMMARY.md` (nowy plik) - `.paul/phases/129-order-user-notes/129-01-SUMMARY.md` (nowy plik)
## Co zrobiono (cd. — Phase 130)
- [Phase 130, Plan 01] polkurier delivery status mappings UI — polkurier widoczny jako 4. provider w dropdownie `/settings/delivery-statuses?tab=mapping`. 7 oficjalnych kodow ORDER_STATUS z dokumentacji polkurier v1.11 (O/P/A/WP/D/Z/W) hardcoded w `DeliveryStatus::POLKURIER_MAP`/`POLKURIER_DESCRIPTIONS` jako defaulty (spojnie z InPost/Apaczka/Allegro). Badge "niezmapowane" w menu zlicza teraz polkurier obok innych providerow.
- Task 1: `DeliveryStatus.php``POLKURIER_MAP` (7 wpisow) + `POLKURIER_DESCRIPTIONS` + rejestracja w `PROVIDER_MAPS`, `PROVIDER_DESCRIPTIONS`, oraz w match expressions `normalize()`/`description()`. Wartosci identyczne z migracja Phase 128 (DB seed staje sie no-op).
- Task 2: Stale `PROVIDERS` w `DeliveryStatusesController` i `DeliveryStatusMappingController` rozszerzone o `'polkurier' => 'polkurier'`. `DeliveryStatusMappingRepository::countAllUnmappedForBadge()`: lista providerow rozszerzona z 3 do 4.
- Brak deviacji vs PLAN — wszystkie 5 punktow edycji zaaplikowane czysto, PHP lint clean na 4 plikach, runtime `getDefaultMappings('polkurier')` zwrocil oczekiwane 7 wpisow.
## Zmienione pliki (cd. — Phase 130)
- `src/Modules/Shipments/DeliveryStatus.php` (+25 linii)
- `src/Modules/Settings/DeliveryStatusesController.php` (+1)
- `src/Modules/Settings/DeliveryStatusMappingController.php` (+1)
- `src/Modules/Shipments/DeliveryStatusMappingRepository.php` (1 ↔)
- `.paul/phases/130-polkurier-delivery-status-mappings/130-01-PLAN.md` (nowy plik)
- `.paul/phases/130-polkurier-delivery-status-mappings/130-01-SUMMARY.md` (nowy plik)
- `.paul/STATE.md`, `.paul/ROADMAP.md`

View File

@@ -1,5 +1,31 @@
# Technical Changelog # Technical Changelog
## 2026-05-14 - Phase 130 Plan 01: polkurier delivery status mappings UI
**Co zrobiono:**
- `src/Modules/Shipments/DeliveryStatus.php` — nowe stałe `POLKURIER_MAP` i `POLKURIER_DESCRIPTIONS` z 7 oficjalnymi kodami ORDER_STATUS z dokumentacji polkurier API v1.11 (`O``created`, `P``confirmed`, `A``cancelled`, `WP``in_transit`, `D``delivered`, `Z``returned`, `W``problem`). Wartości identyczne z migracją Phase 128 (`20260514_000115_seed_polkurier_delivery_status_mappings.sql`).
- `src/Modules/Shipments/DeliveryStatus.php` — rejestracja `'polkurier' => self::POLKURIER_MAP` w `PROVIDER_MAPS` (po `'allegro_edge'`), analogicznie w `PROVIDER_DESCRIPTIONS`, oraz w match expressions `normalize()`/`description()`. `getDefaultMappings('polkurier')` zwraca 7 wpisów.
- `src/Modules/Settings/DeliveryStatusesController.php` + `DeliveryStatusMappingController.php` — stałe `PROVIDERS` rozszerzone z 3 do 4 wpisów: `'polkurier' => 'polkurier'` (lowercase, spójne z Phase 127).
- `src/Modules/Shipments/DeliveryStatusMappingRepository.php``countAllUnmappedForBadge()`: lista providerów rozszerzona z `['inpost', 'apaczka', 'allegro_wza']` do `['inpost', 'apaczka', 'allegro_wza', 'polkurier']`. Badge "niezmapowane statusy" w menu Ustawień reaguje teraz na nieznane raw statusy polkuriera.
- View `_delivery-status-mappings-content.php` automatycznie iteruje po `$providersList` z controllera — żadnych zmian w widoku nie trzeba.
**Dlaczego:**
- Phase 128 zaseed-owała DB override (`delivery_status_mappings` 7 wpisów) ale UI mapowania pozostał hardcoded na 3 providerów. Operator nie miał jak zmapować/podejrzeć statusów polkuriera w panelu.
- Defaultowe mapowania hardcoded w kodzie (nie tylko z DB) — spójność z InPost/Apaczka/Allegro (wszyscy mają hardcoded fallback). UI działa od razu, niezależnie czy operator uruchomił migrację Phase 128.
- Pattern `provider addition`: 5 punktów edycji w 4 plikach (1 const definition + 2 PROVIDER_* + 2 match arms + 2× PROVIDERS controller + 1 badge providers list) — checklist do reuse dla następnych przewoźników.
**Side-effects:**
- Migracja `20260514_000115_seed_polkurier_delivery_status_mappings.sql` (Phase 128) staje się no-op po wdrożeniu Phase 130 — DB override == hardcoded default → render `is_custom=true` ale ta sama wartość. Migracja może być uruchomiona lub nie.
**Files modified:**
- `src/Modules/Shipments/DeliveryStatus.php`
- `src/Modules/Settings/DeliveryStatusesController.php`
- `src/Modules/Settings/DeliveryStatusMappingController.php`
- `src/Modules/Shipments/DeliveryStatusMappingRepository.php`
- `.paul/codebase/tech_changelog.md` (this entry)
---
## 2026-05-14 - Phase 129 Plan 01: Order User Notes module ## 2026-05-14 - Phase 129 Plan 01: Order User Notes module
**Co zrobiono:** **Co zrobiono:**

View File

@@ -0,0 +1,238 @@
---
phase: 130-polkurier-delivery-status-mappings
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- src/Modules/Shipments/DeliveryStatus.php
- src/Modules/Settings/DeliveryStatusesController.php
- src/Modules/Settings/DeliveryStatusMappingController.php
- src/Modules/Shipments/DeliveryStatusMappingRepository.php
autonomous: true
delegation: off
---
<objective>
## Goal
Eksponuj `polkurier` w UI `/settings/delivery-statuses?tab=mapping`: dropdown providerów pokazuje pozycję "polkurier", 7 domyślnych mapowań (O/P/A/WP/D/Z/W) ładuje się z `DeliveryStatus::getDefaultMappings('polkurier')`, a badge "niezmapowane statusy" w menu zlicza również polkurier.
## Purpose
Phase 128 dodała `PolkurierShipmentService`/`PolkurierTrackingService` i seed migrację `delivery_status_mappings(provider='polkurier')`, ale UI mapowania pozostał hardcoded na 3 providerów (`inpost`/`apaczka`/`allegro_wza`). Operator nie ma jak zmapować/podejrzeć statusów polkuriera w panelu — kontrakt zamknięty od strony backendu, otwarty od strony UI. Bez tej fazy operator musi grzebać w SQL żeby zobaczyć/zmienić mapowania, co łamie wzorzec ustanowiony w Phase 108.
## Output
- `POLKURIER_MAP` + `POLKURIER_DESCRIPTIONS` w `DeliveryStatus.php` (7 wpisów) + rejestracja w `PROVIDER_MAPS`/`PROVIDER_DESCRIPTIONS`/`normalize()`/`description()` match.
- `'polkurier' => 'polkurier'` w `PROVIDERS` w obu kontrolerach (`DeliveryStatusesController`, `DeliveryStatusMappingController`).
- `'polkurier'` w pętli `countAllUnmappedForBadge()` w `DeliveryStatusMappingRepository`.
</objective>
<context>
<clarifications>
- **Źródło defaultów** — Skąd UI ma czerpać 7 domyślnych mapowań polkurier (O/P/A/WP/D/Z/W)?
→ Odpowiedź: Hardcoded w `DeliveryStatus.php` (POLKURIER_MAP + POLKURIER_DESCRIPTIONS, analogicznie do InPost/Apaczka/Allegro). DB seed migracji z Phase 128 nadal dostępny jako override.
- **Etykieta UI** — Jaką etykietę pokazać w dropdownie providerów na tabie Mapowanie?
→ Odpowiedź: `polkurier` (lowercase, spójne z hubem integracji Phase 127 i provider code w `shipment_packages.provider`).
- **Badge counter** — Czy badge 'niezmapowane statusy' w menu Ustawienia ma uwzględniać polkurier?
→ Odpowiedź: Tak — dodać `polkurier` do pętli `countAllUnmappedForBadge()`.
</clarifications>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@.paul/codebase/architecture.md
@.paul/codebase/db_schema.md
## Source Files
@src/Modules/Shipments/DeliveryStatus.php
@src/Modules/Settings/DeliveryStatusesController.php
@src/Modules/Settings/DeliveryStatusMappingController.php
@src/Modules/Shipments/DeliveryStatusMappingRepository.php
@resources/views/settings/delivery-statuses.php
## Prior Work
@.paul/phases/128-polkurier-shipment-service/128-01-SUMMARY.md
@.paul/phases/108-delivery-status-management/108-02-SUMMARY.md
</context>
<acceptance_criteria>
## AC-1: Polkurier widoczny w dropdownie providerów
```gherkin
Given operator jest zalogowany i otwiera `/settings/delivery-statuses?tab=mapping`
When dropdown "Provider" jest rozwinięty
Then na liście widoczne są 4 pozycje: InPost, Apaczka, Allegro oraz polkurier
```
## AC-2: 7 domyślnych mapowań polkurier
```gherkin
Given operator wybiera "polkurier" w dropdownie providerów na tabie Mapowanie
When tabela mapowań się ładuje (bez uruchamiania migracji seed Phase 128)
Then widoczne jest dokładnie 7 wierszy z raw statusami: O, P, A, WP, D, Z, W
And każdy wiersz pokazuje znormalizowany status zgodny z dokumentacją polkurier v1.11
(Ocreated, Pconfirmed, Acancelled, WPin_transit, Ddelivered, Zreturned, Wproblem)
And każdy wiersz pokazuje opis PL (np. "Oczekuje na płatność", "Dostarczona")
And wiersze NIE są oznaczone jako "custom" (is_custom=false) to są defaulty z kodu
```
## AC-3: Badge "niezmapowane" zlicza polkurier
```gherkin
Given w `shipment_packages` istnieje wiersz z `provider='polkurier'` i `delivery_status_raw='X'`
And kod 'X' nie jest w domyślnych 7 ani w override'ach `delivery_status_mappings`
When sidebar Ustawień się renderuje (badge "niezmapowane")
Then licznik z `countAllUnmappedForBadge()` wzrasta o 1 z tytułu polkurier
```
## AC-4: Override DB nadpisuje hardcoded default
```gherkin
Given operator zapisuje override dla `provider='polkurier'`, `raw_status='D'` z `normalized_status='problem'`
When operator odświeża tab Mapowanie z `provider=polkurier`
Then wiersz "D" pokazuje normalized='problem' (z DB) zamiast 'delivered' (z kodu)
And wiersz jest oznaczony jako custom (is_custom=true)
```
## AC-5: Zero regresji dla istniejących providerów
```gherkin
Given operator otwiera `/settings/delivery-statuses?tab=mapping&provider=inpost`
When tabela się ładuje
Then liczba i treść wierszy InPost/Apaczka/Allegro pozostaje identyczna jak przed zmianami
And `DeliveryStatus::normalize('inpost', $raw)` zwraca te same wartości
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Hardcoded POLKURIER_MAP + POLKURIER_DESCRIPTIONS w DeliveryStatus.php</name>
<files>src/Modules/Shipments/DeliveryStatus.php</files>
<action>
Dodaj dwie nowe stałe klasowe analogicznie do `INPOST_MAP`/`INPOST_DESCRIPTIONS`:
```php
private const POLKURIER_MAP = [
'O' => self::CREATED,
'P' => self::CONFIRMED,
'A' => self::CANCELLED,
'WP' => self::IN_TRANSIT,
'D' => self::DELIVERED,
'Z' => self::RETURNED,
'W' => self::PROBLEM,
];
private const POLKURIER_DESCRIPTIONS = [
'O' => 'Oczekuje na płatność',
'P' => 'Potwierdzone, list wygenerowany',
'A' => 'Anulowane',
'WP' => 'W przewozie',
'D' => 'Dostarczona',
'Z' => 'Zwrot do nadawcy',
'W' => 'Wyjątek',
];
```
Następnie zarejestruj `'polkurier'` w trzech miejscach:
1. `PROVIDER_MAPS` (po `'allegro_wza'`) — `'polkurier' => self::POLKURIER_MAP,`
2. `PROVIDER_DESCRIPTIONS` (po `'allegro_wza'`) — `'polkurier' => self::POLKURIER_DESCRIPTIONS,`
3. `normalize()` match expression — dodaj `'polkurier' => self::POLKURIER_MAP,`
4. `description()` match expression — dodaj `'polkurier' => self::POLKURIER_DESCRIPTIONS,`
Treść 7 wpisów MUSI być identyczna z migracją Phase 128
(`database/migrations/20260514_000115_seed_polkurier_delivery_status_mappings.sql`).
To gwarantuje że jeśli operator odpali seed migrację po wdrożeniu, nie zmieni się żadne mapowanie
(default == DB override → `is_custom=true` ale ta sama wartość).
Avoid: zmiana kolejności/struktury INPOST/APACZKA/ALLEGRO_WZA — to złamałoby AC-5.
</action>
<verify>
php -r "require 'vendor/autoload.php'; var_export(\App\Modules\Shipments\DeliveryStatus::getDefaultMappings('polkurier'));"
# Oczekiwane: array z 7 kluczami (O/P/A/WP/D/Z/W), każdy z 'normalized' i 'description'.
</verify>
<done>AC-2, AC-5 satisfied: 7 defaultów polkurier z poprawnym normalized+description; existing providers nietknięte.</done>
</task>
<task type="auto">
<name>Task 2: Dodaj 'polkurier' do PROVIDERS w obu kontrolerach + badge counter</name>
<files>src/Modules/Settings/DeliveryStatusesController.php, src/Modules/Settings/DeliveryStatusMappingController.php, src/Modules/Shipments/DeliveryStatusMappingRepository.php</files>
<action>
1. `DeliveryStatusesController.php` (linie 22-26): dodaj `'polkurier' => 'polkurier',` jako 4. wpis w stałej `PROVIDERS`. Zachowaj kolejność: inpost, apaczka, allegro_wza, polkurier.
2. `DeliveryStatusMappingController.php` (linie 22-26): identyczna zmiana w analogicznej stałej `PROVIDERS`.
3. `DeliveryStatusMappingRepository.php` linia 158 — zmień:
```php
$providers = ['inpost', 'apaczka', 'allegro_wza'];
```
na:
```php
$providers = ['inpost', 'apaczka', 'allegro_wza', 'polkurier'];
```
Po tej zmianie `index()` w obu kontrolerach automatycznie zaakceptuje `?provider=polkurier`
(sprawdza `isset(self::PROVIDERS[$provider])`), pobierze defaulty z `DeliveryStatus::getDefaultMappings('polkurier')`
(Task 1), i scali z override'ami z `DeliveryStatusMappingRepository::listByProvider('polkurier')`.
Widok `resources/views/settings/delivery-statuses.php` iteruje po `$providers` (dropdown)
i nie wymaga zmian — automatycznie pokaże nową pozycję.
Avoid: dodanie polkurier w innej pozycji niż na końcu tablicy — może to zmienić default
(`$provider = 'inpost'` w fallback jest niezależny i bezpieczny, ale kolejność wpływa na render dropdownu).
</action>
<verify>
# 1. Sprawdź dropdown:
curl -s -b "session.cookie" https://orderpro.projectpro.pl/settings/delivery-statuses?tab=mapping | grep -c 'value="polkurier"'
# Oczekiwane: 1
# 2. Sprawdź że provider=polkurier renderuje 7 wierszy:
curl -s -b "session.cookie" 'https://orderpro.projectpro.pl/settings/delivery-statuses?tab=mapping&provider=polkurier' | grep -E 'raw_status.*(O|P|A|WP|D|Z|W)' | wc -l
# Oczekiwane: 7
# 3. Smoke regresji — InPost dalej działa:
curl -s -b "session.cookie" 'https://orderpro.projectpro.pl/settings/delivery-statuses?tab=mapping&provider=inpost' | grep -c 'value="inpost"'
# Oczekiwane: 1 (selected)
</verify>
<done>AC-1, AC-3, AC-4, AC-5 satisfied: dropdown pokazuje polkurier, 7 defaultów się renderuje, badge zlicza polkurier, override DB nadpisuje default, istniejące providery bez regresji.</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- `database/migrations/20260514_000115_seed_polkurier_delivery_status_mappings.sql` — migracja Phase 128 zostaje as-is; ten plan dubluje jej treść w kodzie ale NIE zmienia samej migracji (operator może ją odpalić lub nie — funkcjonalność niezależna).
- Stałe `INPOST_MAP`/`APACZKA_MAP`/`ALLEGRO_MAP`/`ALLEGRO_EDGE_MAP` w `DeliveryStatus.php` — żadnych edycji wartości lub kolejności.
- `PolkurierTrackingService` — kontrakt mapowania Phase 128 zostaje nietknięty; ten plan nie zmienia logiki normalizacji w runtime, tylko ekspozycję defaultów w UI.
- Schemat tabeli `delivery_status_mappings` — brak migracji w tym planie.
- `DeliveryStatus::trackingUrl()` (zawiera już branch `polkurier` z Phase 128) — nietknięte.
## SCOPE LIMITS
- Brak dodatkowych mapowań polkurier (np. nieudokumentowanych w v1.11) — tylko 7 oficjalnych kodów z dokumentacji.
- Brak osobnej zakładki/podstrony dla polkurier — reuse istniejącego tab `mapping` z dropdownem.
- Brak zmian w `PROJECT.md`/`ROADMAP.md` — to robi UNIFY.
- Brak migracji DB — defaulty z kodu, override z DB jak dla pozostałych providerów.
- Brak zmian w widoku `delivery-statuses.php` — dropdown iteruje po `$providers` z controllera.
</boundaries>
<verification>
Przed declared complete:
- [ ] `DeliveryStatus::getDefaultMappings('polkurier')` zwraca 7 wpisów z poprawnymi normalized+description (AC-2).
- [ ] Dropdown providerów w `/settings/delivery-statuses?tab=mapping` pokazuje 4 pozycje w kolejności InPost, Apaczka, Allegro, polkurier (AC-1).
- [ ] Selekcja `?provider=polkurier` ładuje 7 wierszy mapowań bez fatal errora (AC-2).
- [ ] Override DB (manual INSERT do `delivery_status_mappings` lub przez UI) zmienia `is_custom=true` dla wiersza (AC-4).
- [ ] `countAllUnmappedForBadge()` dla wstrzykniętego raw statusu `polkurier:XYZ` zwraca +1 (AC-3).
- [ ] Smoke regresji: `?provider=inpost`/`apaczka`/`allegro_wza` zwracają identyczną liczbę wierszy jak przed zmianą (AC-5).
- [ ] `php -l` przechodzi dla wszystkich 4 zmienionych plików.
</verification>
<success_criteria>
- 4 pliki zmodyfikowane (3 controllery + repo + DeliveryStatus.php — łącznie 4 fizyczne pliki, 5 punktów edycji).
- AC-1..AC-5 zweryfikowane.
- Brak zmian schematu DB.
- Phase 128 seed migration nie wymaga modyfikacji — pozostaje no-op (po Task 1 defaulty = wartości w migracji).
- Manual smoke na `/settings/delivery-statuses?tab=mapping&provider=polkurier` po deploy.
</success_criteria>
<output>
After completion, create `.paul/phases/130-polkurier-delivery-status-mappings/130-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,134 @@
---
phase: 130-polkurier-delivery-status-mappings
plan: 01
subsystem: ui
tags: [delivery-statuses, polkurier, mapping, settings]
requires:
- phase: 128-polkurier-shipment-service
provides: PolkurierTrackingService + delivery_status_mappings seed migration (DB-side override)
- phase: 108-delivery-status-management
provides: DeliveryStatus::PROVIDER_MAPS pattern + DeliveryStatusMappingController + view _delivery-status-mappings-content.php
provides:
- polkurier visible in Provider dropdown on /settings/delivery-statuses?tab=mapping
- 7 hardcoded default mappings for polkurier (O/P/A/WP/D/Z/W) in DeliveryStatus.php
- polkurier counted in countAllUnmappedForBadge() so menu badge reacts to unknown polkurier raw statuses
affects:
- future polkurier UI work (paczkomaty selector, presety przesylek)
- any future delivery provider additions (recipe established: 5 edit points)
tech-stack:
added: []
patterns:
- "Provider addition recipe: 1 const + 1 PROVIDER_MAPS + 1 PROVIDER_DESCRIPTIONS + 2 match arms + 2 PROVIDERS controller consts + 1 badge providers list = 5 edit points across 4 files"
key-files:
modified:
- src/Modules/Shipments/DeliveryStatus.php
- src/Modules/Settings/DeliveryStatusesController.php
- src/Modules/Settings/DeliveryStatusMappingController.php
- src/Modules/Shipments/DeliveryStatusMappingRepository.php
key-decisions:
- "Defaultowe mapowania polkurier hardcoded w DeliveryStatus.php (spojnie z InPost/Apaczka/Allegro)"
- "Etykieta dropdownu = 'polkurier' (lowercase, spojne z Phase 127 hub integracji)"
- "Badge counter uwzglednia polkurier (caly framework, nie wybiorczo)"
patterns-established:
- "Provider-addition checklist: trzy hardcoded providers (PROVIDER_MAPS/PROVIDER_DESCRIPTIONS + 2× normalize/description match) + dwa hardcoded controllery (PROVIDERS const) + jeden repo (badge providers list)"
duration: ~15min
started: 2026-05-14T18:00:00Z
completed: 2026-05-14T18:15:00Z
---
# Phase 130 Plan 01: polkurier delivery status mappings UI Summary
**polkurier widoczny w dropdownie `/settings/delivery-statuses?tab=mapping`, 7 oficjalnych kodow ORDER_STATUS (O/P/A/WP/D/Z/W) z dokumentacji v1.11 hardcoded jako defaults; badge "niezmapowane" w menu zlicza polkurier obok inpost/apaczka/allegro_wza.**
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~15 min |
| Started | 2026-05-14T18:00:00Z |
| Completed | 2026-05-14T18:15:00Z |
| Tasks | 2/2 completed |
| Files modified | 4 source files |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: polkurier widoczny w dropdownie providerów | Pass | `PROVIDERS` w `DeliveryStatusesController` + `DeliveryStatusMappingController` zawiera 4 wpisy; widok `_delivery-status-mappings-content.php` iteruje po `$providersList` z controllera |
| AC-2: 7 domyślnych mapowań polkurier | Pass | Live test: `DeliveryStatus::getDefaultMappings('polkurier')` zwrócił 7 wpisów (O→created, P→confirmed, A→cancelled, WP→in_transit, D→delivered, Z→returned, W→problem) z poprawnymi opisami PL |
| AC-3: Badge "niezmapowane" zlicza polkurier | Pass | `DeliveryStatusMappingRepository::countAllUnmappedForBadge()` zmienił listę z `['inpost','apaczka','allegro_wza']` na `[..., 'polkurier']` |
| AC-4: Override DB nadpisuje hardcoded default | Pass | Logika `index()` w obu kontrolerach (niezmieniona) iteruje po `defaults` i nadpisuje `$overrideMap[$rawStatus]` z `delivery_status_mappings` — pattern identyczny jak dla inpost/apaczka/allegro_wza |
| AC-5: Zero regresji dla istniejących providerów | Pass | `INPOST_MAP`/`APACZKA_MAP`/`ALLEGRO_MAP`/`ALLEGRO_EDGE_MAP` nietknięte; `PROVIDER_MAPS`/`PROVIDER_DESCRIPTIONS` zachowują kolejność; `normalize()`/`description()` match dostały tylko jedną nową gałąź `polkurier` |
## Accomplishments
- Hardcoded `POLKURIER_MAP` + `POLKURIER_DESCRIPTIONS` w `DeliveryStatus.php` — 7 wpisów z oficjalnej dokumentacji polkurier API v1.11 (marzec 2026), zgodne wartości z migracją Phase 128 (`20260514_000115_seed_polkurier_delivery_status_mappings.sql`)
- 5 punktów edycji w 4 plikach (1 const definition + 2 PROVIDER_* + 2 match arms + 2× PROVIDERS controller + 1 badge providers list)
- Brak regresji: defaulty inpost/apaczka/allegro pozostały bit-for-bit identyczne; zero zmian w schemacie DB; zero zmian w widoku (dropdown auto-iteruje po providerach z controllera)
## Task Commits
Atomic per-task commit nie wykonany w trakcie APPLY — wszystkie 4 pliki źródłowe zostaną zacommitowane jako jeden commit fazowy `feat(130): polkurier delivery status mappings UI` w kroku transition (zgodnie z konwencją poprzednich faz v3.7).
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `src/Modules/Shipments/DeliveryStatus.php` | Modified (+25 linii) | Dodano `POLKURIER_MAP` (7 wpisów) + `POLKURIER_DESCRIPTIONS` (7 opisów PL) + rejestracja w `PROVIDER_MAPS`, `PROVIDER_DESCRIPTIONS`, oraz w match expressions `normalize()` / `description()` |
| `src/Modules/Settings/DeliveryStatusesController.php` | Modified (+1) | Dodano `'polkurier' => 'polkurier'` do stałej `PROVIDERS` (4 wpis) |
| `src/Modules/Settings/DeliveryStatusMappingController.php` | Modified (+1) | Identyczna zmiana w analogicznej stałej `PROVIDERS` |
| `src/Modules/Shipments/DeliveryStatusMappingRepository.php` | Modified (1 ↔) | `countAllUnmappedForBadge()`: lista providerów rozszerzona o `polkurier` |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| POLKURIER_MAP/DESCRIPTIONS hardcoded w DeliveryStatus.php zamiast tylko z DB seed | Spójność z inpost/apaczka/allegro_wza — wszyscy mają hardcoded defaults i opcjonalne DB overrides. UI tab `polkurier` działa od razu, niezależnie od tego czy operator uruchomił migrację Phase 128. | Migracja `20260514_000115_seed_polkurier_delivery_status_mappings.sql` z Phase 128 staje się no-op (DB override == default → render `is_custom=true` ale ta sama wartość). Można ją uruchomić lub nie. |
| Etykieta dropdownu = `polkurier` (lowercase) | Spójność z provider code w `shipment_packages.provider`, z hubem integracji Phase 127, z PROJECT.md decisions. | Następne integracje powinny używać tej samej konwencji (lowercase brand name). |
| Badge counter dodaje `polkurier` | Cały framework "niezmapowane raw statusy" powinien działać jednolicie dla wszystkich providerów obecnych w UI mapowania. | Operator zobaczy w badge'u nowy raw status polkuriera (gdyby pojawił się jakiś kod spoza udokumentowanych 7) — tak samo jak dla innych przewoźników. |
## Deviations from Plan
### Summary
| Type | Count | Impact |
|------|-------|--------|
| Auto-fixed | 0 | — |
| Scope additions | 0 | — |
| Deferred | 0 | — |
**Total impact:** Brak deviacji — plan wykonany 1:1.
### Deferred Items
Brak — plan wykonany dokładnie jak napisany.
## Issues Encountered
Brak — wszystkie 5 edycji zaaplikowane czysto, PHP lint przeszedł na 4 plikach, runtime test `getDefaultMappings('polkurier')` zwrócił oczekiwane 7 wpisów.
## Next Phase Readiness
**Ready:**
- Mapowanie polkurier w pełni widoczne w UI dla operatora — może podejrzeć i nadpisać każdy z 7 statusów.
- Badge "niezmapowane" zareaguje gdy polkurier zwróci nieudokumentowany raw status.
- Provider-addition recipe utrwalony — następny przewoźnik dodawany w 5 punktach edycji (4 pliki).
**Concerns:**
- Migracja Phase 128 (`20260514_000115_seed_polkurier_delivery_status_mappings.sql`) staje się no-op po wdrożeniu — może ją zostawić jako historyczny ślad albo (opcjonalnie, deferred do osobnej fazy cleanup) zamienić na `ALTER TABLE COMMENT` no-op. Nie blokuje niczego.
- Brak manualnego smoke na żywej bazie — operator musi otworzyć `/settings/delivery-statuses?tab=mapping&provider=polkurier` po deploy.
**Blockers:**
- None.
---
*Phase: 130-polkurier-delivery-status-mappings, Plan: 01*
*Completed: 2026-05-14*

View File

@@ -23,6 +23,7 @@ final class DeliveryStatusMappingController
'inpost' => 'InPost', 'inpost' => 'InPost',
'apaczka' => 'Apaczka', 'apaczka' => 'Apaczka',
'allegro_wza' => 'Allegro', 'allegro_wza' => 'Allegro',
'polkurier' => 'polkurier',
]; ];
public function __construct( public function __construct(

View File

@@ -23,6 +23,7 @@ final class DeliveryStatusesController
'inpost' => 'InPost', 'inpost' => 'InPost',
'apaczka' => 'Apaczka', 'apaczka' => 'Apaczka',
'allegro_wza' => 'Allegro', 'allegro_wza' => 'Allegro',
'polkurier' => 'polkurier',
]; ];
public function __construct( public function __construct(

View File

@@ -296,11 +296,33 @@ final class DeliveryStatus
self::PROBLEM, self::PROBLEM,
]; ];
private const POLKURIER_MAP = [
// Oficjalne kody ORDER_STATUS z dokumentacji polkurier API v1.11 (marzec 2026)
'O' => self::CREATED,
'P' => self::CONFIRMED,
'A' => self::CANCELLED,
'WP' => self::IN_TRANSIT,
'D' => self::DELIVERED,
'Z' => self::RETURNED,
'W' => self::PROBLEM,
];
private const POLKURIER_DESCRIPTIONS = [
'O' => 'Oczekuje na płatność',
'P' => 'Potwierdzone, list wygenerowany',
'A' => 'Anulowane',
'WP' => 'W przewozie',
'D' => 'Dostarczona',
'Z' => 'Zwrot do nadawcy',
'W' => 'Wyjątek',
];
private const PROVIDER_MAPS = [ private const PROVIDER_MAPS = [
'inpost' => self::INPOST_MAP, 'inpost' => self::INPOST_MAP,
'apaczka' => self::APACZKA_MAP, 'apaczka' => self::APACZKA_MAP,
'allegro_wza' => self::ALLEGRO_MAP, 'allegro_wza' => self::ALLEGRO_MAP,
'allegro_edge' => self::ALLEGRO_EDGE_MAP, 'allegro_edge' => self::ALLEGRO_EDGE_MAP,
'polkurier' => self::POLKURIER_MAP,
]; ];
private const PROVIDER_DESCRIPTIONS = [ private const PROVIDER_DESCRIPTIONS = [
@@ -308,6 +330,7 @@ final class DeliveryStatus
'apaczka' => self::APACZKA_DESCRIPTIONS, 'apaczka' => self::APACZKA_DESCRIPTIONS,
'allegro_wza' => self::ALLEGRO_DESCRIPTIONS, 'allegro_wza' => self::ALLEGRO_DESCRIPTIONS,
'allegro_edge' => self::ALLEGRO_EDGE_DESCRIPTIONS, 'allegro_edge' => self::ALLEGRO_EDGE_DESCRIPTIONS,
'polkurier' => self::POLKURIER_DESCRIPTIONS,
]; ];
/** /**
@@ -362,6 +385,7 @@ final class DeliveryStatus
'apaczka' => self::APACZKA_MAP, 'apaczka' => self::APACZKA_MAP,
'allegro_wza' => self::ALLEGRO_MAP, 'allegro_wza' => self::ALLEGRO_MAP,
'allegro_edge' => self::ALLEGRO_EDGE_MAP, 'allegro_edge' => self::ALLEGRO_EDGE_MAP,
'polkurier' => self::POLKURIER_MAP,
default => [], default => [],
}; };
@@ -375,6 +399,7 @@ final class DeliveryStatus
'apaczka' => self::APACZKA_DESCRIPTIONS, 'apaczka' => self::APACZKA_DESCRIPTIONS,
'allegro_wza' => self::ALLEGRO_DESCRIPTIONS, 'allegro_wza' => self::ALLEGRO_DESCRIPTIONS,
'allegro_edge' => self::ALLEGRO_EDGE_DESCRIPTIONS, 'allegro_edge' => self::ALLEGRO_EDGE_DESCRIPTIONS,
'polkurier' => self::POLKURIER_DESCRIPTIONS,
default => [], default => [],
}; };

View File

@@ -155,7 +155,7 @@ final class DeliveryStatusMappingRepository
return $cached; return $cached;
} }
$providers = ['inpost', 'apaczka', 'allegro_wza']; $providers = ['inpost', 'apaczka', 'allegro_wza', 'polkurier'];
$knownKeysByProvider = []; $knownKeysByProvider = [];
foreach ($providers as $prov) { foreach ($providers as $prov) {
$knownKeysByProvider[$prov] = []; $knownKeysByProvider[$prov] = [];