|
|
|
@ -310,6 +310,89 @@ public class CoDelServiceImpl implements CoDelService { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* 安全获取字符串列值(支持可选列) |
|
|
|
* 如果列不存在,返回空字符串 |
|
|
|
* |
|
|
|
* @param row 数据行 |
|
|
|
* @param columnMap 列索引映射 |
|
|
|
* @param columnName 列名 |
|
|
|
* @return 单元格字符串值,如果列不存在返回空字符串 |
|
|
|
*/ |
|
|
|
private String getStringCellValueSafe(XSSFRow row, Map<String, Integer> columnMap, String columnName) { |
|
|
|
Integer columnIndex = columnMap.get(columnName); |
|
|
|
if (columnIndex == null) { |
|
|
|
return ""; // 列不存在,返回空字符串 |
|
|
|
} |
|
|
|
return getStringCellValue(row, columnIndex); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 安全获取数字列值(支持可选列) |
|
|
|
* 如果列不存在,返回null |
|
|
|
* |
|
|
|
* @param row 数据行 |
|
|
|
* @param columnMap 列索引映射 |
|
|
|
* @param columnName 列名 |
|
|
|
* @return 单元格数字值,如果列不存在返回null |
|
|
|
*/ |
|
|
|
private BigDecimal getNumericCellValueSafe(XSSFRow row, Map<String, Integer> columnMap, String columnName) { |
|
|
|
Integer columnIndex = columnMap.get(columnName); |
|
|
|
if (columnIndex == null) { |
|
|
|
return null; // 列不存在,返回null |
|
|
|
} |
|
|
|
return getNumericCellValueOrDefault(row, columnIndex); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 解析Excel第一行,建立列名到列索引的映射关系 |
|
|
|
* |
|
|
|
* @param headerRow 第一行(表头行) |
|
|
|
* @return 列名到列索引的映射Map |
|
|
|
*/ |
|
|
|
private Map<String, Integer> parseExcelHeader(XSSFRow headerRow) { |
|
|
|
Map<String, Integer> columnIndexMap = new HashMap<>(); |
|
|
|
if (headerRow == null) { |
|
|
|
throw new RuntimeException("Excel表头行不能为空!"); |
|
|
|
} |
|
|
|
|
|
|
|
// 遍历第一行的所有单元格,建立列名到索引的映射 |
|
|
|
int lastCellNum = headerRow.getLastCellNum(); |
|
|
|
for (int i = 0; i < lastCellNum; i++) { |
|
|
|
String columnName = getStringCellValue(headerRow, i); |
|
|
|
if (StringUtils.isNotBlank(columnName)) { |
|
|
|
// 去除空格并统一格式 |
|
|
|
columnName = columnName.trim(); |
|
|
|
columnIndexMap.put(columnName, i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 验证必填列是否存在(根据代码中的验证逻辑确定) |
|
|
|
String[] requiredColumns = { |
|
|
|
"PO#", // 必填 |
|
|
|
"PN", // 必填 |
|
|
|
"Qty (pcs)", // 必填 |
|
|
|
"Cargo Ready Date", // 必填 |
|
|
|
"Destination", // 必填 |
|
|
|
"Shipping Mode", // 必填 |
|
|
|
"Currency", // 必填 |
|
|
|
"TP" // 必填 |
|
|
|
}; |
|
|
|
|
|
|
|
List<String> missingColumns = new ArrayList<>(); |
|
|
|
for (String column : requiredColumns) { |
|
|
|
if (!columnIndexMap.containsKey(column)) { |
|
|
|
missingColumns.add(column); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!missingColumns.isEmpty()) { |
|
|
|
throw new RuntimeException("Excel表头缺少必填列: " + String.join(", ", missingColumns)); |
|
|
|
} |
|
|
|
|
|
|
|
return columnIndexMap; |
|
|
|
} |
|
|
|
|
|
|
|
private void importNotifyExcel(EcssCoDelNotifyHeaderData inData, XSSFWorkbook workbook, String site, |
|
|
|
SysUserEntity currentUser, List<EcssCoDelNotifyData> excelList) { |
|
|
|
for (int s = 0; s < workbook.getNumberOfSheets(); s++) { |
|
|
|
@ -319,74 +402,159 @@ public class CoDelServiceImpl implements CoDelService { |
|
|
|
deleteEmptyRow(sheet); |
|
|
|
// 获取行数 |
|
|
|
int rows = sheet.getPhysicalNumberOfRows(); |
|
|
|
// 遍历每一行(从第二行开始) |
|
|
|
for (int j = 1; j < rows; j++) { |
|
|
|
// 创建对象 |
|
|
|
EcssCoDelNotifyData task = new EcssCoDelNotifyData(); |
|
|
|
XSSFRow row0 = sheet.getRow(0); |
|
|
|
if (row0.getCell(0) == null || StringUtils.isBlank(getStringCellValue(row0, 0)) |
|
|
|
|| !getStringCellValue(row0, 0).equals("Ready Date")) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (rows < 4) { |
|
|
|
continue; // 至少需要前2行、表头行(第3行)和一行数据(第4行) |
|
|
|
} |
|
|
|
|
|
|
|
// 获取第三行(表头行) |
|
|
|
XSSFRow headerRow = sheet.getRow(2); |
|
|
|
|
|
|
|
// 验证第一列第3行必须是"PO Rec. Date"且不能为空 |
|
|
|
if (headerRow == null || headerRow.getCell(0) == null |
|
|
|
|| StringUtils.isBlank(getStringCellValue(headerRow, 0)) |
|
|
|
|| !getStringCellValue(headerRow, 0).trim().equals("PO Rec. Date")) { |
|
|
|
log.warn("Sheet {} 的第一列第3行不是 'PO Rec. Date' 或为空,跳过该Sheet", sheet.getSheetName()); |
|
|
|
continue; // 跳过该Sheet |
|
|
|
} |
|
|
|
|
|
|
|
// 解析表头行(第3行),获取列索引映射 |
|
|
|
Map<String, Integer> columnMap = parseExcelHeader(headerRow); |
|
|
|
|
|
|
|
// 遍历每一行(从第四行开始,即索引3) |
|
|
|
for (int j = 3; j < rows; j++) { |
|
|
|
// 获得该行 |
|
|
|
XSSFRow row = sheet.getRow(j); |
|
|
|
if (row==null) { |
|
|
|
if (row == null) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (row.getCell(13) == null || StringUtils.isBlank(getStringCellValue(row, 13))) { |
|
|
|
|
|
|
|
// 检查第一列,如果没有值或者值是空字符串则跳过该行 |
|
|
|
if (row.getCell(0).getCellType() == CellType.BLANK || row.getCell(0).getCellType() == CellType.ERROR |
|
|
|
|| row.getCell(0) == null || StringUtils.isBlank(getStringCellValue(row, 0))) { |
|
|
|
log.debug("第{}行第一列为空,跳过该行", j+1); |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (row.getCell(18) != null && getStringCellValue(row, 18).equals("内销")) { |
|
|
|
|
|
|
|
// 跳过内销数据(如果"内外销方式"列存在) |
|
|
|
Integer saleTypeIdx = columnMap.get("内外销方式"); |
|
|
|
if (saleTypeIdx != null && row.getCell(saleTypeIdx) != null |
|
|
|
&& getStringCellValue(row, saleTypeIdx).equals("内销")) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (row.getCell(0) == null ) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的Ready Date不能为空!"); |
|
|
|
|
|
|
|
// 必填字段验证 |
|
|
|
Integer cargoReadyDateIdx = columnMap.get("Cargo Ready Date"); |
|
|
|
if (row.getCell(cargoReadyDateIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的Cargo Ready Date不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(1) == null) { |
|
|
|
|
|
|
|
Integer poIdx = columnMap.get("PO#"); |
|
|
|
if (row.getCell(poIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的PO#不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(8) == null) { |
|
|
|
|
|
|
|
Integer pnIdx = columnMap.get("PN"); |
|
|
|
if (row.getCell(pnIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的PN不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(11) == null) { |
|
|
|
|
|
|
|
Integer qtyIdx = columnMap.get("Qty (pcs)"); |
|
|
|
if (row.getCell(qtyIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的Qty不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(13) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的CMC Invoice不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(15) == null) { |
|
|
|
|
|
|
|
Integer destinationIdx = columnMap.get("Destination"); |
|
|
|
if (row.getCell(destinationIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的Destination不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(17) == null) { |
|
|
|
|
|
|
|
Integer shippingModeIdx = columnMap.get("Shipping Mode"); |
|
|
|
if (row.getCell(shippingModeIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的Shipping Mode不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(21) == null) { |
|
|
|
|
|
|
|
Integer currencyIdx = columnMap.get("Currency"); |
|
|
|
if (row.getCell(currencyIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的Currency不能为空!"); |
|
|
|
} |
|
|
|
if (row.getCell(22) == null) { |
|
|
|
|
|
|
|
Integer tpIdx = columnMap.get("TP"); |
|
|
|
if (row.getCell(tpIdx) == null) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的TP不能为空!"); |
|
|
|
} |
|
|
|
// 为对象赋值 |
|
|
|
|
|
|
|
// 创建对象并为对象赋值 |
|
|
|
EcssCoDelNotifyData task = new EcssCoDelNotifyData(); |
|
|
|
task.setSite(site); // site |
|
|
|
task.setBuNo(inData.getBuNo()); // bu |
|
|
|
|
|
|
|
// 解析日期 |
|
|
|
Date readDate; |
|
|
|
try { |
|
|
|
//String date = getStringCellValue(row, 0); |
|
|
|
LocalDate localDate = parseDateCell(row.getCell(0)); |
|
|
|
LocalDate localDate = parseDateCell(row.getCell(cargoReadyDateIdx)); |
|
|
|
String formatted = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); |
|
|
|
readDate = DateUtils.getDateByParten(formatted, "yyyy-MM-dd"); |
|
|
|
} catch (ParseException e) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的ReadyDate格式有误!"); |
|
|
|
} |
|
|
|
task.setReadyDate(readDate); |
|
|
|
task.setCustomerPO(getStringCellValue(row, 1)); |
|
|
|
task.setSalesOrder(getStringCellValue(row, 4)); |
|
|
|
task.setLine(getStringCellValue(row, 2)); |
|
|
|
task.setVersion(getStringCellValue(row, 3)); |
|
|
|
task.setSaleslt(getStringCellValue(row, 5)); |
|
|
|
task.setStatus(getStringCellValue(row, 6)); |
|
|
|
task.setFamily(getStringCellValue(row, 7)); |
|
|
|
task.setPn(getStringCellValue(row, 8)); |
|
|
|
|
|
|
|
// 使用动态索引读取数据(必填列) |
|
|
|
task.setCustomerPO(getStringCellValue(row, poIdx)); |
|
|
|
task.setPn(getStringCellValue(row, pnIdx)); |
|
|
|
task.setQty(getNumericCellValueOrDefault(row, qtyIdx)); |
|
|
|
task.setDestination(getStringCellValue(row, destinationIdx)); |
|
|
|
task.setShippingMode(getStringCellValue(row, shippingModeIdx)); |
|
|
|
task.setCurrency(getStringCellValue(row, currencyIdx)); |
|
|
|
task.setTp(getNumericCellValueOrDefault(row, tpIdx)); |
|
|
|
|
|
|
|
// 处理CMC Invoice:如果CMC Invoice为空则取Shipping Number,如果两者都为空则报错 |
|
|
|
String cmcInvoiceValue = getStringCellValueSafe(row, columnMap, "CMC Invoice"); |
|
|
|
String shippingNumberValue = getStringCellValueSafe(row, columnMap, "Shipping Number"); |
|
|
|
|
|
|
|
if (StringUtils.isBlank(cmcInvoiceValue) && StringUtils.isBlank(shippingNumberValue)) { |
|
|
|
throw new RuntimeException("第" + (j+1) + "行的CMC Invoice和Shipping Number不能同时为空!"); |
|
|
|
} |
|
|
|
|
|
|
|
// 如果CMC Invoice为空,则使用Shipping Number |
|
|
|
if (StringUtils.isBlank(cmcInvoiceValue)) { |
|
|
|
task.setCmcInvoice(shippingNumberValue); |
|
|
|
} else { |
|
|
|
task.setCmcInvoice(cmcInvoiceValue); |
|
|
|
} |
|
|
|
task.setShippingNumber(shippingNumberValue); |
|
|
|
|
|
|
|
// 读取可选列(列不存在时返回空值或null) |
|
|
|
task.setSalesOrder(getStringCellValueSafe(row, columnMap, "Sales Order")); |
|
|
|
task.setLine(getStringCellValueSafe(row, columnMap, "Line#")); |
|
|
|
task.setVersion(getStringCellValueSafe(row, columnMap, "Version#")); |
|
|
|
task.setSaleslt(getStringCellValueSafe(row, columnMap, "Saleslt")); |
|
|
|
task.setStatus(getStringCellValueSafe(row, columnMap, "Status")); |
|
|
|
task.setFamily(getStringCellValueSafe(row, columnMap, "Family")); |
|
|
|
task.setPartDescription(getStringCellValueSafe(row, columnMap, "Description")); |
|
|
|
task.setManufacturerName(getStringCellValueSafe(row, columnMap, "Manufacturer Name")); |
|
|
|
task.setCmcComment(getStringCellValueSafe(row, columnMap, "CMC Comment")); |
|
|
|
task.setAwbBl(getStringCellValueSafe(row, columnMap, "AWB/ BL#")); |
|
|
|
task.setForwarderInfo(getStringCellValueSafe(row, columnMap, "Forwarder Info")); |
|
|
|
task.setSo(getStringCellValueSafe(row, columnMap, "SO")); |
|
|
|
task.setUpc(getStringCellValueSafe(row, columnMap, "UPC")); |
|
|
|
task.setRemark(getStringCellValueSafe(row, columnMap, "备注")); |
|
|
|
task.setCategory(getStringCellValueSafe(row, columnMap, "Category")); |
|
|
|
task.setQtyRoll(getStringCellValueSafe(row, columnMap, "QTY/ROLL")); |
|
|
|
task.setQtyBox(getStringCellValueSafe(row, columnMap, "qty/box")); |
|
|
|
task.setSaleType(getStringCellValueSafe(row, columnMap, "内外销方式")); // 内外销 |
|
|
|
|
|
|
|
task.setLt(getNumericCellValueSafe(row, columnMap, "LT (wks)")); |
|
|
|
task.setTtlAmount(getNumericCellValueSafe(row, columnMap, "TTL Amount")); |
|
|
|
task.setVat(getNumericCellValueSafe(row, columnMap, "VAT")); |
|
|
|
task.setSumPrice(getNumericCellValueSafe(row, columnMap, "价税合计")); // 价税合计 |
|
|
|
task.setRoll(getNumericCellValueSafe(row, columnMap, "Roll")); |
|
|
|
|
|
|
|
BigDecimal carton = getNumericCellValueSafe(row, columnMap, "BOX"); |
|
|
|
task.setCarton(carton != null ? carton.setScale(1, RoundingMode.HALF_UP) : null); |
|
|
|
|
|
|
|
// 查询物料信息 |
|
|
|
List<PartData> parts = coDelMapper.getPartNo(site, task.getPn(), currentUser.getUsername(), inData.getBuNo()); |
|
|
|
if (parts.isEmpty()) { |
|
|
|
// 物料不存在时,设置 partNo 为 pn,后续会在批量检查阶段被筛选掉 |
|
|
|
@ -394,34 +562,14 @@ public class CoDelServiceImpl implements CoDelService { |
|
|
|
} else { |
|
|
|
task.setPartNo(parts.get(0).getPartNo()); |
|
|
|
} |
|
|
|
task.setPartDescription(getStringCellValue(row, 9)); |
|
|
|
task.setManufacturerName(getStringCellValue(row, 10)); |
|
|
|
task.setQty(getNumericCellValueOrDefault(row, 11)); |
|
|
|
if (task.getQty().compareTo(BigDecimal.ZERO)==0) { |
|
|
|
|
|
|
|
if (task.getQty().compareTo(BigDecimal.ZERO) == 0) { |
|
|
|
task.setStatus("取消发货"); |
|
|
|
} |
|
|
|
task.setLt(getNumericCellValueOrDefault(row, 12)); |
|
|
|
task.setCmcInvoice(getStringCellValue(row, 13)); |
|
|
|
task.setCmcComment(getStringCellValue(row, 14)); |
|
|
|
task.setDestination(getStringCellValue(row, 15)); |
|
|
|
task.setSaleType(getStringCellValue(row, 18)); |
|
|
|
task.setAwbBl(getStringCellValue(row, 19)); |
|
|
|
task.setShippingNumber(getStringCellValue(row, 16)); |
|
|
|
task.setShippingMode(getStringCellValue(row, 17)); |
|
|
|
task.setForwarderInfo(getStringCellValue(row, 20)); |
|
|
|
task.setCurrency(getStringCellValue(row, 21)); |
|
|
|
task.setTp(getNumericCellValueOrDefault(row, 22)); |
|
|
|
task.setTtlAmount(getNumericCellValueOrDefault(row, 23)); |
|
|
|
task.setVat(getNumericCellValueOrDefault(row, 24)); |
|
|
|
task.setSumPrice(getNumericCellValueOrDefault(row, 25)); |
|
|
|
task.setSo(getStringCellValue(row, 26)); |
|
|
|
task.setUpc(getStringCellValue(row, 27)); |
|
|
|
task.setRemark(getStringCellValue(row, 28)); |
|
|
|
task.setRoll(getNumericCellValueOrDefault(row, 29)); |
|
|
|
task.setCarton(getNumericCellValueOrDefault(row, 30)!=null? Objects.requireNonNull(getNumericCellValueOrDefault(row, 30)).setScale(1, RoundingMode.HALF_UP):null); |
|
|
|
task.setErpFlag("N"); |
|
|
|
task.setNotifyStatus("已计划"); |
|
|
|
task.setUsername(inData.getUsername()); |
|
|
|
|
|
|
|
// 物料存在性检查已移至批量处理阶段,此处不再单独检查 |
|
|
|
excelList.add(task); |
|
|
|
} |
|
|
|
@ -813,37 +961,48 @@ public class CoDelServiceImpl implements CoDelService { |
|
|
|
// 先删除全部明细,再新建明细 |
|
|
|
coDelMapper.deleteAllEcssDelDetail(headerData); |
|
|
|
|
|
|
|
// 构建原数据Map,使用itemNo作为唯一标识 |
|
|
|
// 注意:不能用pn作为key,因为同一个pn可能有多行记录,每行都需要独立比较 |
|
|
|
Map<Integer, EcssCoDelNotifyDetailData> originalDataMap = dbData.stream() |
|
|
|
.collect(Collectors.toMap(EcssCoDelNotifyDetail::getItemNo, detail -> detail, (v1, v2) -> v1)); |
|
|
|
// 智能判断改单逻辑:按PN分组汇总数量,避免因顺序变化导致误判 |
|
|
|
// 构建原数据Map:按PN分组,计算每个PN的总数量 |
|
|
|
Map<String, BigDecimal> originalPnQtyMap = new HashMap<>(); |
|
|
|
for (EcssCoDelNotifyDetailData detail : dbData) { |
|
|
|
String pn = detail.getPn(); |
|
|
|
BigDecimal qty = detail.getQty(); |
|
|
|
originalPnQtyMap.put(pn, originalPnQtyMap.getOrDefault(pn, BigDecimal.ZERO).add(qty)); |
|
|
|
} |
|
|
|
|
|
|
|
// 构建新数据Map:按PN分组,计算每个PN的总数量 |
|
|
|
Map<String, BigDecimal> newPnQtyMap = new HashMap<>(); |
|
|
|
for (EcssCoDelNotifyData excelData : excelList) { |
|
|
|
String pn = excelData.getPn(); |
|
|
|
BigDecimal qty = excelData.getQty(); |
|
|
|
newPnQtyMap.put(pn, newPnQtyMap.getOrDefault(pn, BigDecimal.ZERO).add(qty)); |
|
|
|
} |
|
|
|
|
|
|
|
// 设置itemNo并判断每一行是否有变化(智能判断:按PN比较总数量) |
|
|
|
for (int i = 0; i < excelList.size(); i++) { |
|
|
|
excelList.get(i).setDelNo(headerData.getDelNo()); |
|
|
|
excelList.get(i).setItemNo(i + 1); |
|
|
|
|
|
|
|
// 判断数据是否变化:按itemNo匹配原数据,对比PN和数量 |
|
|
|
Integer itemNo = i + 1; |
|
|
|
EcssCoDelNotifyDetailData originalDetail = originalDataMap.get(itemNo); |
|
|
|
String pn = excelList.get(i).getPn(); |
|
|
|
BigDecimal originalTotalQty = originalPnQtyMap.get(pn); |
|
|
|
BigDecimal newTotalQty = newPnQtyMap.get(pn); |
|
|
|
|
|
|
|
// 判断是否有修改(包括新增、换料、数量变更) |
|
|
|
// 判断是否有修改(按PN比较总数量,避免因顺序变化误判) |
|
|
|
boolean isModified = false; |
|
|
|
boolean isQtyModified = false; |
|
|
|
|
|
|
|
if (originalDetail == null) { |
|
|
|
// 新增行:原数据中不存在该itemNo |
|
|
|
if (originalTotalQty == null) { |
|
|
|
// 新增PN:原数据中不存在该PN |
|
|
|
isModified = true; |
|
|
|
isQtyModified = true; |
|
|
|
} else if (!originalDetail.getPn().equals(excelList.get(i).getPn())) { |
|
|
|
// 换料:PN不同 |
|
|
|
isModified = true; |
|
|
|
isQtyModified = true; |
|
|
|
} else if (!originalDetail.getQty().equals(excelList.get(i).getQty())) { |
|
|
|
// 数量变更:PN相同但数量不同 |
|
|
|
log.info("检测到新增PN: {}, 数量: {}", pn, newTotalQty); |
|
|
|
} else if (originalTotalQty.compareTo(newTotalQty) != 0) { |
|
|
|
// 数量变更:PN存在但总数量不同 |
|
|
|
isModified = true; |
|
|
|
isQtyModified = true; |
|
|
|
log.info("检测到PN数量变更: {}, 原数量: {}, 新数量: {}", pn, originalTotalQty, newTotalQty); |
|
|
|
} |
|
|
|
// 其他情况:PN和数量都相同,无变化,isModified保持false |
|
|
|
// 其他情况:PN和总数量都相同,无变化,isModified保持false |
|
|
|
|
|
|
|
// 只有真正有变化的才标记modifyFlag=true |
|
|
|
excelList.get(i).setModifyFlag(isModified); |
|
|
|
@ -853,6 +1012,13 @@ public class CoDelServiceImpl implements CoDelService { |
|
|
|
excelList.get(i).setModifyQtyFlag(true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 检查是否有PN被删除(在原数据中存在但新数据中不存在) |
|
|
|
for (String originalPn : originalPnQtyMap.keySet()) { |
|
|
|
if (!newPnQtyMap.containsKey(originalPn)) { |
|
|
|
log.info("检测到PN被删除: {}, 原数量: {}", originalPn, originalPnQtyMap.get(originalPn)); |
|
|
|
} |
|
|
|
} |
|
|
|
coDelMapper.batchSaveEcssCoDelNotifyDetail(excelList); |
|
|
|
headerData.setModifyFlag(true); |
|
|
|
// 更新头表字段,包括ReadyDate、ShippingMode、Destination |
|
|
|
@ -3586,7 +3752,8 @@ public class CoDelServiceImpl implements CoDelService { |
|
|
|
} |
|
|
|
|
|
|
|
private static void deleteEmptyRow(XSSFSheet sheet) { |
|
|
|
for (int i = 0; i <= sheet.getLastRowNum(); i++) { |
|
|
|
// 从第三行开始遍历,检查每一行是否为空 |
|
|
|
for (int i = 2; i <= sheet.getLastRowNum(); i++) { |
|
|
|
XSSFRow row = sheet.getRow(i); |
|
|
|
boolean isEmptyRow = true; |
|
|
|
if (row != null) { |
|
|
|
|