94 lines
3.3 KiB
Dart
94 lines
3.3 KiB
Dart
/// Vom Treiber ausgelöstes Scan-Ereignis, bevor es serverseitig
|
|
/// angewendet wurde.
|
|
///
|
|
/// `clientScanId` ist ein vom Client generierter UUID-Schlüssel und dient
|
|
/// als **Idempotenz-Anker**: der Server speichert ihn beim ersten Apply
|
|
/// und antwortet auf jeden weiteren Request mit derselben Id mit
|
|
/// `duplicate` statt einer zweiten Anwendung. So bleibt Network-Retry
|
|
/// (z. B. nach Verbindungsabbruch beim ersten POST) bedeutungslos.
|
|
///
|
|
/// `clientScannedAt` ist die Wall-Clock-Zeit am Gerät zum Zeitpunkt des
|
|
/// Scans — der Server nutzt das nur als Audit-Spur, sortiert aber selbst
|
|
/// nach Server-Empfangszeit, sodass eine schiefe Uhr am Phone die
|
|
/// Reihenfolge nicht durcheinanderbringt.
|
|
class ScanIntent {
|
|
const ScanIntent({
|
|
required this.clientScanId,
|
|
required this.clientScannedAt,
|
|
required this.deliveryItemId,
|
|
required this.action,
|
|
this.actorCarId,
|
|
this.reason,
|
|
this.quantity,
|
|
this.manual = false,
|
|
});
|
|
|
|
final String clientScanId;
|
|
final DateTime clientScannedAt;
|
|
final String deliveryItemId;
|
|
final ScanAction action;
|
|
|
|
/// `true`, wenn der Fahrer die Position manuell als geladen bestätigt hat
|
|
/// (Fallback ohne Barcode). Reine Audit-Information; Default `false`.
|
|
final bool manual;
|
|
|
|
/// Menge für `remove` / `unremove` (Mengen-Gutschrift): wie viele Stück
|
|
/// der Belegzeile gutgeschrieben bzw. wiederhergestellt werden. `null` =
|
|
/// ganze Restmenge. Bei `scan`/`unscan`/`hold`/`unhold` ignoriert.
|
|
final int? quantity;
|
|
|
|
/// Fahrzeug, mit dem gescannt wurde — Audit-Spur. Optional, aber die
|
|
/// App schickt ihn in der Loading-Phase immer mit, weil das Auto zu
|
|
/// dem Zeitpunkt definitiv gewählt ist.
|
|
final String? actorCarId;
|
|
|
|
/// Klartext-Begründung. Bei `unscan` / `hold` / `remove` vom Backend
|
|
/// erwartet, bei `scan` / `unhold` ignoriert.
|
|
final String? reason;
|
|
}
|
|
|
|
/// Auswirkung eines Scan-Ereignisses auf die Pipeline eines Items.
|
|
/// Spiegel des Backend-Enums `AuditAction`.
|
|
///
|
|
/// `unremove` ist die Umkehrung von `remove`: setzt ein `Removed`-Item
|
|
/// zurück auf `InProgress` (oder `Done`, falls die Soll-Menge schon
|
|
/// erreicht war). Der ursprüngliche `remove`-Audit-Eintrag bleibt
|
|
/// erhalten — `unremove` erzeugt einen eigenen Eintrag, sodass die
|
|
/// Historie der Korrektur vollständig nachvollziehbar bleibt.
|
|
enum ScanAction { scan, unscan, hold, unhold, remove, unremove }
|
|
|
|
/// Ergebnis eines Apply-Versuchs vom Server.
|
|
class ScanOutcome {
|
|
const ScanOutcome({
|
|
required this.clientScanId,
|
|
required this.status,
|
|
this.deliveryItemId,
|
|
this.reason,
|
|
});
|
|
|
|
final String clientScanId;
|
|
final ScanOutcomeStatus status;
|
|
|
|
/// Bei `applied` und `duplicate` immer gesetzt, bei `rejected` häufig
|
|
/// `null` (z. B. wenn die Id beim Server gar nicht ankam).
|
|
final String? deliveryItemId;
|
|
|
|
/// Bei `rejected` die Server-Begründung — Standard-Text in der UI.
|
|
final String? reason;
|
|
}
|
|
|
|
enum ScanOutcomeStatus {
|
|
/// Server hat den Scan angewendet — `scannedQuantity` ist hochgezählt
|
|
/// oder Status hat sich geändert.
|
|
applied,
|
|
|
|
/// Server hat denselben `clientScanId` schon einmal verarbeitet —
|
|
/// kein Effekt, aber auch kein Fehler.
|
|
duplicate,
|
|
|
|
/// Server hat den Scan abgelehnt (z. B. Item gehört zu fremder
|
|
/// Lieferung, Soll-Menge schon voll, Item ist auf `removed`). UI muss
|
|
/// optimistische Mutation zurückrollen.
|
|
rejected,
|
|
}
|