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:
@ -23,6 +23,7 @@ import 'package:hl_lieferservice/widget/scanner/article_scanner_stripe.dart';
|
||||
import 'package:hl_lieferservice/widget/scanner/item_matcher.dart';
|
||||
import 'package:hl_lieferservice/widget/scanner/manual_entry_dialog.dart';
|
||||
import 'package:hl_lieferservice/widget/scanner/scan_code_parser.dart';
|
||||
import 'package:hl_lieferservice/widget/orderer_hint.dart';
|
||||
|
||||
/// Vollbild-Sicht eines Kunden in der Beladen-Phase mit aktivem Scanner.
|
||||
///
|
||||
@ -523,6 +524,7 @@ class _CustomerBody extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final customer = details.customerOf(delivery);
|
||||
final recipient = details.recipientOf(delivery);
|
||||
// Items werden vom Aggregat-Helper schon nach Lager gruppiert
|
||||
// geliefert: Standardlager zuerst, danach Filiale alphabetisch.
|
||||
// Nicht-scanbare Positionen und `removed`-Items sind dabei schon
|
||||
@ -611,7 +613,7 @@ class _CustomerBody extends StatelessWidget {
|
||||
// Kunden" wird dadurch räumlich klar.
|
||||
child: Row(
|
||||
children: [
|
||||
_CustomerAvatar(customer: customer),
|
||||
_CustomerAvatar(customer: customer, name: recipient.name),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@ -630,14 +632,18 @@ class _CustomerBody extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
customer?.name ?? '⟨Unbekannter Kunde⟩',
|
||||
recipient.name,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
delivery.deliveryAddressSnapshot.oneLine,
|
||||
recipient.address.oneLine,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
if (recipient.differsFromOrderer)
|
||||
OrdererHint(
|
||||
ordererName: customer?.name ?? '⟨Unbekannter Kunde⟩',
|
||||
),
|
||||
if (delivery.state != DeliveryState.active) ...[
|
||||
const SizedBox(height: 8),
|
||||
_DeliveryStateBadge(delivery: delivery),
|
||||
@ -987,12 +993,13 @@ class _NothingToLoadHint extends StatelessWidget {
|
||||
///
|
||||
/// Farbe ist deterministisch aus der `customer.id` abgeleitet, damit
|
||||
/// Re-Builds und Page-Wechsel den Avatar nicht „flackern" lassen.
|
||||
/// Initialen kommen aus dem Namen — Vor- und Zunamen kombiniert,
|
||||
/// einzelne Worte mit einem Buchstaben.
|
||||
/// Initialen kommen aus dem angezeigten Namen (Empfänger vor Ort) — Vor-
|
||||
/// und Zunamen kombiniert, einzelne Worte mit einem Buchstaben.
|
||||
class _CustomerAvatar extends StatelessWidget {
|
||||
const _CustomerAvatar({required this.customer});
|
||||
const _CustomerAvatar({required this.customer, required this.name});
|
||||
|
||||
final Customer? customer;
|
||||
final String name;
|
||||
|
||||
/// Kleine kuratierte Palette — kräftig genug zum Erkennen, aber nicht
|
||||
/// schreiend. Reihenfolge ist Absicht: die ersten Farben fallen am
|
||||
@ -1009,9 +1016,9 @@ class _CustomerAvatar extends StatelessWidget {
|
||||
];
|
||||
|
||||
String get _initials {
|
||||
final name = customer?.name.trim() ?? '';
|
||||
if (name.isEmpty) return '?';
|
||||
final parts = name
|
||||
final trimmed = name.trim();
|
||||
if (trimmed.isEmpty) return '?';
|
||||
final parts = trimmed
|
||||
.split(RegExp(r'\s+'))
|
||||
.where((p) => p.isNotEmpty)
|
||||
.toList(growable: false);
|
||||
|
||||
Reference in New Issue
Block a user