Phase 108 complete (v3.2 milestone):
Plan 108-01 — Delivery Status DB & CRUD:
- Tabela delivery_statuses z seedem 11 statusow systemowych
- DeliveryStatusRepository (CRUD + per-request static cache)
- DeliveryStatus::setRepository() — DB fallback dla static final class
- Panel /settings/delivery-statuses (zakladki Statusy + Mapowanie)
- Sidebar przebudowany: Statusy zamowien + Statusy przesylek
Plan 108-02 — Automation Dropdowns z DB + UI Refactor:
- Dropdowny automatyzacji ladowane z DB (warunek shipment_status + akcja update_shipment_status)
- Walidacja przez DeliveryStatus::getAllStatuses()
- Osobna podstrona formularza CRUD (delivery-status-form.php)
- Lista uproszczona: rename Terminal -> Koncowy, usunieta kolumna Typ
- BREAKING: drop backward compat dla starych grupowych kluczy automatyzacji
- Bug fix: path params w DeliveryStatusesController via \$request->input('id')
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
327 lines
17 KiB
Markdown
327 lines
17 KiB
Markdown
---
|
|
phase: 108-delivery-status-management
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- database/migrations/20260427_000103_create_delivery_statuses_table.sql
|
|
- src/Modules/Shipments/DeliveryStatusRepository.php
|
|
- src/Modules/Shipments/DeliveryStatus.php
|
|
- src/Modules/Settings/DeliveryStatusesController.php
|
|
- src/Modules/Settings/DeliveryStatusMappingController.php
|
|
- resources/views/settings/delivery-statuses.php
|
|
- resources/views/settings/_delivery-status-mappings-content.php
|
|
- resources/views/settings/delivery-status-mappings.php
|
|
- resources/views/layouts/app.php
|
|
- resources/scss/settings/_delivery-statuses.scss
|
|
- resources/scss/app.scss
|
|
- resources/lang/pl.php
|
|
- routes/web.php
|
|
- .paul/docs/DB_SCHEMA.md
|
|
- .paul/docs/ARCHITECTURE.md
|
|
- .paul/docs/TECH_CHANGELOG.md
|
|
autonomous: true
|
|
delegation: on
|
|
---
|
|
|
|
<objective>
|
|
## Goal
|
|
Wyniesc statusy znormalizowane przesylek do tabeli DB, udostepnic CRUD w nowym panelu ustawien "Statusy przesylek" i dynamicznie ladowac statusy z DB wszedzie tam, gdzie wczesniej uzywano stalych z `DeliveryStatus.php`.
|
|
|
|
## Purpose
|
|
Dodanie nowego statusu znormalizowanego wymaga teraz zmiany kodu i deploymentu. Po tej fazie operator moze dodac wlasny status z UI bez ingerencji w kod. Statusy systemowe (delivered, returned, cancelled) pozostaja nieedytowalne.
|
|
|
|
## Output
|
|
- Tabela `delivery_statuses` z seedem 11 istniejacych statusow
|
|
- `DeliveryStatusRepository` — odczyt z DB z per-request static cache
|
|
- `DeliveryStatus.php` — laduje `ALL_STATUSES` i `LABEL_PL` z DB (fallback na stale przy bledzie)
|
|
- Nowy panel `/settings/delivery-statuses` z dwoma zakladkami: CRUD statusow + mapowanie dostawy
|
|
- Sidebar: "Statusy zamowien" (istniejaca pozycja), nowa pozycja "Statusy przesylek"
|
|
- Walidacja w `DeliveryStatusMappingController` uzywajaca danych z DB
|
|
</objective>
|
|
|
|
<context>
|
|
## Project Context
|
|
@.paul/PROJECT.md
|
|
@.paul/STATE.md
|
|
|
|
## Source Files
|
|
@src/Modules/Shipments/DeliveryStatus.php
|
|
@src/Modules/Settings/DeliveryStatusMappingController.php
|
|
@resources/views/settings/delivery-status-mappings.php
|
|
@resources/views/layouts/app.php
|
|
@resources/lang/pl.php
|
|
@routes/web.php
|
|
@.paul/docs/DB_SCHEMA.md
|
|
@.paul/docs/ARCHITECTURE.md
|
|
</context>
|
|
|
|
<skills>
|
|
## Required Skills
|
|
|
|
| Skill | Priority | When to Invoke | Loaded? |
|
|
|-------|----------|----------------|---------|
|
|
| sonar-scanner (CLI) | required | Po APPLY, przed UNIFY | o |
|
|
</skills>
|
|
|
|
<acceptance_criteria>
|
|
|
|
## AC-1: Tabela delivery_statuses istnieje i zawiera seed 11 statusow
|
|
```gherkin
|
|
Given migracja zostala uruchomiona
|
|
Then tabela delivery_statuses zawiera 11 wierszy odpowiadajacych stalym z DeliveryStatus.php
|
|
And kolumny: id, key, label_pl, color, sort_order, is_terminal, is_system, created_at
|
|
And statusy: delivered, returned, cancelled maja is_system=1, is_terminal=1
|
|
And pozostale 8 statusow maja is_system=0
|
|
```
|
|
|
|
## AC-2: CRUD niebedacych systemowymi statusami dziala z panelu
|
|
```gherkin
|
|
Given operator otwiera /settings/delivery-statuses (zakladka Statusy)
|
|
When doda nowy status z kluczem, etykieta, kolorem
|
|
Then status pojawia sie na liscie i w dropdownie mapowania statusow
|
|
When probuje edytowac status systemowy (delivered/returned/cancelled)
|
|
Then formularz jest zablokowany (readonly/disabled fields lub brak przycisku edycji)
|
|
When probuje usunac status uzyty w delivery_status_mappings lub shipment_packages
|
|
Then otrzymuje blad "Status jest uzywany, nie mozna usunac"
|
|
```
|
|
|
|
## AC-3: Strona /settings/delivery-statuses ma dwie zakladki
|
|
```gherkin
|
|
Given operator otwiera /settings/delivery-statuses
|
|
Then widzi zakladke "Statusy" (CRUD) i "Mapowanie dostawy"
|
|
And klikajac "Mapowanie dostawy" widzi te sama tresc co wczesniej na /settings/delivery-status-mappings
|
|
And /settings/delivery-status-mappings dalej dziala (backward compat dla zakładek)
|
|
```
|
|
|
|
## AC-4: Sidebar odzwierciedla nowa strukture nawigacji
|
|
```gherkin
|
|
Given operator jest w ustawieniach
|
|
Then widzi "Statusy zamowien" (link do /settings/statuses)
|
|
And widzi "Statusy przesylek" (link do /settings/delivery-statuses)
|
|
And stara pozycja "Mapowanie statusow dostawy" znika z sidebara
|
|
And badge z liczba niezmapowanych statusow widnieje przy "Statusy przesylek"
|
|
```
|
|
|
|
## AC-5: DeliveryStatus.php laduje statusy z DB
|
|
```gherkin
|
|
Given tabela delivery_statuses istnieje
|
|
When kod wywola DeliveryStatus::label($key)
|
|
Then zwraca etykiete z DB (nie hardcoded)
|
|
And kolejne wywolania w tym samym request uzywaja per-request static cache
|
|
```
|
|
|
|
## AC-6: Badge renderuje sie dla nowych statusow
|
|
```gherkin
|
|
Given status niebedacy jednym z 11 systemowych ma kolor #ff5500
|
|
When badge jest renderowany w liscie zamowien lub szczegolow przesylki
|
|
Then badge uzywa inline style="background-color: #ff5500" dla nieznanych kluczy CSS
|
|
And istniejace 11 statusow dalej korzysta z hardcoded klas CSS (.delivery-badge--delivered itp.)
|
|
```
|
|
|
|
</acceptance_criteria>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Migracja tabeli delivery_statuses i DeliveryStatusRepository</name>
|
|
<files>database/migrations/20260427_000103_create_delivery_statuses_table.sql, src/Modules/Shipments/DeliveryStatusRepository.php</files>
|
|
<action>
|
|
1. Utworzyc migracje `20260427_000103_create_delivery_statuses_table.sql`:
|
|
- CREATE TABLE `delivery_statuses` (
|
|
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
`key` VARCHAR(50) NOT NULL UNIQUE,
|
|
`label_pl` VARCHAR(100) NOT NULL,
|
|
`color` VARCHAR(7) NOT NULL DEFAULT '#6c757d',
|
|
`sort_order` TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
|
`is_terminal` TINYINT(1) NOT NULL DEFAULT 0,
|
|
`is_system` TINYINT(1) NOT NULL DEFAULT 0,
|
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
- INSERT seed: wszystkie 11 statusow z DeliveryStatus.php (unknown, created, confirmed,
|
|
picked_up, in_transit, out_for_delivery, ready_for_pickup, delivered, returned,
|
|
cancelled, problem) z odpowiednimi wartosciami label_pl, color, sort_order,
|
|
is_terminal (delivered/returned/cancelled = 1), is_system (delivered/returned/cancelled = 1).
|
|
- Kolory bazujac na istniejacych klasach CSS (sprawdzic resources/scss/).
|
|
2. Utworzyc `src/Modules/Shipments/DeliveryStatusRepository.php`:
|
|
- Konstruktor przyjmuje `\Medoo\Medoo $db`
|
|
- `getAll(): array` — SELECT * FROM delivery_statuses ORDER BY sort_order ASC
|
|
z per-request static cache (prywatna static zmienna)
|
|
- `getByKey(string $key): ?array` — szuka w getAll()
|
|
- `getAllAsOptions(): array` — zwraca [key => label_pl] (do dropdownow)
|
|
- `create(array $data): int` — INSERT, zwraca id; waliduje unikalnosc key przed insertem
|
|
- `update(int $id, array $data): void` — UPDATE; blokuje is_system=1
|
|
- `delete(int $id): void` — DELETE; sprawdza czy key nie wystepuje w
|
|
delivery_status_mappings.normalized_status lub shipment_packages.delivery_status;
|
|
blokuje jesli is_system=1 lub uzywany
|
|
- `clearCache(): void` — resetuje static cache (do testow i po mutacjach)
|
|
</action>
|
|
<verify>
|
|
Uruchom migracje na lokalnej bazie. Sprawdz `SELECT COUNT(*) FROM delivery_statuses` = 11.
|
|
Sprawdz ze delivered/returned/cancelled maja is_system=1, is_terminal=1.
|
|
</verify>
|
|
<done>Dane bazodanowe gotowe; repozytorium dostepne do uzycia w pozostalych taskach.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Dynamiczne ladowanie w DeliveryStatus.php + controller + widok CRUD + routing</name>
|
|
<files>src/Modules/Shipments/DeliveryStatus.php, src/Modules/Settings/DeliveryStatusesController.php, src/Modules/Settings/DeliveryStatusMappingController.php, resources/views/settings/delivery-statuses.php, resources/views/settings/_delivery-status-mappings-content.php, resources/views/settings/delivery-status-mappings.php, resources/scss/settings/_delivery-statuses.scss, resources/scss/app.scss, routes/web.php</files>
|
|
<action>
|
|
1. Zaktualizowac `DeliveryStatus.php`:
|
|
- Dodac statyczna metode `setRepository(DeliveryStatusRepository $repo): void` (called once at bootstrap)
|
|
- Zmodyfikowac `label(string $key): string` — gdy repozytorium jest wstrzykniete,
|
|
pobiera z DB przez `getByKey($key)['label_pl']`; fallback na `LABEL_PL[$key] ?? $key`
|
|
- Dodac `getAllStatuses(): array` — zwraca `DeliveryStatusRepository::getAll()` lub
|
|
fallback `ALL_STATUSES` gdy repo niedostepne
|
|
- Dodac `getAllOptions(): array` — zwraca `DeliveryStatusRepository::getAllAsOptions()` lub
|
|
fallback `LABEL_PL`
|
|
- STALE i TERMINAL_STATUSES/providerowe mapy (INPOST_MAP etc.) pozostaja hardcoded (nie
|
|
dotyczace listy statusow uzytkownika)
|
|
- Podpiac `DeliveryStatusRepository` w bootstrapie (app.php lub DI kontener projektu —
|
|
sprawdzic jak inne repozytoria sa inicjalizowane i powtorzyc ten sam wzorzec)
|
|
2. Zaktualizowac `DeliveryStatusMappingController`:
|
|
- Wstrzyknac `DeliveryStatusRepository` przez konstruktor
|
|
- W `save()` i `saveBulk()` — walidacja normalizedStatus przez
|
|
`$this->deliveryStatusRepository->getByKey($normalizedStatus) !== null`
|
|
zamiast `in_array($normalizedStatus, DeliveryStatus::ALL_STATUSES)`
|
|
- Zaktualizowac `REDIRECT_PATH` z `/settings/delivery-status-mappings`
|
|
na `/settings/delivery-statuses?tab=mapping`
|
|
- Zachowac parametr `?provider=` przy redirectach gdzie byl
|
|
3. Wydzielic zawartosc widoku mapowania do include'a:
|
|
- Przeniesc zawartosc `resources/views/settings/delivery-status-mappings.php` do
|
|
`resources/views/settings/_delivery-status-mappings-content.php`
|
|
- W `delivery-status-mappings.php` uzywac `include '_delivery-status-mappings-content.php'`
|
|
(zachowanie backward compat)
|
|
4. Utworzyc `DeliveryStatusesController.php` w `src/Modules/Settings/`:
|
|
- `index()` — laduje statusy z DeliveryStatusRepository, renderuje delivery-statuses.php;
|
|
przekazuje `$tab = $_GET['tab'] ?? 'statuses'` i dane mapowania gdy tab=mapping
|
|
- `store()` — POST create nowego statusu; waliduje key (lowercase, underscored), label_pl,
|
|
color (#hex); zapisuje przez repozytorium; redirect z Flash
|
|
- `update(int $id)` — POST edit; blokuje is_system=1; redirect z Flash
|
|
- `destroy(int $id)` — POST delete; blokuje is_system=1 i uzywane; redirect z Flash
|
|
- Każda akcja mutujaca: walidacja CSRF `_token`, potem `DeliveryStatusRepository::clearCache()`
|
|
5. Utworzyc widok `resources/views/settings/delivery-statuses.php`:
|
|
- Dwie zakladki: "Statusy" i "Mapowanie dostawy"
|
|
- Persystencja aktywnej zakladki przez `?tab=` param (nie localStorage — zeby linki
|
|
z sidebara "Statusy przesylek" i redirect po save trafialy w dobra zakladke)
|
|
- Zakladka "Statusy":
|
|
* Tabela statusow: kolor (swatchek), klucz, etykieta, sort_order, is_terminal,
|
|
akcje (edycja/usun dla nie-systemowych; informacja "systemowy" dla systemowych)
|
|
* Formularz dodawania nowego statusu (inline pod tabela lub modal)
|
|
* Formularz edycji (inline row edit lub osobny formularz)
|
|
* Potwierdzenie usuwania: `window.OrderProAlerts.confirm()`
|
|
* Formularz dodawania: pola key (slug, lowercase, max 50), label_pl, color (input type=color),
|
|
sort_order (number), is_terminal (checkbox)
|
|
- Zakladka "Mapowanie dostawy":
|
|
* include '_delivery-status-mappings-content.php'
|
|
6. Dodac styl `resources/scss/settings/_delivery-statuses.scss`:
|
|
- `.delivery-status-swatch` — maly kwadrat koloru (16x16px inline-block)
|
|
- `.delivery-status-system-badge` — np. szary badge "systemowy"
|
|
- Dodac `@use 'settings/delivery-statuses'` do `app.scss`
|
|
7. Dodac trasy w `routes/web.php`:
|
|
- GET `/settings/delivery-statuses` → `DeliveryStatusesController::index`
|
|
- POST `/settings/delivery-statuses` → `DeliveryStatusesController::store`
|
|
- POST `/settings/delivery-statuses/{id}/update` → `DeliveryStatusesController::update`
|
|
- POST `/settings/delivery-statuses/{id}/delete` → `DeliveryStatusesController::destroy`
|
|
</action>
|
|
<verify>
|
|
- GET /settings/delivery-statuses zwraca 200, widac zakladki
|
|
- Dodanie nowego statusu przez CRUD pojawia sie na liscie
|
|
- Proba edycji/usuniecia statusu systemowego jest blokowana (HTTP 400 lub redirect z bledem)
|
|
- GET /settings/delivery-status-mappings dalej dziala (backward compat)
|
|
- redirect po save mapowania idzie do /settings/delivery-statuses?tab=mapping
|
|
</verify>
|
|
<done>AC-2, AC-3, AC-5 spelnione.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Sidebar, jezyk, badge rendering i dokumentacja</name>
|
|
<files>resources/views/layouts/app.php, resources/lang/pl.php, resources/views/orders/show.php, resources/views/shipments/prepare.php, .paul/docs/DB_SCHEMA.md, .paul/docs/ARCHITECTURE.md, .paul/docs/TECH_CHANGELOG.md</files>
|
|
<action>
|
|
1. Zaktualizowac `resources/lang/pl.php`:
|
|
- `navigation.statuses` → 'Statusy zamowien'
|
|
- Dodac `navigation.delivery_statuses` => 'Statusy przesylek'
|
|
2. Zaktualizowac sidebar `resources/views/layouts/app.php`:
|
|
- Zmieniac istniejaca pozycje "Statusy" (href=/settings/statuses) tylko etykiete na
|
|
$t('navigation.statuses') (juz uzywana, ale tresc sie zmieni po kroku 1)
|
|
- Podmiana calego bloku sidebar z "Mapowanie statusow dostawy" (linie ~130-147):
|
|
* Nowy link "Statusy przesylek" href=/settings/delivery-statuses
|
|
* active gdy $currentSettings === 'delivery-statuses'
|
|
LUB $currentSettings === 'delivery-status-mappings' (backward compat)
|
|
* Badge z liczba niezmapowanych (zachowac istniejaca logike z DeliveryStatusMappingRepository)
|
|
3. Zaktualizowac badge rendering:
|
|
- W `resources/views/orders/show.php` i `resources/views/shipments/prepare.php`:
|
|
Aktualny wzorzec:
|
|
`<span class="delivery-badge delivery-badge--<?= $e($pkgDeliveryStatus) ?>">`
|
|
Zmienic na helper lub inline logike:
|
|
- Jesli `$pkgDeliveryStatus` jest jednym z 11 stalych — uzyj klasy CSS jak dotychczas
|
|
- W przeciwnym razie: pobierz kolor z DeliveryStatus::getByKey() i dodaj
|
|
`style="background-color: <?= $e($color) ?>"`
|
|
Wzorzec do uzycia (zdefiniowac helper w DeliveryStatus lub inline w widoku):
|
|
```php
|
|
$statusColor = DeliveryStatus::getColor($pkgDeliveryStatus);
|
|
$isSystemStatus = in_array($pkgDeliveryStatus, DeliveryStatus::ALL_STATUSES);
|
|
$badgeClass = 'delivery-badge' . ($isSystemStatus ? ' delivery-badge--' . $pkgDeliveryStatus : '');
|
|
$badgeStyle = $isSystemStatus ? '' : 'background-color: ' . $statusColor . ';';
|
|
```
|
|
`<span class="<?= $e($badgeClass) ?>" <?= $badgeStyle ? 'style="' . $e($badgeStyle) . '"' : '' ?>>`
|
|
- Dodac do `DeliveryStatus.php` metode `getColor(string $key): string` — pobiera kolor z
|
|
repozytorium lub zwraca '#6c757d' jako fallback
|
|
4. Zaktualizowac `.paul/docs/DB_SCHEMA.md` (nowa tabela delivery_statuses)
|
|
5. Zaktualizowac `.paul/docs/ARCHITECTURE.md` (DeliveryStatusRepository, DeliveryStatusesController)
|
|
6. Zaktualizowac `.paul/docs/TECH_CHANGELOG.md` (entry dla Phase 108 Plan 01)
|
|
</action>
|
|
<verify>
|
|
- Sidebar pokazuje "Statusy zamowien" i "Statusy przesylek", brak "Mapowanie statusow dostawy"
|
|
- Badge dla istniejacych 11 statusow renderuje sie klasa CSS jak wczesniej
|
|
- Badge dla nowego custom statusu renderuje sie z inline style
|
|
- Na stronie zamowien i przesylki brak bledow PHP
|
|
</verify>
|
|
<done>AC-4, AC-6 spelnione; dokumentacja aktualna.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<boundaries>
|
|
|
|
## DO NOT CHANGE
|
|
- Logika eventow automatyzacji, reguł i akcji niezwiazana z lista statusow
|
|
- Provider mapy (INPOST_MAP, APACZKA_MAP, ALLEGRO_MAP) — pozostaja hardcoded compile-time
|
|
- TERMINAL_STATUSES — stala pozostaje w kodzie dla logiki biznesowej; DB `is_terminal` jest dodatkowa informacja dla UI
|
|
- Runtime konfiguracji DB hostow (`DB_HOST` / `DB_HOST_REMOTE`)
|
|
- Istniejace CSS klasy `.delivery-badge--{status}` dla 11 systemowych statusow
|
|
|
|
## SCOPE LIMITS
|
|
- Brak zmian w logice normalizacji statusow dostawcow (normalize(), normalizeWithOverrides())
|
|
- Brak zmian w cronie ani harmonogramie
|
|
- Automatyzacje — dropdown statusow aktualizowany w Plan 02 (nie w tym planie)
|
|
|
|
</boundaries>
|
|
|
|
<verification>
|
|
Before declaring plan complete:
|
|
- [ ] `SELECT COUNT(*) FROM delivery_statuses` = 11
|
|
- [ ] GET /settings/delivery-statuses zwraca 200 z dwoma zakladkami
|
|
- [ ] Dodanie nowego statusu przez CRUD jest widoczne na liscie
|
|
- [ ] Statusy systemowe sa zablokowane przed edycja i usunieciem
|
|
- [ ] GET /settings/delivery-status-mappings nadal dziala (200)
|
|
- [ ] Redirect po save mapowania idzie do /settings/delivery-statuses?tab=mapping
|
|
- [ ] Sidebar pokazuje "Statusy zamowien" i "Statusy przesylek"
|
|
- [ ] Badge istniejacych statusow bez regresji
|
|
- [ ] Badge nowego custom statusu renderuje sie z inline style
|
|
- [ ] Dokumentacja .paul/docs/* zaktualizowana
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Operator moze dodac nowy status znormalizowany z panelu bez deploymentu
|
|
- Status systemowy (delivered/returned/cancelled) jest nieedytowalny z UI
|
|
- Strona /settings/delivery-statuses ma dwie dzialajace zakladki
|
|
- Sidebar jest uporzadkowany zgodnie z nowa struktura
|
|
- Brak regresji w istniejacym wyswietlaniu odznaczen statusow
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.paul/phases/108-delivery-status-management/108-01-SUMMARY.md`
|
|
</output>
|