186 lines
5.8 KiB
Dart
186 lines
5.8 KiB
Dart
// ignore_for_file: invalid_use_of_protected_member
|
|
|
|
part of '../../registration_page.dart';
|
|
|
|
extension _RegistrationAttachmentPart on _RegistrationPageState {
|
|
/// Handle FJ- attachment scan: pick category, then register location.
|
|
Future<void> _handleAttachmentScan(String zongpaiNo) async {
|
|
if (_crossPaichaPending) {
|
|
_triggerDoubleVibration();
|
|
return;
|
|
}
|
|
|
|
final baseUrl = await _baseUrl();
|
|
if (baseUrl == null || !mounted) return;
|
|
|
|
// 1. Fetch categories (cache in the page state)
|
|
final catResult = await _apiService.fetchAttachmentCategories(
|
|
baseUrl: baseUrl,
|
|
);
|
|
if (!catResult.success || !mounted) {
|
|
_feedbackService.trigger(FeedbackEvent.scanInvalid);
|
|
_showStatusOverride(
|
|
catResult.errorMessage ?? '加载附件类型失败',
|
|
StatusDotColor.red,
|
|
const Duration(seconds: 2),
|
|
);
|
|
return;
|
|
}
|
|
final categories = catResult.categories;
|
|
|
|
// 2. Pick category (single choice)
|
|
final picked = await showAttachmentCategoryPicker(
|
|
context: context,
|
|
categories: categories,
|
|
);
|
|
if (picked == null || !mounted) return;
|
|
|
|
// 3. Now treat this zongpai as "scanned" with the picked category
|
|
// For the registration flow: append scanned zongpai (for location binding)
|
|
// and store category context for the submit path
|
|
_feedbackService.trigger(FeedbackEvent.scanValid);
|
|
setState(() {
|
|
if (_mode == RegistrationMode.multiCode) {
|
|
if (!_zongpaiNos.contains(zongpaiNo)) {
|
|
_zongpaiNos.add(zongpaiNo);
|
|
}
|
|
} else {
|
|
if (_zongpaiNos.isEmpty) {
|
|
_zongpaiNos.add(zongpaiNo);
|
|
} else {
|
|
_zongpaiNos[0] = zongpaiNo;
|
|
}
|
|
}
|
|
// Store the last-scanned attachment category for submit
|
|
_pendingAttachmentCategory = picked.id;
|
|
_clearStatusOverride();
|
|
});
|
|
|
|
// 4. Refresh the overview (the zongpai is now a product scan for display,
|
|
// attachment status will be shown via a separate banner/tag)
|
|
final shouldRefresh = _overviewZongpaiNo != zongpaiNo;
|
|
if (shouldRefresh) {
|
|
_loadOverview(zongpaiNo);
|
|
}
|
|
}
|
|
|
|
/// Handle a product scan with attachment-config integration.
|
|
/// Called from the existing _handleZongpaiScan when a product code is scanned.
|
|
Future<void> _checkAndConfigureAttachment(String zongpaiNo) async {
|
|
final baseUrl = await _baseUrl();
|
|
if (baseUrl == null || !mounted) return;
|
|
|
|
// Fetch attachment status for this zongpai
|
|
final status = await _apiService.fetchAttachmentStatus(
|
|
baseUrl: baseUrl,
|
|
zongpaiNo: zongpaiNo,
|
|
);
|
|
if (!mounted) return;
|
|
|
|
if (!status.success) {
|
|
// Network error or other — defer to product scan flow without blocking
|
|
return;
|
|
}
|
|
|
|
if (status.determination == 'none') {
|
|
// Already determined none — nothing to configure
|
|
return;
|
|
}
|
|
|
|
if (status.determination == 'undetermined' ||
|
|
status.determination == 'has') {
|
|
// Fetch categories for the dialog
|
|
final catResult = await _apiService.fetchAttachmentCategories(
|
|
baseUrl: baseUrl,
|
|
);
|
|
if (!catResult.success || !mounted) return;
|
|
|
|
// Fetch ERP quantity for default expected_qty
|
|
final overview = _overview;
|
|
final erpQty = overview?.success == true
|
|
? overview!.items
|
|
.where((i) => i.zongpaiNo == zongpaiNo)
|
|
.fold<int>(0, (sum, i) => sum + i.quantity)
|
|
: 0;
|
|
|
|
final result = await showAttachmentConfigDialog(
|
|
context: context,
|
|
zongpaiNo: zongpaiNo,
|
|
categories: catResult.categories,
|
|
prefillItems: status.items,
|
|
erpQuantity: erpQty > 0 ? erpQty : 1,
|
|
);
|
|
if (result == null || !mounted) return;
|
|
|
|
// Submit config
|
|
final configResult = await _apiService.putAttachmentConfig(
|
|
baseUrl: baseUrl,
|
|
zongpaiNo: zongpaiNo,
|
|
determination: result.determination,
|
|
items: result.items,
|
|
);
|
|
if (!mounted) return;
|
|
|
|
if (!configResult.success) {
|
|
_feedbackService.trigger(FeedbackEvent.submitFailure);
|
|
_showStatusOverride(
|
|
configResult.errorMessage ?? '配置失败',
|
|
StatusDotColor.red,
|
|
const Duration(seconds: 2),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Submit attachment location for the given zongpai.
|
|
Future<bool> _submitAttachmentLocation(
|
|
String baseUrl,
|
|
String zongpaiNo,
|
|
int categoryId,
|
|
) async {
|
|
final result = await _apiService.registerAttachmentLocation(
|
|
baseUrl: baseUrl,
|
|
zongpaiNo: zongpaiNo,
|
|
categoryId: categoryId,
|
|
locationCode: _locationCode!,
|
|
);
|
|
|
|
if (!mounted) return false;
|
|
|
|
if (result.success) {
|
|
return true;
|
|
} else if (result.isDuplicate) {
|
|
_feedbackService.trigger(FeedbackEvent.duplicateError);
|
|
if (result.conflictInfo != null) {
|
|
final msg =
|
|
'附件 $zongpaiNo 已上架至 ${result.conflictInfo!['location_code']}';
|
|
_showStatusOverride(
|
|
msg,
|
|
StatusDotColor.red,
|
|
const Duration(seconds: 2),
|
|
);
|
|
}
|
|
return false;
|
|
} else if (result.isAlreadyOffShelf) {
|
|
_feedbackService.trigger(FeedbackEvent.submitFailure);
|
|
_showStatusOverride(
|
|
result.errorMessage ?? '该附件已下架至转运区域,不可重新上架',
|
|
StatusDotColor.red,
|
|
const Duration(seconds: 2),
|
|
);
|
|
return false;
|
|
} else {
|
|
final isNetwork = result.errorMessage == '网络异常,请检查网络连接';
|
|
_feedbackService.trigger(
|
|
isNetwork ? FeedbackEvent.networkError : FeedbackEvent.submitFailure,
|
|
);
|
|
_showStatusOverride(
|
|
result.errorMessage ?? '提交失败',
|
|
isNetwork ? StatusDotColor.yellow : StatusDotColor.red,
|
|
const Duration(seconds: 2),
|
|
);
|
|
return false;
|
|
}
|
|
}
|
|
}
|