/// Events für den [`TourBloc`]. /// /// Bewusst minimaler Scope für Phase C+D-2: Lese-Pfad, Reorder, /// Car-Assign. Scan-, Hold-, Cancel-, Complete-, Discount- und /// Notiz-Events kommen in C+D-3 / C+D-4 zurück. sealed class TourEvent { const TourEvent(); } /// Initial-Load der heutigen Tour des angemeldeten Fahrers. /// Account-Filter sitzt im JWT — kein zusätzliches Argument nötig. class LoadTour extends TourEvent { const LoadTour(); } /// Pull-to-refresh / manueller Reload aus der Übersicht. Vorhandener /// `TourLoaded`-State bleibt sichtbar, bis der neue Snapshot da ist; /// `TourLoading` wird nur emittiert, wenn vorher kein State existierte. class RefreshTour extends TourEvent { const RefreshTour(); } /// Schreibt die Sortier-Reihenfolge aller Lieferungen einer Tour an das /// Backend. Der Bloc fordert die UI nicht auf, die vollständige Reihenfolge /// zu kennen — sie wird aus der Liste übergeben. class ReorderDeliveries extends TourEvent { const ReorderDeliveries({required this.orderedDeliveryIds}); final List orderedDeliveryIds; } /// Weist einer Lieferung ein Fahrzeug zu — oder hebt die Zuweisung auf /// (`carId == null`). class AssignCarToDelivery extends TourEvent { const AssignCarToDelivery({required this.deliveryId, required this.carId}); final String deliveryId; final String? carId; } /// Bulk-Variante: weist mehreren Lieferungen in einer atomaren Aktion das /// gleiche Fahrzeug zu. Notwendig, weil flutter_bloc Events standardmäßig /// **concurrent** verarbeitet — N parallel laufende `AssignCarToDelivery`- /// Handler lesen alle den Initial-State und überschreiben sich gegenseitig /// beim `emit`, sodass nur die letzte Zuweisung sichtbar bleibt. Der /// Bulk-Handler verarbeitet die Liste sequenziell und emittiert genau /// einen Zwischen-State am Ende. /// /// Backend-seitig macht der Handler trotzdem N einzelne HTTP-Calls, weil /// der `PATCH /deliveries/{id}/assigned-car`-Endpoint keine Liste kennt. class AssignCarToDeliveries extends TourEvent { const AssignCarToDeliveries({ required this.deliveryIds, required this.carId, }); final List deliveryIds; final String? carId; } /// Scan-Trigger aus der Loading-Phase. Der Bloc inkrementiert lokal /// **optimistisch** die Scan-Quantität, ruft anschließend `POST /scans` /// und rollt im `rejected`-Fall lokal zurück. `duplicate` ist still /// (lokal schon hochgezählt, Server bestätigt nicht erneut). /// /// `actorCarId` ist die UUID des aktuell gewählten Fahrzeugs — das /// Backend nutzt das nur als Audit-Spur; an der Lieferung selbst /// passiert dadurch nichts. class ScanItem extends TourEvent { const ScanItem({ required this.deliveryItemId, required this.actorCarId, this.manual = false, }); final String deliveryItemId; final String actorCarId; /// `true` = manuelle Zeilen-Bestätigung (Fallback ohne Barcode): die /// **gesamte Restmenge** wird auf einmal als geladen verbucht und im /// Backend als `manual` protokolliert. `false` = regulärer Einzel-Scan (+1). final bool manual; } /// Umkehrung eines Scans (z. B. „falsch gescannt"). `reason` ist vom /// Backend für `unscan` erforderlich. class UnscanItem extends TourEvent { const UnscanItem({ required this.deliveryItemId, required this.actorCarId, required this.reason, }); final String deliveryItemId; final String actorCarId; final String reason; } /// Pausiert ein Item (`scan_status=held`). Reversibel über [UnholdItem]. /// `reason` Pflicht. class HoldItem extends TourEvent { const HoldItem({ required this.deliveryItemId, required this.actorCarId, required this.reason, }); final String deliveryItemId; final String actorCarId; final String reason; } /// Setzt ein pausiertes Item zurück auf `in_progress`. Kein Reason /// nötig — der Server löscht beim Unhold den `held_reason`. class UnholdItem extends TourEvent { const UnholdItem({ required this.deliveryItemId, required this.actorCarId, }); final String deliveryItemId; final String actorCarId; } /// Entfernt ein Item aus der Lieferung (`scan_status=removed`). /// `reason` Pflicht. Reversibel über [UnremoveItem] — die Historie /// bleibt im Audit-Log vollständig erhalten. class RemoveItem extends TourEvent { const RemoveItem({ required this.deliveryItemId, required this.actorCarId, required this.reason, this.quantity, this.saveReasonAsNote = false, }); final String deliveryItemId; final String actorCarId; final String reason; /// Mengen-Gutschrift: wie viele Stück gutgeschrieben werden. `null` = /// ganze Restmenge (= klassisches „ganze Zeile entfernen"). final int? quantity; /// Wenn `true`, wird der `reason` nach erfolgreichem Entfernen zusätzlich /// als Lieferungs-Notiz gespeichert. Gesetzt aus dem Gutschrift-Flow /// (Step „Artikel & Gutschriften"); im Beladen-Flow `false`, dort wäre /// eine Notiz pro Abbuchung nur Rauschen. final bool saveReasonAsNote; } /// Stellt ein entferntes Item wieder her — geht nur, wenn der aktuelle /// Status `removed` ist. Kein Reason nötig (Backend-Konvention wie bei /// `unscan` und `unhold`). Audit-Log behält den ursprünglichen /// `remove`-Eintrag und fügt einen neuen `unremove`-Eintrag hinzu. class UnremoveItem extends TourEvent { const UnremoveItem({ required this.deliveryItemId, required this.actorCarId, this.quantity, }); final String deliveryItemId; final String actorCarId; /// Mengen-Gutschrift zurücknehmen: wie viele Stück wiederhergestellt /// werden. `null` = gesamte Gutschrift zurück. final int? quantity; } // ─── Delivery-Lifecycle ─────────────────────────────────────────────── /// Bricht eine Lieferung endgültig ab. `reason` ist Pflicht. class CancelDelivery extends TourEvent { const CancelDelivery({required this.deliveryId, required this.reason}); final String deliveryId; final String reason; } /// Pausiert eine Lieferung. `reason` ist Pflicht. Reversibel über /// [ResumeDelivery]. class HoldDelivery extends TourEvent { const HoldDelivery({required this.deliveryId, required this.reason}); final String deliveryId; final String reason; } /// Setzt eine pausierte Lieferung zurück auf `active`. class ResumeDelivery extends TourEvent { const ResumeDelivery({required this.deliveryId}); final String deliveryId; } /// Schließt eine Lieferung ab: lädt beide Unterschriften hoch, dokumentiert /// die Bestätigungen des Kunden und setzt die Lieferung auf `completed`. class CompleteDelivery extends TourEvent { const CompleteDelivery({ required this.deliveryId, required this.customerSignaturePng, required this.driverSignaturePng, required this.receiptConfirmed, required this.notesAcknowledged, required this.acknowledgedNoteIds, this.paymentMethodId, this.actorCarId, this.paymentCollected = false, }); final String deliveryId; final List customerSignaturePng; final List driverSignaturePng; final bool receiptConfirmed; final bool notesAcknowledged; final List acknowledgedNoteIds; /// Vom Fahrer im Summary gewählte Zahlungsmethode (Override). `null` = /// die am Beleg hinterlegte Methode bleibt. Wird beim Abschluss persistiert. final String? paymentMethodId; final String? actorCarId; /// Fahrer hat das Vor-Ort-Inkasso (Bar/EC) des offenen Betrags bestätigt. /// `false`, wenn kein Inkasso anfiel (offen == 0 oder „Auf Rechnung"). final bool paymentCollected; } /// Legt eine neue (Text- oder Bild-)Notiz an einer Lieferung an. Aktuell /// wird nur der Text-Pfad von der UI getriggert; `imageAttachment` ist als /// Storage-Key (z. B. Pre-Signed-URL-Key) gedacht und wartet auf die /// zukünftige Foto-Upload-Phase. /// Setzt/ändert die Betrags-Gutschrift einer Lieferung (Geld-Nachlass). class SetDeliveryCredit extends TourEvent { const SetDeliveryCredit({ required this.deliveryId, required this.amountCents, required this.reason, required this.actorCarId, }); final String deliveryId; final int amountCents; final String reason; final String actorCarId; } /// Entfernt die Betrags-Gutschrift einer Lieferung. class RemoveDeliveryCredit extends TourEvent { const RemoveDeliveryCredit({ required this.deliveryId, required this.actorCarId, }); final String deliveryId; final String actorCarId; } /// Setzt/ändert den Wert eines Service für eine Lieferung (Checkbox/Zahl). class SetDeliveryServiceValue extends TourEvent { const SetDeliveryServiceValue({ required this.deliveryId, required this.serviceId, required this.actorCarId, this.boolValue, this.numericValue, }); final String deliveryId; final String serviceId; final String actorCarId; final bool? boolValue; final int? numericValue; } /// Entfernt den Service-Wert einer Lieferung (Service „nicht gesetzt"). class RemoveDeliveryServiceValue extends TourEvent { const RemoveDeliveryServiceValue({ required this.deliveryId, required this.serviceId, }); final String deliveryId; final String serviceId; } class AddDeliveryNote extends TourEvent { const AddDeliveryNote({ required this.deliveryId, this.text, this.imageAttachment, this.creditDeliveryItemId, }); final String deliveryId; final String? text; final String? imageAttachment; /// Optionaler Gutschrift-Bezug (DeliveryItem-Id). Gesetzt, wenn die Notiz /// einen Gutschrift-Grund dokumentiert — ermöglicht das Löschen beim /// Unremove. final String? creditDeliveryItemId; } /// Ändert Text/Bild einer bestehenden Notiz. class UpdateDeliveryNote extends TourEvent { const UpdateDeliveryNote({ required this.deliveryId, required this.noteId, this.text, this.imageAttachment, }); final String deliveryId; final String noteId; final String? text; final String? imageAttachment; } /// Löscht eine Notiz. class DeleteDeliveryNote extends TourEvent { const DeleteDeliveryNote({required this.deliveryId, required this.noteId}); final String deliveryId; final String noteId; } /// Lädt ein Bild als Notiz hoch (geht über DOCUframe). class UploadDeliveryNoteImage extends TourEvent { const UploadDeliveryNoteImage({ required this.deliveryId, required this.filename, required this.mime, required this.bytes, }); final String deliveryId; final String filename; final String mime; final List bytes; }