|
|
|
@ -89,7 +89,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
Map<String, Object> summary = new HashMap<>(); |
|
|
|
summary.put("cmcInvoice", invoice); |
|
|
|
|
|
|
|
// 格式化日期为字符串 |
|
|
|
// 格式化日期为字符串(取第一条数据的日期) |
|
|
|
Date readyDate = dataList.get(0).getReadyDate(); |
|
|
|
String formattedDate = readyDate != null ? DateUtils.format(readyDate, "yyyy-MM-dd") : ""; |
|
|
|
summary.put("readyDate", formattedDate); |
|
|
|
@ -196,22 +196,23 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
List<String> failList = new ArrayList<>(); |
|
|
|
|
|
|
|
// 添加Sheet错误信息到失败列表 |
|
|
|
// 注意:只添加那些数据未被过滤的错误(skipped=false),已被过滤的错误(skipped=true)不需要再显示 |
|
|
|
for (SheetErrorInfo error : sheetErrors) { |
|
|
|
if (error.getSkipped()) { |
|
|
|
// 跳过类型的错误,作为警告信息 |
|
|
|
failList.add("Sheet [" + error.getSheetName() + "] 已跳过:" + error.getErrorMessage()); |
|
|
|
} else { |
|
|
|
// 验证失败类型的错误 |
|
|
|
failList.add("Sheet [" + error.getSheetName() + "] 错误:" + error.getErrorMessage()); |
|
|
|
if (error.getErrorDetails() != null && !error.getErrorDetails().isEmpty()) { |
|
|
|
// 限制显示前5个错误详情 |
|
|
|
int limit = Math.min(5, error.getErrorDetails().size()); |
|
|
|
for (int i = 0; i < limit; i++) { |
|
|
|
failList.add(" - " + error.getErrorDetails().get(i)); |
|
|
|
} |
|
|
|
if (error.getErrorDetails().size() > 5) { |
|
|
|
failList.add(" - ... 还有 " + (error.getErrorDetails().size() - 5) + " 个错误"); |
|
|
|
} |
|
|
|
// 跳过类型的错误(如多个Invoice、日期不一致),数据已在预览时被过滤,不需要在保存结果中显示 |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// 其他类型的错误(如数据格式错误、必填字段为空等),数据仍然存在,可能导致保存失败 |
|
|
|
failList.add("Sheet [" + error.getSheetName() + "] 错误:" + error.getErrorMessage()); |
|
|
|
if (error.getErrorDetails() != null && !error.getErrorDetails().isEmpty()) { |
|
|
|
// 限制显示前5个错误详情 |
|
|
|
int limit = Math.min(5, error.getErrorDetails().size()); |
|
|
|
for (int i = 0; i < limit; i++) { |
|
|
|
failList.add(" - " + error.getErrorDetails().get(i)); |
|
|
|
} |
|
|
|
if (error.getErrorDetails().size() > 5) { |
|
|
|
failList.add(" - ... 还有 " + (error.getErrorDetails().size() - 5) + " 个错误"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -532,6 +533,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
} |
|
|
|
|
|
|
|
boolean hasRowError = false; // 标记当前Sheet是否有行错误 |
|
|
|
List<EcssCoDelNotifyData> currentSheetData = new ArrayList<>(); // 记录当前Sheet的数据 |
|
|
|
|
|
|
|
// 遍历每一行(从第四行开始,即索引3) |
|
|
|
for (int j = 3; j < rows; j++) { |
|
|
|
@ -611,6 +613,10 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
task.setSite(site); // site |
|
|
|
task.setBuNo(inData.getBuNo()); // bu |
|
|
|
|
|
|
|
// 记录Excel行号和Sheet名称(用于错误提示) |
|
|
|
task.setExcelRowNumber(j + 1); // j是索引,j+1是Excel中的实际行号 |
|
|
|
task.setExcelSheetName(sheetName); |
|
|
|
|
|
|
|
// 解析日期 |
|
|
|
Date readDate; |
|
|
|
try { |
|
|
|
@ -719,9 +725,106 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
task.setUsername(inData.getUsername()); |
|
|
|
|
|
|
|
// 物料存在性检查已移至批量处理阶段,此处不再单独检查 |
|
|
|
excelList.add(task); |
|
|
|
// 先添加到当前Sheet的数据列表,稍后根据校验结果决定是否添加到总列表 |
|
|
|
currentSheetData.add(task); |
|
|
|
} |
|
|
|
|
|
|
|
// 校验1:检查当前Sheet中的CmcInvoice唯一性 |
|
|
|
Set<String> uniqueInvoices = currentSheetData.stream() |
|
|
|
.map(EcssCoDelNotifyData::getCmcInvoice) |
|
|
|
.collect(Collectors.toSet()); |
|
|
|
|
|
|
|
boolean hasMultipleInvoices = uniqueInvoices.size() > 1; |
|
|
|
boolean hasDateInconsistency = false; |
|
|
|
|
|
|
|
if (hasMultipleInvoices) { |
|
|
|
// 发现多个不同的CmcInvoice |
|
|
|
if (currentSheetError == null) { |
|
|
|
currentSheetError = new SheetErrorInfo(); |
|
|
|
currentSheetError.setSheetName(sheetName); |
|
|
|
currentSheetError.setSheetIndex(s); |
|
|
|
currentSheetError.setErrorDetails(new ArrayList<>()); |
|
|
|
} |
|
|
|
// 无论currentSheetError是否已存在,都要标记为跳过 |
|
|
|
currentSheetError.setErrorType("DATA_ERROR"); |
|
|
|
currentSheetError.setErrorMessage("数据错误,该Sheet数据将不会导入"); |
|
|
|
currentSheetError.setSkipped(true); |
|
|
|
|
|
|
|
// 统计每个发票号出现的行 |
|
|
|
Map<String, List<Integer>> invoiceRowsMap = new HashMap<>(); |
|
|
|
for (EcssCoDelNotifyData data : currentSheetData) { |
|
|
|
String invoice = data.getCmcInvoice(); |
|
|
|
invoiceRowsMap.putIfAbsent(invoice, new ArrayList<>()); |
|
|
|
invoiceRowsMap.get(invoice).add(data.getExcelRowNumber()); |
|
|
|
} |
|
|
|
|
|
|
|
List<String> invoiceDetails = new ArrayList<>(); |
|
|
|
for (Map.Entry<String, List<Integer>> entry : invoiceRowsMap.entrySet()) { |
|
|
|
String invoice = entry.getKey(); |
|
|
|
List<Integer> dataRows = entry.getValue(); |
|
|
|
Collections.sort(dataRows); |
|
|
|
String rowStr = dataRows.stream().map(String::valueOf).collect(Collectors.joining("、")); |
|
|
|
invoiceDetails.add("[" + invoice + "] (第" + rowStr + "行)"); |
|
|
|
} |
|
|
|
|
|
|
|
String errorMsg = "存在多个CMC Invoice:" + String.join(" | ", invoiceDetails); |
|
|
|
currentSheetError.addErrorDetail(errorMsg); |
|
|
|
hasRowError = true; |
|
|
|
} |
|
|
|
|
|
|
|
// 校验2:检查当前Sheet中的Cargo Ready Date一致性(按发票号分组) |
|
|
|
Map<String, Map<String, List<Integer>>> invoiceDateMap = new HashMap<>(); |
|
|
|
for (EcssCoDelNotifyData data : currentSheetData) { |
|
|
|
String invoice = data.getCmcInvoice(); |
|
|
|
Date readyDate = data.getReadyDate(); |
|
|
|
String dateKey = readyDate != null ? DateUtils.format(readyDate, "yyyy-MM-dd") : ""; |
|
|
|
|
|
|
|
invoiceDateMap.putIfAbsent(invoice, new HashMap<>()); |
|
|
|
invoiceDateMap.get(invoice).putIfAbsent(dateKey, new ArrayList<>()); |
|
|
|
invoiceDateMap.get(invoice).get(dateKey).add(data.getExcelRowNumber()); |
|
|
|
} |
|
|
|
|
|
|
|
// 检查是否有发票存在多个不同的日期 |
|
|
|
for (Map.Entry<String, Map<String, List<Integer>>> entry : invoiceDateMap.entrySet()) { |
|
|
|
String invoice = entry.getKey(); |
|
|
|
Map<String, List<Integer>> dateGroups = entry.getValue(); |
|
|
|
|
|
|
|
if (dateGroups.size() > 1) { |
|
|
|
// 发现日期不一致 |
|
|
|
hasDateInconsistency = true; |
|
|
|
if (currentSheetError == null) { |
|
|
|
currentSheetError = new SheetErrorInfo(); |
|
|
|
currentSheetError.setSheetName(sheetName); |
|
|
|
currentSheetError.setSheetIndex(s); |
|
|
|
currentSheetError.setErrorDetails(new ArrayList<>()); |
|
|
|
} |
|
|
|
// 无论currentSheetError是否已存在,都要标记为跳过 |
|
|
|
currentSheetError.setErrorType("DATA_ERROR"); |
|
|
|
currentSheetError.setErrorMessage("数据错误,该Sheet数据将不会导入"); |
|
|
|
currentSheetError.setSkipped(true); |
|
|
|
|
|
|
|
List<String> dateDetails = new ArrayList<>(); |
|
|
|
for (Map.Entry<String, List<Integer>> dateEntry : dateGroups.entrySet()) { |
|
|
|
String date = dateEntry.getKey().isEmpty() ? "未填写" : dateEntry.getKey(); |
|
|
|
List<Integer> dataRows = dateEntry.getValue(); |
|
|
|
Collections.sort(dataRows); |
|
|
|
String rowStr = dataRows.stream().map(String::valueOf).collect(Collectors.joining("、")); |
|
|
|
dateDetails.add(date + " (第" + rowStr + "行)"); |
|
|
|
} |
|
|
|
|
|
|
|
String errorMsg = "存在不同的Ready Date:" + String.join(" | ", dateDetails); |
|
|
|
currentSheetError.addErrorDetail(errorMsg); |
|
|
|
hasRowError = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 只有在没有严重错误(多个Invoice或日期不一致)时,才将数据添加到总列表 |
|
|
|
if (!hasMultipleInvoices && !hasDateInconsistency) { |
|
|
|
excelList.addAll(currentSheetData); |
|
|
|
} else { |
|
|
|
log.warn("Sheet [{}] 因数据错误被跳过,共 {} 条数据未导入", sheetName, currentSheetData.size()); |
|
|
|
} |
|
|
|
|
|
|
|
// 在Sheet处理结束时,如果有行错误,添加到错误列表 |
|
|
|
if (hasRowError && currentSheetError != null) { |
|
|
|
sheetErrors.add(currentSheetError); |
|
|
|
@ -762,7 +865,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
// 处理公式类型 - 获取缓存结果 |
|
|
|
else if (cellType == CellType.FORMULA) { |
|
|
|
CellType cachedType = cell.getCachedFormulaResultType(); |
|
|
|
|
|
|
|
|
|
|
|
if (cachedType == CellType.NUMERIC) { |
|
|
|
// 公式结果是数值类型且是日期格式 |
|
|
|
if (DateUtil.isCellDateFormatted(cell)) { |
|
|
|
@ -809,7 +912,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
// 处理公式类型 - 获取缓存结果 |
|
|
|
if (cellType == CellType.FORMULA) { |
|
|
|
CellType cachedType = cell.getCachedFormulaResultType(); |
|
|
|
|
|
|
|
|
|
|
|
if (cachedType == CellType.NUMERIC) { |
|
|
|
// 公式结果是数值类型 - 直接获取数值并转换为字符串 |
|
|
|
// 检查是否是日期格式 |
|
|
|
@ -868,7 +971,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
// 处理公式类型 - 获取缓存结果 |
|
|
|
if (cellType == CellType.FORMULA) { |
|
|
|
CellType cachedType = cell.getCachedFormulaResultType(); |
|
|
|
|
|
|
|
|
|
|
|
if (cachedType == CellType.NUMERIC) { |
|
|
|
return (int) Math.round(cell.getNumericCellValue()); |
|
|
|
} else if (cachedType == CellType.STRING) { |
|
|
|
@ -911,7 +1014,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
("Qty (pcs)".equalsIgnoreCase(columnName) || "TP".equalsIgnoreCase(columnName)); |
|
|
|
|
|
|
|
CellType cellType = cell.getCellType(); |
|
|
|
|
|
|
|
|
|
|
|
if (cellType == CellType.NUMERIC) { |
|
|
|
BigDecimal value = BigDecimal.valueOf(cell.getNumericCellValue()); |
|
|
|
return value.setScale(6, RoundingMode.HALF_UP); // 四舍五入保留四位小数 |
|
|
|
@ -931,7 +1034,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
} else if (cellType == CellType.FORMULA) { |
|
|
|
// 获取缓存结果 |
|
|
|
CellType cachedType = cell.getCachedFormulaResultType(); |
|
|
|
|
|
|
|
|
|
|
|
if (cachedType == CellType.NUMERIC) { |
|
|
|
BigDecimal formulaValue = BigDecimal.valueOf(cell.getNumericCellValue()); |
|
|
|
return formulaValue.setScale(6, RoundingMode.HALF_UP); // 四舍五入保留四位小数 |
|
|
|
@ -979,7 +1082,8 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { |
|
|
|
if (!sheetErrors.isEmpty()) { |
|
|
|
StringBuilder errorMsg = new StringBuilder("以下Sheet存在问题:\n"); |
|
|
|
for (SheetErrorInfo error : sheetErrors) { |
|
|
|
errorMsg.append("Sheet [").append(error.getSheetName()).append("]: ").append(error.getErrorMessage()).append("\n"); |
|
|
|
errorMsg.append("Sheet [").append(error.getSheetName()).append("]: "). |
|
|
|
append(String.join("\n", error.getErrorDetails())).append("\n\n"); |
|
|
|
} |
|
|
|
throw new RuntimeException(errorMsg.toString()); |
|
|
|
} |
|
|
|
|