107 lines
3.0 KiB
Dart
107 lines
3.0 KiB
Dart
import 'package:hl_lieferservice/dto/article.dart';
|
|
|
|
import 'component.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,
|
|
required this.isParent,
|
|
this.components = const [],
|
|
this.scannedDate,
|
|
this.removeNoteId,
|
|
this.warehouseNr,
|
|
this.warehouseName,
|
|
});
|
|
|
|
final String name;
|
|
final String articleNumber;
|
|
final int internalId;
|
|
final bool isParent;
|
|
final List<Component> components;
|
|
final String? warehouseNr;
|
|
final String? warehouseName;
|
|
|
|
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);
|
|
}
|
|
|
|
/// Whether this article is fully scanned.
|
|
///
|
|
/// For parent articles (Stückliste): delegates to components — all must be
|
|
/// individually scanned. For regular articles: the classic amount check.
|
|
bool get isFullyScanned {
|
|
if (isParent && components.isNotEmpty) {
|
|
return components.every((c) => c.isFullyScanned);
|
|
}
|
|
return scannedAmount + scannedRemovedAmount >= amount;
|
|
}
|
|
|
|
/// Find a component by its article number, or `null` if none matches.
|
|
Component? findComponent(String articleNumber) {
|
|
for (final c in components) {
|
|
if (c.articleNumber == articleNumber) return c;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// Whether this article *or* any of its components carries [articleNumber].
|
|
bool hasArticleNumber(String articleNumber) {
|
|
if (this.articleNumber == articleNumber) return true;
|
|
return components.any((c) => c.articleNumber == articleNumber);
|
|
}
|
|
|
|
bool unscanned() {
|
|
if (isParent && components.isNotEmpty) {
|
|
return components.every((c) => c.scannedAmount == 0);
|
|
}
|
|
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),
|
|
isParent: dto.isParent,
|
|
components: dto.components?.map(Component.fromDTO).toList() ?? [],
|
|
warehouseNr: dto.warehouseNr?.isEmpty ?? true ? null : dto.warehouseNr,
|
|
warehouseName:
|
|
dto.warehouseName?.isEmpty ?? true ? null : dto.warehouseName,
|
|
);
|
|
}
|
|
}
|