From 43aec4ac0d05dfc1a78445d6f0b27ceb73f161f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=A6=E9=B8=BF=E5=B1=95?= <18031053041@163.com> Date: Thu, 29 Jan 2026 17:26:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=B9=E6=AC=A1=E8=A7=84=E5=88=99bug?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MaterialBaseInfoApplicationService.java | 6 +- .../StockInOrderApplicationService.java | 19 +- .../StockReceiptOrderApplicationService.java | 369 +++++++++++++++++- .../repository/po/InMaterialDetailPO.java | 33 ++ .../entity/ReceiptMaterialDetail.java | 68 ++++ .../ReceiptMaterialDetailImpl.java | 189 +++++++-- .../po/ReceiptMaterialDetailPO.java | 33 ++ .../todo/ReceiptMaterialDetailDO.java | 65 +++ .../service/StockInOrderDomainService.java | 198 ++++++++++ .../InMaterialDetailMapper.xml | 10 +- .../ReceiptMaterialDetailMapper.xml | 31 +- 11 files changed, 967 insertions(+), 54 deletions(-) diff --git a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java index a85a4c75b..8a253446d 100644 --- a/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java +++ b/mhd-modules/mhd-system/src/main/java/com/mhd/basic/application/service/materialBaseInfo/MaterialBaseInfoApplicationService.java @@ -120,7 +120,11 @@ public class MaterialBaseInfoApplicationService { throw new ServiceException("获取货主信息失败"); } UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class); - materialBaseInfoDO.setShipperName(userPo.getUserName()); + // 如果原始shipperName不为空,保留原始值(导入或手动输入时应该保留完整名称) + // 只有在原始shipperName为空时,才使用查询到的userName + if (materialBaseInfoDO.getShipperName() == null || materialBaseInfoDO.getShipperName().trim().isEmpty()) { + materialBaseInfoDO.setShipperName(userPo.getUserName()); + } } public List getMaterialStockList(String shipperName, String materialName, diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java index 0bc9998ef..42cc33424 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java @@ -1616,23 +1616,20 @@ public class StockInOrderApplicationService { // 如果编号不匹配,再根据名称匹配(支持去除空格后匹配) if (!matched && StringUtils.isNotEmpty(normalizedShipperName) && userName != null) { String normalizedUserName = String.valueOf(userName).trim(); - // 精确匹配 + // 精确匹配(优先) if (normalizedShipperName.equals(normalizedUserName)) { matched = true; log.debug("通过名称精确匹配成功,货主名称:{},货主ID:{}", normalizedShipperName, userId); } - // 如果精确匹配失败,尝试包含匹配(支持部分匹配) + // 如果精确匹配失败,尝试包含匹配(列表中的名称包含导入的名称,例如列表中是"珠海百思科鞋材有限公司",导入的是"百思科") + // 注意:这里不使用反向包含匹配(导入的名称包含列表中的名称),因为这样会误匹配(例如导入"珠海百思科鞋材有限公司"会匹配到"百思科") if (!matched && normalizedUserName.contains(normalizedShipperName)) { matched = true; log.debug("通过名称包含匹配成功,货主名称:{},列表中的名称:{},货主ID:{}", normalizedShipperName, normalizedUserName, userId); } - // 如果包含匹配也失败,尝试反向包含匹配 - if (!matched && normalizedShipperName.contains(normalizedUserName)) { - matched = true; - log.debug("通过名称反向包含匹配成功,货主名称:{},列表中的名称:{},货主ID:{}", - normalizedShipperName, normalizedUserName, userId); - } + // 不再使用反向包含匹配,避免误匹配 + // 例如:导入"珠海百思科鞋材有限公司"不应该匹配到列表中的"百思科" } if (matched && userId != null) { @@ -1698,7 +1695,11 @@ public class StockInOrderApplicationService { throw new ServiceException("获取货主信息失败:返回数据为空(货主ID: " + shipperId + ")"); } stockInOrderDO.setShipperCode(userPo.getUserMemberCode()); - stockInOrderDO.setShipperName(userPo.getUserName()); + // 如果原始shipperName不为空,保留原始值(导入时读取的客户名称应该保留) + // 只有在原始shipperName为空时,才使用查询到的userName + if (StringUtils.isBlank(stockInOrderDO.getShipperName())) { + stockInOrderDO.setShipperName(userPo.getUserName()); + } } /** diff --git a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java index 9965953ac..b304fb3a6 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java @@ -43,12 +43,17 @@ import org.springframework.stereotype.Service; import com.mhd.common.core.utils.StringUtils; import org.springframework.util.CollectionUtils; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -136,23 +141,52 @@ public class StockReceiptOrderApplicationService { receiptMaterialDetailDO.setReceiptOrderNumber(stockReceiptOrderPO.getReceiptOrderNumber()); List receiptMaterialDetailPOList = receiptMaterialDetailDomainService.queryListChildren(receiptMaterialDetailDO); - // 为每个物料明细设置更多属性(根据物料绑定的批次属性,过滤isDisplay=1的属性) - receiptMaterialDetailPOList.forEach(receiptMaterialDetailPO -> { - List materialMoreDetailList = - getMaterialMoreDetailByBatch(receiptMaterialDetailPO.getMaterialBaseInfoId()); - receiptMaterialDetailPO.setMaterialMoreDetailList(materialMoreDetailList); - }); + // 性能优化:批量获取批次属性,避免N+1查询问题 + // 1. 收集所有唯一的materialBaseInfoId + Set materialBaseInfoIdSet = receiptMaterialDetailPOList.stream() + .map(ReceiptMaterialDetailPO::getMaterialBaseInfoId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + // 2. 批量查询批次属性(使用Map缓存,避免重复查询相同的materialBaseInfoId) + Map> batchDetailMap = new HashMap<>(); + for (Long materialBaseInfoId : materialBaseInfoIdSet) { + try { + AjaxResult ajaxResult = systemServiceFeign.getBatchDetailListByMaterialBaseInfoId(materialBaseInfoId); + if (ajaxResult != null && "200".equals(String.valueOf(ajaxResult.get("code")))) { + List batchDetailFeignPOList = JSON.parseArray( + JSONObject.toJSONString(ajaxResult.get("data")), BatchDetailFeignPO.class); + if (!CollectionUtils.isEmpty(batchDetailFeignPOList)) { + // 过滤isDisplay=1的属性 + List filteredList = batchDetailFeignPOList.stream() + .filter(batchDetail -> batchDetail.getIsDisplay() != null && batchDetail.getIsDisplay() == 1) + .collect(Collectors.toList()); + batchDetailMap.put(materialBaseInfoId, filteredList); + } + } + } catch (Exception e) { + log.warn("获取物料批次属性失败,物料基础信息ID:{},错误:{}", materialBaseInfoId, e.getMessage()); + } + } + + // 3. 为每个物料明细设置更多属性(从缓存中获取),递归处理所有层级 + setMaterialMoreDetailListRecursively(receiptMaterialDetailPOList, batchDetailMap); stockReceiptOrderPO.setMaterialDetailList(receiptMaterialDetailPOList); + log.info("返回收货单信息,receiptOrderId={}, materialDetailList大小={}", + stockReceiptOrderPO.getReceiptOrderId(), + receiptMaterialDetailPOList != null ? receiptMaterialDetailPOList.size() : 0); return stockReceiptOrderPO; } /** * 根据物料基础信息ID获取批次属性(更多属性),只返回isDisplay=1的属性 + * 并根据fieldName从物料明细中获取对应的字段值 * @param materialBaseInfoId 物料基础信息ID + * @param receiptMaterialDetailPO 收货物料明细对象,用于根据fieldName获取字段值 * @return 更多属性列表 */ - private List getMaterialMoreDetailByBatch(Long materialBaseInfoId) { + private List getMaterialMoreDetailByBatch(Long materialBaseInfoId, ReceiptMaterialDetailPO receiptMaterialDetailPO) { List materialMoreDetailPOList = new ArrayList<>(); if (materialBaseInfoId == null) { return materialMoreDetailPOList; @@ -178,6 +212,32 @@ public class StockReceiptOrderApplicationService { materialMoreDetailPO.setAttributeFormat(batchDetailFeignPO.getAttributeFormat()); materialMoreDetailPO.setAttributeOption(batchDetailFeignPO.getAttributeOption()); materialMoreDetailPO.setRemark(batchDetailFeignPO.getRemark()); + + // 根据fieldName或batchLabels从物料明细中获取对应的字段值 + if (receiptMaterialDetailPO != null) { + String fieldValue = null; + String usedFieldName = null; + // 优先使用fieldName(如果存在) + if (StringUtils.isNotBlank(batchDetailFeignPO.getFieldName())) { + usedFieldName = batchDetailFeignPO.getFieldName(); + fieldValue = getFieldValueByFieldName(receiptMaterialDetailPO, usedFieldName); + log.debug("批次属性 batchDetailId={}, fieldName={}, 获取到的值={}", + batchDetailFeignPO.getBatchDetailId(), usedFieldName, fieldValue); + } + // 如果fieldName为空,尝试根据batchLabels映射到字段名 + else if (StringUtils.isNotBlank(batchDetailFeignPO.getBatchLabels())) { + String fieldNameByLabel = getFieldNameByBatchLabel(batchDetailFeignPO.getBatchLabels()); + if (StringUtils.isNotBlank(fieldNameByLabel)) { + usedFieldName = fieldNameByLabel; + fieldValue = getFieldValueByFieldName(receiptMaterialDetailPO, usedFieldName); + log.debug("批次属性 batchDetailId={}, batchLabels={}, 映射字段名={}, 获取到的值={}", + batchDetailFeignPO.getBatchDetailId(), batchDetailFeignPO.getBatchLabels(), + usedFieldName, fieldValue); + } + } + materialMoreDetailPO.setAttributeValue(fieldValue); + } + materialMoreDetailPOList.add(materialMoreDetailPO); }); } @@ -188,6 +248,300 @@ public class StockReceiptOrderApplicationService { return materialMoreDetailPOList; } + + /** + * 递归为物料明细设置更多属性 + * @param receiptMaterialDetailPOList 物料明细列表 + * @param batchDetailMap 批次属性Map + */ + private void setMaterialMoreDetailListRecursively(List receiptMaterialDetailPOList, + Map> batchDetailMap) { + if (CollectionUtils.isEmpty(receiptMaterialDetailPOList)) { + return; + } + + receiptMaterialDetailPOList.forEach(receiptMaterialDetailPO -> { + Long materialBaseInfoId = receiptMaterialDetailPO.getMaterialBaseInfoId(); + + // 只保留isDisplay=1的批次属性(从batchDetailMap中获取,已经过滤过了) + // 创建新的materialMoreDetailList,只包含isDisplay=1的属性 + List materialMoreDetailList = new ArrayList<>(); + + // 创建batchDetailId到MaterialMoreDetailPO的映射,用于快速查找已有的属性值 + Map batchDetailIdToMaterialMoreDetailMap = new HashMap<>(); + List existingList = receiptMaterialDetailPO.getMaterialMoreDetailList(); + if (!CollectionUtils.isEmpty(existingList)) { + for (MaterialMoreDetailPO existing : existingList) { + if (existing.getBatchDetailId() != null) { + batchDetailIdToMaterialMoreDetailMap.put(existing.getBatchDetailId(), existing); + } + } + } + + if (materialBaseInfoId != null && batchDetailMap.containsKey(materialBaseInfoId)) { + List batchDetailFeignPOList = batchDetailMap.get(materialBaseInfoId); + // 用于跟踪已添加到列表中的batchDetailId + Set addedBatchDetailIds = new HashSet<>(); + + for (BatchDetailFeignPO batchDetailFeignPO : batchDetailFeignPOList) { + MaterialMoreDetailPO materialMoreDetailPO = batchDetailIdToMaterialMoreDetailMap.get(batchDetailFeignPO.getBatchDetailId()); + + // 如果不存在,创建新的 + if (materialMoreDetailPO == null) { + materialMoreDetailPO = new MaterialMoreDetailPO(); + materialMoreDetailPO.setBatchId(batchDetailFeignPO.getBatchId()); + materialMoreDetailPO.setBatchDetailId(batchDetailFeignPO.getBatchDetailId()); + materialMoreDetailPO.setBatchLabels(batchDetailFeignPO.getBatchLabels()); + materialMoreDetailPO.setInputControl(batchDetailFeignPO.getInputControl()); + materialMoreDetailPO.setAttributeFormat(batchDetailFeignPO.getAttributeFormat()); + materialMoreDetailPO.setAttributeOption(batchDetailFeignPO.getAttributeOption()); + materialMoreDetailPO.setRemark(batchDetailFeignPO.getRemark()); + } else { + // 如果已存在,更新属性(保留已有的attributeValue) + materialMoreDetailPO.setBatchId(batchDetailFeignPO.getBatchId()); + materialMoreDetailPO.setBatchLabels(batchDetailFeignPO.getBatchLabels()); + materialMoreDetailPO.setInputControl(batchDetailFeignPO.getInputControl()); + materialMoreDetailPO.setAttributeFormat(batchDetailFeignPO.getAttributeFormat()); + materialMoreDetailPO.setAttributeOption(batchDetailFeignPO.getAttributeOption()); + materialMoreDetailPO.setRemark(batchDetailFeignPO.getRemark()); + } + + // 确保添加到列表中(使用batchDetailId来避免重复) + Long batchDetailId = batchDetailFeignPO.getBatchDetailId(); + if (batchDetailId != null && !addedBatchDetailIds.contains(batchDetailId)) { + materialMoreDetailList.add(materialMoreDetailPO); + addedBatchDetailIds.add(batchDetailId); + } + + // 根据fieldName或batchLabels从物料明细中获取对应的字段值 + if (receiptMaterialDetailPO != null) { + String fieldValue = null; + String usedFieldName = null; + // 优先使用fieldName(如果存在) + if (StringUtils.isNotBlank(batchDetailFeignPO.getFieldName())) { + usedFieldName = batchDetailFeignPO.getFieldName(); + fieldValue = getFieldValueByFieldName(receiptMaterialDetailPO, usedFieldName); + log.info("批次属性 batchDetailId={}, fieldName={}, 获取到的值={}", + batchDetailFeignPO.getBatchDetailId(), usedFieldName, fieldValue); + } + // 如果fieldName为空,尝试根据batchLabels映射到字段名 + else if (StringUtils.isNotBlank(batchDetailFeignPO.getBatchLabels())) { + String fieldNameByLabel = getFieldNameByBatchLabel(batchDetailFeignPO.getBatchLabels()); + if (StringUtils.isNotBlank(fieldNameByLabel)) { + usedFieldName = fieldNameByLabel; + fieldValue = getFieldValueByFieldName(receiptMaterialDetailPO, usedFieldName); + log.info("批次属性 batchDetailId={}, batchLabels={}, 映射字段名={}, 获取到的值={}", + batchDetailFeignPO.getBatchDetailId(), batchDetailFeignPO.getBatchLabels(), + usedFieldName, fieldValue); + } + } + // 只有当获取到值时才更新attributeValue(避免覆盖已有的值) + if (fieldValue != null) { + materialMoreDetailPO.setAttributeValue(fieldValue); + log.info("设置更多属性:batchDetailId={}, batchLabels={}, attributeValue={}", + materialMoreDetailPO.getBatchDetailId(), materialMoreDetailPO.getBatchLabels(), + materialMoreDetailPO.getAttributeValue()); + } + } + } + } + receiptMaterialDetailPO.setMaterialMoreDetailList(materialMoreDetailList); + log.info("物料明细 uniqueId={}, materialBaseInfoId={}, materialMoreDetailList大小={}", + receiptMaterialDetailPO.getUniqueId(), receiptMaterialDetailPO.getMaterialBaseInfoId(), + materialMoreDetailList != null ? materialMoreDetailList.size() : 0); + + // 递归处理子集 + if (!CollectionUtils.isEmpty(receiptMaterialDetailPO.getChildren())) { + setMaterialMoreDetailListRecursively(receiptMaterialDetailPO.getChildren(), batchDetailMap); + } + }); + } + + /** + * 根据批次标签(batchLabels)映射到字段名 + * @param batchLabel 批次标签 + * @return 字段名,如果找不到映射则返回null + */ + private String getFieldNameByBatchLabel(String batchLabel) { + if (StringUtils.isBlank(batchLabel)) { + return null; + } + + // 批次标签到字段名的映射关系 + // 可以根据实际业务需求扩展这个映射表 + Map labelToFieldNameMap = new HashMap<>(); + labelToFieldNameMap.put("Invoice No.", "invoiceNo"); + labelToFieldNameMap.put("Invoice No", "invoiceNo"); + labelToFieldNameMap.put("发票号", "invoiceNo"); + labelToFieldNameMap.put("Batch Ref NO's", "batchRefNo"); + labelToFieldNameMap.put("Batch Ref NO", "batchRefNo"); + labelToFieldNameMap.put("批次参考号", "batchRefNo"); + labelToFieldNameMap.put("Sheet Ref NO's", "sheetRefNo"); + labelToFieldNameMap.put("Sheet Ref NO", "sheetRefNo"); + labelToFieldNameMap.put("单据参考号", "sheetRefNo"); + labelToFieldNameMap.put("箱号/卡板号", "boxPalletNo"); + labelToFieldNameMap.put("箱号", "boxPalletNo"); + labelToFieldNameMap.put("卡板号", "boxPalletNo"); + labelToFieldNameMap.put("申报数量", "declaredQuantity"); + labelToFieldNameMap.put("申报单位", "declarationUnit"); + labelToFieldNameMap.put("原产国", "originCountry"); + labelToFieldNameMap.put("币制", "currency"); + labelToFieldNameMap.put("单位", "unit"); + labelToFieldNameMap.put("升", "liter"); + labelToFieldNameMap.put("尺寸", "dimensions"); + labelToFieldNameMap.put("箱数", "boxCount"); + labelToFieldNameMap.put("件数", "pieceCount"); + labelToFieldNameMap.put("入库数量", "inboundQuantity"); + labelToFieldNameMap.put("总净重", "totalNetWeight"); + labelToFieldNameMap.put("总毛重", "totalGrossWeight"); + labelToFieldNameMap.put("总体积", "totalVolume"); + labelToFieldNameMap.put("总面积", "totalArea"); + labelToFieldNameMap.put("总价", "totalPrice"); + + // 精确匹配 + String fieldName = labelToFieldNameMap.get(batchLabel.trim()); + if (StringUtils.isNotBlank(fieldName)) { + return fieldName; + } + + // 模糊匹配(包含关系) + for (Map.Entry entry : labelToFieldNameMap.entrySet()) { + if (batchLabel.contains(entry.getKey()) || entry.getKey().contains(batchLabel)) { + return entry.getValue(); + } + } + + // 如果找不到映射,尝试将批次标签转换为驼峰命名(简单处理) + // 例如:"Invoice No." -> "invoiceNo" + return convertLabelToFieldName(batchLabel); + } + + /** + * 将批次标签转换为字段名(驼峰命名) + * @param label 批次标签 + * @return 字段名 + */ + private String convertLabelToFieldName(String label) { + if (StringUtils.isBlank(label)) { + return null; + } + + // 移除特殊字符,转换为小写,用空格或特殊字符分割 + String cleaned = label.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5\\s]", " ") + .trim() + .toLowerCase(); + + // 如果是中文,无法自动转换,返回null + if (cleaned.matches(".*[\\u4e00-\\u9fa5].*")) { + return null; + } + + // 将空格分割的单词转换为驼峰命名 + String[] words = cleaned.split("\\s+"); + if (words.length == 0) { + return null; + } + + StringBuilder fieldName = new StringBuilder(words[0]); + for (int i = 1; i < words.length; i++) { + if (words[i].length() > 0) { + fieldName.append(words[i].substring(0, 1).toUpperCase()) + .append(words[i].substring(1)); + } + } + + return fieldName.toString(); + } + + /** + * 根据字段名从对象中获取字段值(使用反射) + * @param obj 对象 + * @param fieldName 字段名 + * @return 字段值(转换为字符串) + */ + private String getFieldValueByFieldName(Object obj, String fieldName) { + if (obj == null || StringUtils.isBlank(fieldName)) { + return null; + } + + try { + // 兼容:如果传的是下划线命名(数据库列名风格),先转成驼峰字段名再取 + // 例如:box_pallet_no -> boxPalletNo + String normalizedFieldName = fieldName; + if (normalizedFieldName.contains("_")) { + normalizedFieldName = snakeToCamel(normalizedFieldName); + } + + // 获取对象的Class + Class clazz = obj.getClass(); + + // 尝试获取字段(包括父类字段) + Field field = null; + Class currentClass = clazz; + while (currentClass != null && field == null) { + try { + field = currentClass.getDeclaredField(normalizedFieldName); + } catch (NoSuchFieldException e) { + currentClass = currentClass.getSuperclass(); + } + } + + if (field == null) { + log.warn("字段不存在:{}(normalized:{}),对象类型:{}", fieldName, normalizedFieldName, clazz.getName()); + return null; + } + + // 设置可访问 + field.setAccessible(true); + + // 获取字段值 + Object value = field.get(obj); + + // 转换为字符串 + if (value == null) { + log.info("字段 {} 的值为 null,对象类型:{}", normalizedFieldName, clazz.getName()); + return null; + } + + String result; + // 处理日期类型字段 + if (value instanceof Date) { + result = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, (Date) value); + } else { + result = value.toString(); + } + + log.info("通过反射获取字段值成功,字段名:{}(原始:{}),值:{},对象类型:{}", + normalizedFieldName, fieldName, result, clazz.getName()); + return result; + } catch (Exception e) { + log.warn("通过反射获取字段值失败,字段名:{},对象类型:{},错误:{}", fieldName, obj.getClass().getName(), e.getMessage()); + return null; + } + } + + private String snakeToCamel(String snake) { + if (StringUtils.isBlank(snake)) { + return null; + } + String s = snake.trim().toLowerCase(); + StringBuilder sb = new StringBuilder(); + boolean upperNext = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '_') { + upperNext = true; + continue; + } + if (upperNext) { + sb.append(Character.toUpperCase(c)); + upperNext = false; + } else { + sb.append(c); + } + } + return sb.toString(); + } /** * 获取收货单详细信息 @@ -836,3 +1190,4 @@ public class StockReceiptOrderApplicationService { receiptMaterialDetailDO.setDistributeRuleName(materialGoodsRulePO.getRuleName()); } } + diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/inMaterialDetail/repository/po/InMaterialDetailPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/inMaterialDetail/repository/po/InMaterialDetailPO.java index d62911da7..86affc133 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/inMaterialDetail/repository/po/InMaterialDetailPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/inMaterialDetail/repository/po/InMaterialDetailPO.java @@ -10,6 +10,8 @@ import lombok.Data; import java.math.BigDecimal; import java.util.List; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; /** @@ -348,4 +350,35 @@ public class InMaterialDetailPO extends StockInOrderBasePO { @Excel(name = "总价") private BigDecimal totalPrice; + @ApiModelProperty("生产日期") + @Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date productionDate; + + @ApiModelProperty("过期日期") + @Excel(name = "过期日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date expiryDate; + + @ApiModelProperty("存货日期") + @Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date inventoryDate; + + @ApiModelProperty("扩展属性1") + @Excel(name = "扩展属性1") + private String extAttr1; + + @ApiModelProperty("扩展属性2") + @Excel(name = "扩展属性2") + private String extAttr2; + + @ApiModelProperty("扩展属性3") + @Excel(name = "扩展属性3") + private String extAttr3; + + @ApiModelProperty("扩展属性4") + @Excel(name = "扩展属性4") + private String extAttr4; + } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/entity/ReceiptMaterialDetail.java b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/entity/ReceiptMaterialDetail.java index 0a60ce242..59f7897d4 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/entity/ReceiptMaterialDetail.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/entity/ReceiptMaterialDetail.java @@ -214,5 +214,73 @@ public class ReceiptMaterialDetail extends BaseVOEntity { @Excel(name = "备注") private String remark; + @ApiModelProperty("总净重(KG)") + @Excel(name = "总净重(KG)") + private BigDecimal totalNetWeight; + + @ApiModelProperty("总毛重(KG)") + @Excel(name = "总毛重(KG)") + private BigDecimal totalGrossWeight; + + @ApiModelProperty("总体积(CBM)") + @Excel(name = "总体积(CBM)") + private BigDecimal totalVolume; + + @ApiModelProperty("总面积(SQM)") + @Excel(name = "总面积(SQM)") + private BigDecimal totalArea; + + @ApiModelProperty("Invoice No.") + @Excel(name = "Invoice No.") + private String invoiceNo; + + @ApiModelProperty("Batch Ref NO's") + @Excel(name = "Batch Ref NO's") + private String batchRefNo; + + @ApiModelProperty("Sheet Ref NO's") + @Excel(name = "Sheet Ref NO's") + private String sheetRefNo; + + @ApiModelProperty("箱号/卡板号") + @Excel(name = "箱号/卡板号") + private String boxPalletNo; + + @ApiModelProperty("申报数量") + @Excel(name = "申报数量") + private BigDecimal declaredQuantity; + + @ApiModelProperty("申报单位") + @Excel(name = "申报单位") + private String declarationUnit; + + @ApiModelProperty("原产国") + @Excel(name = "原产国") + private String originCountry; + + @ApiModelProperty("币制") + @Excel(name = "币制") + private String currency; + + @ApiModelProperty("单位") + @Excel(name = "单位") + private String unit; + + @ApiModelProperty("升") + @Excel(name = "升") + private BigDecimal liter; + + @ApiModelProperty("尺寸") + @Excel(name = "尺寸") + private String dimensions; + + @ApiModelProperty("箱数") + @Excel(name = "箱数") + private BigDecimal boxCount; + + @ApiModelProperty("件数") + @Excel(name = "件数") + private BigDecimal pieceCount; + } diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java index 3aeec1fd9..1ae796e4a 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java @@ -13,6 +13,7 @@ import com.mhd.common.core.utils.uuid.IdGenerator; import com.mhd.common.core.web.domain.AjaxResult; import com.mhd.common.security.utils.SecurityUtils; import com.mhd.system.api.SystemServiceFeign; +import com.mhd.system.api.domain.BatchDetailFeignPO; import com.mhd.system.api.model.LoginUser; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.mhd.wms.domain.inMaterialDetail.entity.InMaterialDetail; @@ -43,11 +44,15 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import com.mhd.common.core.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; import javax.annotation.Resource; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -56,6 +61,7 @@ import java.util.stream.Collectors; * @author gen * @date 2024-06-17 */ +@Slf4j @Service public class ReceiptMaterialDetailImpl extends ServiceImpl implements IReceiptMaterialDetailService{ @Autowired @@ -291,7 +297,7 @@ public class ReceiptMaterialDetailImpl extends ServiceImplfieldName映射,兼容attributeOption) updateInMaterialDetailFromAttributeOption(receiptMaterialDetailDOList); } @@ -306,64 +312,185 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl (batchDetailId -> fieldName) + Map> batchFieldNameCache = new HashMap<>(); + updateInMaterialDetailFromAttributeOption(receiptMaterialDetailDOList, batchFieldNameCache); + } + + private void updateInMaterialDetailFromAttributeOption(List receiptMaterialDetailDOList, + Map> batchFieldNameCache) { + if (CollectionUtils.isEmpty(receiptMaterialDetailDOList)) { + return; + } LoginUser loginUser = SecurityUtils.getLoginUser(); for (ReceiptMaterialDetailDO receiptMaterialDetailDO : receiptMaterialDetailDOList) { Long inUniqueId = receiptMaterialDetailDO.getInUniqueId(); if (inUniqueId == null) { + // 处理子项 + List children = receiptMaterialDetailDO.getChildren(); + if (!CollectionUtils.isEmpty(children)) { + updateInMaterialDetailFromAttributeOption(children, batchFieldNameCache); + } continue; } + List materialMoreDetailList = receiptMaterialDetailDO.getMaterialMoreDetailList(); if (CollectionUtils.isEmpty(materialMoreDetailList)) { + // 处理子项 + List children = receiptMaterialDetailDO.getChildren(); + if (!CollectionUtils.isEmpty(children)) { + updateInMaterialDetailFromAttributeOption(children, batchFieldNameCache); + } continue; } - // 构建UpdateWrapper + + // 构建UpdateWrapper(用列名动态set) UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.lambda().eq(InMaterialDetail::getUniqueId, inUniqueId); + updateWrapper.eq("unique_id", inUniqueId); boolean hasUpdate = false; - - // 遍历materialMoreDetailList,根据attributeOption映射到对应字段 + + // 构建 batchDetailId -> fieldName 映射(按物料维度缓存) + Map batchDetailIdToFieldName = null; + Long materialBaseInfoId = receiptMaterialDetailDO.getMaterialBaseInfoId(); + if (materialBaseInfoId != null) { + batchDetailIdToFieldName = batchFieldNameCache.get(materialBaseInfoId); + if (batchDetailIdToFieldName == null) { + batchDetailIdToFieldName = loadBatchDetailIdToFieldName(materialBaseInfoId); + batchFieldNameCache.put(materialBaseInfoId, batchDetailIdToFieldName); + } + } + for (MaterialMoreDetailDO materialMoreDetail : materialMoreDetailList) { - String attributeOption = materialMoreDetail.getAttributeOption(); String attributeValue = materialMoreDetail.getAttributeValue(); - - // 如果attributeValue为空,跳过 - if (attributeValue == null || attributeValue.trim().isEmpty()) { + if (StringUtils.isBlank(attributeValue)) { continue; } - - // 根据attributeOption映射到入库单明细表的字段 - if ("InvoiceNo".equalsIgnoreCase(attributeOption)) { - updateWrapper.lambda().set(InMaterialDetail::getInvoiceNo, attributeValue); - hasUpdate = true; - } else if ("BatchRefNo".equalsIgnoreCase(attributeOption)) { - updateWrapper.lambda().set(InMaterialDetail::getBatchRefNo, attributeValue); - hasUpdate = true; - } else if ("SheetRefNo".equalsIgnoreCase(attributeOption)) { - updateWrapper.lambda().set(InMaterialDetail::getSheetRefNo, attributeValue); - hasUpdate = true; - } else if ("BoxPalletNo".equalsIgnoreCase(attributeOption)) { - updateWrapper.lambda().set(InMaterialDetail::getBoxPalletNo, attributeValue); - hasUpdate = true; + + String fieldName = null; + Long batchDetailId = materialMoreDetail.getBatchDetailId(); + if (batchDetailId != null && batchDetailIdToFieldName != null) { + fieldName = batchDetailIdToFieldName.get(batchDetailId); } + + // 兼容旧逻辑:fieldName取不到时用attributeOption(例如 InvoiceNo -> invoiceNo) + if (StringUtils.isBlank(fieldName)) { + String attributeOption = materialMoreDetail.getAttributeOption(); + fieldName = lowerFirst(attributeOption); + } + + if (StringUtils.isBlank(fieldName)) { + continue; + } + + // camelCase -> snake_case 列名 + String columnName = camelToSnake(fieldName); + if (StringUtils.isBlank(columnName)) { + continue; + } + + // 数字字段尝试转BigDecimal,其它按String + Object val = coerceInMaterialDetailValue(fieldName, attributeValue); + updateWrapper.set(columnName, val); + hasUpdate = true; } - - // 如果有字段需要更新,则执行更新 + if (hasUpdate) { - updateWrapper.lambda() - .set(InMaterialDetail::getUpdateBy, loginUser.getUserid()) - .set(InMaterialDetail::getUpdateByName, loginUser.getUsername()) - .set(InMaterialDetail::getUpdateTime, new Date()); + updateWrapper + .set("update_by", loginUser.getUserid()) + .set("update_by_name", loginUser.getUsername()) + .set("update_time", new Date()); iInMaterialDetailService.update(updateWrapper); } - + // 处理子项 List children = receiptMaterialDetailDO.getChildren(); if (!CollectionUtils.isEmpty(children)) { - updateInMaterialDetailFromAttributeOption(children); + updateInMaterialDetailFromAttributeOption(children, batchFieldNameCache); } } } + private Map loadBatchDetailIdToFieldName(Long materialBaseInfoId) { + Map result = new HashMap<>(); + try { + AjaxResult ajaxResult = systemServiceFeign.getBatchDetailListByMaterialBaseInfoId(materialBaseInfoId); + if (ajaxResult == null || !"200".equals(String.valueOf(ajaxResult.get("code")))) { + return result; + } + List list = JSON.parseArray(JSON.toJSONString(ajaxResult.get("data")), BatchDetailFeignPO.class); + if (CollectionUtils.isEmpty(list)) { + return result; + } + for (BatchDetailFeignPO po : list) { + if (po.getBatchDetailId() == null) { + continue; + } + String fieldName = po.getFieldName(); + if (StringUtils.isBlank(fieldName)) { + // 兼容:fieldName为空时尝试用attributeOption + fieldName = lowerFirst(po.getAttributeOption()); + } + if (StringUtils.isNotBlank(fieldName)) { + result.put(po.getBatchDetailId(), fieldName); + } + } + } catch (Exception e) { + log.warn("加载批次属性fieldName失败,materialBaseInfoId:{},错误:{}", materialBaseInfoId, e.getMessage()); + } + return result; + } + + private String lowerFirst(String s) { + if (StringUtils.isBlank(s)) { + return null; + } + if (s.length() == 1) { + return s.toLowerCase(); + } + return s.substring(0, 1).toLowerCase() + s.substring(1); + } + + private String camelToSnake(String camel) { + if (StringUtils.isBlank(camel)) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < camel.length(); i++) { + char c = camel.charAt(i); + if (Character.isUpperCase(c)) { + if (i > 0) { + sb.append('_'); + } + sb.append(Character.toLowerCase(c)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + private Object coerceInMaterialDetailValue(String fieldName, String raw) { + if (raw == null) { + return null; + } + // 这些字段在库里通常是NUMBER + if ("liter".equals(fieldName) + || "declaredQuantity".equals(fieldName) + || "boxCount".equals(fieldName) + || "pieceCount".equals(fieldName) + || "totalNetWeight".equals(fieldName) + || "totalGrossWeight".equals(fieldName) + || "totalVolume".equals(fieldName) + || "totalArea".equals(fieldName)) { + try { + return new BigDecimal(raw.trim()); + } catch (Exception ignored) { + return raw; + } + } + return raw; + } + /** * @description 从入库单明细表中获取InvoiceNo、BatchRefNo、SheetRefNo、BoxPalletNo字段的值并填充到materialMoreDetailList的attributeValue中 * @author Auto diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/po/ReceiptMaterialDetailPO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/po/ReceiptMaterialDetailPO.java index f16bbd0d5..d0a122512 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/po/ReceiptMaterialDetailPO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/po/ReceiptMaterialDetailPO.java @@ -12,6 +12,8 @@ import lombok.Data; import java.math.BigDecimal; import java.util.List; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; /** @@ -252,6 +254,37 @@ public class ReceiptMaterialDetailPO extends BaseVOEntity { @Excel(name = "箱号/卡板号") private String boxPalletNo; + @ApiModelProperty("生产日期") + @Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date productionDate; + + @ApiModelProperty("过期日期") + @Excel(name = "过期日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date expiryDate; + + @ApiModelProperty("存货日期") + @Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date inventoryDate; + + @ApiModelProperty("扩展属性1") + @Excel(name = "扩展属性1") + private String extAttr1; + + @ApiModelProperty("扩展属性2") + @Excel(name = "扩展属性2") + private String extAttr2; + + @ApiModelProperty("扩展属性3") + @Excel(name = "扩展属性3") + private String extAttr3; + + @ApiModelProperty("扩展属性4") + @Excel(name = "扩展属性4") + private String extAttr4; + @ApiModelProperty("物料明细子集") private List children; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/todo/ReceiptMaterialDetailDO.java b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/todo/ReceiptMaterialDetailDO.java index b57a51108..29aa26dc5 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/todo/ReceiptMaterialDetailDO.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/todo/ReceiptMaterialDetailDO.java @@ -11,6 +11,8 @@ import lombok.Data; import java.math.BigDecimal; import java.util.List; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; /** @@ -218,6 +220,69 @@ public class ReceiptMaterialDetailDO extends BaseVOEntity { @Excel(name = "是否生成上架单: 1-是 2-否") private Integer genStockShelf; + @ApiModelProperty("总净重(KG)") + @Excel(name = "总净重(KG)") + private BigDecimal totalNetWeight; + + @ApiModelProperty("总毛重(KG)") + @Excel(name = "总毛重(KG)") + private BigDecimal totalGrossWeight; + + @ApiModelProperty("总体积(CBM)") + @Excel(name = "总体积(CBM)") + private BigDecimal totalVolume; + + @ApiModelProperty("总面积(SQM)") + @Excel(name = "总面积(SQM)") + private BigDecimal totalArea; + + @ApiModelProperty("Invoice No.") + @Excel(name = "Invoice No.") + private String invoiceNo; + + @ApiModelProperty("Batch Ref NO's") + @Excel(name = "Batch Ref NO's") + private String batchRefNo; + + @ApiModelProperty("Sheet Ref NO's") + @Excel(name = "Sheet Ref NO's") + private String sheetRefNo; + + @ApiModelProperty("箱号/卡板号") + @Excel(name = "箱号/卡板号") + private String boxPalletNo; + + @ApiModelProperty("生产日期") + @Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date productionDate; + + @ApiModelProperty("过期日期") + @Excel(name = "过期日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date expiryDate; + + @ApiModelProperty("存货日期") + @Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date inventoryDate; + + @ApiModelProperty("扩展属性1") + @Excel(name = "扩展属性1") + private String extAttr1; + + @ApiModelProperty("扩展属性2") + @Excel(name = "扩展属性2") + private String extAttr2; + + @ApiModelProperty("扩展属性3") + @Excel(name = "扩展属性3") + private String extAttr3; + + @ApiModelProperty("扩展属性4") + @Excel(name = "扩展属性4") + private String extAttr4; + @ApiModelProperty(name = "组织ID集合") private List organizationIdList; diff --git a/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java b/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java index 8b1737de1..d94db5807 100644 --- a/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java +++ b/mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/service/StockInOrderDomainService.java @@ -40,6 +40,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @@ -297,6 +298,11 @@ public class StockInOrderDomainService { ReceiptMaterialDetailDO receiptMaterialDetailDO = new ReceiptMaterialDetailDO(); BeanUtils.copyProperties(inMaterialDetailPO, receiptMaterialDetailDO); receiptMaterialDetailDO.setInUniqueId(inMaterialDetailPO.getUniqueId()); + + // 复制特定字段:生产日期、过期日期、存货日期、批次参考号、单据参考号、箱号/卡板号、扩展属性1-4 + // 这些字段可能使用驼峰命名或下划线命名,使用反射获取和设置 + copySpecialFields(inMaterialDetailPO, receiptMaterialDetailDO); + receiptMaterialDetailDOList.add(receiptMaterialDetailDO); }); stockReceiptOrderDO.setMaterialDetailList(receiptMaterialDetailDOList); @@ -452,4 +458,196 @@ public class StockInOrderDomainService { } } + /** + * @description 复制特定字段从入库单明细到收货明细 + * 包括:生产日期、过期日期、存货日期、批次参考号、单据参考号、箱号/卡板号、扩展属性1-4 + * @author gen + * @date 2026/1/29 + * @param source 源对象(InMaterialDetailPO) + * @param target 目标对象(ReceiptMaterialDetailDO) + */ + private void copySpecialFields(InMaterialDetailPO source, ReceiptMaterialDetailDO target) { + if (source == null || target == null) { + return; + } + + try { + // 字段映射:源字段名 -> 目标字段名(支持驼峰和下划线两种命名方式) + Map fieldMappings = new HashMap<>(); + fieldMappings.put("productionDate", "productionDate"); + fieldMappings.put("production_date", "productionDate"); + fieldMappings.put("expiryDate", "expiryDate"); + fieldMappings.put("expiry_date", "expiryDate"); + fieldMappings.put("inventoryDate", "inventoryDate"); + fieldMappings.put("inventory_date", "inventoryDate"); + fieldMappings.put("batchRefNo", "batchRefNo"); + fieldMappings.put("batch_ref_no", "batchRefNo"); + fieldMappings.put("sheetRefNo", "sheetRefNo"); + fieldMappings.put("sheet_ref_no", "sheetRefNo"); + fieldMappings.put("boxPalletNo", "boxPalletNo"); + fieldMappings.put("box_pallet_no", "boxPalletNo"); + fieldMappings.put("extAttr1", "extAttr1"); + fieldMappings.put("ext_attr_1", "extAttr1"); + fieldMappings.put("extAttr2", "extAttr2"); + fieldMappings.put("ext_attr_2", "extAttr2"); + fieldMappings.put("extAttr3", "extAttr3"); + fieldMappings.put("ext_attr_3", "extAttr3"); + fieldMappings.put("extAttr4", "extAttr4"); + fieldMappings.put("ext_attr_4", "extAttr4"); + + // 使用反射复制字段值 + for (Map.Entry entry : fieldMappings.entrySet()) { + String sourceFieldName = entry.getKey(); + String targetFieldName = entry.getValue(); + + // 尝试从源对象获取字段值(支持驼峰和下划线命名) + Object value = getFieldValue(source, sourceFieldName); + if (value != null) { + // 设置到目标对象(使用驼峰命名) + setFieldValue(target, targetFieldName, value); + log.info("复制字段成功:{} -> {},值:{}", sourceFieldName, targetFieldName, value); + } else { + log.debug("源对象字段 {} 的值为 null,跳过复制", sourceFieldName); + } + } + } catch (Exception e) { + log.warn("复制特定字段时发生异常,源对象:{},目标对象:{},错误:{}", + source.getClass().getSimpleName(), target.getClass().getSimpleName(), e.getMessage()); + } + } + + /** + * @description 使用反射获取字段值(支持驼峰和下划线命名) + */ + private Object getFieldValue(Object obj, String fieldName) { + if (obj == null || StringUtils.isBlank(fieldName)) { + return null; + } + + try { + Class clazz = obj.getClass(); + Field field = null; + + // 先尝试直接获取字段(驼峰命名) + try { + field = clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // 如果失败,尝试转换为驼峰命名(如果是下划线命名) + if (fieldName.contains("_")) { + String camelCaseName = snakeToCamel(fieldName); + try { + field = clazz.getDeclaredField(camelCaseName); + } catch (NoSuchFieldException ex) { + // 继续查找父类 + } + } + } + + // 如果当前类找不到,查找父类 + if (field == null) { + Class currentClass = clazz.getSuperclass(); + while (currentClass != null && field == null) { + try { + field = currentClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + if (fieldName.contains("_")) { + String camelCaseName = snakeToCamel(fieldName); + try { + field = currentClass.getDeclaredField(camelCaseName); + } catch (NoSuchFieldException ex) { + // 继续查找父类 + } + } + } + currentClass = currentClass.getSuperclass(); + } + } + + if (field != null) { + field.setAccessible(true); + return field.get(obj); + } + } catch (Exception e) { + log.debug("获取字段值失败,对象:{},字段名:{},错误:{}", + obj.getClass().getSimpleName(), fieldName, e.getMessage()); + } + + return null; + } + + /** + * @description 使用反射设置字段值 + */ + private void setFieldValue(Object obj, String fieldName, Object value) { + if (obj == null || StringUtils.isBlank(fieldName)) { + return; + } + + try { + Class clazz = obj.getClass(); + Field field = null; + + // 先尝试直接获取字段(驼峰命名) + try { + field = clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // 如果失败,查找父类 + Class currentClass = clazz.getSuperclass(); + while (currentClass != null && field == null) { + try { + field = currentClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException ex) { + // 继续查找父类 + } + currentClass = currentClass.getSuperclass(); + } + } + + if (field != null) { + field.setAccessible(true); + // 类型转换:如果值类型不匹配,尝试转换 + Class fieldType = field.getType(); + if (value != null && !fieldType.isAssignableFrom(value.getClass())) { + // 尝试类型转换 + if (fieldType == Date.class && value instanceof String) { + // 字符串转日期(简单处理,实际可能需要更复杂的解析) + value = null; // 暂时不转换,避免解析错误 + } else if (fieldType == String.class) { + value = String.valueOf(value); + } + } + if (value != null && fieldType.isAssignableFrom(value.getClass())) { + field.set(obj, value); + } + } + } catch (Exception e) { + log.debug("设置字段值失败,对象:{},字段名:{},值:{},错误:{}", + obj.getClass().getSimpleName(), fieldName, value, e.getMessage()); + } + } + + /** + * @description 下划线命名转驼峰命名 + */ + private String snakeToCamel(String snakeCase) { + if (StringUtils.isBlank(snakeCase)) { + return snakeCase; + } + + String[] parts = snakeCase.split("_"); + if (parts.length == 0) { + return snakeCase; + } + + StringBuilder camelCase = new StringBuilder(parts[0].toLowerCase()); + for (int i = 1; i < parts.length; i++) { + if (parts[i].length() > 0) { + camelCase.append(parts[i].substring(0, 1).toUpperCase()) + .append(parts[i].substring(1).toLowerCase()); + } + } + + return camelCase.toString(); + } + } diff --git a/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml b/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml index 6b5f27649..bf31d0b9a 100644 --- a/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml +++ b/mhd_wms/src/main/resources/mapper/inMaterialDetail/InMaterialDetailMapper.xml @@ -73,6 +73,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + + + + @@ -91,7 +98,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.level, a.parent_unique_id, a.remark, a.create_time, a.create_by,a.create_by_name, a.update_time, a.update_by, a.update_by_name, a.del_flag, a.over_stock_id, a.over_stock_status, a.over_stock_type, a.SPECIFICATION_MODEL, a.SKU_CODE, a.INVOICE_NO, a.LITER, a.DIMENSIONS, a.DECLARATION_UNIT, a.BATCH_REF_NO, a.SHEET_REF_NO, a.ORIGIN_COUNTRY, a.BOX_PALLET_NO, a.CURRENCY, a.UNIT, a.DECLARED_QUANTITY, a.BOX_COUNT, a.PIECE_COUNT, a.INBOUND_QUANTITY, - a.TOTAL_NET_WEIGHT, a.TOTAL_GROSS_WEIGHT, a.TOTAL_VOLUME, a.TOTAL_AREA, a.TOTAL_PRICE + a.TOTAL_NET_WEIGHT, a.TOTAL_GROSS_WEIGHT, a.TOTAL_VOLUME, a.TOTAL_AREA, a.TOTAL_PRICE, + a.PRODUCTION_DATE, a.EXPIRY_DATE, a.INVENTORY_DATE, a.EXT_ATTR_1, a.EXT_ATTR_2, a.EXT_ATTR_3, a.EXT_ATTR_4 ,CASE WHEN (a.quantity - a.receipt_quantity) < 0 THEN 0 ELSE (a.quantity - a.receipt_quantity) diff --git a/mhd_wms/src/main/resources/mapper/receiptMaterialDetail/ReceiptMaterialDetailMapper.xml b/mhd_wms/src/main/resources/mapper/receiptMaterialDetail/ReceiptMaterialDetailMapper.xml index c49d35bb2..397136c3a 100644 --- a/mhd_wms/src/main/resources/mapper/receiptMaterialDetail/ReceiptMaterialDetailMapper.xml +++ b/mhd_wms/src/main/resources/mapper/receiptMaterialDetail/ReceiptMaterialDetailMapper.xml @@ -62,10 +62,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - - - + + + + + + + + + + + @@ -76,7 +83,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.BAR_CODE, c.SPECIFICATION_MODEL, a.QUANTITY, a.ALREADY_RECEIPT_QUANTITY, a.RECEIPT_QUANTITY, a.RECEIPT_STATUS, a.PACK_ID, a.PACK_CODE, a.PACK_NAME, a.PACK_DETAIL_ID, a.UNIT_CODE, a.UNIT_NAME, a.UNIT_NUMBER, a.MATERIAL_WAREHOUSE_CONTROL_ID, a.SERIAL_NUMBER_MANAGE, a.QUALITY_INSPECTION_MANAGE, a.QUALITY_INSPECTION_STAGE, a.QUALITY_INSPECTION_RULE, a.QUALITY_INSPECTION_RATIO, a.QUALITY_INSPECTION_TERM, a.QUALITY_INSPECTION_RESULTS, a.ALLOW_OVERCHARGE, a.OVERCHARGE_RATIO, a.BATCH_NUMBER, a.MATERIAL_STATUS_CODE, a.MATERIAL_STATUS_NAME, a.DISTRIBUTE_RULE_ID, a.DISTRIBUTE_RULE_CODE, a.DISTRIBUTE_RULE_NAME, a.CONTAINER_ID, a.CONTAINER_CODE, a.CONTAINER_TYPE, a.CONTAINER_TYPE_NAME, a.LEVEL, a.PARENT_UNIQUE_ID, a.IN_UNIQUE_ID, a.ALLOW_MODIFY, a.REMARK, a.CREATE_TIME, a.CREATE_BY, a.CREATE_BY_NAME, a.UPDATE_TIME, a.UPDATE_BY, a.UPDATE_BY_NAME, a.GEN_STOCK_SHELF, a.DEL_FLAG, - b.TOTAL_NET_WEIGHT, b.TOTAL_GROSS_WEIGHT, b.TOTAL_VOLUME, b.TOTAL_AREA, b.INVOICE_NO, b.BATCH_REF_NO, b.SHEET_REF_NO, b.BOX_PALLET_NO + ifnull(a.TOTAL_NET_WEIGHT, b.TOTAL_NET_WEIGHT) TOTAL_NET_WEIGHT, + ifnull(a.TOTAL_GROSS_WEIGHT, b.TOTAL_GROSS_WEIGHT) TOTAL_GROSS_WEIGHT, + ifnull(a.TOTAL_VOLUME, b.TOTAL_VOLUME) TOTAL_VOLUME, + ifnull(a.TOTAL_AREA, b.TOTAL_AREA) TOTAL_AREA, + ifnull(a.INVOICE_NO, b.INVOICE_NO) INVOICE_NO, + ifnull(a.BATCH_REF_NO, b.BATCH_REF_NO) BATCH_REF_NO, + ifnull(a.SHEET_REF_NO, b.SHEET_REF_NO) SHEET_REF_NO, + ifnull(a.BOX_PALLET_NO, b.BOX_PALLET_NO) BOX_PALLET_NO, + ifnull(a.PRODUCTION_DATE, b.PRODUCTION_DATE) PRODUCTION_DATE, + ifnull(a.EXPIRY_DATE, b.EXPIRY_DATE) EXPIRY_DATE, + ifnull(a.INVENTORY_DATE, b.INVENTORY_DATE) INVENTORY_DATE, + ifnull(a.EXT_ATTR_1, b.EXT_ATTR_1) EXT_ATTR_1, + ifnull(a.EXT_ATTR_2, b.EXT_ATTR_2) EXT_ATTR_2, + ifnull(a.EXT_ATTR_3, b.EXT_ATTR_3) EXT_ATTR_3, + ifnull(a.EXT_ATTR_4, b.EXT_ATTR_4) EXT_ATTR_4 from RECEIPT_MATERIAL_DETAIL a LEFT JOIN IN_MATERIAL_DETAIL b ON a.IN_UNIQUE_ID = b.UNIQUE_ID AND b.DEL_FLAG = 1 LEFT JOIN MATERIAL_BASE_INFO c ON a.MATERIAL_BASE_INFO_ID = c.MATERIAL_BASE_INFO_ID AND c.DEL_FLAG = 1