342 lines
10 KiB
Dart
342 lines
10 KiB
Dart
/// 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<String> 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<String> 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<int> customerSignaturePng;
|
|
final List<int> driverSignaturePng;
|
|
final bool receiptConfirmed;
|
|
final bool notesAcknowledged;
|
|
final List<String> 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<int> bytes;
|
|
}
|