Final commit.
This commit is contained in:
93
lib/domain/entity/scan_intent.dart
Normal file
93
lib/domain/entity/scan_intent.dart
Normal file
@ -0,0 +1,93 @@
|
||||
/// 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,
|
||||
}
|
||||
Reference in New Issue
Block a user