feat: abweichende Lieferadresse und Empfänger vor Ort anzeigen
Belege können im ERP eine eigene Lieferadresse (LieferAdressId) mit anderer Person tragen als der Besteller. Die App zeigt jetzt überall den Empfänger vor Ort: - TourDetails.recipientOf liefert Empfänger (Name aus der Lieferadresse, sonst Besteller), Lieferanschrift und differsFromOrderer. - Sortieren, Auswählen, Beladen und Liefer-Übersicht: Empfängername + Lieferadresse, bei Abweichung „Bestellt von: <Kunde>". - Lieferdetails: hervorgehobene Karte „Abweichende Lieferadresse" mit Empfänger, Anschrift und Kontakt; Kunden-Block als „Besteller (Kunde)" mit Adresse, Kundennummer und Kontaktdaten. - Maps navigiert zur Lieferadresse statt zur Kundenadresse; AppBar, Unterschrift und Beladen-Avatar nutzen den Empfänger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -1,9 +1,11 @@
|
||||
import 'address.dart';
|
||||
import 'article.dart';
|
||||
import 'contact_source.dart';
|
||||
import 'customer.dart';
|
||||
import 'delivery.dart';
|
||||
import 'delivery_credit.dart';
|
||||
import 'delivery_payment.dart';
|
||||
import 'delivery_recipient.dart';
|
||||
import 'delivery_item.dart';
|
||||
import 'delivery_note.dart';
|
||||
import 'delivery_service_value.dart';
|
||||
@ -97,6 +99,52 @@ class TourDetails {
|
||||
|
||||
Customer? customerOf(Delivery delivery) => customers[delivery.customerId];
|
||||
|
||||
/// Empfänger vor Ort: Name und Kontakt aus der ERP-Lieferadresse, sonst
|
||||
/// der Besteller. [DeliveryRecipient.differsFromOrderer] ist gesetzt,
|
||||
/// sobald Anschrift oder Name vom Besteller abweichen.
|
||||
///
|
||||
/// Der Namensvergleich läuft ERP-Adresse gegen ERP-Adresse (Lieferadresse
|
||||
/// vs. Belegadresse, jeweils `Name1..3`), damit ein nur in `Name2`
|
||||
/// geführter Vorname keinen Fehlalarm auslöst. Groß-/Kleinschreibung und
|
||||
/// Leerzeichen zählen nicht als Abweichung.
|
||||
DeliveryRecipient recipientOf(Delivery delivery) {
|
||||
final customer = customerOf(delivery);
|
||||
final deliverySource = contactSourceWithRole(delivery, ContactRole.delivery);
|
||||
final ordererName = contactSourceWithRole(delivery, ContactRole.header)?.fullName ??
|
||||
customer?.name ??
|
||||
'';
|
||||
final recipientName = deliverySource?.fullName;
|
||||
|
||||
final addressDiffers = customer != null &&
|
||||
!_sameAddress(delivery.deliveryAddressSnapshot, customer.address);
|
||||
final nameDiffers = recipientName != null &&
|
||||
_normalized(recipientName) != _normalized(ordererName);
|
||||
|
||||
return DeliveryRecipient(
|
||||
name: recipientName ?? customer?.name ?? '⟨Unbekannter Kunde⟩',
|
||||
address: delivery.deliveryAddressSnapshot,
|
||||
contact: deliverySource,
|
||||
differsFromOrderer: addressDiffers || nameDiffers,
|
||||
);
|
||||
}
|
||||
|
||||
/// Erste Adress-Quelle einer Lieferung mit der Rolle [role], oder `null`.
|
||||
ContactSource? contactSourceWithRole(Delivery delivery, ContactRole role) {
|
||||
for (final s in contactSourcesOf(delivery)) {
|
||||
if (s.role == role) return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static String _normalized(String value) =>
|
||||
value.trim().toLowerCase().replaceAll(RegExp(r'\s+'), ' ');
|
||||
|
||||
static bool _sameAddress(Address a, Address b) =>
|
||||
_normalized(a.street) == _normalized(b.street) &&
|
||||
_normalized(a.houseNumber) == _normalized(b.houseNumber) &&
|
||||
_normalized(a.postalCode) == _normalized(b.postalCode) &&
|
||||
_normalized(a.city) == _normalized(b.city);
|
||||
|
||||
Iterable<CustomerContact> contactsOf(Delivery delivery) sync* {
|
||||
for (final id in delivery.contactPersonIds) {
|
||||
final c = contacts[id];
|
||||
|
||||
Reference in New Issue
Block a user