diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/entity/ReservationDeliveryDetailsLink.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/entity/ReservationDeliveryDetailsLink.java index 9aeb5fc53..bb05c7873 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/entity/ReservationDeliveryDetailsLink.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/entity/ReservationDeliveryDetailsLink.java @@ -34,6 +34,9 @@ public class ReservationDeliveryDetailsLink extends BaseVOEntity { @ApiModelProperty(value = "客户编号") private String customerNumber; + @ApiModelProperty(value = "客户id") + private Long customerId; + @ApiModelProperty(value = "配送名称") private String deliveryName; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/po/ReservationDeliveryDetailsLinkPO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/po/ReservationDeliveryDetailsLinkPO.java index 498df9728..75e2dcecc 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/po/ReservationDeliveryDetailsLinkPO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/po/ReservationDeliveryDetailsLinkPO.java @@ -42,7 +42,8 @@ public class ReservationDeliveryDetailsLinkPO extends BaseVOEntity { @ApiModelProperty(value = "客户编号") private String customerNumber; - + @ApiModelProperty(value = "客户id") + private Long customerId; @ApiModelProperty(value = "配送名称") private String deliveryName; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/todo/ReservationDeliveryDetailsLinkDO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/todo/ReservationDeliveryDetailsLinkDO.java index ebd583b46..e54093ef5 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/todo/ReservationDeliveryDetailsLinkDO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationDeliveryDetailsLink/repository/todo/ReservationDeliveryDetailsLinkDO.java @@ -41,7 +41,8 @@ public class ReservationDeliveryDetailsLinkDO extends BaseVOEntity { @ApiModelProperty(value = "客户编号") private String customerNumber; - + @ApiModelProperty(value = "客户id") + private Long customerId; @ApiModelProperty(value = "配送名称") private String deliveryName; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/entity/ReservationInMaterialDetail.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/entity/ReservationInMaterialDetail.java index ddd677c15..84ffc560f 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/entity/ReservationInMaterialDetail.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/entity/ReservationInMaterialDetail.java @@ -63,6 +63,10 @@ public class ReservationInMaterialDetail extends BaseVOEntity { @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/po/ReservationInMaterialDetailPO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/po/ReservationInMaterialDetailPO.java index c3203fdf1..f6f111ea6 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/po/ReservationInMaterialDetailPO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/po/ReservationInMaterialDetailPO.java @@ -62,6 +62,10 @@ public class ReservationInMaterialDetailPO extends ReservationStockInOrderBasePO @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDO.java index a694c322c..9d95286ff 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDO.java @@ -60,6 +60,10 @@ public class ReservationInMaterialDetailDO extends ReservationStockInOrderBaseDO @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDTO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDTO.java index 35d6b5ce2..d46d7c2a4 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDTO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationInMaterialDetail/repository/todo/ReservationInMaterialDetailDTO.java @@ -63,6 +63,10 @@ public class ReservationInMaterialDetailDTO extends BaseVOEntity { @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/DynamicDeliveryExcelListener.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/DynamicDeliveryExcelListener.java index 72337c91f..9b898afb5 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/DynamicDeliveryExcelListener.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/DynamicDeliveryExcelListener.java @@ -17,14 +17,13 @@ import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** - * 维他奶出库Excel解析监听器(最终完整版) + * 维他奶出库Excel解析监听器(新模板版) + * 新模板特点:货品明细与客户配送明细左右分栏展示 * 核心功能: - * 1. 正确解析多单元格数据(解决发票张数/纪录合共读取错误) - * 2. 支持动态行数的货品明细/客户配送明细解析 + * 1. 左侧栏:第1-3行解析表头(送货日期/送货线号/车次),第5行解析纪录合共,第7行起解析货品明细 + * 2. 右侧栏:第2行解析发票张数/小计,第4行起解析客户配送明细 * 3. 自动处理文本型数字转换(String→Integer/BigDecimal) * 4. 完整的异常处理和日志记录 */ @@ -32,83 +31,101 @@ public class DynamicDeliveryExcelListener extends AnalysisEventListener productDetailList = new ArrayList<>(); - private List customerDeliveryDetailList = new ArrayList<>(); + private final DeliveryHeader deliveryHeader = new DeliveryHeader(); + private final List productDetailList = new ArrayList<>(); + private final List customerDeliveryDetailList = new ArrayList<>(); - // ---------------------- 解析状态管理(动态切换) ---------------------- - public enum ParseStatus { - IDLE, // 空闲状态(未进入任何表格) - PRODUCT_DETAIL,// 货品明细解析状态 - CUSTOMER_DETAIL// 客户配送明细解析状态 - } - private ParseStatus currentStatus = ParseStatus.IDLE; + // 当前行号(1-based,与Excel行号一致) + private int currentRowNum = 0; // ---------------------- 核心解析方法(EasyExcel回调) ---------------------- @Override public void invoke(Map data, AnalysisContext context) { + currentRowNum = context.readRowHolder().getRowIndex() + 1; try { - int rowNum = context.readRowHolder().getRowIndex() + 1; - LOGGER.debug("第{}行:开始解析,所有单元格数据:{}", rowNum, data); + LOGGER.debug("第{}行:开始解析,所有单元格数据:{}", currentRowNum, data); - // 1. 获取第一列数据(用于状态判断,标签通常在第一列) - String firstCellValue = getFirstCellValue(data); - LOGGER.debug("第{}行:第一列数据(状态判断依据):{}", rowNum, firstCellValue); + // 左侧区域解析(A-E列) + parseLeftSection(data); - // 2. 状态切换判断(传递完整data,支持多单元格解析) - if (isStatusSwitchTrigger(firstCellValue)) { - switchStatus(firstCellValue, rowNum, data); - return; - } - - // 3. 根据当前状态解析对应表格数据 - switch (currentStatus) { - case PRODUCT_DETAIL: - if (isValidProductDetailRow(data, firstCellValue)) { - parseProductDetail(data, rowNum); - } - break; - case CUSTOMER_DETAIL: - if (isValidCustomerDetailRow(data, firstCellValue)) { - parseCustomerDeliveryDetail(data, rowNum); - } - break; - case IDLE: - // 空闲状态:解析表头信息(送货日期行,多单元格数据) - if (firstCellValue.contains(KEYWORD_DELIVERY_DATE)) { - parseHeaderInfo(data, rowNum); - } - break; - } + // 右侧区域解析(F-M列) + parseRightSection(data); } catch (ExcelDataConvertException e) { - // Excel内置转换异常(如日期格式错误) - int rowNum = context.readRowHolder().getRowIndex() + 1; LOGGER.error("第{}行:Excel数据转换异常,列号:{},列名:{}", - rowNum, e.getColumnIndex() + 1, getColumnNameByIndex(data, e.getColumnIndex()), e); - throw new RuntimeException("Excel数据转换异常(行:" + rowNum + ",列:" + (e.getColumnIndex() + 1) + ")", e); + currentRowNum, e.getColumnIndex() + 1, getColumnNameByIndex(data, e.getColumnIndex()), e); + throw new RuntimeException("Excel数据转换异常(行:" + currentRowNum + ",列:" + (e.getColumnIndex() + 1) + ")", e); } catch (Exception e) { - // 其他解析异常 - int rowNum = context.readRowHolder().getRowIndex() + 1; - LOGGER.error("第{}行:Excel解析异常,所有单元格数据:{}", rowNum, data, e); - throw new RuntimeException("Excel解析异常(行:" + rowNum + ")", e); + LOGGER.error("第{}行:Excel解析异常,所有单元格数据:{}", currentRowNum, data, e); + throw new RuntimeException("Excel解析异常(行:" + currentRowNum + ")", e); + } + } + + // ---------------------- 左侧区域解析(货品相关信息) ---------------------- + private void parseLeftSection(Map data) { + switch (currentRowNum) { + case 1: + // 第1行:送货日期(A列=标签,B列=值) + parseDeliveryDate(data); + break; + case 2: + // 第2行:送货线号(A列=标签,B列=值) + parseDeliveryLineNo(data); + break; + case 3: + // 第3行:车次(A列=标签,B列=值) + parseTrainNumber(data); + break; + case 4: + // 第4行:货品明细标题行,无需解析 + LOGGER.debug("第{}行:货品明细标题行,跳过", currentRowNum); + break; + case 5: + // 第5行:纪录合共(A列=标签,B列=总记录数,D列=总箱数,E列=总支数) + parseTotalRecord(data); + break; + case 6: + // 第6行:货品明细列标题(貨品編號/簡稱/箱/支),跳过 + LOGGER.debug("第{}行:货品明细列标题行,跳过", currentRowNum); + break; + default: + // 第7行起:货品明细数据行(遇到空行自动结束) + if (currentRowNum >= 7 && isValidProductDetailRow(data)) { + parseProductDetail(data, currentRowNum); + } + break; + } + } + + // ---------------------- 右侧区域解析(客户配送相关信息) ---------------------- + private void parseRightSection(Map data) { + switch (currentRowNum) { + case 1: + // 第1行:客户配送明细标题行,无需解析 + LOGGER.debug("第{}行:客户配送明细标题行,跳过", currentRowNum); + break; + case 2: + // 第2行:发票张数/小计(F列=發票張數标签,G列=数值;J列=小計标签,K/L/M列=数值) + parseInvoiceCount(data); + break; + case 3: + // 第3行:客户配送明细列标题(類别/發票編號/客户編號/名稱/箱/包/金額),跳过 + LOGGER.debug("第{}行:客户配送明细列标题行,跳过", currentRowNum); + break; + default: + // 第4行起:客户配送明细数据行(遇到空行自动结束) + if (currentRowNum >= 4 && isValidCustomerDetailRow(data)) { + parseCustomerDeliveryDetail(data, currentRowNum); + } + break; } } @@ -116,8 +133,10 @@ public class DynamicDeliveryExcelListener extends AnalysisEventListener data) { - if (firstCellValue.contains(KEYWORD_PRODUCT_DETAIL)) { - currentStatus = ParseStatus.PRODUCT_DETAIL; - LOGGER.info("第{}行:检测到【{}】标签,切换到【货品明细】解析状态", rowNum, KEYWORD_PRODUCT_DETAIL); - } else if (firstCellValue.contains(KEYWORD_TOTAL_RECORD)) { - currentStatus = ParseStatus.IDLE; - parseTotalRecord(data, rowNum); // 解析纪录合共(多单元格) - LOGGER.info("第{}行:检测到【{}】标签,切换到【空闲】状态,已解析货品明细{}条", - rowNum, KEYWORD_TOTAL_RECORD, productDetailList.size()); - } else if (firstCellValue.contains(KEYWORD_CUSTOMER_DETAIL)) { - currentStatus = ParseStatus.CUSTOMER_DETAIL; - LOGGER.info("第{}行:检测到【{}】标签,切换到【客户配送明细】解析状态", rowNum, KEYWORD_CUSTOMER_DETAIL); - } else if (firstCellValue.contains(KEYWORD_INVOICE_COUNT)) { - currentStatus = ParseStatus.IDLE; - parseInvoiceCount(data, rowNum); // 解析发票张数(多单元格,核心修复) - LOGGER.info("第{}行:检测到【{}】标签,切换到【空闲】状态,已解析客户配送明细{}条", - rowNum, KEYWORD_INVOICE_COUNT, customerDeliveryDetailList.size()); + // ---------------------- 左侧:表头信息解析 ---------------------- + private void parseDeliveryDate(Map data) { + Object value = getValueSafely(data, 1); // B列 + if (value != null) { + Date deliveryDate = convertToDate(value); + deliveryHeader.setDeliveryDate(deliveryDate); + LOGGER.debug("第{}行:送货日期解析完成,值={}", currentRowNum, deliveryDate); } } - // ---------------------- 数据有效性校验方法 ---------------------- + private void parseDeliveryLineNo(Map data) { + Object value = getValueSafely(data, 1); // B列 + if (value != null) { + String deliveryLineNo = value.toString().trim(); + deliveryHeader.setDeliveryLineNo(deliveryLineNo); + LOGGER.debug("第{}行:送货线号解析完成,值={}", currentRowNum, deliveryLineNo); + } + } + + private void parseTrainNumber(Map data) { + Object value = getValueSafely(data, 1); // B列 + Integer trainNumber = convertToInteger(value); + deliveryHeader.setTrainNumber(trainNumber); + LOGGER.debug("第{}行:车次解析完成,值={}", currentRowNum, trainNumber); + } + + // ---------------------- 左侧:纪录合共解析 ---------------------- + /** + * 第5行:纪录合共 + * 列对应关系:0=A列=紀錄合共标签,1=B列=总记录数,3=D列=总箱数,4=E列=总支数 + */ + private void parseTotalRecord(Map data) { + Object totalRecordLabel = getValueSafely(data, 0); + if (totalRecordLabel == null || !totalRecordLabel.toString().trim().contains(KEYWORD_TOTAL_RECORD)) { + LOGGER.warn("第{}行:不是纪录合共行,跳过解析,第一列内容:{}", currentRowNum, totalRecordLabel); + return; + } + + Integer totalRecordCount = convertToInteger(getValueSafely(data, 1)); // B列 + Integer totalBoxCount = convertToInteger(getValueSafely(data, 3)); // D列 + Integer totalPieceCount = convertToInteger(getValueSafely(data, 4)); // E列 + + deliveryHeader.setTotalRecordCount(totalRecordCount); + deliveryHeader.setTotalBoxCount(totalBoxCount); + deliveryHeader.setTotalPieceCount(totalPieceCount); + + LOGGER.debug("第{}行:解析纪录合共完成,总记录数={},总箱数={},总支数={}", + currentRowNum, totalRecordCount, totalBoxCount, totalPieceCount); + } + + // ---------------------- 左侧:货品明细解析 ---------------------- /** * 校验货品明细行是否有效(排除表头和空行) */ - private boolean isValidProductDetailRow(Map data, String firstCellValue) { - // 有效条件:1.货品编号(第一列)不为空 2.不是表头行(表头第一列是"貨品編號") - Object productCode = getValueSafely(data, 0); + private boolean isValidProductDetailRow(Map data) { + Object productCode = getValueSafely(data, 0); // A列 return productCode != null - && !"貨品編號".equals(productCode.toString().trim()) - && !productCode.toString().trim().isEmpty(); + && !productCode.toString().trim().isEmpty() + && !"貨品編號".equals(productCode.toString().trim()); } + /** + * 解析货品明细(第7行起) + * 列对应关系:0=A列=貨品編號,1=B列=簡稱,2=C列=箱,3=D列=支 + */ + private void parseProductDetail(Map data, int rowNum) { + ProductDetail productDetail = new ProductDetail(); + productDetail.setProductCode(convertToString(getValueSafely(data, 0))); + productDetail.setProductName(convertToString(getValueSafely(data, 1))); + productDetail.setBoxCount(convertToInteger(getValueSafely(data, 2))); + productDetail.setPieceCount(convertToInteger(getValueSafely(data, 3))); + + productDetailList.add(productDetail); + LOGGER.debug("第{}行:解析货品明细完成,货品编号={},名称={},箱数={},支数={}", + rowNum, productDetail.getProductCode(), productDetail.getProductName(), + productDetail.getBoxCount(), productDetail.getPieceCount()); + } + + // ---------------------- 右侧:发票张数与小计解析 ---------------------- + /** + * 第2行:发票张数与小计 + * 通过关键字定位标签,再读取右侧相邻列,避免空列导致索引偏移 + */ + private void parseInvoiceCount(Map data) { + // 1. 定位并解析发票张数 + Integer invoiceCount = findValueAfterKeyword(data, KEYWORD_INVOICE_COUNT); + if (invoiceCount != null) { + deliveryHeader.setInvoiceCount(invoiceCount); + } + + // 2. 定位并解析小计(标签右侧第1列=箱,第2列=支,第3列=金额) + Integer subtotalStartIndex = findKeywordIndex(data, KEYWORD_SUBTOTAL); + if (subtotalStartIndex != null && subtotalStartIndex >= 0) { + Integer subtotalBoxCount = convertToInteger(getValueSafely(data, subtotalStartIndex + 1)); + Integer subtotalPieceCount = convertToInteger(getValueSafely(data, subtotalStartIndex + 2)); + BigDecimal subtotalAmount = convertToBigDecimal(getValueSafely(data, subtotalStartIndex + 3)); + + deliveryHeader.setSubtotalBoxCount(subtotalBoxCount); + deliveryHeader.setSubtotalPieceCount(subtotalPieceCount); + deliveryHeader.setSubtotalAmount(subtotalAmount); + + LOGGER.debug("第{}行:解析小计完成,箱数={},支数={},金额={}", + currentRowNum, subtotalBoxCount, subtotalPieceCount, subtotalAmount); + } else { + LOGGER.warn("第{}行:未找到小计标签,小计信息置空", currentRowNum); + deliveryHeader.setSubtotalBoxCount(0); + deliveryHeader.setSubtotalPieceCount(0); + deliveryHeader.setSubtotalAmount(BigDecimal.ZERO); + } + + LOGGER.debug("第{}行:解析发票张数行完成,发票张数={},小计金额={}", + currentRowNum, deliveryHeader.getInvoiceCount(), deliveryHeader.getSubtotalAmount()); + } + + // ---------------------- 右侧:客户配送明细解析 ---------------------- /** * 校验客户配送明细行是否有效(排除表头和空行) */ - private boolean isValidCustomerDetailRow(Map data, String firstCellValue) { - // 有效条件:1.类别(第一列)不为空 2.不是表头行(表头第一列是"類别") - Object category = getValueSafely(data, 0); + private boolean isValidCustomerDetailRow(Map data) { + Object category = getValueSafely(data, 5); // F列 return category != null - && !"類别".equals(category.toString().trim()) - && !category.toString().trim().isEmpty(); - } - - // ---------------------- 具体数据解析方法(全部支持多单元格) ---------------------- - /** - * 解析表头信息(送货日期、送货线号、车次) - * 列对应关系:0=送貨日期标签,1=送貨日期值,2=送貨線號标签,3=送貨線號值,4=車次标签,5=車次值 - */ - private void parseHeaderInfo(Map data, int rowNum) { - try { - // 读取多单元格数据(标签在左,数值在右) - Date deliveryDate = getValueSafely(data, 1, Date.class); // 第2列:送货日期值 - String deliveryLineNo = getValueSafely(data, 3, String.class); // 第4列:送货线号值 - Integer trainNumber = getValueSafely(data, 5, Integer.class); // 第6列:车次值 - - // 赋值(空值处理) - if (deliveryDate != null) { - deliveryHeader.setDeliveryDate(deliveryDate); - } - deliveryHeader.setDeliveryLineNo(deliveryLineNo); - deliveryHeader.setTrainNumber(getDefaultValue(trainNumber, 0)); - - LOGGER.debug("第{}行:解析表头信息完成,送货日期={},送货线号={},车次={}", - rowNum, deliveryHeader.getDeliveryDate(), - deliveryHeader.getDeliveryLineNo(), deliveryHeader.getTrainNumber()); - } catch (Exception e) { - LOGGER.error("第{}行:解析表头信息失败,所有单元格数据:{}", rowNum, data, e); - throw new RuntimeException("解析表头信息失败(行:" + rowNum + ")", e); - } + && !category.toString().trim().isEmpty() + && !"類别".equals(category.toString().trim()); } /** - * 解析纪录合共(多单元格版) - * 列对应关系:0=紀錄合共标签,1=总记录数值,4=總計标签,5=总箱数值,6=总支数值 - */ - private void parseTotalRecord(Map data, int rowNum) { - try { - // 1. 验证是否为纪录合共行(第一列包含标签) - Object totalRecordLabel = getValueSafely(data, 0, String.class); - if (totalRecordLabel == null || !totalRecordLabel.toString().trim().contains(KEYWORD_TOTAL_RECORD)) { - LOGGER.warn("第{}行:不是纪录合共行,跳过解析,第一列内容:{}", rowNum, totalRecordLabel); - return; - } - - // 2. 读取多单元格数值(标签右侧对应列) - Integer totalRecordCount = getValueSafely(data, 1, Integer.class); // 第2列:总记录数 - Integer totalBoxCount = getValueSafely(data, 5, Integer.class); // 第6列:总箱数 - Integer totalPieceCount = getValueSafely(data, 6, Integer.class); // 第7列:总支数 - - // 3. 赋值与日志 - deliveryHeader.setTotalRecordCount(getDefaultValue(totalRecordCount, 0)); - deliveryHeader.setTotalBoxCount(getDefaultValue(totalBoxCount, 0)); - deliveryHeader.setTotalPieceCount(getDefaultValue(totalPieceCount, 0)); - - LOGGER.debug("第{}行:解析纪录合共完成,总记录数={},总箱数={},总支数={}", - rowNum, deliveryHeader.getTotalRecordCount(), - deliveryHeader.getTotalBoxCount(), deliveryHeader.getTotalPieceCount()); - } catch (Exception e) { - LOGGER.error("第{}行:解析纪录合共失败,所有单元格数据:{}", rowNum, data, e); - throw new RuntimeException("解析纪录合共失败(行:" + rowNum + ")", e); - } - } - - /** - * 核心修复:解析发票张数(多单元格版,正确读取右侧单元格) - * 列对应关系: - * - 0=發票張數标签列(A列),1=发票张数数值列(B列) - * - 4=小計标签列(E列),5=小计箱数列(F列),6=小计支数列(G列),7=小计金额列(H列) - */ - private void parseInvoiceCount(Map data, int rowNum) { - try { - // 1. 验证是否为发票张数行(第一列包含标签) - Object invoiceLabel = getValueSafely(data, 0, String.class); - if (invoiceLabel == null || !invoiceLabel.toString().trim().contains(KEYWORD_INVOICE_COUNT)) { - LOGGER.warn("第{}行:不是发票张数行,跳过解析,第一列内容:{}", rowNum, invoiceLabel); - return; - } - - // 2. 解析发票张数(标签右侧第1列:B列,索引1) - Integer invoiceCount = getValueSafely(data, 1, Integer.class); - deliveryHeader.setInvoiceCount(getDefaultValue(invoiceCount, 0)); - LOGGER.debug("第{}行:解析发票张数,标签列(A列):{},数值列(B列):{}", - rowNum, invoiceLabel, deliveryHeader.getInvoiceCount()); - - // 3. 解析小计信息(标签在E列,数值在F/G/H列) - Object subtotalLabel = getValueSafely(data, 3, String.class); // E列:小計标签 - if (subtotalLabel != null && subtotalLabel.toString().trim().contains(KEYWORD_SUBTOTAL)) { - Integer subtotalBoxCount = getValueSafely(data, 4, Integer.class); // F列:小计箱数 - Integer subtotalPieceCount = getValueSafely(data, 5, Integer.class); // G列:小计支数 - BigDecimal subtotalAmount = getValueSafely(data, 6, BigDecimal.class); // H列:小计金额 - - // 赋值(空值处理) - deliveryHeader.setSubtotalBoxCount(getDefaultValue(subtotalBoxCount, 0)); - deliveryHeader.setSubtotalPieceCount(getDefaultValue(subtotalPieceCount, 0)); - deliveryHeader.setSubtotalAmount(getDefaultValue(subtotalAmount, BigDecimal.ZERO)); - - LOGGER.debug("第{}行:解析小计信息,标签列(E列):{},箱数列(F列):{},支数列(G列):{},金额列(H列):{}", - rowNum, subtotalLabel, - deliveryHeader.getSubtotalBoxCount(), - deliveryHeader.getSubtotalPieceCount(), - deliveryHeader.getSubtotalAmount()); - } else { - LOGGER.warn("第{}行:未找到小计标签(E列),或标签内容不匹配,跳过小计解析", rowNum); - deliveryHeader.setSubtotalBoxCount(0); - deliveryHeader.setSubtotalPieceCount(0); - deliveryHeader.setSubtotalAmount(BigDecimal.ZERO); - } - - // 4. 解析完成日志 - LOGGER.debug("第{}行:解析发票张数行完成,最终结果:发票张数={},小计金额={}", - rowNum, deliveryHeader.getInvoiceCount(), deliveryHeader.getSubtotalAmount()); - } catch (Exception e) { - LOGGER.error("第{}行:解析发票张数失败,所有单元格数据:{}", rowNum, data, e); - throw new RuntimeException("解析发票张数失败(行:" + rowNum + "),请检查Excel列对应关系", e); - } - } - - /** - * 解析货品明细(多单元格,动态行数适配) - * 列对应关系:0=貨品編號,1=簡稱,4=箱,5=支 - */ - private void parseProductDetail(Map data, int rowNum) { - try { - ProductDetail productDetail = new ProductDetail(); - // 读取对应列的多单元格数据 - String productCode = getValueSafely(data, 0, String.class); // 第1列:货品编号 - String productName = getValueSafely(data, 1, String.class); // 第2列:货品简称 - Integer boxCount = getValueSafely(data, 4, Integer.class); // 第5列:箱数 - Integer pieceCount = getValueSafely(data, 5, Integer.class); // 第6列:支数 - - // 赋值(空值处理+去空格) - productDetail.setProductCode(getDefaultValue(productCode, "").trim()); - productDetail.setProductName(getDefaultValue(productName, "").trim()); - productDetail.setBoxCount(getDefaultValue(boxCount, 0)); - productDetail.setPieceCount(getDefaultValue(pieceCount, 0)); - - // 添加到列表 - productDetailList.add(productDetail); - LOGGER.debug("第{}行:解析货品明细完成,货品编号={},名称={},箱数={},支数={}", - rowNum, productDetail.getProductCode(), productDetail.getProductName(), - productDetail.getBoxCount(), productDetail.getPieceCount()); - } catch (Exception e) { - LOGGER.error("第{}行:解析货品明细失败,所有单元格数据:{}", rowNum, data, e); - throw new RuntimeException("解析货品明细失败(行:" + rowNum + ")", e); - } - } - - /** - * 解析客户配送明细(多单元格,动态行数适配) - * 列对应关系:0=類别,1=發票編號,2=客户編號,3=名稱,4=箱,5=包,6=金額 + * 解析客户配送明细(第4行起) + * 列对应关系:5=F列=類别,6=G列=發票編號,7=H列=客户編號,8=I列=名稱, + * 9=J列=箱,10=K列=包,11=L列=金額 */ private void parseCustomerDeliveryDetail(Map data, int rowNum) { - try { - CustomerDeliveryDetail customerDetail = new CustomerDeliveryDetail(); - // 读取对应列的多单元格数据 - String category = getValueSafely(data, 0, String.class); // 第1列:类别 - String invoiceNo = getValueSafely(data, 1, String.class); // 第2列:发票编号 - String customerCode = getValueSafely(data, 2, String.class); // 第3列:客户编号 - String customerName = getValueSafely(data, 3, String.class); // 第4列:客户名称 - Integer boxCount = getValueSafely(data, 4, Integer.class); // 第5列:箱数 - Integer packageCount = getValueSafely(data, 5, Integer.class); // 第6列:包数 - BigDecimal amount = getValueSafely(data, 6, BigDecimal.class); // 第7列:金额 + CustomerDeliveryDetail customerDetail = new CustomerDeliveryDetail(); + customerDetail.setCategory(convertToString(getValueSafely(data, 5))); + customerDetail.setInvoiceNo(convertToString(getValueSafely(data, 6))); + customerDetail.setCustomerCode(convertToString(getValueSafely(data, 7))); + customerDetail.setCustomerName(convertToString(getValueSafely(data, 8))); + customerDetail.setBoxCount(convertToInteger(getValueSafely(data, 9))); + customerDetail.setPackageCount(convertToInteger(getValueSafely(data, 10))); + customerDetail.setAmount(convertToBigDecimal(getValueSafely(data, 11))); - // 赋值(空值处理+去空格) - customerDetail.setCategory(getDefaultValue(category, "").trim()); - customerDetail.setInvoiceNo(getDefaultValue(invoiceNo, "").trim()); - customerDetail.setCustomerCode(getDefaultValue(customerCode, "").trim()); - customerDetail.setCustomerName(getDefaultValue(customerName, "").trim()); - customerDetail.setBoxCount(getDefaultValue(boxCount, 0)); - customerDetail.setPackageCount(getDefaultValue(packageCount, 0)); - customerDetail.setAmount(getDefaultValue(amount, BigDecimal.ZERO)); - - // 添加到列表 - customerDeliveryDetailList.add(customerDetail); - LOGGER.debug("第{}行:解析客户配送明细完成,客户编号={},名称={},金额={}", - rowNum, customerDetail.getCustomerCode(), customerDetail.getCustomerName(), - customerDetail.getAmount()); - } catch (Exception e) { - LOGGER.error("第{}行:解析客户配送明细失败,所有单元格数据:{}", rowNum, data, e); - throw new RuntimeException("解析客户配送明细失败(行:" + rowNum + ")", e); - } + customerDeliveryDetailList.add(customerDetail); + LOGGER.debug("第{}行:解析客户配送明细完成,类别={},发票编号={},客户编号={},名称={},箱数={},包数={},金额={}", + rowNum, customerDetail.getCategory(), customerDetail.getInvoiceNo(), + customerDetail.getCustomerCode(), customerDetail.getCustomerName(), + customerDetail.getBoxCount(), customerDetail.getPackageCount(), customerDetail.getAmount()); } // ---------------------- 核心工具方法(支持多单元格+类型转换) ---------------------- /** - * 获取第一列数据(用于状态判断) + * 根据列索引安全获取值 + * 优先按Map的key直接查找(适配EasyExcel以列号为key的情况),找不到再按位置顺序查找 + * 注意:EasyExcel在某些情况下(如合并单元格、headRowNumber=0)可能将表头文本作为key, + * 此时key不是数字字符串,需跳过这些key,走位置兜底逻辑 */ - private String getFirstCellValue(Map data) { + private Object getValueSafely(Map data, int columnIndex) { if (data == null || data.isEmpty()) { - return ""; + return null; } - Object firstValue = data.values().iterator().next(); - return firstValue != null ? firstValue.toString().trim() : ""; + + String strIndex = String.valueOf(columnIndex); + // 1. 直接按key查找(兼容key为String或Integer的情况,跳过非数字key) + for (Object keyObj : data.keySet()) { + if (keyObj != null && strIndex.equals(keyObj.toString())) { + return data.get(keyObj); + } + } + + // 2. 兜底:按顺序位置查找(保持与原逻辑兼容) + int index = 0; + for (Object value : data.values()) { + if (index == columnIndex) { + return value; + } + index++; + } + + LOGGER.warn("第{}行列索引{}超出当前行单元格数量({}列),返回null", + currentRowNum, columnIndex, data.size()); + return null; } /** @@ -392,115 +343,121 @@ public class DynamicDeliveryExcelListener extends AnalysisEventListener data, int columnIndex) { - if (data == null || data.isEmpty()) { + private Integer findKeywordIndex(Map data, String keyword) { + if (data == null || data.isEmpty() || keyword == null) { return null; } - int index = 0; - for (Object value : data.values()) { - if (index == columnIndex) { - return value; + for (Object keyObj : data.keySet()) { + Object value = data.get(keyObj); + if (value != null && value.toString().trim().contains(keyword)) { + try { + return Integer.parseInt(keyObj.toString()); + } catch (NumberFormatException e) { + // key不是数字(可能是表头文本如"客户配送明细"),跳过,不打印警告避免日志刷屏 + LOGGER.debug("第{}行:关键字'{}'所在列key不是数字,key={},跳过", + currentRowNum, keyword, keyObj); + } } - index++; } - LOGGER.warn("列索引{}超出当前行单元格数量({}列),返回null", columnIndex, data.size()); return null; } /** - * 按列索引安全获取值(支持多类型转换,核心工具) - * 功能:1. 直接类型匹配 2. String转数字/日期 3. 数字类型间转换 + * 查找关键字所在列的右侧相邻列值,并转为Integer */ - private T getValueSafely(Map data, int columnIndex, Class expectedType) { - Object value = getValueSafely(data, columnIndex); - if (value == null) { - LOGGER.debug("列索引{}:单元格值为null,返回null", columnIndex); + private Integer findValueAfterKeyword(Map data, String keyword) { + Integer keywordIndex = findKeywordIndex(data, keyword); + if (keywordIndex == null) { + LOGGER.warn("第{}行:未找到关键字'{}'", currentRowNum, keyword); return null; } + return convertToInteger(getValueSafely(data, keywordIndex + 1)); + } - // 1. 直接类型匹配 - if (expectedType.isInstance(value)) { - return expectedType.cast(value); + /** + * Object转String + */ + private String convertToString(Object value) { + return value == null ? "" : value.toString().trim(); + } + + /** + * Object转Integer(支持文本型数字、Number类型) + */ + private Integer convertToInteger(Object value) { + if (value == null) { + return 0; + } + if (value instanceof Number) { + return ((Number) value).intValue(); } - - // 2. String类型转目标类型(核心:处理文本型数字) if (value instanceof String) { String strValue = ((String) value).trim(); if (strValue.isEmpty()) { - LOGGER.debug("列索引{}:单元格值为空字符串,返回null", columnIndex); - return null; + return 0; } - - // String → Integer - if (expectedType == Integer.class) { - try { - return expectedType.cast(Integer.parseInt(strValue)); - } catch (NumberFormatException e) { - LOGGER.warn("列索引{}:String转Integer失败,原始值:{}", columnIndex, strValue, e); - return null; - } - } - - // String → Long - if (expectedType == Long.class) { - try { - return expectedType.cast(Long.parseLong(strValue)); - } catch (NumberFormatException e) { - LOGGER.warn("列索引{}:String转Long失败,原始值:{}", columnIndex, strValue, e); - return null; - } - } - - // String → BigDecimal(支持千分位符号,如"1,234.56") - if (expectedType == BigDecimal.class) { - try { - String cleanValue = strValue.replace(",", ""); // 去除千分位逗号 - return expectedType.cast(new BigDecimal(cleanValue)); - } catch (NumberFormatException e) { - LOGGER.warn("列索引{}:String转BigDecimal失败,原始值:{}", columnIndex, strValue, e); - return null; - } - } - - // String → Date(支持多种日期格式) - if (expectedType == Date.class) { - try { - return expectedType.cast(DateUtils.parseDate(strValue, SUPPORTED_DATE_FORMATS)); - } catch (ParseException e) { - LOGGER.warn("列索引{}:String转Date失败,原始值:{},支持格式:{}", - columnIndex, strValue, Arrays.toString(SUPPORTED_DATE_FORMATS), e); - return null; - } + try { + return Integer.parseInt(strValue); + } catch (NumberFormatException e) { + LOGGER.warn("第{}行:值转换为Integer失败,值:{},返回0", currentRowNum, value, e); } } - - // 3. 数字类型间转换(如Double→Integer,Long→BigDecimal) - if (value instanceof Number) { - Number numValue = (Number) value; - if (expectedType == Integer.class) { - return expectedType.cast(numValue.intValue()); - } - if (expectedType == Long.class) { - return expectedType.cast(numValue.longValue()); - } - if (expectedType == BigDecimal.class) { - return expectedType.cast(new BigDecimal(numValue.toString())); - } - } - - // 4. 不支持的转换 - LOGGER.warn("列索引{}:不支持的类型转换,期望类型:{},实际类型:{},原始值:{}", - columnIndex, expectedType.getSimpleName(), value.getClass().getSimpleName(), value); - return null; + return 0; } /** - * 空值处理:返回默认值 + * Object转BigDecimal(支持千分位符号,如"1,234.56") */ - private T getDefaultValue(T value, T defaultValue) { - return value != null ? value : defaultValue; + private BigDecimal convertToBigDecimal(Object value) { + if (value == null) { + return BigDecimal.ZERO; + } + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } + if (value instanceof Number) { + return new BigDecimal(value.toString()); + } + if (value instanceof String) { + String strValue = ((String) value).trim().replace(",", ""); + if (strValue.isEmpty()) { + return BigDecimal.ZERO; + } + try { + return new BigDecimal(strValue); + } catch (NumberFormatException e) { + LOGGER.warn("第{}行:值转换为BigDecimal失败,值:{},返回0", currentRowNum, value, e); + } + } + return BigDecimal.ZERO; + } + + /** + * Object转Date(支持Date类型、String类型) + */ + private Date convertToDate(Object value) { + if (value == null) { + return null; + } + if (value instanceof Date) { + return (Date) value; + } + if (value instanceof String) { + String strValue = ((String) value).trim(); + if (strValue.isEmpty()) { + return null; + } + try { + return DateUtils.parseDate(strValue, SUPPORTED_DATE_FORMATS); + } catch (ParseException e) { + LOGGER.warn("第{}行:值转换为Date失败,值:{},支持格式:{}", + currentRowNum, strValue, Arrays.toString(SUPPORTED_DATE_FORMATS), e); + } + } + return null; } // ---------------------- Getter方法(供Service层获取解析结果) ---------------------- @@ -515,4 +472,4 @@ public class DynamicDeliveryExcelListener extends AnalysisEventListener getCustomerDeliveryDetailList() { return customerDeliveryDetailList; } -} \ No newline at end of file +} diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/StockInExcelListener.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/StockInExcelListener.java index 1d9300a52..c9ca998ce 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/StockInExcelListener.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/listener/StockInExcelListener.java @@ -17,7 +17,7 @@ import java.util.Map; /** * 入库单Excel解析监听器 - * 功能:1. 解析第一行表头数据 2. 解析第二行开始的产品明细 3. 支持文本型数字转换 + * 功能:1. 解析第一行表头数据 2. 跳过第二行合计行、第三行列名行 3. 解析第四行开始的产品明细 4. 支持文本型数字转换 */ public class StockInExcelListener extends AnalysisEventListener> { private static final Logger LOGGER = LoggerFactory.getLogger(StockInExcelListener.class); @@ -44,8 +44,16 @@ public class StockInExcelListener extends AnalysisEventListener= 3) { + // 2. 跳过第二行:合计行(Total: xxx) + else if (currentRowNum == 2) { + LOGGER.debug("第{}行是合计行,跳过解析", currentRowNum); + } + // 3. 跳过第三行:表格列名行(產品編號、產品名稱...) + else if (currentRowNum == 3) { + LOGGER.debug("第{}行是表格列名行,跳过解析", currentRowNum); + } + // 4. 解析第四行及以后:产品明细 + else if (currentRowNum >= 4) { if (isValidProductRow(data)) { StockInProductDetail detail = parseProductDetail(data); productDetailList.add(detail); @@ -66,19 +74,19 @@ public class StockInExcelListener extends AnalysisEventListener data) { - // 入库日期(第2列,索引1) - Object stockInDateObj = getValueSafely(data, 1); + // 入库日期:查找包含"入库日期"标签的下一个值 + Object stockInDateObj = getValueAfterLabel(data, "入库日期"); if (stockInDateObj != null) { Date stockInDate = convertToDate(stockInDateObj); stockInHeader.setStockInDate(stockInDate); LOGGER.debug("第1行:入库日期解析完成,值:{}", stockInDate); } - // OrderNO(第4列,索引3) - Object orderNoObj = getValueSafely(data, 3); + // OrderNO:查找包含"OrderNO"标签的下一个值 + Object orderNoObj = getValueAfterLabel(data, "OrderNO"); if (orderNoObj != null) { String orderNo = orderNoObj.toString().trim(); stockInHeader.setOrderNo(orderNo); @@ -86,7 +94,7 @@ public class StockInExcelListener extends AnalysisEventListener data) { StockInProductDetail detail = new StockInProductDetail(); // 产品编号(第1列,索引0)- 支持文本型数字转换 - detail.setProductCode(convertToString(getValueSafely(data, 0)).toString()); + detail.setProductCode(convertToString(getValueSafely(data, 0))); // 产品名称(第2列,索引1) detail.setProductName(convertToString(getValueSafely(data, 1))); - // 箱含量(第5列,索引4) - detail.setBoxCapacity(convertToInteger(getValueSafely(data, 4))); - // 件数(第6列,索引5) - detail.setPieceCount(convertToInteger(getValueSafely(data, 5))); - // 箱数(第7列,索引6) - detail.setBoxCount(convertToInteger(getValueSafely(data, 6))); - // 饮用日期(第8列,索引7) - detail.setDrinkDate(convertToDate(getValueSafely(data, 7))); + // 箱含量/规格(第3列,索引2) + detail.setBoxCapacity(convertToInteger(getValueSafely(data, 2))); + // 件数(第4列,索引3) + detail.setPieceCount(convertToInteger(getValueSafely(data, 3))); + // 箱数/Qty(cases)(第5列,索引4) + detail.setBoxCount(convertToInteger(getValueSafely(data, 4))); + // 饮用日期(第6列,索引5) + detail.setDrinkDate(convertToDate(getValueSafely(data, 5))); LOGGER.debug("第{}行产品明细解析完成,产品编号:{},产品名称:{}", currentRowNum, detail.getProductCode(), detail.getProductName()); @@ -120,12 +129,11 @@ public class StockInExcelListener extends AnalysisEventListener data) { - // 有效条件:产品编号不为空 + 不是合计行(合计行产品编号为null,且包含"Total") + // 有效条件:产品编号不为空 + 不是合计行 Object productCodeObj = getValueSafely(data, 0); - Object productNameObj = getValueSafely(data, 1); - // 排除合计行(如第7行:Total:68) - if (productNameObj != null && productNameObj.toString().contains("Total")) { + // 排除合计行(整行包含"Total"字样) + if (containsAnyValue(data, "Total")) { LOGGER.debug("第{}行是合计行,跳过解析", currentRowNum); return false; } @@ -186,6 +194,40 @@ public class StockInExcelListener extends AnalysisEventListener data, String label) { + if (data == null || data.isEmpty()) { + return null; + } + + Object prevValue = null; + for (Object value : data.values()) { + if (prevValue != null && prevValue.toString().contains(label)) { + return value; + } + prevValue = value; + } + + return null; + } + + /** + * 判断当前行是否有任意单元格包含指定文本 + */ + private boolean containsAnyValue(Map data, String text) { + if (data == null || data.isEmpty()) { + return false; + } + for (Object value : data.values()) { + if (value != null && value.toString().contains(text)) { + return true; + } + } + return false; + } + /** * 通用转换:Object转String */ diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java index d1d948da4..67f9b4558 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/persistence/ReservationStockInOrderImpl.java @@ -174,9 +174,21 @@ public class ReservationStockInOrderImpl extends ServiceImpl productDetailList = deliveryDataDTO.getProductDetailList(); + // 判空处理:货品明细和客户配送明细可能为空列表 + List productDetailList = listener.getProductDetailList(); + if (productDetailList == null) { + productDetailList = new ArrayList<>(); + } + deliveryDataDTO.setProductDetailList(productDetailList); + List customerDeliveryDetailList = listener.getCustomerDeliveryDetailList(); + if (customerDeliveryDetailList == null) { + customerDeliveryDetailList = new ArrayList<>(); + } + deliveryDataDTO.setCustomerDeliveryDetailList(customerDeliveryDetailList); + + LOGGER.info("Excel解析完成,货品明细{}条,客户配送明细{}条", + productDetailList.size(), customerDeliveryDetailList.size()); + List> shipperIds = new ArrayList<>(); Set processedShipperIds = new HashSet<>(); for (ProductDetail productDetail : productDetailList) { @@ -192,20 +204,25 @@ public class ReservationStockInOrderImpl extends ServiceImpl 1) { - throw new Exception("出库物料不是同一个货主!"); + // 货品明细不为空时,校验货主信息 + if (!productDetailList.isEmpty()) { + if (shipperIds.isEmpty()) { + throw new Exception("出库物料货主不存在!"); + } + if (shipperIds.size() > 1) { + throw new Exception("出库物料不是同一个货主!"); + } } ReservationStockOutOrderDO reservationStockOutOrderDO = new ReservationStockOutOrderDO(); reservationStockOutOrderDO.setOutOrderNumber(OrderSequence.getOrderCode("CK")); - reservationStockOutOrderDO.setShipperId((Long) shipperIds.get(0).get("shipperId")); - reservationStockOutOrderDO.setShipperName((String) shipperIds.get(0).get("shipperName")); - reservationStockOutOrderDO.setShipperCode((String) shipperIds.get(0).get("shipperCode")); + // 货主信息:有货品明细时从解析结果取,无货品明细时从登录用户取 + if (!shipperIds.isEmpty()) { + reservationStockOutOrderDO.setShipperId((Long) shipperIds.get(0).get("shipperId")); + reservationStockOutOrderDO.setShipperName((String) shipperIds.get(0).get("shipperName")); + reservationStockOutOrderDO.setShipperCode((String) shipperIds.get(0).get("shipperCode")); + } reservationStockOutOrderDO.setNeedTransportFlag("1"); reservationStockOutOrderDO.setNeedDeclareFlag("1"); reservationStockOutOrderDO.setOrganizationId(loginUser.getUserPo().getOrganizationId()); @@ -267,7 +284,7 @@ public class ReservationStockInOrderImpl extends ServiceImpl customerDeliveryDetailList = deliveryDataDTO.getCustomerDeliveryDetailList(); + // 客户配送明细判空处理:为空时跳过关联保存 for (CustomerDeliveryDetail customerDeliveryDetail : customerDeliveryDetailList) { ReservationDeliveryDetailsLink reservationDeliveryDetailsLink = new ReservationDeliveryDetailsLink(); reservationDeliveryDetailsLink.setInvoiceNumber(customerDeliveryDetail.getInvoiceNo()); @@ -388,7 +405,7 @@ public class ReservationStockInOrderImpl extends ServiceImpl materialDetailList = stockOutOrderPO.getMaterialDetailList(); - if (CollectionUtils.isEmpty(materialDetailList)) { - for (ReservationOutMaterialDetailPO reservationOutMaterialDetailPO : materialDetailList) { - reservationOutMaterialDetailPO.setKhdm(userNcCode); + if (stockOutOrderPO.getMaterialDetailList() != null && stockOutOrderPO.getMaterialDetailList().size() > 0) { + List materialDetailList = stockOutOrderPO.getMaterialDetailList(); + if (CollectionUtils.isEmpty(materialDetailList)) { + for (ReservationOutMaterialDetailPO reservationOutMaterialDetailPO : materialDetailList) { + reservationOutMaterialDetailPO.setKhdm(userNcCode); + } + stockOutOrderPO.setMaterialDetailList(materialDetailList); } - stockOutOrderPO.setMaterialDetailList(materialDetailList); - } - List detailList = stockOutOrderPO.getMaterialDetailList(); - String outOrderNumber = stockOutOrderPO.getOutOrderNumber(); - for (ReservationOutMaterialDetailPO reservationOutMaterialDetailPO : detailList) { - Long materialBaseInfoId = reservationOutMaterialDetailPO.getMaterialBaseInfoId(); - List inventoryAdjustmentRecordPOS = reservationInMaterialDetailService.getkctzjl(materialBaseInfoId, outOrderNumber, "出库"); - if (inventoryAdjustmentRecordPOS != null && inventoryAdjustmentRecordPOS.size() > 0) { - InventoryAdjustmentRecordPO inventoryAdjustmentRecordPO = inventoryAdjustmentRecordPOS.get(0); - reservationOutMaterialDetailPO.setAllocationBeforeQuantity(inventoryAdjustmentRecordPO.getAllocationBeforeQuantity()); - reservationOutMaterialDetailPO.setAllocationAfterQuantity(inventoryAdjustmentRecordPO.getAllocationAfterQuantity()); - reservationOutMaterialDetailPO.setFreezeAfterQuantity(inventoryAdjustmentRecordPO.getFreezeAfterQuantity()); - reservationOutMaterialDetailPO.setFreezeBeforeQuantity(inventoryAdjustmentRecordPO.getFreezeBeforeQuantity()); - reservationOutMaterialDetailPO.setInventoryAfterQuantity(inventoryAdjustmentRecordPO.getInventoryAfterQuantity()); - reservationOutMaterialDetailPO.setInventoryBeforeQuantity(inventoryAdjustmentRecordPO.getInventoryBeforeQuantity()); - reservationOutMaterialDetailPO.setNetWeight(inventoryAdjustmentRecordPO.getNetWeight()); - reservationOutMaterialDetailPO.setGrossWeight(inventoryAdjustmentRecordPO.getGrossWeight()); - reservationOutMaterialDetailPO.setVolume(inventoryAdjustmentRecordPO.getVolume()); - reservationOutMaterialDetailPO.setArea(inventoryAdjustmentRecordPO.getArea()); - reservationOutMaterialDetailPO.setAdjustedNetWeight(inventoryAdjustmentRecordPO.getAdjustedNetWeight()); - reservationOutMaterialDetailPO.setAdjustedGrossWeight(inventoryAdjustmentRecordPO.getAdjustedGrossWeight()); - reservationOutMaterialDetailPO.setAdjustedVolume(inventoryAdjustmentRecordPO.getAdjustedVolume()); - reservationOutMaterialDetailPO.setAdjustedArea(inventoryAdjustmentRecordPO.getAdjustedArea()); - } - if(materialBaseInfoId != null){ - MaterialBaseInfoPO materialBaseInfoPO = reservationStockInOrderMapper.getinfo(materialBaseInfoId); - if(materialBaseInfoPO != null && materialBaseInfoPO.getUnitPrice() != null){ - reservationOutMaterialDetailPO.setUnitPrice(materialBaseInfoPO.getUnitPrice()); + List detailList = stockOutOrderPO.getMaterialDetailList(); + String outOrderNumber = stockOutOrderPO.getOutOrderNumber(); + for (ReservationOutMaterialDetailPO reservationOutMaterialDetailPO : detailList) { + Long materialBaseInfoId = reservationOutMaterialDetailPO.getMaterialBaseInfoId(); + List inventoryAdjustmentRecordPOS = reservationInMaterialDetailService.getkctzjl(materialBaseInfoId, outOrderNumber, "出库"); + if (inventoryAdjustmentRecordPOS != null && inventoryAdjustmentRecordPOS.size() > 0) { + InventoryAdjustmentRecordPO inventoryAdjustmentRecordPO = inventoryAdjustmentRecordPOS.get(0); + reservationOutMaterialDetailPO.setAllocationBeforeQuantity(inventoryAdjustmentRecordPO.getAllocationBeforeQuantity()); + reservationOutMaterialDetailPO.setAllocationAfterQuantity(inventoryAdjustmentRecordPO.getAllocationAfterQuantity()); + reservationOutMaterialDetailPO.setFreezeAfterQuantity(inventoryAdjustmentRecordPO.getFreezeAfterQuantity()); + reservationOutMaterialDetailPO.setFreezeBeforeQuantity(inventoryAdjustmentRecordPO.getFreezeBeforeQuantity()); + reservationOutMaterialDetailPO.setInventoryAfterQuantity(inventoryAdjustmentRecordPO.getInventoryAfterQuantity()); + reservationOutMaterialDetailPO.setInventoryBeforeQuantity(inventoryAdjustmentRecordPO.getInventoryBeforeQuantity()); + reservationOutMaterialDetailPO.setNetWeight(inventoryAdjustmentRecordPO.getNetWeight()); + reservationOutMaterialDetailPO.setGrossWeight(inventoryAdjustmentRecordPO.getGrossWeight()); + reservationOutMaterialDetailPO.setVolume(inventoryAdjustmentRecordPO.getVolume()); + reservationOutMaterialDetailPO.setArea(inventoryAdjustmentRecordPO.getArea()); + reservationOutMaterialDetailPO.setAdjustedNetWeight(inventoryAdjustmentRecordPO.getAdjustedNetWeight()); + reservationOutMaterialDetailPO.setAdjustedGrossWeight(inventoryAdjustmentRecordPO.getAdjustedGrossWeight()); + reservationOutMaterialDetailPO.setAdjustedVolume(inventoryAdjustmentRecordPO.getAdjustedVolume()); + reservationOutMaterialDetailPO.setAdjustedArea(inventoryAdjustmentRecordPO.getAdjustedArea()); + } + if(materialBaseInfoId != null){ + MaterialBaseInfoPO materialBaseInfoPO = reservationStockInOrderMapper.getinfo(materialBaseInfoId); + if(materialBaseInfoPO != null && materialBaseInfoPO.getUnitPrice() != null){ + reservationOutMaterialDetailPO.setUnitPrice(materialBaseInfoPO.getUnitPrice()); + } } } } @@ -377,6 +379,10 @@ public class ReservationStockOutOrderApplicationService { List reservationDeliveryDetailsLinks = reservationDeliveryDetailsLinkMapper.selectList(new LambdaQueryWrapper() .eq(ReservationDeliveryDetailsLink::getOrderNumber, stockOutOrderPO.getOutOrderNumber())); stockOutOrderPO.setReservationDeliveryDetailsLinkList(reservationDeliveryDetailsLinks); + Long shipperId = stockOutOrderPO.getShipperId(); + if (shipperId != null && shipperId == 0L) { + stockOutOrderPO.setShipperId(null); + } return stockOutOrderPO; } diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java index 8384108c2..18ee27e12 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockOutOrder/service/ReservationStockOutOrderDomainService.java @@ -148,7 +148,11 @@ public class ReservationStockOutOrderDomainService { reservationDeliveryDetailsLinkService.saveBatch(reservationDeliveryDetailsLinkList); } } - return outMaterialDetailService.batchInsert(stockOutOrderDO.getOutOrderNumber(), stockOutOrderDO.getMaterialDetailList()); + List materialDetailList = stockOutOrderDO.getMaterialDetailList(); + if (materialDetailList != null && !materialDetailList.isEmpty()) { + return outMaterialDetailService.batchInsert(stockOutOrderDO.getOutOrderNumber(), stockOutOrderDO.getMaterialDetailList()); + } + return true; } /** @@ -979,7 +983,7 @@ public class ReservationStockOutOrderDomainService { reservationStockInOrderMapper.insert(reservationStockInOrder); reservationDeliveryDetailsLink.setReturnOrderNumber(reservationStockInOrder.getInOrderNumber()); reservationDeliveryDetailsLinkService.updateById(reservationDeliveryDetailsLink); - reservationDeliveryDetailsLinkService.updateW(reservationStockInOrder.getInOrderNumber(), reservationDeliveryDetailsLink.getOrderNumber()); + reservationDeliveryDetailsLinkService.updateW(reservationStockInOrder.getInOrderNumber(), reservationDeliveryDetailsLink.getInvoiceNumber()); String returnOrderNumber = stockOutOrder.getReturnOrderNumber(); if (returnOrderNumber == null) { stockOutOrder.setReturnOrderNumber(reservationStockInOrder.getInOrderNumber()); diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/entity/ReserveInMaterialDetail.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/entity/ReserveInMaterialDetail.java index ac4c6c09a..2c4bb9e1e 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/entity/ReserveInMaterialDetail.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/entity/ReserveInMaterialDetail.java @@ -63,6 +63,10 @@ public class ReserveInMaterialDetail extends BaseVOEntity { @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/po/ReserveInMaterialDetailPO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/po/ReserveInMaterialDetailPO.java index 66043e8f1..b83e00eb6 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/po/ReserveInMaterialDetailPO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/po/ReserveInMaterialDetailPO.java @@ -63,6 +63,10 @@ public class ReserveInMaterialDetailPO extends ReserveStockInOrderBasePO { @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDO.java index b55266c2a..c54d29dea 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDO.java @@ -61,6 +61,10 @@ public class ReserveInMaterialDetailDO extends ReserveStockInOrderBaseDO { @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDTO.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDTO.java index 7201a9163..17f87552a 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDTO.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveInMaterialDetail/repository/todo/ReserveInMaterialDetailDTO.java @@ -63,6 +63,10 @@ public class ReserveInMaterialDetailDTO extends BaseVOEntity { @Excel(name = "物料名称") private String materialName; + @ApiModelProperty("物料名称") + @Excel(name = "物料名称") + private String reserveMaterialName; + @ApiModelProperty("物料条形码") @Excel(name = "物料条形码") private String barCode; diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java index 41d0f6a55..79e937e65 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockInOrder/service/ReserveStockInOrderDomainService.java @@ -670,7 +670,7 @@ public class ReserveStockInOrderDomainService { MaterialBaseInfoPO materialBaseInfoPO = reservationStockInOrderMapper.getinfo(inMaterialDetailDO.getMaterialBaseInfoId()); //MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoService.getInfo(inMaterialDetailDO.getMaterialBaseInfoId()); if (materialBaseInfoPO == null){ - throw new ServiceException("物料基础信息不存在"); + return; } inMaterialDetailDO.setMaterialCode(materialBaseInfoPO.getMaterialCode()); inMaterialDetailDO.setMaterialName(materialBaseInfoPO.getMaterialName()); diff --git a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java index ca1c77ad2..9795e5dc6 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java +++ b/mhd_oms/src/main/java/com/mhd/oms/interfaces/facade/reservationStockInOrder/ReservationStockInOrderApi.java @@ -209,24 +209,28 @@ public class ReservationStockInOrderApi extends BaseController { /** - * 上传并解析Excel文件 + * 上传并解析Excel文件(默认读取"出库导入"工作表) * @param file Excel文件 - * @param sheetName 工作表名称(出库导入/参考数据) * @return 解析后的出库数据 */ @PostMapping("/parseExcel") public ResponseEntity> parseExcel( @RequestParam("file") MultipartFile file) { + Map result = new HashMap<>(); try { DeliveryDataDTO deliveryDataDTO = reservationStockInOrderService.parseExcelFile(file, ""); - Map result = new HashMap<>(); result.put("result", deliveryDataDTO); - result.put("code",200); + result.put("code", 200); + result.put("msg", "解析成功"); return new ResponseEntity<>(result, HttpStatus.OK); } catch (IllegalArgumentException e) { - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + result.put("code", 400); + result.put("msg", e.getMessage()); + return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST); } catch (Exception e) { - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + result.put("code", 500); + result.put("msg", e.getMessage()); + return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR); } } diff --git a/mhd_oms/src/main/resources/mapper/reservationDeliveryDetailsLink/ReservationDeliveryDetailsLinkMapper.xml b/mhd_oms/src/main/resources/mapper/reservationDeliveryDetailsLink/ReservationDeliveryDetailsLinkMapper.xml index e5577aa5d..3310a687f 100644 --- a/mhd_oms/src/main/resources/mapper/reservationDeliveryDetailsLink/ReservationDeliveryDetailsLinkMapper.xml +++ b/mhd_oms/src/main/resources/mapper/reservationDeliveryDetailsLink/ReservationDeliveryDetailsLinkMapper.xml @@ -61,6 +61,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - update NGWL_TEST_WMS.DELIVERY_DETAILS_LINK set RETURN_ORDER_NUMBER = #{returnOrderNumber} where ORDER_NUMBER = #{orderNumber} + update NGWL_TEST_WMS.DELIVERY_DETAILS_LINK set RETURN_ORDER_NUMBER = #{returnOrderNumber} where INVOICE_NUMBER = #{orderNumber} \ No newline at end of file diff --git a/mhd_oms/src/main/resources/mapper/reserveInMaterialDetail/ReserveInMaterialDetailMapper.xml b/mhd_oms/src/main/resources/mapper/reserveInMaterialDetail/ReserveInMaterialDetailMapper.xml index d47119e44..0f30ba04c 100644 --- a/mhd_oms/src/main/resources/mapper/reserveInMaterialDetail/ReserveInMaterialDetailMapper.xml +++ b/mhd_oms/src/main/resources/mapper/reserveInMaterialDetail/ReserveInMaterialDetailMapper.xml @@ -96,6 +96,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -109,7 +110,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.lot_no ,a.reserve_quantity,a.reserve_gross_weight,a.reserve_net_weight,a.reserve_volume,a.reserve_area,a.reserve_price,a.reserve_unit_price,a.shelf_life, a.material_detail_id, a.organization_id, a.organization_name, a.top_organization_id, a.unique_id, a.in_order_number, a.material_base_info_id, a.material_code, a.material_name, a.bar_code, a.quantity, a.receipt_quantity, a.shelves_quantity, - a.receipt_status, a.shelves_status, a.pack_id, a.pack_code, a.pack_name, + a.receipt_status, a.shelves_status, a.pack_id, a.pack_code, a.pack_name,a.RESERVE_MATERIAL_NAME, CASE WHEN a.pack_detail_id IS NULL OR TRIM(a.pack_detail_id) = '' THEN NULL ELSE CAST(a.pack_detail_id AS BIGINT)