- boxing_models.dart: add BoxingMode, BoxingPhase, BoxingPageArguments - boxing_box_mutations.dart: box item add/replace/remove operations - boxing_calculations.dart: pure calculation helpers (quantities, validation) - boxing_status_presenter.dart: status bar text/dot determination - dialogs/cross_paichan_dialog.dart: cross-paichan confirmation dialog - widgets/boxing_notice_banners.dart: notice banner widgets - Add unit tests for mutations, calculations, and status presenter Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
136 lines
3.8 KiB
Dart
136 lines
3.8 KiB
Dart
import 'package:pad_scanner/pages/boxing/boxing_models.dart';
|
|
import 'package:pad_scanner/services/api_service.dart';
|
|
|
|
class BoxMutationResult {
|
|
final List<BoxDetailData> boxes;
|
|
final int maxBoxNo;
|
|
|
|
const BoxMutationResult({required this.boxes, required this.maxBoxNo});
|
|
}
|
|
|
|
int maxBoxNoFor(List<BoxDetailData> boxes) {
|
|
return boxes.fold<int>(0, (max, box) => box.boxNo > max ? box.boxNo : max);
|
|
}
|
|
|
|
BoxMutationResult addExistingBoxItem({
|
|
required List<BoxDetailData> existingBoxes,
|
|
required int boxNo,
|
|
required int quantity,
|
|
required int? boxItemId,
|
|
required String zongpaiNo,
|
|
required String? workOrderNo,
|
|
required int? totalQuantity,
|
|
}) {
|
|
final item = BoxItemData(
|
|
boxItemId: boxItemId,
|
|
zongpaiNo: zongpaiNo,
|
|
workOrderNo: workOrderNo,
|
|
quantity: quantity,
|
|
totalQuantity: totalQuantity,
|
|
);
|
|
final index = existingBoxes.indexWhere((box) => box.boxNo == boxNo);
|
|
if (index < 0) {
|
|
final boxes = [
|
|
...existingBoxes,
|
|
BoxDetailData(boxNo: boxNo, items: [item]),
|
|
]..sort((a, b) => a.boxNo.compareTo(b.boxNo));
|
|
return BoxMutationResult(boxes: boxes, maxBoxNo: maxBoxNoFor(boxes));
|
|
}
|
|
|
|
final boxes = List<BoxDetailData>.from(existingBoxes);
|
|
final box = boxes[index];
|
|
boxes[index] = BoxDetailData(boxNo: box.boxNo, items: [...box.items, item]);
|
|
return BoxMutationResult(boxes: boxes, maxBoxNo: maxBoxNoFor(boxes));
|
|
}
|
|
|
|
BoxMutationResult replaceExistingBoxItem({
|
|
required List<BoxDetailData> existingBoxes,
|
|
required CurrentZongpaiBoxData editing,
|
|
required int boxNo,
|
|
required int quantity,
|
|
required String zongpaiNo,
|
|
required String? workOrderNo,
|
|
required int? totalQuantity,
|
|
}) {
|
|
final updatedItem = BoxItemData(
|
|
boxItemId: editing.boxItemId,
|
|
zongpaiNo: zongpaiNo,
|
|
workOrderNo: workOrderNo,
|
|
quantity: quantity,
|
|
totalQuantity: totalQuantity,
|
|
);
|
|
return _replaceItemById(
|
|
existingBoxes: existingBoxes,
|
|
boxItemId: editing.boxItemId,
|
|
targetBoxNo: boxNo,
|
|
updatedItem: updatedItem,
|
|
);
|
|
}
|
|
|
|
BoxMutationResult replaceExistingPackedItem({
|
|
required List<BoxDetailData> existingBoxes,
|
|
required ManyToOnePackedItem item,
|
|
required int boxNo,
|
|
required int quantity,
|
|
}) {
|
|
final updatedItem = BoxItemData(
|
|
boxItemId: item.boxItemId,
|
|
zongpaiNo: item.zongpaiNo,
|
|
workOrderNo: item.workOrderNo,
|
|
quantity: quantity,
|
|
totalQuantity: item.totalQuantity,
|
|
);
|
|
return _replaceItemById(
|
|
existingBoxes: existingBoxes,
|
|
boxItemId: item.boxItemId,
|
|
targetBoxNo: boxNo,
|
|
updatedItem: updatedItem,
|
|
);
|
|
}
|
|
|
|
BoxMutationResult removeExistingBoxItem({
|
|
required List<BoxDetailData> existingBoxes,
|
|
required int boxItemId,
|
|
}) {
|
|
final boxes = <BoxDetailData>[];
|
|
for (final box in existingBoxes) {
|
|
final items = box.items
|
|
.where((item) => item.boxItemId != boxItemId)
|
|
.toList();
|
|
if (items.isNotEmpty) {
|
|
boxes.add(BoxDetailData(boxNo: box.boxNo, items: items));
|
|
}
|
|
}
|
|
return BoxMutationResult(boxes: boxes, maxBoxNo: maxBoxNoFor(boxes));
|
|
}
|
|
|
|
BoxMutationResult _replaceItemById({
|
|
required List<BoxDetailData> existingBoxes,
|
|
required int boxItemId,
|
|
required int targetBoxNo,
|
|
required BoxItemData updatedItem,
|
|
}) {
|
|
final boxes = <BoxDetailData>[];
|
|
for (final box in existingBoxes) {
|
|
final items = box.items.where((item) {
|
|
return item.boxItemId != boxItemId;
|
|
}).toList();
|
|
if (items.isNotEmpty) {
|
|
boxes.add(BoxDetailData(boxNo: box.boxNo, items: items));
|
|
}
|
|
}
|
|
|
|
final targetIndex = boxes.indexWhere((box) => box.boxNo == targetBoxNo);
|
|
if (targetIndex >= 0) {
|
|
final target = boxes[targetIndex];
|
|
boxes[targetIndex] = BoxDetailData(
|
|
boxNo: target.boxNo,
|
|
items: [...target.items, updatedItem],
|
|
);
|
|
} else {
|
|
boxes.add(BoxDetailData(boxNo: targetBoxNo, items: [updatedItem]));
|
|
}
|
|
boxes.sort((a, b) => a.boxNo.compareTo(b.boxNo));
|
|
return BoxMutationResult(boxes: boxes, maxBoxNo: maxBoxNoFor(boxes));
|
|
}
|