Added components to article
This commit is contained in:
@ -1,5 +1,7 @@
|
||||
import 'package:hl_lieferservice/dto/article.dart';
|
||||
|
||||
import 'component.dart';
|
||||
|
||||
class Article {
|
||||
Article({
|
||||
required this.name,
|
||||
@ -11,13 +13,21 @@ class Article {
|
||||
required this.scannable,
|
||||
required this.scannedAmount,
|
||||
required this.scannedRemovedAmount,
|
||||
required this.isParent,
|
||||
this.components = const [],
|
||||
this.scannedDate,
|
||||
this.removeNoteId
|
||||
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;
|
||||
@ -36,7 +46,35 @@ class Article {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -58,6 +96,11 @@ class Article {
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
34
lib/model/component.dart
Normal file
34
lib/model/component.dart
Normal file
@ -0,0 +1,34 @@
|
||||
import 'package:hl_lieferservice/dto/component.dart';
|
||||
|
||||
class Component {
|
||||
Component({
|
||||
required this.articleNumber,
|
||||
required this.name,
|
||||
required this.quantity,
|
||||
required this.position,
|
||||
this.scannedAmount = 0,
|
||||
});
|
||||
|
||||
final String articleNumber;
|
||||
final String name;
|
||||
final double quantity;
|
||||
final double position;
|
||||
|
||||
int scannedAmount;
|
||||
|
||||
/// Required scan count derived from BOM quantity (e.g. 7.0 → 7).
|
||||
int get requiredAmount => quantity.ceil();
|
||||
|
||||
bool get isFullyScanned => scannedAmount >= requiredAmount;
|
||||
|
||||
bool get needsScanning => scannedAmount < requiredAmount;
|
||||
|
||||
factory Component.fromDTO(ComponentDTO dto) {
|
||||
return Component(
|
||||
articleNumber: dto.articleNr,
|
||||
name: dto.name,
|
||||
quantity: double.tryParse(dto.quantity) ?? 0.0,
|
||||
position: double.tryParse(dto.pos) ?? 0.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -295,29 +295,42 @@ class Delivery implements Comparable<Delivery> {
|
||||
|
||||
List<Article> getDeliveredArticles() {
|
||||
return articles
|
||||
.where(
|
||||
(article) => article.scannedAmount > 0 || !article.scannable,
|
||||
)
|
||||
.where((article) {
|
||||
if (!article.scannable) return true;
|
||||
if (article.isParent && article.components.isNotEmpty) {
|
||||
return article.isFullyScanned;
|
||||
}
|
||||
return article.scannedAmount > 0;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
bool containsArticle(String articleNr) {
|
||||
return articles.any((article) => article.articleNumber == articleNr);
|
||||
return articles.any((article) => article.hasArticleNumber(articleNr));
|
||||
}
|
||||
|
||||
Article getArticle(String nr) {
|
||||
return articles.firstWhere((article) => article.articleNumber == nr);
|
||||
}
|
||||
|
||||
/// Find the parent article whose BOM contains [componentArticleNr].
|
||||
Article? findParentOfComponent(String componentArticleNr) {
|
||||
for (final article in articles) {
|
||||
if (article.isParent &&
|
||||
article.findComponent(componentArticleNr) != null) {
|
||||
return article;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Article> getScannableArticles() {
|
||||
return articles.where((article) => article.scannable).toList();
|
||||
}
|
||||
|
||||
bool allArticlesScanned() {
|
||||
return getScannableArticles().every(
|
||||
(article) =>
|
||||
article.amount ==
|
||||
article.scannedAmount + article.scannedRemovedAmount,
|
||||
(article) => article.isFullyScanned,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user