--- phase: 19-ui-integration plan: 01 type: execute wave: 1 depends_on: ["18-01"] files_modified: - resources/views/shipments/prepare.php - resources/views/orders/index.php - src/Modules/Printing/PrintApiController.php - src/Modules/Printing/PrintJobRepository.php - resources/views/settings/printing.php - routes/web.php - resources/scss/_printing.scss autonomous: false --- ## Goal Dodać przycisk "Drukuj" w widoku przesyłki (prepare.php) oraz zbiorczą akcję "Drukuj etykiety" z listy zamówień — obie wywołujące POST /api/print/jobs. Dodać podgląd kolejki wydruku w ustawieniach drukowania ze statusami zleceń. ## Purpose Użytkownik może jednym kliknięciem wysłać etykietę do zdalnej drukarki (Windows Client z fazy 20) bez ręcznego pobierania i drukowania. Zbiorcze drukowanie oszczędza czas przy wielu zamówieniach. ## Output - Przycisk "Drukuj" obok "Pobierz" w prepare.php z AJAX feedback - Zbiorcza akcja "Drukuj etykiety" na liście zamówień (zaznaczone checkboxy) - Sekcja "Kolejka wydruku" w ustawieniach drukowania z historią zleceń ## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md ## Prior Work @.paul/phases/18-print-queue-backend/18-01-SUMMARY.md - Phase 18 created: PrintApiController (createJob, listPending, downloadLabel, markComplete) - API key auth middleware for Windows client - print_jobs table (order_id, package_id, label_path, status, created_by) - createJob() expects package_id, validates label exists ## Source Files @resources/views/shipments/prepare.php — "Pobierz" button at line ~109 @resources/views/orders/index.php — lista zamówień z checkboxami @src/Modules/Printing/PrintApiController.php — existing REST endpoints @src/Modules/Printing/PrintJobRepository.php — DB operations @resources/views/settings/printing.php — API key management @routes/web.php — route registration ## Required Skills (from SPECIAL-FLOWS.md) | Skill | Priority | When to Invoke | Loaded? | |-------|----------|----------------|---------| | sonar-scanner | required | Po APPLY, przed UNIFY | ○ | ## Skill Invocation Checklist - [ ] sonar-scanner loaded (run before UNIFY) ## AC-1: Przycisk "Drukuj" w widoku przesyłki ```gherkin Given przesyłka ma wygenerowaną etykietę (label_path istnieje) When użytkownik klika "Drukuj" obok przycisku "Pobierz" Then AJAX POST /api/print/jobs z package_id And przycisk zmienia się na "Wysłano ✓" z krótkim feedbackiem And w razie błędu wyświetla OrderProAlerts.alert z komunikatem ``` ## AC-2: Zbiorcze drukowanie z listy zamówień ```gherkin Given użytkownik zaznaczył ≥1 zamówienie z etykietą na liście zamówień When klika akcję "Drukuj etykiety" (bulk action) Then dla każdego zaznaczonego zamówienia tworzony jest print job And wyświetla podsumowanie: "Wysłano N zleceń do drukarki" And zamówienia bez etykiety są pomijane z informacją ``` ## AC-3: Kolejka wydruku w ustawieniach ```gherkin Given użytkownik otwiera Ustawienia > Drukowanie When strona się ładuje Then widzi sekcję "Kolejka wydruku" pod sekcją "Klucze API" And lista pokazuje ostatnie zlecenia: data, zamówienie, status (pending/completed/failed) And może filtrować po statusie ``` ## AC-4: Endpoint bulk create ```gherkin Given request POST /api/print/jobs/bulk z tablicą package_ids When co najmniej 1 package_id ma etykietę Then tworzy print jobs dla wszystkich valid packages And zwraca JSON z listą created + skipped ``` Task 1: Przycisk "Drukuj" w prepare.php + bulk endpoint resources/views/shipments/prepare.php, src/Modules/Printing/PrintApiController.php, src/Modules/Printing/PrintJobRepository.php, routes/web.php 1. W prepare.php obok przycisku "Pobierz" (form POST label) dodaj przycisk "Drukuj": - Button z klasą `btn btn-sm btn-outline-primary btn-print-label` - data-package-id="{$pkg['id']}" data-order-id="{$orderId}" - Ikona drukarki (fa-print lub SVG) - Widoczny tylko gdy $pkgLabelPath istnieje (ten sam warunek co "Pobierz") 2. JavaScript AJAX handler na dole prepare.php (lub w osobnym module): - Click `.btn-print-label` → POST /api/print/jobs z {package_id, _token} - Success → zmień tekst na "Wysłano ✓", disable button na 3s - Error → OrderProAlerts.alert('Błąd: ' + response.error) - Duplikat (job already pending) → OrderProAlerts.alert('Zlecenie już w kolejce') 3. W PrintApiController dodaj metodę bulkCreateJobs(): - Przyjmuje JSON {package_ids: [1,2,3], _token} - Waliduje CSRF - Dla każdego package_id: sprawdź label_path, utwórz job lub skip - Zwraca {created: [{id, package_id}], skipped: [{package_id, reason}]} 4. W PrintJobRepository dodaj findPendingByPackageId(int $packageId): - Sprawdza czy istnieje pending job dla danego package - Używane do ochrony przed duplikatami 5. W routes/web.php dodaj: - POST /api/print/jobs/bulk → PrintApiController::bulkCreateJobs (session auth) Avoid: Nie zmieniaj istniejących endpointów API key auth (GET /api/print/jobs/pending itd.) Avoid: Nie dodawaj natywnych alert() — używaj OrderProAlerts - Przycisk "Drukuj" widoczny obok "Pobierz" w prepare.php - AJAX POST tworzy rekord w print_jobs - Bulk endpoint zwraca poprawny JSON - Duplikat nie tworzy drugiego pending job AC-1 satisfied (przycisk + AJAX), AC-4 satisfied (bulk endpoint) Task 2: Zbiorcze drukowanie z listy zamówień + kolejka w ustawieniach resources/views/orders/index.php, resources/views/settings/printing.php, src/Modules/Settings/PrintSettingsController.php, src/Modules/Printing/PrintJobRepository.php, routes/web.php, resources/scss/_printing.scss 1. W orders/index.php dodaj bulk action "Drukuj etykiety": - Dodaj opcję w dropdown/select akcji zbiorczych (wzoruj się na istniejących bulk actions) - JavaScript: zbierz package_ids z zaznaczonych zamówień - POST /api/print/jobs/bulk z zebraną tablicą - Pokaż wynik: "Wysłano {N} zleceń. Pominięto {M} (brak etykiety)." - Użyj OrderProAlerts.alert() dla wyniku 2. W PrintJobRepository dodaj getRecentJobs(int $limit = 50, ?string $statusFilter = null): - SELECT z JOIN na orders (numer zamówienia) i shipment_packages (tracking) - Sortowanie: created_at DESC - Opcjonalny filtr statusu 3. W PrintSettingsController dodaj metodę index() rozszerzoną o dane kolejki: - Pobierz listę ostatnich print jobs (getRecentJobs) - Przekaż do widoku 4. W settings/printing.php pod sekcją "Klucze API" dodaj sekcję "Kolejka wydruku": - Tabela: Data | Zamówienie | Tracking | Status | Akcje - Status badges: pending (żółty), completed (zielony), failed (czerwony) - Filtr statusu (select/buttons nad tabelą) - Paginacja jeśli >20 rekordów (lub scroll) - Przycisk "Ponów" przy failed jobs (POST /api/print/jobs z tym samym package_id) 5. Dodaj _printing.scss z stylami: - .print-status-badge (pending/completed/failed kolory) - .print-queue-table (kompaktowy layout) - Zaimportuj w głównym pliku SCSS Avoid: Nie modyfikuj sekcji API keys w printing.php — dodaj nową sekcję pod spodem Avoid: Nie dodawaj osobnej strony — kolejka jest częścią ustawień drukowania - Bulk action widoczna na liście zamówień - Zaznaczenie + klik → zlecenia w print_jobs - Kolejka wydruku widoczna w ustawieniach - Filtrowanie po statusie działa - Style badge'ów poprawne AC-2 satisfied (bulk z listy), AC-3 satisfied (kolejka w ustawieniach) Przycisk "Drukuj" w widoku przesyłki, zbiorcze drukowanie z listy zamówień, kolejka wydruku w ustawieniach drukowania. 1. Otwórz zamówienie z wygenerowaną etykietą → widok przesyłki 2. Sprawdź: obok "Pobierz" jest przycisk "Drukuj" 3. Kliknij "Drukuj" → powinno pojawić się "Wysłano ✓" 4. Kliknij ponownie → powinien pojawić się alert "Zlecenie już w kolejce" 5. Wróć do listy zamówień → zaznacz kilka z etykietami 6. Wybierz akcję "Drukuj etykiety" → podsumowanie ile wysłano/pominięto 7. Otwórz Ustawienia > Drukowanie → sprawdź sekcję "Kolejka wydruku" 8. Sprawdź: widać zlecenia z kroków 3 i 6 ze statusem "pending" 9. Sprawdź filtrowanie po statusie Type "approved" to continue, or describe issues to fix ## DO NOT CHANGE - database/migrations/* (schemat z fazy 18 jest stabilny) - src/Modules/Printing/ApiKeyMiddleware.php (auth middleware gotowe) - Endpointy API key auth (GET /api/print/jobs/pending, download, complete) — te są dla Windows Client ## SCOPE LIMITS - Nie buduj Windows Client (to faza 20) - Nie dodawaj WebSocket/polling do auto-odświeżania statusów — wystarczy ręczne odświeżenie - Nie zmieniaj flow pobierania etykiet ("Pobierz" pozostaje bez zmian) - Nie dodawaj nowych tabel DB — używaj istniejącej print_jobs Before declaring plan complete: - [ ] Przycisk "Drukuj" widoczny w prepare.php obok "Pobierz" - [ ] AJAX feedback działa (success + error + duplikat) - [ ] Bulk endpoint /api/print/jobs/bulk tworzy zlecenia - [ ] Bulk action w index.php działa z checkboxami - [ ] Kolejka wydruku widoczna w ustawieniach drukowania - [ ] Filtrowanie statusu w kolejce - [ ] Style SCSS skompilowane (brak inline CSS) - [ ] Brak natywnych alert()/confirm() — tylko OrderProAlerts - [ ] Wszystkie acceptance criteria spełnione - Wszystkie 4 AC spełnione - Brak regresji w istniejącym flow pobierania etykiet - Kod zgodny z konwencjami projektu (camelCase, Medoo, XSS escape) - Brak nowych issues SonarQube na zmienionych plikach After completion, create `.paul/phases/19-ui-integration/19-01-SUMMARY.md`