Phase 29 complete (v1.3): - Tabela delivery_status_mappings z DB overrides - DeliveryStatus: normalizeWithOverrides(), descriptionWithOverrides(), getDefaultMappings() - UI ustawień: tabela mapowań per provider (InPost/Apaczka/Allegro), bulk save, reset, resetAll - 5 endpointów w routes/web.php, link w menu bocznym Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
268 lines
11 KiB
Markdown
268 lines
11 KiB
Markdown
---
|
|
phase: 29-delivery-status-mapping-ui
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: ["28-01"]
|
|
files_modified:
|
|
- database/migrations/20260323_000070_create_delivery_status_mappings_table.sql
|
|
- src/Modules/Shipments/DeliveryStatusMappingRepository.php
|
|
- src/Modules/Shipments/DeliveryStatus.php
|
|
- src/Modules/Settings/DeliveryStatusMappingController.php
|
|
- resources/views/settings/delivery-status-mappings.php
|
|
- routes/web.php
|
|
autonomous: false
|
|
---
|
|
|
|
<objective>
|
|
## Goal
|
|
Umożliwić użytkownikowi konfigurację mapowania surowych statusów z API przewoźników na znormalizowane statusy widoczne w aplikacji — bez zmian w kodzie.
|
|
|
|
## Purpose
|
|
Każdy przewoźnik zwraca inne statusy (InPost: `adopted_at_sorting_center`, Apaczka: `NEW`/`CONFIRMED`, Allegro: `IN_TRANSIT`). Obecnie mapowania są zahardkodowane w DeliveryStatus.php. Użytkownik powinien móc:
|
|
- Zobaczyć wszystkie mapowania (domyślne + własne)
|
|
- Zmienić przypisanie surowego statusu do innego znormalizowanego statusu
|
|
- Zmienić opis wyświetlany przy surowym statusie
|
|
|
|
## Output
|
|
- Tabela DB `delivery_status_mappings` na custom overrides
|
|
- Strona ustawień z tabelą mapowań per provider
|
|
- DeliveryStatus sprawdza DB overrides przed fallback na stałe
|
|
</objective>
|
|
|
|
<context>
|
|
## Project Context
|
|
@.paul/PROJECT.md
|
|
@.paul/ROADMAP.md
|
|
@.paul/STATE.md
|
|
|
|
## Prior Work
|
|
@.paul/phases/28-shipment-tracking-ui/28-01-SUMMARY.md
|
|
|
|
## Source Files
|
|
@src/Modules/Shipments/DeliveryStatus.php
|
|
@src/Modules/Settings/AllegroStatusMappingController.php
|
|
@src/Modules/Settings/AllegroStatusMappingRepository.php
|
|
@resources/views/settings/statuses.php
|
|
@routes/web.php
|
|
</context>
|
|
|
|
<skills>
|
|
## Required Skills (from SPECIAL-FLOWS.md)
|
|
|
|
| Skill | Priority | When to Invoke | Loaded? |
|
|
|-------|----------|----------------|---------|
|
|
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
|
|
|
## Skill Invocation Checklist
|
|
- [ ] sonar-scanner uruchomiony po zakończeniu APPLY
|
|
</skills>
|
|
|
|
<acceptance_criteria>
|
|
|
|
## AC-1: Lista mapowań per provider
|
|
```gherkin
|
|
Given użytkownik jest na stronie Ustawienia > Mapowanie statusów dostawy
|
|
When wybiera providera (InPost / Apaczka / Allegro)
|
|
Then widzi tabelę z kolumnami: Status surowy, Opis, Status znormalizowany
|
|
And każdy wiersz pokazuje aktualne przypisanie (domyślne lub custom)
|
|
And wiersze z custom override są wyróżnione wizualnie
|
|
```
|
|
|
|
## AC-2: Edycja mapowania statusu
|
|
```gherkin
|
|
Given użytkownik widzi tabelę mapowań dla wybranego providera
|
|
When zmienia "Status znormalizowany" w wierszu (select z opcjami: Utworzona, Potwierdzona, W tranzycie, etc.)
|
|
And klika Zapisz
|
|
Then mapowanie jest zapisane w tabeli delivery_status_mappings
|
|
And przy następnym pobraniu statusu z API, nowe mapowanie jest używane
|
|
```
|
|
|
|
## AC-3: Edycja opisu statusu
|
|
```gherkin
|
|
Given użytkownik widzi tabelę mapowań
|
|
When zmienia tekst w kolumnie "Opis" dla surowego statusu
|
|
And klika Zapisz
|
|
Then opis jest zapisany w delivery_status_mappings
|
|
And tooltip w badge'u statusu pokazuje nowy opis
|
|
```
|
|
|
|
## AC-4: Reset do domyślnych
|
|
```gherkin
|
|
Given użytkownik ma custom override dla statusu
|
|
When klika przycisk "Resetuj" obok wiersza
|
|
Then custom override jest usunięty z delivery_status_mappings
|
|
And mapowanie wraca do domyślnego z DeliveryStatus.php
|
|
```
|
|
|
|
## AC-5: DeliveryStatus używa custom overrides
|
|
```gherkin
|
|
Given istnieje wpis w delivery_status_mappings (provider='apaczka', raw_status='NEW', normalized_status='confirmed')
|
|
When system wywołuje DeliveryStatus::normalize('apaczka', 'NEW')
|
|
Then zwraca 'confirmed' (z DB) zamiast 'created' (domyślny)
|
|
```
|
|
|
|
</acceptance_criteria>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Migracja DB + Repository</name>
|
|
<files>database/migrations/20260323_000070_create_delivery_status_mappings_table.sql, src/Modules/Shipments/DeliveryStatusMappingRepository.php</files>
|
|
<action>
|
|
**Migracja — tabela delivery_status_mappings:**
|
|
```sql
|
|
CREATE TABLE IF NOT EXISTS delivery_status_mappings (
|
|
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
provider VARCHAR(32) NOT NULL,
|
|
raw_status VARCHAR(64) NOT NULL,
|
|
normalized_status VARCHAR(32) NOT NULL,
|
|
description VARCHAR(255) NOT NULL DEFAULT '',
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
UNIQUE KEY uq_provider_raw (provider, raw_status)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
```
|
|
Idempotentna (IF NOT EXISTS).
|
|
|
|
**DeliveryStatusMappingRepository:**
|
|
- `listByProvider(string $provider): array` — SELECT * WHERE provider = :provider
|
|
- `upsertMapping(string $provider, string $rawStatus, string $normalizedStatus, string $description): void` — INSERT ON DUPLICATE KEY UPDATE
|
|
- `deleteMapping(string $provider, string $rawStatus): void` — DELETE WHERE provider AND raw_status
|
|
- `getAllOverrides(): array` — SELECT * (dla cache w DeliveryStatus)
|
|
|
|
Wzoruj na AllegroStatusMappingRepository (konstruktor z PDO, prepared statements).
|
|
Avoid: nie dodawaj logiki biznesowej do repozytorium.
|
|
</action>
|
|
<verify>
|
|
php -l na obu plikach
|
|
Migracja wykonuje się bez błędów na DB
|
|
</verify>
|
|
<done>Tabela DB gotowa, repozytorium CRUD działa — fundament dla AC-2, AC-3, AC-4</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: DeliveryStatus — DB overrides + kontroler + widok + routing</name>
|
|
<files>src/Modules/Shipments/DeliveryStatus.php, src/Modules/Settings/DeliveryStatusMappingController.php, resources/views/settings/delivery-status-mappings.php, routes/web.php</files>
|
|
<action>
|
|
**DeliveryStatus — metody z DB override:**
|
|
- Dodaj nowe statyczne metody:
|
|
- `normalizeWithOverrides(string $provider, string $rawStatus, array $overrides): string`
|
|
- `descriptionWithOverrides(string $provider, string $rawStatus, array $overrides): string`
|
|
- $overrides to tablica ['provider:raw_status' => ['normalized_status' => X, 'description' => Y]]
|
|
- Najpierw szukaj w $overrides, potem fallback na istniejące stałe (INPOST_MAP, etc.)
|
|
- Dodaj `getDefaultMappings(string $provider): array` — zwraca wszystkie mapowania z hardkodowanych stałych jako tablicę [raw_status => [normalized, description]]
|
|
|
|
**DeliveryStatusMappingController:**
|
|
- Konstruktor: Template, Translator, AuthService, DeliveryStatusMappingRepository
|
|
- `index(Request): Response`:
|
|
- Parametr GET `provider` (domyślnie 'inpost')
|
|
- Pobierz domyślne mapowania z DeliveryStatus::getDefaultMappings($provider)
|
|
- Pobierz custom overrides z repo: listByProvider($provider)
|
|
- Merge: custom nadpisuje domyślne
|
|
- Przekaż do widoku: provider, mappings, providers list, csrfToken, normalized status options
|
|
- `save(Request): Response`:
|
|
- Waliduj CSRF
|
|
- Odczytaj POST: provider, raw_status, normalized_status, description
|
|
- Waliduj: normalized_status musi być jednym z DeliveryStatus::ALL_STATUSES
|
|
- Wywołaj repo->upsertMapping(...)
|
|
- Flash success, redirect
|
|
- `reset(Request): Response`:
|
|
- Waliduj CSRF
|
|
- Odczytaj POST: provider, raw_status
|
|
- Wywołaj repo->deleteMapping(...)
|
|
- Flash success, redirect
|
|
|
|
**Widok delivery-status-mappings.php:**
|
|
- Nawigacja providerów: InPost | Apaczka | Allegro (linki z ?provider=X)
|
|
- Tabela z kolumnami:
|
|
- Status surowy (readonly, tekst)
|
|
- Opis (input text, edytowalny)
|
|
- Status znormalizowany (select z opcjami z LABEL_PL)
|
|
- Akcje: Zapisz (jeśli zmieniony) | Resetuj (jeśli custom)
|
|
- Każdy wiersz jako osobny mini-formularz POST (jak w statuses.php pattern)
|
|
- Wiersze z custom override: dodaj klasę CSS `is-custom` (np. lekkie tło)
|
|
- Formularz bulk save: jeden przycisk "Zapisz wszystkie" z JS zbierającym dane
|
|
|
|
**routes/web.php:**
|
|
- GET `/settings/delivery-status-mappings` → index
|
|
- POST `/settings/delivery-status-mappings/save` → save
|
|
- POST `/settings/delivery-status-mappings/reset` → reset
|
|
- Wszystkie z $authMiddleware
|
|
- Zainicjalizuj kontroler w sekcji controller instantiation
|
|
|
|
**Menu nawigacji:**
|
|
- Dodaj link "Mapowanie statusów" w menu ustawień (layout/sidebar)
|
|
|
|
Avoid:
|
|
- NIE zmieniaj istniejących metod normalize() i description() — nowe metody obok
|
|
- NIE usuwaj hardkodowanych stałych — to fallback
|
|
- NIE dodawaj JS frameworków — czyste formularze HTML
|
|
</action>
|
|
<verify>
|
|
php -l na wszystkich zmienionych plikach PHP
|
|
Strona /settings/delivery-status-mappings ładuje się bez błędów
|
|
Zmiana mapowania i zapis działa
|
|
</verify>
|
|
<done>AC-1, AC-2, AC-3, AC-4, AC-5 satisfied</done>
|
|
</task>
|
|
|
|
<task type="checkpoint:human-verify" gate="blocking">
|
|
<what-built>Strona ustawień mapowania statusów dostawy — tabela mapowań per provider, edycja przypisań i opisów, reset do domyślnych.</what-built>
|
|
<how-to-verify>
|
|
1. Otwórz Ustawienia > Mapowanie statusów dostawy
|
|
2. Sprawdź zakładkę InPost — tabela ze statusami i ich opisami
|
|
3. Przełącz na Apaczka — sprawdź czy statusy tekstowe (NEW, CONFIRMED) są widoczne
|
|
4. Zmień mapowanie jednego statusu (np. NEW → Potwierdzona zamiast Utworzona) i Zapisz
|
|
5. Sprawdź czy badge w zamówieniu #22 odzwierciedla zmianę
|
|
6. Kliknij Resetuj — sprawdź czy wraca do domyślnego
|
|
7. Zmień opis statusu i sprawdź tooltip w badge'u
|
|
</how-to-verify>
|
|
<resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<boundaries>
|
|
|
|
## DO NOT CHANGE
|
|
- src/Modules/Shipments/ShipmentTrackingInterface.php
|
|
- src/Modules/Shipments/InpostTrackingService.php
|
|
- src/Modules/Shipments/ApaczkaTrackingService.php
|
|
- src/Modules/Shipments/AllegroTrackingService.php
|
|
- src/Modules/Cron/ShipmentTrackingHandler.php
|
|
- Istniejące stałe w DeliveryStatus.php (INPOST_MAP, APACZKA_MAP, etc.) — to fallback
|
|
|
|
## SCOPE LIMITS
|
|
- Tylko UI do konfiguracji mapowań — bez zmian w logice trackingu
|
|
- Brak nowych zależności npm/composer
|
|
- Brak JavaScript frameworków — czyste formularze HTML + POST
|
|
- Tracking services (InPost/Apaczka/Allegro) muszą przekazywać overrides do DeliveryStatus — to integracja w ShipmentTrackingHandler, nie w tym planie jeśli wymaga dużych zmian
|
|
|
|
</boundaries>
|
|
|
|
<verification>
|
|
Before declaring plan complete:
|
|
- [ ] php -l przechodzi na wszystkich zmienionych plikach
|
|
- [ ] Migracja wykonuje się bez błędów
|
|
- [ ] Strona mapowań ładuje się dla każdego providera
|
|
- [ ] Zmiana mapowania zapisuje się w DB
|
|
- [ ] Reset usuwa custom override
|
|
- [ ] DeliveryStatus::normalizeWithOverrides() zwraca custom wartość gdy override istnieje
|
|
- [ ] DeliveryStatus::normalizeWithOverrides() zwraca domyślną gdy brak override
|
|
- [ ] All acceptance criteria met
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Tabela delivery_status_mappings utworzona
|
|
- Strona ustawień działa z 3 providerami
|
|
- Edycja mapowania i opisu zapisuje się poprawnie
|
|
- Reset do domyślnych działa
|
|
- DeliveryStatus respektuje custom overrides
|
|
- Brak nowych zależności
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.paul/phases/29-delivery-status-mapping-ui/29-01-SUMMARY.md`
|
|
</output>
|