Final commit.
This commit is contained in:
152
lib/domain/entity/delivery.dart
Normal file
152
lib/domain/entity/delivery.dart
Normal file
@ -0,0 +1,152 @@
|
||||
import 'address.dart';
|
||||
import 'delivery_item.dart';
|
||||
|
||||
/// Lebenszyklus einer Lieferung.
|
||||
///
|
||||
/// - `active`: Standard nach Anlage; Fahrer kann scannen/ausliefern.
|
||||
/// - `held`: Pausiert (Kunde nicht da, Termin verschoben) — kein Bearbeitungsfortschritt.
|
||||
/// - `canceled`: Abgebrochen — wird nicht mehr ausgeliefert.
|
||||
/// - `completed`: Abgeschlossen — Signatur und Notizen sind hinterlegt.
|
||||
enum DeliveryState { active, held, canceled, completed }
|
||||
|
||||
/// Eine einzelne Auslieferung an einen Kunden innerhalb einer Tour.
|
||||
///
|
||||
/// Anders als im alten Modell trägt `Delivery` hier ausschließlich
|
||||
/// Logistik-Daten — keine Preise, keine Rabatte, keine Zahlungsoptionen.
|
||||
/// Diese ERP-Themen sind in Phase C+D-2 absichtlich nicht migriert und
|
||||
/// hängen hinter `FeatureFlags`.
|
||||
class Delivery {
|
||||
const Delivery({
|
||||
required this.id,
|
||||
required this.tourId,
|
||||
required this.customerId,
|
||||
required this.contactPersonIds,
|
||||
required this.deliveryAddressSnapshot,
|
||||
required this.erpBelegartId,
|
||||
required this.erpBelegnummer,
|
||||
required this.state,
|
||||
required this.sortOrder,
|
||||
required this.items,
|
||||
required this.prepaidAmount,
|
||||
required this.paymentMethodId,
|
||||
this.assignedCarId,
|
||||
this.desiredTime,
|
||||
this.specialAgreements,
|
||||
this.stateReason,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String tourId;
|
||||
final String customerId;
|
||||
|
||||
/// 0..n Kontakte am Kunden, die für diese Lieferung relevant sind.
|
||||
/// Lookup über `TourDetails.contactById`.
|
||||
final List<String> contactPersonIds;
|
||||
|
||||
/// Eingefrorene Lieferadresse zum Zeitpunkt der Belegerzeugung — bleibt
|
||||
/// stabil, auch wenn die Stammadresse am Kunden später geändert wird.
|
||||
final Address deliveryAddressSnapshot;
|
||||
|
||||
/// ERP-Belegart (Lieferschein, Rechnung, …) und -Nummer. Für die App nur
|
||||
/// informativ; in Notizen/Reklamationen ist die Belegnummer der vom
|
||||
/// Kunden verständliche Bezugspunkt.
|
||||
final int erpBelegartId;
|
||||
final String erpBelegnummer;
|
||||
|
||||
final DeliveryState state;
|
||||
|
||||
/// Optionaler Klartext, warum `state` auf `held`/`canceled` steht. Vom
|
||||
/// Backend nicht-leer erzwungen, sobald ein Reason-pflichtiger Zustand
|
||||
/// gesetzt wird.
|
||||
final String? stateReason;
|
||||
|
||||
/// Sortier-Reihenfolge innerhalb der Tour, gesetzt durch
|
||||
/// `PUT /tours/{id}/delivery-order`. Niedriger = früher.
|
||||
final int sortOrder;
|
||||
|
||||
/// UUID des Fahrzeugs, dem diese Lieferung beim Laden zugewiesen wurde.
|
||||
/// `null` = noch nicht zugewiesen.
|
||||
final String? assignedCarId;
|
||||
|
||||
/// Bei Bestellung schon bezahlter Betrag in EUR. `0.0` wenn der Kunde
|
||||
/// alles bei Lieferung zahlt. Wird vom ERP-Sync gesetzt.
|
||||
final double prepaidAmount;
|
||||
|
||||
/// FK auf eine `PaymentMethod` (UUID). Auflösung zu Display-Name und
|
||||
/// Aktiv-Status geht über die Stammdaten-Liste, die die App separat
|
||||
/// lädt — nicht hier embeddet, damit das Tour-Aggregat klein bleibt.
|
||||
final String paymentMethodId;
|
||||
|
||||
final String? desiredTime;
|
||||
final String? specialAgreements;
|
||||
|
||||
final List<DeliveryItem> items;
|
||||
|
||||
// ─── Abgeleitete Sicht-Eigenschaften ──────────────────────────────────
|
||||
|
||||
/// Nur Items, die der Treiber tatsächlich scannen muss. Nicht-scanbare
|
||||
/// Artikel (Dienstleistungen, Versand) sowie bereits entfernte Items
|
||||
/// werden nicht mitgezählt.
|
||||
Iterable<DeliveryItem> scannableItems(
|
||||
bool Function(String articleId) isScannable,
|
||||
) sync* {
|
||||
for (final item in items) {
|
||||
if (item.isRemoved) continue;
|
||||
if (!isScannable(item.articleId)) continue;
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
|
||||
/// `true`, sobald *alle* scanbaren Items dieser Lieferung als `done`
|
||||
/// markiert sind. Wird in der Loading-Übersicht angezeigt und
|
||||
/// kontrolliert in der Detail-Phase den Übergang zur Signatur.
|
||||
bool allScannableItemsDone(bool Function(String articleId) isScannable) {
|
||||
final scannables = scannableItems(isScannable).toList();
|
||||
if (scannables.isEmpty) return false;
|
||||
return scannables.every((item) => item.isDone);
|
||||
}
|
||||
|
||||
Delivery copyWith({
|
||||
String? id,
|
||||
String? tourId,
|
||||
String? customerId,
|
||||
List<String>? contactPersonIds,
|
||||
Address? deliveryAddressSnapshot,
|
||||
int? erpBelegartId,
|
||||
String? erpBelegnummer,
|
||||
DeliveryState? state,
|
||||
String? stateReason,
|
||||
int? sortOrder,
|
||||
String? assignedCarId,
|
||||
Object? desiredTime = _sentinel,
|
||||
Object? specialAgreements = _sentinel,
|
||||
List<DeliveryItem>? items,
|
||||
double? prepaidAmount,
|
||||
String? paymentMethodId,
|
||||
}) {
|
||||
return Delivery(
|
||||
id: id ?? this.id,
|
||||
tourId: tourId ?? this.tourId,
|
||||
customerId: customerId ?? this.customerId,
|
||||
contactPersonIds: contactPersonIds ?? this.contactPersonIds,
|
||||
deliveryAddressSnapshot: deliveryAddressSnapshot ?? this.deliveryAddressSnapshot,
|
||||
erpBelegartId: erpBelegartId ?? this.erpBelegartId,
|
||||
erpBelegnummer: erpBelegnummer ?? this.erpBelegnummer,
|
||||
state: state ?? this.state,
|
||||
stateReason: stateReason ?? this.stateReason,
|
||||
sortOrder: sortOrder ?? this.sortOrder,
|
||||
assignedCarId: assignedCarId ?? this.assignedCarId,
|
||||
desiredTime: identical(desiredTime, _sentinel)
|
||||
? this.desiredTime
|
||||
: desiredTime as String?,
|
||||
specialAgreements: identical(specialAgreements, _sentinel)
|
||||
? this.specialAgreements
|
||||
: specialAgreements as String?,
|
||||
items: items ?? this.items,
|
||||
prepaidAmount: prepaidAmount ?? this.prepaidAmount,
|
||||
paymentMethodId: paymentMethodId ?? this.paymentMethodId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const Object _sentinel = Object();
|
||||
Reference in New Issue
Block a user