fix(145): correct polkurier cod return codes
Phase 145 complete: - send COD.codtype=S for standard Polkurier COD return time - send COD.return_cod=BA for bank-account transfer - add regression coverage and PAUL documentation
This commit is contained in:
@@ -13,8 +13,8 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów
|
||||
| Attribute | Value |
|
||||
|-----------|-------|
|
||||
| Version | 3.9.0-dev |
|
||||
| Status | v3.13 Imported Notes Badge Count Hotfix complete - Phase 144 closed |
|
||||
| Last Updated | 2026-05-18 (Phase 144 unified) |
|
||||
| Status | v3.14 Polkurier COD Return Time Hotfix complete - Phase 145 closed |
|
||||
| Last Updated | 2026-05-18 (Phase 145 unified) |
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -144,6 +144,7 @@ Sprzedawca może obsługiwać zamówienia ze wszystkich kanałów
|
||||
- [x] Polkurier Shipment Prepare Prefill: `/orders/{id}/shipment/prepare` rozpoznaje mapowania shopPRO z `provider='polkurier'`, preselectuje przewoznika i usluge oraz nie fallbackuje do Allegro — Phase 142
|
||||
- [x] Orders List Sidebar UI Hotfix: `/orders/list` startuje bez opisowego boksu "Zamowienia", a zapisany zwiniety sidebar jest stosowany przed pierwszym renderem strony — Phase 143
|
||||
- [x] Imported Notes Badge Count Hotfix: badge `[N]` na `/orders/list` zlicza wszystkie `order_notes` zamowienia, lacznie z notatkami importowanymi z shopPRO i notatkami autorskimi operatora — Phase 144
|
||||
- [x] Polkurier COD Return Time Hotfix: payload pobrania wysyla `COD.codtype='S'` oraz `COD.return_cod='BA'`, zamiast blednego `transfer` w polu terminu zwrotu pobrania — Phase 145
|
||||
- [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`; od Phase 144 badge korzysta z `notes_count` i liczy wszystkie rekordy `order_notes`, takze importowane ze zrodla. Brak admin override (brak systemu rol w aplikacji) — edit/delete tylko dla autora — Phase 129/144
|
||||
@@ -293,6 +294,7 @@ 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 |
|
||||
| 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 |
|
||||
| Polkurier COD defaults: `codtype='S'`, `return_cod='BA'` | API Polkurier rozdziela termin zwrotu pobrania (`S/1D/4D/16D`) od sposobu zwrotu (`BA/PO/MB`). orderPRO uzywa standardowego terminu i przelewu na konto, zgodnie z dotychczasowa walidacja rachunku bankowego. | 2026-05-18 | 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 |
|
||||
|
||||
@@ -326,6 +328,6 @@ Quick Reference:
|
||||
|
||||
---
|
||||
*PROJECT.md — Updated when requirements or context change*
|
||||
*Last updated: 2026-05-18 after Phase 144 closure*
|
||||
*Last updated: 2026-05-18 after Phase 145 closure*
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,23 @@ orderPRO to narzedzie do wielokanalowego zarzadzania sprzedaza. Projekt przechod
|
||||
|
||||
## Current Milestone
|
||||
|
||||
v3.14 Polkurier COD Return Time Hotfix - Complete
|
||||
|
||||
Pilny hotfix tworzenia przesylek pobraniowych Polkurier: API odrzuca `create_order`, bo payload wysyla bledna wartosc czasu zwrotu pobrania. `codtype` ma uzywac kodu terminu (`S`, `1D`, `4D`, `16D`), a `return_cod` kodu sposobu zwrotu (`BA`, `PO`, `MB`).
|
||||
|
||||
Progress: 1 of 1 phases complete (100%).
|
||||
|
||||
| Phase | Name | Plans | Status |
|
||||
|-------|------|-------|--------|
|
||||
| 145 | Polkurier COD Return Time Hotfix | 1/1 | Complete (2026-05-18; PHPUnit/Sonar/live smoke follow-up pending) |
|
||||
|
||||
### Phase 145: Polkurier COD Return Time Hotfix
|
||||
|
||||
Focus: Naprawic payload COD w `PolkurierShipmentService`, aby przesylki pobraniowe wysylaly `codtype='S'` jako standardowy termin zwrotu pobrania oraz `return_cod='BA'` jako przelew na konto bankowe. Brak zmian DB i brak UI konfiguracji terminow w tym hotfixie.
|
||||
Plans: 145-01 (complete; `.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-SUMMARY.md`)
|
||||
|
||||
## Previous Milestone
|
||||
|
||||
v3.13 Imported Notes Badge Count Hotfix - Complete
|
||||
|
||||
Pilny hotfix dla listy zamowien: notatki zaimportowane ze zrodla, np. shopPRO, maja byc zliczane razem z notatkami autorskimi w badge `[N]` przy numerze zamowienia.
|
||||
@@ -21,7 +38,7 @@ Progress: 1 of 1 phases complete (100%).
|
||||
Focus: Zmienic licznik badge notatek na `/orders/list`, aby uzywal wszystkich rekordow `order_notes` dla zamowienia, a nie tylko `note_type='user'`. Zamowienie `1034` z importowana notatka shopPRO powinno pokazac cyfre na liscie.
|
||||
Plans: 144-01 (complete; `.paul/phases/144-imported-notes-badge-count/144-01-SUMMARY.md`)
|
||||
|
||||
## Previous Milestone
|
||||
## Earlier Milestone
|
||||
|
||||
v3.12 Orders List Sidebar UI Hotfix - Complete
|
||||
|
||||
@@ -687,4 +704,4 @@ Archive: `.paul/milestones/v0.1-ROADMAP.md`
|
||||
|
||||
---
|
||||
*Roadmap created: 2026-03-12*
|
||||
*Last updated: 2026-05-18 - Phase 144 complete; v3.13 Imported Notes Badge Count Hotfix complete*
|
||||
*Last updated: 2026-05-18 - Phase 145 complete; v3.14 Polkurier COD Return Time Hotfix complete*
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
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.13 Imported Notes Badge Count Hotfix complete; Phase 144 unified.
|
||||
**Current focus:** v3.14 Polkurier COD Return Time Hotfix complete; Phase 145 unified.
|
||||
|
||||
## Current Position
|
||||
|
||||
Milestone: v3.13 Imported Notes Badge Count Hotfix
|
||||
Phase: 144 of 144 (Imported Notes Badge Count Hotfix) - Complete
|
||||
Plan: 144-01 complete
|
||||
Milestone: v3.14 Polkurier COD Return Time Hotfix
|
||||
Phase: 145 of 145 (Polkurier COD Return Time Hotfix) - Complete
|
||||
Plan: 145-01 complete
|
||||
Status: Milestone complete, ready for next milestone or release decision
|
||||
Last activity: 2026-05-18 12:39 - Unified .paul/phases/144-imported-notes-badge-count/144-01-PLAN.md
|
||||
Last activity: 2026-05-18 13:28 - Unified .paul/phases/145-polkurier-cod-return-time-hotfix/145-01-PLAN.md
|
||||
|
||||
Progress:
|
||||
- Milestone v3.13: [##########] 100% (1 of 1 phases complete)
|
||||
- Phase 144: [##########] 100% (complete)
|
||||
- Milestone v3.14: [##########] 100% (1 of 1 phases complete)
|
||||
- Phase 145: [##########] 100% (complete)
|
||||
|
||||
## Loop Position
|
||||
|
||||
@@ -29,19 +29,19 @@ PLAN -> APPLY -> UNIFY
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-05-18 12:39
|
||||
Stopped at: Phase 144 complete; v3.13 milestone complete
|
||||
Last session: 2026-05-18 13:28
|
||||
Stopped at: Phase 145 complete; v3.14 milestone complete
|
||||
Next action: Run $paul-complete-milestone or start next milestone planning
|
||||
Resume file: .paul/phases/144-imported-notes-badge-count/144-01-SUMMARY.md
|
||||
Resume file: .paul/phases/145-polkurier-cod-return-time-hotfix/145-01-SUMMARY.md
|
||||
|
||||
## Pending parallel work
|
||||
- None — Phase 118, 121, 122 wszystkie zacommitowane (8f14851, 360eef1).
|
||||
|
||||
## Git State
|
||||
|
||||
Last commit: HEAD fix(144): count imported order notes in list badge
|
||||
Last phase commit: HEAD fix(144): count imported order notes in list badge
|
||||
Previous: fix(143): polish orders list and sidebar first paint
|
||||
Last commit: HEAD fix(145): correct polkurier cod return codes
|
||||
Last phase commit: HEAD fix(145): correct polkurier cod return codes
|
||||
Previous: fix(144): count imported order notes in list badge
|
||||
Branch: main
|
||||
|
||||
### Skill Audit (Phase 139)
|
||||
@@ -81,6 +81,12 @@ Branch: main
|
||||
|----------|---------|-------|
|
||||
| `sonar-scanner` | gap documented | Attempted after APPLY with `sonar-scanner --version`; CLI is not available in PATH. |
|
||||
|
||||
### Skill Audit (Phase 145)
|
||||
|
||||
| Expected | Invoked | Notes |
|
||||
|----------|---------|-------|
|
||||
| `sonar-scanner` | gap documented | Attempted after APPLY with `sonar-scanner --version`; CLI is not available in PATH. |
|
||||
|
||||
### Skill Audit (Phase 129)
|
||||
|
||||
| Expected | Invoked | Notes |
|
||||
@@ -139,6 +145,7 @@ Branch: main
|
||||
|
||||
### Recent Decisions
|
||||
|
||||
- Phase 145 fixed the Polkurier COD payload contract: `COD.codtype='S'` for standard return time and `COD.return_cod='BA'` for bank-account transfer. No UI configurability or schema change was added.
|
||||
- Phase 144 changed the `/orders/list` notes badge contract from operator-only notes to all `order_notes` rows; detail view grouping and note CRUD/import behavior remain unchanged.
|
||||
- Phase 134 is documentation-only: no runtime code or schema changes were made.
|
||||
- Backlog entries are annotated, not deleted; stale/implemented cleanup is deferred to later phases.
|
||||
@@ -159,6 +166,7 @@ Branch: main
|
||||
|
||||
### Blockers / Concerns
|
||||
|
||||
- Phase 145 APPLY: `vendor/bin/phpunit` is missing, so `tests/Unit/PolkurierShipmentServiceTest.php` was linted and covered by an ad-hoc runtime smoke instead of PHPUnit; `sonar-scanner` is unavailable in PATH.
|
||||
- Phase 144 APPLY: `vendor/bin/phpunit` is missing, so `tests/Unit/OrdersRepositoryNotesCountTest.php` was linted and covered by an ad-hoc SQLite runtime smoke instead of PHPUnit; `sonar-scanner` is unavailable in PATH.
|
||||
- Phase 134: `sonar-scanner` is still unavailable in PATH.
|
||||
- Phase 135: `vendor/bin/phpunit` and `sonar-scanner` are unavailable in PATH/checkout; syntax checks and ad-hoc SQLite/runtime smoke passed.
|
||||
@@ -177,6 +185,9 @@ Branch: main
|
||||
|
||||
## Pending Actions
|
||||
|
||||
- Phase 145 follow-up: after restoring `vendor/`, run `vendor/bin/phpunit tests/Unit/PolkurierShipmentServiceTest.php`.
|
||||
- Phase 145 follow-up: run SonarQube scan after restoring `sonar-scanner` in PATH.
|
||||
- Phase 145 follow-up: with explicit operator intent, create one live Polkurier COD shipment and confirm API accepts `codtype='S'` / `return_cod='BA'` without the previous return-time error.
|
||||
- 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) 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.
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
- `OrdersRepository` zwraca `notes_count` liczony ze wszystkich rekordow `order_notes` dla zamowienia.
|
||||
- Dodano test regresyjny `OrdersRepositoryNotesCountTest` i wykonano SQLite smoke `notes_count=2` dla notatki `message` + `user`.
|
||||
- Gap: PHPUnit i SonarQube scan Phase 144 pozostaja do wykonania po przywroceniu `vendor/` i `sonar-scanner`.
|
||||
- [Phase 145, Plan 01] Naprawiono payload COD Polkuriera, ktory powodowal blad `create_order` o dozwolonym zbiorze `[S, 1D, 4D, 16D]`.
|
||||
- `PolkurierShipmentService` wysyla teraz `COD.codtype='S'` oraz `COD.return_cod='BA'`, zachowujac walidacje i czyszczenie numeru konta bankowego.
|
||||
- Dodano test regresyjny `PolkurierShipmentServiceTest` oraz ad-hoc runtime smoke dla payloadu COD.
|
||||
- Gap: PHPUnit i SonarQube scan Phase 145 pozostaja do wykonania po przywroceniu `vendor/` i `sonar-scanner`.
|
||||
|
||||
## Zmienione pliki
|
||||
|
||||
@@ -61,3 +65,7 @@
|
||||
- `src/Modules/Orders/OrdersController.php`
|
||||
- `tests/Unit/OrdersRepositoryNotesCountTest.php`
|
||||
- `DOCS/DB_SCHEMA.md`
|
||||
- `.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-PLAN.md`
|
||||
- `.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-SUMMARY.md`
|
||||
- `src/Modules/Shipments/PolkurierShipmentService.php`
|
||||
- `tests/Unit/PolkurierShipmentServiceTest.php`
|
||||
|
||||
180
.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-PLAN.md
Normal file
180
.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-PLAN.md
Normal file
@@ -0,0 +1,180 @@
|
||||
---
|
||||
phase: 145-polkurier-cod-return-time-hotfix
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/Modules/Shipments/PolkurierShipmentService.php
|
||||
- tests/Unit/PolkurierShipmentServiceTest.php
|
||||
- DOCS/ARCHITECTURE.md
|
||||
- DOCS/TECH_CHANGELOG.md
|
||||
autonomous: true
|
||||
delegation: off
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Naprawic tworzenie przesylek pobraniowych Polkurier, aby payload COD wysylal do API dozwolony termin zwrotu pobrania.
|
||||
|
||||
## Purpose
|
||||
Operator nie moze utworzyc przesylki pobraniowej, bo Polkurier odrzuca `create_order` komunikatem: "Parametr czasu zwrotu pobrania musi zawierac sie w zbiorze [S, 1D, 4D, 16D]". Obecny payload myli sposob zwrotu pobrania z terminem zwrotu pobrania.
|
||||
|
||||
## Output
|
||||
Poprawiony payload COD w `PolkurierShipmentService`, test regresyjny budowania danych COD oraz aktualizacja dokumentacji technicznej.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
<clarifications>
|
||||
- **Brak pytan** - Problem jest jednoznaczny po analizie kodu i dokumentacji Polkurier: `codtype` oznacza termin zwrotu pobrania (`S`, `1D`, `4D`, `16D`), a `return_cod` oznacza sposob zwrotu (`BA`, `PO`, `MB`). Obecny kod wysyla `return_cod='transfer'`, a `codtype='transfer'`.
|
||||
-> Odpowiedz: No clarifications needed - proceeding.
|
||||
</clarifications>
|
||||
|
||||
## Project Context
|
||||
@AGENTS.md
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
@.paul/STATE.md
|
||||
@DOCS/ARCHITECTURE.md
|
||||
@DOCS/DB_SCHEMA.md
|
||||
|
||||
## Prior Work
|
||||
@.paul/phases/127-polkurier-integration-foundation/127-01-PLAN.md
|
||||
@.paul/phases/128-polkurier-shipment-service/128-01-PLAN.md
|
||||
@.paul/phases/140-shoppro-polkurier-delivery-mapping/140-01-PLAN.md
|
||||
@.paul/phases/142-polkurier-shipment-prepare-prefill/142-01-PLAN.md
|
||||
|
||||
## Source Files
|
||||
@src/Modules/Shipments/PolkurierShipmentService.php
|
||||
@src/Modules/Settings/PolkurierApiClient.php
|
||||
@src/Modules/Shipments/ShipmentPackageRepository.php
|
||||
@tests/Unit/ApaczkaShipmentServiceTest.php
|
||||
@tests/Unit/ShipmentPreparePolkurierMappingTest.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| `sonar-scanner` | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Poprawny Termin Zwrotu Pobrania
|
||||
```gherkin
|
||||
Given operator tworzy przesylke Polkurier z kwota pobrania wieksza od 0
|
||||
When orderPRO buduje payload `create_order`
|
||||
Then sekcja `COD.codtype` zawiera dozwolona wartosc terminu zwrotu pobrania, domyslnie `S`
|
||||
And nie zawiera juz blednej wartosci `transfer`
|
||||
```
|
||||
|
||||
## AC-2: Poprawny Sposob Zwrotu Pobrania
|
||||
```gherkin
|
||||
Given operator tworzy przesylke Polkurier z pobraniem na konto bankowe firmy
|
||||
When orderPRO buduje payload `create_order`
|
||||
Then sekcja `COD.return_cod` zawiera dozwolony kod sposobu zwrotu, domyslnie `BA`
|
||||
And `COD.codbankaccount` nadal zawiera oczyszczony numer konta bankowego
|
||||
```
|
||||
|
||||
## AC-3: Brak Regresji Dla Przesylek Bez COD
|
||||
```gherkin
|
||||
Given operator tworzy zwykla przesylke Polkurier bez pobrania
|
||||
When orderPRO buduje payload `create_order`
|
||||
Then sekcja `COD` nie jest dodawana
|
||||
And dotychczasowy zapis paczki i payload pozostaja bez zmian
|
||||
```
|
||||
|
||||
## AC-4: Brak Zmiany Schematu
|
||||
```gherkin
|
||||
Given hotfix dotyczy tylko mapowania wartosci wysylanych do API Polkurier
|
||||
When plan zostanie wdrozony
|
||||
Then nie powstaje migracja ani zmiana struktury tabel
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Wydzielic i poprawic budowanie payloadu COD Polkurier</name>
|
||||
<files>src/Modules/Shipments/PolkurierShipmentService.php</files>
|
||||
<action>
|
||||
- Zastap obecny inline blok `COD` mala prywatna metoda odpowiedzialna tylko za COD.
|
||||
- Metoda ma zwracac `null`, gdy `cod_amount <= 0`, zeby przesylki bez pobrania nie dostawaly sekcji `COD`.
|
||||
- Dla pobrania ustaw `codtype` na dozwolony termin zwrotu pobrania. Domyslnie uzyj `S`, bo dokumentacja opisuje to jako standardowy zwrot 5-7 dni roboczych.
|
||||
- Dla sposobu zwrotu ustaw `return_cod` na `BA`, czyli przelew na konto bankowe.
|
||||
- Zachowaj obecna walidacje numeru konta: brak rachunku bankowego nadal ma rzucac `ShipmentException` z aktualnym komunikatem.
|
||||
- Nie dodawaj UI ani nowych ustawien; to hotfix blednego payloadu, nie konfigurator terminow COD.
|
||||
</action>
|
||||
<verify>C:\xampp\php\php.exe -l src/Modules/Shipments/PolkurierShipmentService.php</verify>
|
||||
<done>AC-1, AC-2 i AC-3 spelnione w kodzie budujacym payload.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Dodac test regresyjny COD dla Polkuriera</name>
|
||||
<files>tests/Unit/PolkurierShipmentServiceTest.php</files>
|
||||
<action>
|
||||
- Dodaj test jednostkowy dla prywatnej metody budujacej COD przez `ReflectionMethod`, zgodnie ze stylem `ApaczkaShipmentServiceTest`.
|
||||
- Assert dla pobrania: `codtype === 'S'`, `return_cod === 'BA'`, `codamount` jest liczba zaokraglona do 2 miejsc, a `codbankaccount` ma same cyfry.
|
||||
- Dodaj test, ze `cod_amount=0` zwraca `null`.
|
||||
- Dodaj test, ze pobranie bez numeru konta rzuca `ShipmentException`.
|
||||
- Test ma uzywac mockow repozytoriow/API i nie ma laczyc sie z Polkurier ani baza danych.
|
||||
</action>
|
||||
<verify>C:\xampp\php\php.exe -l tests/Unit/PolkurierShipmentServiceTest.php; vendor/bin/phpunit tests/Unit/PolkurierShipmentServiceTest.php jezeli vendor/bin/phpunit jest dostepny</verify>
|
||||
<done>AC-1, AC-2 i AC-3 zabezpieczone testami albo gap PHPUnit udokumentowany, jesli vendor nadal jest niedostepny.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Zaktualizowac dokumentacje techniczna</name>
|
||||
<files>DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
|
||||
<action>
|
||||
- W `DOCS/ARCHITECTURE.md` dopisz kontrakt COD dla Polkuriera: `codtype='S'` jako standardowy termin zwrotu i `return_cod='BA'` jako przelew na konto.
|
||||
- W `DOCS/TECH_CHANGELOG.md` dodaj wpis 2026-05-18 opisujacy hotfix bledu `create_order` przy pobraniu.
|
||||
- Nie aktualizuj `DOCS/DB_SCHEMA.md`, bo nie ma migracji ani zmiany tabel.
|
||||
</action>
|
||||
<verify>rg -n "codtype|return_cod|Polkurier|polkurier" DOCS/ARCHITECTURE.md DOCS/TECH_CHANGELOG.md</verify>
|
||||
<done>AC-4 spelnione i dokumentacja opisuje nowy kontrakt payloadu.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- `database/migrations/*` - brak zmiany schematu.
|
||||
- `resources/views/shipments/prepare.php` - formularz prefillu byl naprawiany w Phase 142; ten blad jest w payloadzie API.
|
||||
- `src/Modules/Settings/PolkurierApiClient.php` - wrapper API i obsluga bledow zostaja bez zmian.
|
||||
- `src/Modules/Settings/ShopproIntegrationsController.php` oraz widoki mapowan shopPRO - mapowania dostaw nie sa przyczyna bledu COD.
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Nie dodawac konfiguracji wyboru `S/1D/4D/16D` w UI w tym planie.
|
||||
- Nie dodawac przekazu pocztowego `PO` ani skarbonki `MB`; domyslny i wymagany teraz przypadek to przelew bankowy.
|
||||
- Nie wykonywac realnego utworzenia przesylki Polkurier bez jawnej decyzji operatora, bo to moze nadac prawdziwa paczke.
|
||||
- Nie zmieniac logiki etykiet, statusow, trackingu ani mapowan shopPRO.
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] `C:\xampp\php\php.exe -l src/Modules/Shipments/PolkurierShipmentService.php`
|
||||
- [ ] `C:\xampp\php\php.exe -l tests/Unit/PolkurierShipmentServiceTest.php`
|
||||
- [ ] `vendor/bin/phpunit tests/Unit/PolkurierShipmentServiceTest.php` jezeli zaleznosci sa dostepne
|
||||
- [ ] `rg -n "codtype|return_cod|Polkurier|polkurier" DOCS/ARCHITECTURE.md DOCS/TECH_CHANGELOG.md`
|
||||
- [ ] `git diff --check`
|
||||
- [ ] `sonar-scanner` jezeli CLI jest dostepny; w przeciwnym razie udokumentowac gap
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Przesylka pobraniowa Polkurier nie wysyla juz `transfer` w polu wymagajacym `[S, 1D, 4D, 16D]`.
|
||||
- Payload COD uzywa `codtype='S'` i `return_cod='BA'`.
|
||||
- Przesylki bez pobrania nadal nie zawieraja sekcji `COD`.
|
||||
- Walidacja numeru konta bankowego zostaje zachowana.
|
||||
- Dokumentacja techniczna odzwierciedla hotfix.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
phase: 145-polkurier-cod-return-time-hotfix
|
||||
plan: 01
|
||||
subsystem: shipments
|
||||
tags: [polkurier, cod, payload, shipments]
|
||||
requires:
|
||||
- phase: 128-polkurier-shipment-service
|
||||
provides: Polkurier shipment creation flow and COD payload support
|
||||
provides:
|
||||
- Polkurier COD payload uses API-valid return-time and return-method codes
|
||||
- Regression test for COD payload construction
|
||||
affects: [polkurier, shipments, cod]
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [private payload builder covered by reflection-based unit test]
|
||||
key-files:
|
||||
created:
|
||||
- tests/Unit/PolkurierShipmentServiceTest.php
|
||||
modified:
|
||||
- src/Modules/Shipments/PolkurierShipmentService.php
|
||||
- DOCS/ARCHITECTURE.md
|
||||
- DOCS/TECH_CHANGELOG.md
|
||||
key-decisions:
|
||||
- "Polkurier COD return time defaults to `S` and return method defaults to `BA`."
|
||||
patterns-established:
|
||||
- "Provider-specific API code mappings stay in the shipment service unless UI configurability is explicitly required."
|
||||
duration: 13min
|
||||
started: 2026-05-18T13:05:00+02:00
|
||||
completed: 2026-05-18T13:18:00+02:00
|
||||
---
|
||||
|
||||
# Phase 145 Plan 01: Polkurier COD Return Time Hotfix Summary
|
||||
|
||||
Polkurier cash-on-delivery shipments now send API-valid COD codes: `COD.codtype='S'` and `COD.return_cod='BA'`.
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | 13min |
|
||||
| Started | 2026-05-18 13:05 |
|
||||
| Completed | 2026-05-18 13:18 |
|
||||
| Tasks | 3 completed |
|
||||
| Files modified | 4 runtime/test/docs files + PAUL docs |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: Poprawny Termin Zwrotu Pobrania | Pass | `buildCodPayload()` sends `codtype='S'`, not `transfer`. |
|
||||
| AC-2: Poprawny Sposob Zwrotu Pobrania | Pass | `return_cod='BA'`; `codbankaccount` is sanitized to digits. |
|
||||
| AC-3: Brak Regresji Dla Przesylek Bez COD | Pass | `cod_amount <= 0` returns `null`, so `COD` is omitted. |
|
||||
| AC-4: Brak Zmiany Schematu | Pass | No migrations or DB schema changes. |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Replaced invalid Polkurier COD values that caused `create_order` to reject COD shipments.
|
||||
- Preserved the existing company bank-account requirement for COD shipments.
|
||||
- Added a unit-level regression test for COD payload shape, zero-COD omission, and missing bank-account validation.
|
||||
- Updated architecture and technical changelog documentation.
|
||||
|
||||
## Task Commits
|
||||
|
||||
No task-level commits were created during APPLY. Phase commit is created during UNIFY.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `src/Modules/Shipments/PolkurierShipmentService.php` | Modified | Extracted COD payload builder and set Polkurier-valid codes. |
|
||||
| `tests/Unit/PolkurierShipmentServiceTest.php` | Created | Regression coverage for COD payload construction. |
|
||||
| `DOCS/ARCHITECTURE.md` | Modified | Documents the Polkurier COD payload contract. |
|
||||
| `DOCS/TECH_CHANGELOG.md` | Modified | Records the Phase 145 hotfix. |
|
||||
| `.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-PLAN.md` | Created | Executable PAUL plan. |
|
||||
| `.paul/phases/145-polkurier-cod-return-time-hotfix/145-01-SUMMARY.md` | Created | Completion record. |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Default COD return time is `S` | Polkurier accepts `[S, 1D, 4D, 16D]`; `S` is the standard return-time option. | Fixes the reported API error without adding UI scope. |
|
||||
| Default COD return method is `BA` | Current orderPRO flow requires a company bank account, so bank transfer is the matching return method. | Keeps behavior aligned with existing validation. |
|
||||
| No UI configurability for `1D/4D/16D` | The request is a hotfix for invalid payload values. | Avoids scope creep and schema/config changes. |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Summary
|
||||
|
||||
| Type | Count | Impact |
|
||||
|------|-------|--------|
|
||||
| Auto-fixed | 0 | None |
|
||||
| Scope additions | 0 | None |
|
||||
| Deferred | 2 | Environment-only verification gaps |
|
||||
|
||||
### Deferred Items
|
||||
|
||||
- Run `vendor/bin/phpunit tests/Unit/PolkurierShipmentServiceTest.php` after dependencies are restored.
|
||||
- Run `sonar-scanner` after the CLI is restored in PATH.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| `vendor/bin/phpunit` missing | Linted the test and ran an ad-hoc runtime smoke through `C:\xampp\php\php.exe`. |
|
||||
| `sonar-scanner` missing in PATH | Documented the required-skill gap in STATE/SUMMARY. |
|
||||
|
||||
## Verification Results
|
||||
|
||||
| Check | Result |
|
||||
|-------|--------|
|
||||
| `C:\xampp\php\php.exe -l src/Modules/Shipments/PolkurierShipmentService.php` | Pass |
|
||||
| `C:\xampp\php\php.exe -l tests/Unit/PolkurierShipmentServiceTest.php` | Pass |
|
||||
| Ad-hoc runtime smoke for `buildCodPayload()` | Pass |
|
||||
| `rg -n "codtype|return_cod|Polkurier|polkurier" DOCS/ARCHITECTURE.md DOCS/TECH_CHANGELOG.md` | Pass |
|
||||
| `git diff --check` | Pass; only Windows line-ending warnings |
|
||||
| `vendor/bin/phpunit tests/Unit/PolkurierShipmentServiceTest.php` | Gap: binary missing |
|
||||
| `sonar-scanner --version` | Gap: CLI missing in PATH |
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- Polkurier COD shipments should no longer fail on invalid return-time value.
|
||||
- Test file is ready to run once PHPUnit dependencies return.
|
||||
|
||||
**Concerns:**
|
||||
- Live Polkurier COD shipment smoke was not executed to avoid creating a real shipment without explicit operator action.
|
||||
|
||||
**Blockers:**
|
||||
- None for code completion.
|
||||
|
||||
---
|
||||
*Phase: 145-polkurier-cod-return-time-hotfix, Plan: 01*
|
||||
*Completed: 2026-05-18*
|
||||
@@ -156,6 +156,7 @@ Phase 135 fixes daily net totals: `OrdersStatisticsRepository::netAmountSql()` p
|
||||
|
||||
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=<servicecode>`, and `provider_service_name=<name>`. No schema change is required; the shipment prepare flow reads the shared mapping and preselects `provider='polkurier'` with the stored delivery method id instead of falling back to Allegro.
|
||||
Phase 145 fixes the Polkurier COD payload contract. For cash-on-delivery shipments, `PolkurierShipmentService` sends `COD.codtype='S'` (standard return time) and `COD.return_cod='BA'` (bank-account transfer), while preserving the existing bank-account requirement and sanitized numeric `codbankaccount`.
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Technical Changelog
|
||||
|
||||
## 2026-05-18 - Phase 145 Plan 01: Polkurier COD Return Time Hotfix
|
||||
|
||||
**Co zrobiono:**
|
||||
- Naprawiono payload COD wysylany do Polkurier `create_order`.
|
||||
- `PolkurierShipmentService` wysyla teraz `COD.codtype='S'` jako standardowy termin zwrotu pobrania oraz `COD.return_cod='BA'` jako przelew na konto bankowe.
|
||||
- Zachowano oczyszczanie numeru rachunku bankowego do samych cyfr i dotychczasowy blad walidacji, gdy konto firmowe nie jest uzupelnione.
|
||||
- Dodano test regresyjny budowania payloadu COD dla Polkuriera.
|
||||
|
||||
**Dlaczego:**
|
||||
- API Polkurier odrzucalo przesylki pobraniowe komunikatem o dozwolonym zbiorze `[S, 1D, 4D, 16D]`, bo orderPRO wysylal wartosc `transfer` w polu terminu zwrotu pobrania.
|
||||
|
||||
**BREAKING / migracja:**
|
||||
- Brak migracji DB i brak zmian breaking. Hotfix zmienia tylko wartosci wysylane w sekcji `COD` payloadu Polkurier.
|
||||
|
||||
## 2026-05-18 - Phase 144 Plan 01: Imported Notes Badge Count Hotfix
|
||||
|
||||
**Co zrobiono:**
|
||||
|
||||
@@ -150,18 +150,9 @@ final class PolkurierShipmentService implements ShipmentProviderInterface
|
||||
}
|
||||
|
||||
$cod = max(0.0, (float) ($formData['cod_amount'] ?? 0));
|
||||
if ($cod > 0) {
|
||||
$companySettings = $this->companySettings->getSettings();
|
||||
$bankAccount = preg_replace('/[^0-9]/', '', (string) ($companySettings['bank_account'] ?? '')) ?? '';
|
||||
if ($bankAccount === '') {
|
||||
throw new ShipmentException('Przesylka COD wymaga numeru konta bankowego. Uzupelnij go w Ustawienia > Firma.');
|
||||
}
|
||||
$apiPayload['COD'] = [
|
||||
'codtype' => 'transfer',
|
||||
'codamount' => round($cod, 2),
|
||||
'codbankaccount' => $bankAccount,
|
||||
'return_cod' => 'transfer',
|
||||
];
|
||||
$codPayload = $this->buildCodPayload($formData);
|
||||
if ($codPayload !== null) {
|
||||
$apiPayload['COD'] = $codPayload;
|
||||
}
|
||||
|
||||
$carrierLabel = $this->resolveCarrierLabel($courierCode);
|
||||
@@ -618,6 +609,31 @@ final class PolkurierShipmentService implements ShipmentProviderInterface
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $formData
|
||||
* @return array{codtype: string, codamount: float, codbankaccount: string, return_cod: string}|null
|
||||
*/
|
||||
private function buildCodPayload(array $formData): ?array
|
||||
{
|
||||
$cod = max(0.0, (float) ($formData['cod_amount'] ?? 0));
|
||||
if ($cod <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$companySettings = $this->companySettings->getSettings();
|
||||
$bankAccount = preg_replace('/[^0-9]/', '', (string) ($companySettings['bank_account'] ?? '')) ?? '';
|
||||
if ($bankAccount === '') {
|
||||
throw new ShipmentException('Przesylka COD wymaga numeru konta bankowego. Uzupelnij go w Ustawienia > Firma.');
|
||||
}
|
||||
|
||||
return [
|
||||
'codtype' => 'S',
|
||||
'codamount' => round($cod, 2),
|
||||
'codbankaccount' => $bankAccount,
|
||||
'return_cod' => 'BA',
|
||||
];
|
||||
}
|
||||
|
||||
private function nextBusinessDay(): string
|
||||
{
|
||||
$ts = time();
|
||||
|
||||
80
tests/Unit/PolkurierShipmentServiceTest.php
Normal file
80
tests/Unit/PolkurierShipmentServiceTest.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Core\Exceptions\ShipmentException;
|
||||
use App\Modules\Orders\OrdersRepository;
|
||||
use App\Modules\Settings\CompanySettingsRepository;
|
||||
use App\Modules\Settings\PolkurierApiClient;
|
||||
use App\Modules\Settings\PolkurierIntegrationRepository;
|
||||
use App\Modules\Shipments\PolkurierShipmentService;
|
||||
use App\Modules\Shipments\ShipmentPackageRepository;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionMethod;
|
||||
|
||||
final class PolkurierShipmentServiceTest extends TestCase
|
||||
{
|
||||
private CompanySettingsRepository $companySettings;
|
||||
private PolkurierShipmentService $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->companySettings = $this->createMock(CompanySettingsRepository::class);
|
||||
$this->service = new PolkurierShipmentService(
|
||||
$this->createMock(PolkurierIntegrationRepository::class),
|
||||
$this->createMock(PolkurierApiClient::class),
|
||||
$this->createMock(ShipmentPackageRepository::class),
|
||||
$this->companySettings,
|
||||
$this->createMock(OrdersRepository::class)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $formData
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
private function invokeBuildCodPayload(array $formData): ?array
|
||||
{
|
||||
$method = new ReflectionMethod(PolkurierShipmentService::class, 'buildCodPayload');
|
||||
$method->setAccessible(true);
|
||||
$result = $method->invoke($this->service, $formData);
|
||||
|
||||
return is_array($result) ? $result : null;
|
||||
}
|
||||
|
||||
public function testBuildCodPayloadUsesPolkurierAllowedCodes(): void
|
||||
{
|
||||
$this->companySettings
|
||||
->method('getSettings')
|
||||
->willReturn(['bank_account' => '12 3456-7890 1234 5678 9012 3456']);
|
||||
|
||||
$payload = $this->invokeBuildCodPayload(['cod_amount' => '123.456']);
|
||||
|
||||
self::assertSame('S', $payload['codtype'] ?? null);
|
||||
self::assertSame(123.46, $payload['codamount'] ?? null);
|
||||
self::assertSame('12345678901234567890123456', $payload['codbankaccount'] ?? null);
|
||||
self::assertSame('BA', $payload['return_cod'] ?? null);
|
||||
}
|
||||
|
||||
public function testBuildCodPayloadReturnsNullWithoutCodAmount(): void
|
||||
{
|
||||
$this->companySettings
|
||||
->expects(self::never())
|
||||
->method('getSettings');
|
||||
|
||||
self::assertNull($this->invokeBuildCodPayload(['cod_amount' => '0']));
|
||||
}
|
||||
|
||||
public function testBuildCodPayloadRequiresBankAccount(): void
|
||||
{
|
||||
$this->companySettings
|
||||
->method('getSettings')
|
||||
->willReturn(['bank_account' => '']);
|
||||
|
||||
$this->expectException(ShipmentException::class);
|
||||
$this->expectExceptionMessage('Przesylka COD wymaga numeru konta bankowego.');
|
||||
|
||||
$this->invokeBuildCodPayload(['cod_amount' => '50.00']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user