Files
votianlt/app/lib/models/delivery_station.dart
T
Sven 5e6044e4b1 fix: Stationsabschluss absichern und Kundenformulare anpassen
Sperrt nachträgliche Aufgabenabschlüsse in App und Backend und zeigt erledigte Aufträge trotz offener optionaler Aufgaben grün an. Ergänzt Regressionstests, die Anredeauswahl und optionale Steuerangaben für Kunden. Enthält App-Version 0.9.25, Backend-Version 0.9.26 und das aktualisierte Frontend-Bundle.
2026-10-06 15:09:51 +02:00

137 lines
3.8 KiB
Dart

import 'task.dart';
class DeliveryStation {
final int stationOrder;
final String company;
final String? salutation;
final String firstName;
final String lastName;
final String phone;
final String street;
final String houseNumber;
final String addressAddition;
final String zip;
final String city;
final String deliveryDate;
final String deliveryTime;
final List<Task> tasks;
DeliveryStation({
required this.stationOrder,
required this.company,
this.salutation,
required this.firstName,
required this.lastName,
required this.phone,
required this.street,
required this.houseNumber,
required this.addressAddition,
required this.zip,
required this.city,
required this.deliveryDate,
required this.deliveryTime,
required this.tasks,
});
static String _readString(dynamic value, {String fallback = ''}) {
if (value is String) {
return value;
}
if (value is num || value is bool) {
return value.toString();
}
return fallback;
}
factory DeliveryStation.fromJson(Map<String, dynamic> json) {
final stationOrder =
json['stationOrder'] is num
? (json['stationOrder'] as num).toInt()
: int.tryParse(json['stationOrder']?.toString() ?? '') ?? 0;
final tasks =
(json['tasks'] as List? ?? const []).map((rawTask) {
final taskJson = Map<String, dynamic>.from(rawTask as Map);
taskJson['stationOrder'] = stationOrder;
return Task.fromJson(taskJson);
}).toList()
..sort((a, b) => (a.taskOrder ?? 0).compareTo(b.taskOrder ?? 0));
return DeliveryStation(
stationOrder: stationOrder,
company: _readString(json['company']),
salutation: json['salutation']?.toString(),
firstName: _readString(json['firstName']),
lastName: _readString(json['lastName']),
phone: _readString(json['phone']),
street: _readString(json['street']),
houseNumber: _readString(json['houseNumber']),
addressAddition: _readString(json['addressAddition']),
zip: _readString(json['zip']),
city: _readString(json['city']),
deliveryDate: _readString(json['deliveryDate']),
deliveryTime: _readString(json['deliveryTime']),
tasks: tasks,
);
}
Map<String, dynamic> toJson() {
return {
'stationOrder': stationOrder,
'company': company,
'salutation': salutation,
'firstName': firstName,
'lastName': lastName,
'phone': phone,
'street': street,
'houseNumber': houseNumber,
'addressAddition': addressAddition,
'zip': zip,
'city': city,
'deliveryDate': deliveryDate,
'deliveryTime': deliveryTime,
'tasks': tasks.map((task) => task.toJson()).toList(),
};
}
DeliveryStation normalized() {
String t(String? value) => (value ?? '').trim();
return DeliveryStation(
stationOrder: stationOrder,
company: t(company),
salutation: t(salutation),
firstName: t(firstName),
lastName: t(lastName),
phone: t(phone),
street: t(street),
houseNumber: t(houseNumber),
addressAddition: t(addressAddition),
zip: t(zip),
city: t(city),
deliveryDate: t(deliveryDate),
deliveryTime: t(deliveryTime),
tasks: tasks,
);
}
String get displayName {
final name = [
firstName.trim(),
lastName.trim(),
].where((part) => part.isNotEmpty).join(' ');
return name.isNotEmpty ? name : company;
}
String get formattedAddress {
final streetPart = [
street.trim(),
houseNumber.trim(),
].where((part) => part.isNotEmpty).join(' ');
final cityPart = [
zip.trim(),
city.trim(),
].where((part) => part.isNotEmpty).join(' ');
return [streetPart, cityPart].where((part) => part.isNotEmpty).join(', ');
}
}