--- phase: 87-shipment-delete plan: 01 type: execute wave: 1 depends_on: [] files_modified: - src/Modules/Shipments/ShipmentPackageRepository.php - src/Modules/Shipments/ShipmentController.php - routes/web.php - resources/views/orders/show.php autonomous: true delegation: off --- ## Goal Dodanie możliwości usuwania przesyłek (shipment_packages) z zakładki Przesyłki w szczegółach zamówienia, z pytaniem potwierdzającym przed usunięciem. ## Purpose Użytkownik potrzebuje możliwości usunięcia błędnie utworzonej lub niepotrzebnej przesyłki bez konieczności ingerencji w bazę danych. ## Output - Przycisk "Usuń" przy każdej przesyłce w tabeli na /orders/{id}#shipments - Potwierdzenie przez OrderProAlerts.confirm przed wysłaniem żądania - Endpoint POST /orders/{id}/shipment/{packageId}/delete z walidacją CSRF - Usunięcie rekordu z shipment_packages + pliku etykiety (jeśli istnieje) - Wpis w activity log zamówienia ## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md ## Source Files @src/Modules/Shipments/ShipmentPackageRepository.php @src/Modules/Shipments/ShipmentController.php @routes/web.php @resources/views/orders/show.php No specialized flows required. ## AC-1: Przycisk usuwania widoczny przy przesyłce ```gherkin Given zamówienie ma co najmniej jedną przesyłkę w shipment_packages When użytkownik otwiera szczegóły zamówienia i zakładkę Przesyłki Then przy każdej przesyłce w tabeli "Wygenerowane przesylki" widoczny jest przycisk "Usuń" ``` ## AC-2: Potwierdzenie przed usunięciem ```gherkin Given użytkownik widzi przycisk "Usuń" przy przesyłce When kliknie przycisk "Usuń" Then wyświetla się okno potwierdzenia OrderProAlerts.confirm z pytaniem "Czy na pewno chcesz usunąć tę przesyłkę?" And przesyłka NIE jest usuwana dopóki użytkownik nie potwierdzi ``` ## AC-3: Usunięcie przesyłki po potwierdzeniu ```gherkin Given użytkownik potwierdził usunięcie przesyłki When żądanie POST trafia do /orders/{id}/shipment/{packageId}/delete Then rekord shipment_packages jest usuwany z bazy danych And plik etykiety (label_path) jest usuwany z dysku (jeśli istnieje) And w activity log zamówienia pojawia się wpis "shipment_deleted" And użytkownik jest przekierowany z powrotem na /orders/{id} z komunikatem sukcesu ``` Task 1: Backend — repository delete + controller endpoint + route src/Modules/Shipments/ShipmentPackageRepository.php, src/Modules/Shipments/ShipmentController.php, routes/web.php 1. ShipmentPackageRepository — dodaj metodę `delete(int $id): void`: - DELETE FROM shipment_packages WHERE id = :id - Prepared statement, spójne z resztą repo 2. ShipmentController — dodaj metodę `delete(Request $request): Response`: - Pobierz orderId i packageId z requestu - Waliduj CSRF token (wzorzec z metody create) - Pobierz pakiet przez packageRepository->findById - Sprawdź czy pakiet istnieje i należy do tego zamówienia (order_id match) - Jeśli label_path istnieje na dysku — usuń plik (unlink) - Wywołaj packageRepository->delete($packageId) - Zapisz activity log: ordersRepository->recordActivity($orderId, 'shipment_deleted', opis z tracking_number/provider/id, null, 'user', $actorName) - Flash::set('order.success', 'Przesylka zostala usunieta.') - Redirect do /orders/{orderId} 3. routes/web.php — dodaj route tuż po linii z /shipment/manual: - $router->post('/orders/{id}/shipment/{packageId}/delete', [$shipmentController, 'delete'], [$authMiddleware]); Grep for 'delete' in ShipmentController.php and ShipmentPackageRepository.php; check route in web.php AC-3 satisfied: przesyłka usuwana z DB, etykieta z dysku, activity log zapisany, redirect z flash message Task 2: Frontend — przycisk Usuń z potwierdzeniem w widoku zamówienia resources/views/orders/show.php W tabeli "Wygenerowane przesylki" (sekcja packagesList), dodaj kolumnę "Akcje" w thead. W tbody, w nowej kolumnie dla każdej przesyłki dodaj formularz POST: - action="/orders/{orderId}/shipment/{packageId}/delete" - hidden _token (CSRF) - przycisk "Usuń" klasy btn btn--sm btn--danger - Na submit formularza: event.preventDefault(), wywołaj window.OrderProAlerts.confirm z pytaniem "Czy na pewno chcesz usunąć tę przesyłkę?" i w onConfirm: form.submit() Skrypt JS inline (lub w bloku script na dole) obsługujący confirm: - Delegacja na .btn-delete-package click - preventDefault, pobranie closest form - OrderProAlerts.confirm({title: 'Usuwanie przesyłki', message: 'Czy na pewno chcesz usunąć tę przesyłkę?', onConfirm: () => form.submit()}) Otworzyć /orders/{id} z przesyłkami — widoczny przycisk Usuń, kliknięcie pokazuje confirm dialog AC-1 i AC-2 satisfied: przycisk widoczny, potwierdzenie wymagane przed usunięciem ## DO NOT CHANGE - shipment_packages table schema (no migrations) - Logika tworzenia przesyłek (create, createManual) - Sekcja "Wysylki z Allegro" (to dane zewnętrzne, nie lokalne pakiety) - Automation triggers (nie emituj eventu przy usuwaniu) ## SCOPE LIMITS - Usuwanie dotyczy tylko rekordów z tabeli shipment_packages (lokalne przesyłki) - Nie usuwamy przesyłek z API przewoźnika (tylko lokalny rekord) - Brak soft-delete — twarde usunięcie z bazy Before declaring plan complete: - [ ] Metoda delete() w ShipmentPackageRepository działa (prepared statement) - [ ] Endpoint POST /orders/{id}/shipment/{packageId}/delete zwraca redirect - [ ] CSRF walidacja działa (bez tokena = błąd) - [ ] Plik etykiety usuwany z dysku gdy istnieje - [ ] Activity log zapisany po usunięciu - [ ] Przycisk "Usuń" widoczny w tabeli przesyłek - [ ] OrderProAlerts.confirm wyświetla się przed usunięciem - [ ] Wszystkie acceptance criteria spełnione - Wszystkie zadania ukończone - Wszystkie weryfikacje przeszły - Brak błędów PHP/JS - Przesyłka usuwana po potwierdzeniu, z cleanup etykiety i wpisem w logu After completion, create `.paul/phases/87-shipment-delete/87-01-SUMMARY.md`