diff --git a/src/main/java/com/xujie/sys/modules/ecss/data/EcssCoDelNotifyData.java b/src/main/java/com/xujie/sys/modules/ecss/data/EcssCoDelNotifyData.java index 23f156f8..dafb9d75 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/data/EcssCoDelNotifyData.java +++ b/src/main/java/com/xujie/sys/modules/ecss/data/EcssCoDelNotifyData.java @@ -27,4 +27,14 @@ public class EcssCoDelNotifyData extends EcssCoDelNotify { private Boolean modifyFlag; private Boolean modifyQtyFlag; + + /** + * Excel文件中的实际行号(用于错误提示,不保存到数据库) + */ + private transient Integer excelRowNumber; + + /** + * Excel文件中的Sheet名称(用于错误提示,不保存到数据库) + */ + private transient String excelSheetName; } diff --git a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java index 3e4b059c..ac4eb085 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java @@ -89,7 +89,7 @@ public class CoDelExcelServiceImpl implements CoDelExcelService { Map 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 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 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 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> invoiceRowsMap = new HashMap<>(); + for (EcssCoDelNotifyData data : currentSheetData) { + String invoice = data.getCmcInvoice(); + invoiceRowsMap.putIfAbsent(invoice, new ArrayList<>()); + invoiceRowsMap.get(invoice).add(data.getExcelRowNumber()); + } + + List invoiceDetails = new ArrayList<>(); + for (Map.Entry> entry : invoiceRowsMap.entrySet()) { + String invoice = entry.getKey(); + List 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>> 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>> entry : invoiceDateMap.entrySet()) { + String invoice = entry.getKey(); + Map> 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 dateDetails = new ArrayList<>(); + for (Map.Entry> dateEntry : dateGroups.entrySet()) { + String date = dateEntry.getKey().isEmpty() ? "未填写" : dateEntry.getKey(); + List 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()); } diff --git a/src/main/resources/mapper/ecss/CoDelMapper.xml b/src/main/resources/mapper/ecss/CoDelMapper.xml index f810df3d..7ef75aa1 100644 --- a/src/main/resources/mapper/ecss/CoDelMapper.xml +++ b/src/main/resources/mapper/ecss/CoDelMapper.xml @@ -75,6 +75,15 @@ and a.modifyFlag=1 + + AND a.fscFlag = 'Y' + + + AND a.boxSizeFlag = 'Y' + + + AND a.walMartOrderFlag = 'Y' + and ISNULL(a.export_flag,'N') = #{query.exportFlag} diff --git a/src/main/resources/templates/declaration-all-template-WOERMA-pdf.xlsx b/src/main/resources/templates/declaration-all-template-WOERMA-pdf.xlsx index 378fd758..54310ce0 100644 Binary files a/src/main/resources/templates/declaration-all-template-WOERMA-pdf.xlsx and b/src/main/resources/templates/declaration-all-template-WOERMA-pdf.xlsx differ diff --git a/src/main/resources/templates/declaration-all-template-WOERMA.xlsx b/src/main/resources/templates/declaration-all-template-WOERMA.xlsx index d5efd7bb..5b63cc4c 100644 Binary files a/src/main/resources/templates/declaration-all-template-WOERMA.xlsx and b/src/main/resources/templates/declaration-all-template-WOERMA.xlsx differ diff --git a/src/main/resources/templates/declaration-packingList-template-WOERMA.xlsx b/src/main/resources/templates/declaration-packingList-template-WOERMA.xlsx index e27633bb..4904b1e2 100644 Binary files a/src/main/resources/templates/declaration-packingList-template-WOERMA.xlsx and b/src/main/resources/templates/declaration-packingList-template-WOERMA.xlsx differ