Initial draft

This commit is contained in:
Dennis Nemec
2025-09-20 16:14:06 +02:00
commit b19a6e1cd4
219 changed files with 10317 additions and 0 deletions

24
lib/model/address.dart Normal file
View File

@ -0,0 +1,24 @@
import 'package:hl_lieferservice/dto/address.dart';
class Address {
const Address(
{required this.street,
required this.city,
required this.postalCode});
final String street;
final String postalCode;
final String city;
factory Address.fromDTO(AddressDTO dto) {
return Address(
street: dto.streetName,
city: dto.city,
postalCode: dto.postalCode);
}
@override
String toString() {
return "$street $postalCode $city";
}
}

64
lib/model/article.dart Normal file
View File

@ -0,0 +1,64 @@
import 'package:flutter/cupertino.dart';
import 'package:hl_lieferservice/dto/article.dart';
class Article {
Article({
required this.name,
required this.articleNumber,
required this.amount,
required this.internalId,
required this.price,
required this.tax,
required this.scannable,
required this.scannedAmount,
required this.scannedRemovedAmount,
this.scannedDate,
this.removeNoteId
});
final String name;
final String articleNumber;
final int internalId;
int amount;
double price;
double tax;
bool scannable;
DateTime? scannedDate;
String? removeNoteId;
int scannedAmount;
int scannedRemovedAmount;
double getGrossPrice() {
return price * amount * ((100 + tax) / 100);
}
double getGrossPriceScanned() {
return price * scannedAmount * ((100 + tax) / 100);
}
bool unscanned() {
return scannedAmount == 0;
}
int getScannedAmount() {
return scannedAmount;
}
factory Article.fromDTO(ArticleDTO dto) {
return Article(
name: dto.name,
scannedAmount: int.parse(
dto.scannedAmount != "" ? dto.scannedAmount : "0",
),
scannedRemovedAmount: int.tryParse(dto.scannedRemovedAmount) ?? 0,
removeNoteId: dto.removeNoteId,
internalId: int.parse(dto.internalId),
articleNumber: dto.articleNr,
amount: int.parse(dto.quantity == "" ? "0" : dto.quantity),
price: double.parse(dto.price == "" ? "0.0" : dto.price),
scannable: dto.scannable,
tax: double.parse(dto.taxRate == "" ? "19" : dto.taxRate),
);
}
}

6
lib/model/car.dart Normal file
View File

@ -0,0 +1,6 @@
class Car {
Car({required this.id, required this.plate});
int id;
String plate;
}

14
lib/model/customer.dart Normal file
View File

@ -0,0 +1,14 @@
import 'package:hl_lieferservice/dto/customer.dart';
import 'address.dart';
class Customer {
const Customer({required this.name, required this.address});
final String name;
final Address address;
factory Customer.fromDTO(CustomerDTO dto) {
return Customer(name: dto.name, address: Address.fromDTO(dto.address));
}
}

373
lib/model/delivery.dart Normal file
View File

@ -0,0 +1,373 @@
import 'package:flutter/cupertino.dart';
import 'package:hl_lieferservice/dto/contact_person.dart';
import 'package:hl_lieferservice/dto/delivery.dart';
import 'package:hl_lieferservice/dto/image.dart';
import 'package:hl_lieferservice/dto/note.dart';
import 'package:hl_lieferservice/dto/note_template.dart';
import 'package:hl_lieferservice/model/tour.dart';
import 'package:hl_lieferservice/util.dart';
import '../dto/payment.dart';
import 'article.dart';
import 'customer.dart';
class PaymentOptions {
PaymentOptions({this.value = 0.0, this.selectedPaymentMethod = "none"});
double value;
String selectedPaymentMethod;
}
class Note {
Note({required this.content, required this.id});
final int id;
String content;
factory Note.fromDto(NoteDTO dto) {
return Note(content: dto.note, id: int.parse(dto.id));
}
}
class NoteTemplate {
NoteTemplate({
required this.title,
required this.content,
required this.language,
});
String title;
String content;
String language;
factory NoteTemplate.fromDTO(NoteTemplateDTO dto) {
return NoteTemplate(
title: dto.title,
content: dto.note,
language: dto.language,
);
}
}
class ContactPerson {
const ContactPerson({required this.name, required this.phoneNumber});
final String name;
final String? phoneNumber;
factory ContactPerson.fromDTO(ContactPersonDTO dto) {
String phone;
String phoneRegex = r'([0-9]+|[0-9]+(-|\/))[0-9]+';
if (dto.phoneNo == "" && dto.mobileNo != "") {
phone = dto.mobileNo;
} else if (dto.phoneNo != "" && dto.mobileNo == "") {
phone = dto.phoneNo;
} else {
phone = dto.mobileNo;
}
return ContactPerson(
name: dto.name,
phoneNumber: concatenateRegexMatches(phone, phoneRegex),
);
}
}
enum DeliveryState { canceled, finished, ongoing, onhold }
class Discount {
Discount({this.note, this.noteId, required this.article});
String? note;
String? noteId;
/// The article refers to the special discount article such as "GUTSCHRIFT10"
/// for example.
Article article;
}
class ImageNote {
const ImageNote({
required this.name,
required this.url,
required this.objectId,
});
final String name;
final String url;
final String objectId;
factory ImageNote.fromDTO(ImageDTO dto) {
return ImageNote(name: dto.name, url: dto.url, objectId: dto.oid);
}
factory ImageNote.make(String objectId, String name) {
String url = "/v1/preview/1920_1080_100_png/$objectId";
return ImageNote(name: name, url: url, objectId: objectId);
}
}
class DeliveryOption {
DeliveryOption({
required this.numerical,
required this.value,
required this.display,
required this.key,
});
bool numerical;
String value;
String display;
String key;
factory DeliveryOption.fromDTO(DeliveryOptionDTO dto) {
return DeliveryOption(
numerical: dto.numerical,
value: dto.value,
display: dto.display,
key: dto.key,
);
}
dynamic getValue() {
if (!numerical) {
if (value.isEmpty) {
return false;
} else {
return bool.parse(value);
}
} else {
if (value.isEmpty) {
return 0;
} else {
return int.parse(value);
}
}
}
DeliveryOption copyWith({
bool? numerical,
String? value,
String? display,
String? key,
}) {
return DeliveryOption(
numerical: numerical ?? this.numerical,
value: value ?? this.value,
display: display ?? this.display,
key: key ?? this.key,
);
}
}
class Delivery {
Delivery({
required this.customer,
required this.id,
required this.articles,
required this.paymentOptions,
required this.notes,
required this.price,
required this.filePaths,
required this.currency,
required this.images,
required this.prepayment,
required this.paymentAtDelivery,
required this.payment,
required this.options,
this.state = DeliveryState.ongoing,
this.contactPerson,
required this.totalGrossValue,
required this.totalNetValue,
this.desiredTime,
this.discount,
this.specialAgreements,
this.carId,
});
final Customer customer;
final String id;
List<Article> articles;
final ContactPerson? contactPerson;
final double price;
final String currency;
double totalGrossValue;
double totalNetValue;
String? desiredTime;
List<String> filePaths;
Discount? discount;
DeliveryState state;
String? specialAgreements;
PaymentOptions paymentOptions;
int? carId;
List<Note> notes;
List<ImageNote> images;
double prepayment;
double paymentAtDelivery;
Payment payment;
List<DeliveryOption> options;
Delivery copyWith({
Customer? customer,
String? id,
List<Article>? articles,
ContactPerson? contactPerson,
double? price,
String? currency,
double? totalGrossValue,
double? totalNetValue,
String? desiredTime,
List<String>? filePaths,
Discount? discount,
DeliveryState? state,
String? specialAgreements,
PaymentOptions? paymentOptions,
int? carId,
List<Note>? notes,
List<ImageNote>? images,
double? prepayment,
double? paymentAtDelivery,
Payment? payment,
List<DeliveryOption>? options,
}) {
return Delivery(
customer: customer ?? this.customer,
id: id ?? this.id,
articles: articles ?? this.articles,
contactPerson: contactPerson ?? this.contactPerson,
price: price ?? this.price,
currency: currency ?? this.currency,
totalGrossValue: totalGrossValue ?? this.totalGrossValue,
totalNetValue: totalNetValue ?? this.totalNetValue,
desiredTime: desiredTime ?? this.desiredTime,
filePaths: filePaths ?? this.filePaths,
discount: discount ?? this.discount,
state: state ?? this.state,
specialAgreements: specialAgreements ?? this.specialAgreements,
paymentOptions: paymentOptions ?? this.paymentOptions,
carId: carId ?? this.carId,
notes: notes ?? this.notes,
images: images ?? this.images,
prepayment: prepayment ?? this.prepayment,
paymentAtDelivery: paymentAtDelivery ?? this.paymentAtDelivery,
payment: payment ?? this.payment,
options: options ?? this.options,
);
}
Article? findArticleWithNoteId(String noteId) {
Article? filteredArticle =
articles.where((article) => article.removeNoteId == noteId).firstOrNull;
if (filteredArticle == null && discount?.article != null) {
filteredArticle = discount?.article;
}
return filteredArticle;
}
double getGrossPrice() {
return articles.fold(0, (acc, article) {
double price = article.getGrossPriceScanned();
if (!article.scannable) {
price = article.getGrossPrice();
}
return acc + price;
});
}
double getOpenPrice() {
return getGrossPrice() - prepayment;
}
List<Article> getDeliveredArticles() {
return articles
.where(
(article) {
debugPrint("Scannable: ${article.scannable}");
return article.scannedAmount > 0 || !article.scannable;
},
)
.toList();
}
bool containsArticle(String articleNr) {
return articles.any((article) => article.articleNumber == articleNr);
}
Article getArticle(String nr) {
return articles.firstWhere((article) => article.articleNumber == nr);
}
List<Article> getScannableArticles() {
return articles.where((article) => article.scannable).toList();
}
bool allArticlesScanned() {
return getScannableArticles().every(
(article) =>
article.amount ==
article.scannedAmount + article.scannedRemovedAmount,
);
}
void scanArticle(String nr) {
if (!containsArticle(nr)) {
return;
}
Article article = getArticle(nr);
if (article.scannedAmount < article.amount) {
article.scannedAmount += 1;
}
}
factory Delivery.fromDTO(DeliveryDTO dto) {
double getPrice() {
return double.parse(dto.totalPrice == "" ? "0" : dto.totalPrice);
}
return Delivery(
customer: Customer.fromDTO(dto.customer),
id: dto.internalReceiptNo,
articles: dto.articles.map(Article.fromDTO).toList(),
paymentOptions: PaymentOptions(value: getPrice()),
notes: dto.notes.map(Note.fromDto).toList(),
price: getPrice(),
payment: Payment.fromDTO(dto.payment),
specialAgreements: dto.specialAggreements,
desiredTime: dto.desiredTime,
prepayment: double.tryParse(dto.prepayment) ?? 0.0,
discount:
dto.discount == null
? null
: Discount(
article: Article.fromDTO(dto.discount!.article),
note: dto.discount!.note,
noteId: dto.discount!.noteId,
),
paymentAtDelivery: double.tryParse(dto.paymentAtDelivery) ?? 0.0,
images: dto.images.map(ImageNote.fromDTO).toList(),
carId: int.tryParse(dto.carId),
totalGrossValue: double.parse(
dto.totalGrossValue == "" ? "0" : dto.totalGrossValue,
),
totalNetValue: double.parse(
dto.totalNetValue == "" ? "0" : dto.totalNetValue,
),
filePaths: [],
options:
dto.options.map((option) => DeliveryOption.fromDTO(option)).toList(),
state:
dto.state != ""
? getDeliveryStateFromString(dto.state)
: DeliveryState.ongoing,
contactPerson: ContactPerson.fromDTO(dto.contactPerson),
currency: dto.currency ?? "EUR",
);
}
}

71
lib/model/tour.dart Normal file
View File

@ -0,0 +1,71 @@
import 'package:hl_lieferservice/dto/payment.dart';
import 'car.dart';
import 'delivery.dart';
class Payment {
const Payment({
required this.description,
required this.shortcode,
required this.id,
});
final String id;
final String description;
final String shortcode;
factory Payment.fromDTO(PaymentMethodDTO dto) {
return Payment(
description: dto.description,
shortcode: dto.shortCode,
id: dto.id,
);
}
}
class Tour {
Tour({
required this.date,
required this.deliveries,
required this.driver,
required this.discountArticleNumber,
required this.paymentMethods,
});
final DateTime date;
final String discountArticleNumber;
Driver driver;
final List<Delivery> deliveries;
List<Payment> paymentMethods;
int getFinishedDeliveries(int carId) {
return deliveries
.where((delivery) => delivery.carId == carId)
.where((delivery) => delivery.state == DeliveryState.finished)
.toList()
.length;
}
}
class Driver {
Driver({
required this.teamNumber,
required this.name,
required this.salutation,
required this.cars,
});
final int teamNumber;
final String name;
final String salutation;
List<Car> cars;
/// If the driver is representing a company, then the company name is returned.
String getSalutatedLastName() {
if (salutation != "Firma") {
return "$salutation, ${name.split(" ").first}";
}
return "$salutation, $name";
}
}

5
lib/model/user.dart Normal file
View File

@ -0,0 +1,5 @@
class User {
const User({required this.id});
final String id;
}