feat: Anschrift unter „Alle Kontaktinfos" anzeigen
Jede Kontaktquelle zeigt ihre Anschrift (inkl. Zusatz, Land nur im Ausland), sofern das ERP eine pflegt. Die Anschrift zählt beim Zusammenführen gleicher Quellen mit — gleicher Name an anderer Adresse bleibt eine eigene Karte. API-Client neu generiert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -117,6 +117,7 @@ extension ApiContactSourceMapper on api.ContactSource {
|
||||
name3: name3,
|
||||
abteilung: abteilung,
|
||||
funktion: funktion,
|
||||
address: address?.toDomain(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import 'address.dart';
|
||||
|
||||
/// Adress-Rolle eines Beleg-Kontakts. Spiegelt die fünf Adress-FKs am
|
||||
/// ERP-`Belegkopf` (bzw. den Umweg über `Kunden.AdressId`). Die App nutzt
|
||||
/// das primär als Gruppierungs-Label in der Detail-Ansicht.
|
||||
@ -95,6 +97,7 @@ class ContactSource {
|
||||
this.name3,
|
||||
this.abteilung,
|
||||
this.funktion,
|
||||
this.address,
|
||||
});
|
||||
|
||||
final String id;
|
||||
@ -109,6 +112,10 @@ class ContactSource {
|
||||
final String? abteilung;
|
||||
final String? funktion;
|
||||
|
||||
/// Anschrift dieses ERP-Adress-Datensatzes; `null`, wenn dort weder
|
||||
/// Straße noch Ort gepflegt sind (z. B. reiner Ansprechpartner).
|
||||
final Address? address;
|
||||
|
||||
/// Zusammengesetzte Anzeige des Namens — Anrede + Titel + Name1..3 in
|
||||
/// dieser Reihenfolge, leere Felder werden übersprungen. Gibt `null`
|
||||
/// zurück, wenn die Quelle gar keinen Namen trägt (kann vorkommen, wenn
|
||||
@ -189,6 +196,7 @@ class MergedContactSource {
|
||||
required this.abteilung,
|
||||
required this.funktion,
|
||||
required this.channels,
|
||||
this.address,
|
||||
});
|
||||
|
||||
/// Alle Rollen, die diesen zusammengeführten Kontakt liefern.
|
||||
@ -208,6 +216,9 @@ class MergedContactSource {
|
||||
/// liefert (kind + ERP-Position).
|
||||
final List<ContactChannel> channels;
|
||||
|
||||
/// Anschrift, falls im ERP gepflegt (bei allen Quellen der Gruppe gleich).
|
||||
final Address? address;
|
||||
|
||||
/// Zusammengesetzter Anzeigename — identisch zu [ContactSource.displayName].
|
||||
String? get displayName {
|
||||
final parts = <String>[
|
||||
|
||||
@ -211,6 +211,9 @@ class TourDetails {
|
||||
s.name3 ?? '',
|
||||
s.abteilung ?? '',
|
||||
s.funktion ?? '',
|
||||
// Anschrift gehört zur Identität: gleicher Name an anderer Adresse
|
||||
// ist ein anderer Datensatz.
|
||||
s.address?.oneLineWithAddition ?? '',
|
||||
].join('|');
|
||||
final sortedChannels = List<ContactChannel>.of(channels)
|
||||
..sort((a, b) {
|
||||
@ -240,6 +243,7 @@ class TourDetails {
|
||||
abteilung: first.abteilung,
|
||||
funktion: first.funktion,
|
||||
channels: channelsOf(first),
|
||||
address: first.address,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1151,6 +1151,36 @@ class _ContactSourceTile extends StatelessWidget {
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
if (source.address case final address?) ...[
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.home_outlined,
|
||||
size: 18,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${address.street} ${address.houseNumber}'.trim(),
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
Text(
|
||||
'${address.postalCode} ${address.city}'.trim(),
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
..._addressExtras(address, fontSize: 14),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
if (channels.isEmpty) ...[
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
|
||||
Reference in New Issue
Block a user