--- phase: 28-shipment-tracking-ui plan: 01 type: execute wave: 1 depends_on: ["27-01"] files_modified: - resources/views/orders/show.php - resources/views/shipments/prepare.php - resources/views/settings/cron.php - resources/scss/modules/_shipments.scss - src/Modules/Settings/CronSettingsController.php - src/Modules/Cron/CronRepository.php autonomous: false --- ## Goal Wyświetlić status dostawy przesyłek w UI (szczegóły zamówienia + strona przygotowania przesyłki), dodać ustawienie interwału trackingu w zakładce crona, oraz obsłużyć link śledzenia dla przesyłek ręcznych. ## Purpose Sprzedawca widzi aktualny status dostawy bez opuszczania aplikacji — oszczędza czas i eliminuje ręczne sprawdzanie na stronach przewoźników. ## Output - Kolumna "Status dostawy" w tabelach paczek (show.php + prepare.php) - Kolorowe badge'e statusów z polskimi labelami - Link śledzenia dla przesyłek z tracking number (URL budowany z providera) - Ustawienie interwału trackingu crona w settings/cron.php - Sekcja tracking info w boksie "Płatność i wysyłka" ## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md ## Prior Work @.paul/phases/27-shipment-tracking-backend/27-01-SUMMARY.md ## Source Files @resources/views/orders/show.php @resources/views/shipments/prepare.php @resources/views/settings/cron.php @src/Modules/Settings/CronSettingsController.php @src/Modules/Cron/CronRepository.php @src/Modules/Shipments/DeliveryStatus.php @src/Modules/Shipments/ShipmentPackageRepository.php ## 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 ## AC-1: Status dostawy w tabeli paczek na stronie zamówienia ```gherkin Given zamówienie ma przesyłkę ze statusem delivery_status = 'in_transit' i delivery_status_raw = 'adopted_at_sorting_center' When użytkownik otwiera stronę szczegółów zamówienia Then w tabeli paczek (zakładka Przesyłki) widoczna jest kolumna "Status dostawy" And status wyświetla się jako kolorowy badge "W tranzycie" And po najechaniu (title) widać surowy status: "adopted_at_sorting_center — Przyjęta w centrum sortowania" ``` ## AC-2: Status dostawy w tabeli paczek na stronie przygotowania przesyłki ```gherkin Given zamówienie ma istniejące paczki z różnymi delivery_status When użytkownik otwiera stronę przygotowania przesyłki Then w sekcji "Wygenerowane przesyłki" widoczna jest kolumna "Status dostawy" And każda paczka pokazuje badge ze statusem dostawy ``` ## AC-3: Link śledzenia przesyłki ```gherkin Given paczka ma tracking_number i znany provider (inpost/apaczka/allegro_wza) When użytkownik widzi tabelę paczek Then obok numeru śledzenia wyświetla się ikonka linku (🔗) otwierająca stronę śledzenia przewoźnika And dla InPost link to https://inpost.pl/sledzenie-przesylek?number={tracking_number} And dla Apaczka link to https://www.apaczka.pl/sledz-paczke/?numer={tracking_number} And dla Allegro link budowany z allegro tracking URL And dla manual bez linku (chyba że user poda URL w przyszłości) ``` ## AC-4: Ustawienie interwału trackingu w cronie ```gherkin Given użytkownik jest na stronie Ustawienia > Cron When widzi tabelę harmonogramów crona Then przy rekordzie shipment_tracking_sync widoczny jest edytowalny interwał (w minutach) And po zmianie wartości i zapisaniu formularza interwał jest aktualizowany w cron_schedules And dozwolone wartości: 5-120 minut ``` ## AC-5: Info o śledzeniu w boksie "Płatność i wysyłka" ```gherkin Given zamówienie ma przesyłkę z delivery_status != 'unknown' When użytkownik otwiera szczegóły zamówienia Then w boksie "Płatność i wysyłka" widoczna jest sekcja "Status dostawy" And wyświetla znormalizowany status z kolorowym badge + datę ostatniej aktualizacji And dla wielu paczek pokazuje status najnowszej (ostatnio zaktualizowanej) ``` Task 1: Style SCSS + DeliveryStatus badge helper + tracking URL builder resources/scss/modules/_shipments.scss, src/Modules/Shipments/DeliveryStatus.php **SCSS — badge'e statusów dostawy** (w _shipments.scss, lub nowy plik jeśli nie istnieje): - `.delivery-badge` — bazowy styl: inline-block, padding 2px 8px, border-radius 3px, font-size 0.8em - `.delivery-badge--unknown` — szary (#999 bg, #fff text) - `.delivery-badge--created` — jasnoniebieski (#e3f2fd bg, #1565c0 text) - `.delivery-badge--confirmed` — niebieski (#bbdefb bg, #0d47a1 text) - `.delivery-badge--in_transit` — pomarańczowy (#fff3e0 bg, #e65100 text) - `.delivery-badge--out_for_delivery` — ciemnopomarańczowy (#ffe0b2 bg, #bf360c text) - `.delivery-badge--ready_for_pickup` — fioletowy (#f3e5f5 bg, #6a1b9a text) - `.delivery-badge--delivered` — zielony (#e8f5e9 bg, #2e7d32 text) - `.delivery-badge--returned` — czerwony (#ffebee bg, #c62828 text) - `.delivery-badge--cancelled` — ciemnoszary (#e0e0e0 bg, #616161 text) - `.delivery-badge--problem` — żółto-czerwony (#fff8e1 bg, #f57f17 text) **DeliveryStatus — metoda trackingUrl()**: - Dodaj static method `trackingUrl(string $provider, string $trackingNumber): ?string` - InPost: `https://inpost.pl/sledzenie-przesylek?number={trackingNumber}` - Apaczka: `https://www.apaczka.pl/sledz-paczke/?numer={trackingNumber}` - Allegro WZA: `https://allegro.pl/przesylka/{trackingNumber}` (generyczny tracking Allegro) - Manual / unknown: return null - Zwracaj null jeśli trackingNumber jest pusty Zbuilduj SCSS: sprawdź jak inne pliki SCSS są buildowane w projekcie (npx sass lub ręczny build). Avoid: nie dodawaj nowych zależności npm/composer php -l src/Modules/Shipments/DeliveryStatus.php Sprawdź że DeliveryStatus::trackingUrl('inpost', 'ABC123') zwraca poprawny URL Sprawdź że SCSS kompiluje się bez błędów AC-3 (częściowo) satisfied: tracking URL builder gotowy Task 2: UI — status dostawy w show.php i prepare.php + boks Płatność i wysyłka resources/views/orders/show.php, resources/views/shipments/prepare.php **show.php — tabela paczek (zakładka Przesyłki):** - Dodaj kolumnę "Status dostawy" po kolumnie "Status" w nagłówku tabeli - Dla każdej paczki wyświetl: ```php $deliveryStatus = $pkg['delivery_status'] ?? 'unknown'; $deliveryRaw = $pkg['delivery_status_raw'] ?? ''; $label = \App\Modules\Shipments\DeliveryStatus::label($deliveryStatus); $description = $deliveryRaw !== '' ? \App\Modules\Shipments\DeliveryStatus::description($pkg['provider'] ?? '', $deliveryRaw) : ''; $title = $deliveryRaw !== '' ? e($deliveryRaw) . ' — ' . e($description) : ''; ``` - Badge: `{$label}` - Kolumna "Nr śledzenia": dodaj link śledzenia obok numeru tracking ```php $trackingUrl = \App\Modules\Shipments\DeliveryStatus::trackingUrl($pkg['provider'] ?? '', $pkg['tracking_number'] ?? ''); ``` Jeśli trackingUrl !== null: `🔗` **show.php — boks "Płatność i wysyłka":** - Po istniejących wierszach (carrier, send_date_max, shipments count) dodaj wiersz "Status dostawy" - Pokaż status najnowszej paczki (ostatnia z $packagesList posortowana by delivery_status_updated_at DESC) - Badge + data ostatniej aktualizacji: `{label} {date}` - Wyświetlaj TYLKO jeśli $packagesList nie jest pusta i najnowszy delivery_status != 'unknown' **prepare.php — sekcja "Wygenerowane przesyłki":** - Dodaj kolumnę "Status dostawy" analogicznie jak w show.php - Badge z tooltip surowego statusu - Link śledzenia obok tracking number Avoid: - NIE dodawaj inline CSS — używaj klas z _shipments.scss - NIE zmieniaj logiki kontrolerów — dane delivery_status są już w $packagesList z bazy - Helper e() do escape HTML Ręczna weryfikacja wizualna (checkpoint) AC-1, AC-2, AC-3, AC-5 satisfied Status dostawy w tabelach paczek (show.php + prepare.php) oraz w boksie Płatność i wysyłka. Kolorowe badge'e, tooltip z surowym statusem, linki śledzenia. 1. Otwórz stronę szczegółów zamówienia które ma przesyłkę 2. Sprawdź zakładkę "Przesyłki" — czy jest kolumna "Status dostawy" z badge 3. Najedź na badge — czy tooltip pokazuje surowy status 4. Sprawdź link 🔗 obok numeru śledzenia — czy otwiera stronę przewoźnika 5. Sprawdź boks "Płatność i wysyłka" — czy jest wiersz "Status dostawy" 6. Otwórz stronę przygotowania przesyłki — czy sekcja istniejących paczek ma kolumnę statusu Type "approved" to continue, or describe issues to fix Task 3: Ustawienie interwału trackingu w cronie resources/views/settings/cron.php, src/Modules/Settings/CronSettingsController.php, src/Modules/Cron/CronRepository.php **CronRepository — nowa metoda:** - `updateScheduleInterval(string $jobType, int $intervalSeconds): void` - UPDATE cron_schedules SET interval_seconds = :interval WHERE job_type = :job_type **CronSettingsController::save() — dodaj obsługę interwału trackingu:** - Odczytaj POST param `tracking_interval_minutes` (int, default 15) - Waliduj: min 5, max 120 - Przelicz na sekundy: $intervalSeconds = $minutes * 60 - Wywołaj: $cronRepository->updateScheduleInterval('shipment_tracking_sync', $intervalSeconds) **cron.php — dodaj sekcję ustawień trackingu:** - Pod istniejącym formularzem "Uruchamianie z poziomu web" dodaj nową sekcję - Nagłówek: "Śledzenie przesyłek" - Input number: `tracking_interval_minutes`, min=5, max=120 - Wartość domyślna: aktualny interval_seconds z cron_schedules / 60 - Label: "Interwał sprawdzania statusu (minuty)" - Opis: "Jak często system automatycznie sprawdza status dostawy przesyłek" - Umieść w tym samym formularzu POST (żeby jedno "Zapisz" zapisywało wszystko) **CronSettingsController::index() — przekaż interwał do widoku:** - Pobierz z $schedulesList rekord job_type='shipment_tracking_sync' - Oblicz: $trackingIntervalMinutes = (int)(interval_seconds / 60) - Przekaż do widoku Avoid: - NIE twórz osobnego formularza — rozszerz istniejący - NIE usuwaj istniejących ustawień crona php -l na zmienionych plikach PHP Sprawdź że zmiana interwału na 10 minut zapisuje interval_seconds=600 w cron_schedules AC-4 satisfied: interwał trackingu konfigurowalny w UI ## DO NOT CHANGE - src/Modules/Shipments/ShipmentProviderInterface.php - src/Modules/Shipments/InpostShipmentService.php - src/Modules/Shipments/ApaczkaShipmentService.php - src/Modules/Shipments/AllegroShipmentService.php - src/Modules/Shipments/ShipmentTrackingInterface.php - src/Modules/Shipments/InpostTrackingService.php (Phase 27) - src/Modules/Shipments/ApaczkaTrackingService.php (Phase 27) - src/Modules/Shipments/AllegroTrackingService.php (Phase 27) - src/Modules/Cron/ShipmentTrackingHandler.php (Phase 27) - src/Modules/Cron/CronHandlerFactory.php (Phase 27) - database/migrations/* (brak nowych migracji w tej fazie) ## SCOPE LIMITS - Tylko UI i ustawienia — bez zmian w logice backendu trackingu - Brak nowych migracji DB - Brak nowych routów API - Brak JavaScript — badge'e i linki to czysty HTML/PHP - Tracking URL budowany statycznie z providera + tracking_number (nie z API) Before declaring plan complete: - [ ] php -l przechodzi na wszystkich zmienionych plikach - [ ] SCSS kompiluje się bez błędów - [ ] Badge'e statusów wyświetlają się poprawnie w show.php - [ ] Badge'e statusów wyświetlają się poprawnie w prepare.php - [ ] Link śledzenia otwiera poprawny URL dla InPost/Apaczka/Allegro - [ ] Boks "Płatność i wysyłka" pokazuje status najnowszej paczki - [ ] Interwał trackingu zapisuje się poprawnie w cron_schedules - [ ] Istniejące ustawienia crona działają bez zmian - [ ] All acceptance criteria met - Wszystkie taski ukończone (+ checkpoint approved) - Badge'e widoczne z poprawnymi kolorami - Linki śledzenia działają dla 3 providerów - Interwał trackingu konfigurowalny 5-120 min - Brak nowych zależności After completion, create `.paul/phases/28-shipment-tracking-ui/28-01-SUMMARY.md`