107 lines
3.6 KiB
Dart
107 lines
3.6 KiB
Dart
import 'scan_progress.dart';
|
||
|
||
/// Eine Belegzeile innerhalb einer Lieferung.
|
||
///
|
||
/// Verweist über `articleId` auf den Artikel-Stamm (lookup via
|
||
/// `TourDetails.articleById`) und über `warehouseId` auf das Lager. Die
|
||
/// Soll-/Ist-Quantitäten leben hier: `requiredQuantity` ist statisch (ERP),
|
||
/// `scanProgress.scannedQuantity` wandert mit jedem Scan nach oben.
|
||
///
|
||
/// `komponentenArtikelNr` markiert Stücklisten-Komponenten. Im neuen
|
||
/// Backend gibt es **keine** Parent-/Child-Hierarchie mehr — jedes Item ist
|
||
/// gleichrangig; das Feld dient nur noch der Anzeige ("Teil von X") und
|
||
/// hat keinerlei Scan-Semantik.
|
||
class DeliveryItem {
|
||
const DeliveryItem({
|
||
required this.id,
|
||
required this.deliveryId,
|
||
required this.articleId,
|
||
required this.warehouseId,
|
||
required this.belegzeilenNr,
|
||
required this.requiredQuantity,
|
||
required this.scanProgress,
|
||
this.unitPrice = 0,
|
||
this.komponentenArtikelNr,
|
||
this.parentArtikelNr,
|
||
});
|
||
|
||
final String id;
|
||
final String deliveryId;
|
||
final String articleId;
|
||
final String warehouseId;
|
||
|
||
/// ERP-Belegzeilen-Nummer. Bestimmt die Reihenfolge der Items in der
|
||
/// Detail-Ansicht (aufsteigend).
|
||
final int belegzeilenNr;
|
||
final int requiredQuantity;
|
||
final ScanProgress scanProgress;
|
||
|
||
/// Stückpreis (brutto, EUR) aus dem ERP-Sync.
|
||
final double unitPrice;
|
||
|
||
final String? komponentenArtikelNr;
|
||
|
||
/// Artikelnummer des Oberartikels, zu dem diese Komponente gehört (aus dem
|
||
/// Sync). `null` bei Oberartikeln/regulären Zeilen. Die Liste rückt
|
||
/// Komponenten unter ihrem Oberartikel ein.
|
||
final String? parentArtikelNr;
|
||
|
||
/// `true`, wenn dieses Item eine Stücklisten-Komponente ist (gehört unter
|
||
/// einen Oberartikel).
|
||
bool get isComponent => parentArtikelNr != null;
|
||
|
||
// ─── Abgeleitete Sicht-Eigenschaften ──────────────────────────────────
|
||
|
||
/// Tatsächlich auszuliefernde Menge = Soll − Gutschrift. Nie negativ.
|
||
int get deliveredQuantity {
|
||
final d = requiredQuantity - scanProgress.creditedQuantity;
|
||
return d < 0 ? 0 : d;
|
||
}
|
||
|
||
/// Wert der ausgelieferten Menge dieser Position (brutto, EUR).
|
||
double get lineTotal => unitPrice * deliveredQuantity;
|
||
|
||
/// Vollständig gescannt (Status `done` oder Ist ≥ Soll).
|
||
bool get isDone =>
|
||
scanProgress.status == ScanStatus.done ||
|
||
scanProgress.scannedQuantity >= requiredQuantity;
|
||
|
||
/// Aktuell pausiert.
|
||
bool get isHeld => scanProgress.status == ScanStatus.held;
|
||
|
||
/// Nach dem Laden wieder entfernt.
|
||
bool get isRemoved => scanProgress.status == ScanStatus.removed;
|
||
|
||
/// Noch offene Restmenge (für Loading-UI). Nicht negativ.
|
||
int get remainingQuantity {
|
||
final remaining = requiredQuantity - scanProgress.scannedQuantity;
|
||
return remaining < 0 ? 0 : remaining;
|
||
}
|
||
|
||
DeliveryItem copyWith({
|
||
String? id,
|
||
String? deliveryId,
|
||
String? articleId,
|
||
String? warehouseId,
|
||
int? belegzeilenNr,
|
||
int? requiredQuantity,
|
||
ScanProgress? scanProgress,
|
||
double? unitPrice,
|
||
String? komponentenArtikelNr,
|
||
String? parentArtikelNr,
|
||
}) {
|
||
return DeliveryItem(
|
||
id: id ?? this.id,
|
||
deliveryId: deliveryId ?? this.deliveryId,
|
||
articleId: articleId ?? this.articleId,
|
||
warehouseId: warehouseId ?? this.warehouseId,
|
||
belegzeilenNr: belegzeilenNr ?? this.belegzeilenNr,
|
||
requiredQuantity: requiredQuantity ?? this.requiredQuantity,
|
||
scanProgress: scanProgress ?? this.scanProgress,
|
||
unitPrice: unitPrice ?? this.unitPrice,
|
||
komponentenArtikelNr: komponentenArtikelNr ?? this.komponentenArtikelNr,
|
||
parentArtikelNr: parentArtikelNr ?? this.parentArtikelNr,
|
||
);
|
||
}
|
||
}
|