From 37dd374bda0fd3cedce50c1e5ba10f3701caff66 Mon Sep 17 00:00:00 2001 From: rcx <3084692334@qq.com> Date: Fri, 11 Sep 2026 15:14:46 +0800 Subject: [PATCH] =?UTF-8?q?fix(wms):=20=E5=85=A5=E5=BA=93=E5=8D=95?= =?UTF-8?q?=E5=AF=BC=E5=85=A5"=E8=AF=A5=E8=B4=A7=E4=B8=BB=E4=B8=8B?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E8=AF=A5=E6=96=99=E5=8F=B7"?= =?UTF-8?q?=E8=AF=AF=E6=8A=A5=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 根因:Excel客户名称按USER表user_name解析货主ID,同名双账号(如3519/3525)解析到非档案归属账号,带错误shipperId查物料必为空 - 料号匹配:主查询(料号+顶级组织+解析shipperId)为空时,去掉货主条件按档案shipper_name与Excel客户名称等值兜底匹配,命中后以档案货主纠正单据shipperId/shipperCode/shipperName - 新增pickMaterialByCode挑选:料号精确等值优先于LIKE模糊命中,避免子串料号截胡 - SKU校验:档案条码barCode为空时跳过比对,档案有值时仍严格校验 - 校验失败输出诊断日志并附解析shipperId/登录topOrganizationId,区分货主错配(原因A)与组织口径(原因B) --- .../StockInOrderApplicationService.java | 106 ++++++++++++++++-- 1 file changed, 98 insertions(+), 8 deletions(-) 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 03d02de33..2e6033b25 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 @@ -2040,21 +2040,71 @@ public class StockInOrderApplicationService { r.getMaterialCode(), topOrganizationId, shipperId); List materialList = materialBaseInfoService.queryList(queryDO); log.info("料号查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0); - MaterialBaseInfoPO materialBaseInfoPO = null; - if (materialList != null && !materialList.isEmpty()) { - materialBaseInfoPO = materialList.get(0); + MaterialBaseInfoPO materialBaseInfoPO = pickMaterialByCode(materialList, r.getMaterialCode(), shipperId, order.getShipperName()); + // 兜底:按名称解析出的shipperId可能与物料档案shipper_id不一致(系统中存在同名货主账号, + // 按user_name精确匹配解析到了另一个同名列货主),此时去掉货主ID条件再查一次, + // 用物料档案冗余的shipper_name与Excel客户名称等值匹配 + if (materialBaseInfoPO == null && StringUtils.isNotBlank(order.getShipperName())) { + MaterialBaseInfoDO fallbackDO = new MaterialBaseInfoDO(); + fallbackDO.setMaterialCode(r.getMaterialCode()); + if (topOrganizationId != null) { + fallbackDO.setTopOrganizationId(topOrganizationId); + } + List fallbackList = materialBaseInfoService.queryList(fallbackDO); + materialBaseInfoPO = pickMaterialByCode(fallbackList, r.getMaterialCode(), null, order.getShipperName()); + if (materialBaseInfoPO != null) { + log.warn("导入料号校验:按解析shipperId未匹配到物料,已按档案货主名称兜底匹配。料号: [{}], 解析shipperId: {}, 档案shipperId: {}, 档案shipperName: {}", + r.getMaterialCode(), shipperId, materialBaseInfoPO.getShipperId(), materialBaseInfoPO.getShipperName()); + // 以档案货主为准纠正单据货主信息,避免后续shipperParam按错误的shipperId反查覆盖货主名称 + if (materialBaseInfoPO.getShipperId() != null) { + shipperId = materialBaseInfoPO.getShipperId(); + order.setShipperId(shipperId); + } + if (StringUtils.isNotBlank(materialBaseInfoPO.getShipperCode())) { + order.setShipperCode(materialBaseInfoPO.getShipperCode()); + } + if (StringUtils.isNotBlank(materialBaseInfoPO.getShipperName())) { + order.setShipperName(materialBaseInfoPO.getShipperName()); + } + } + } + if (materialBaseInfoPO != null) { materialBaseInfoId = materialBaseInfoPO.getMaterialBaseInfoId(); - log.info("通过料号查询到物料基础信息,料号: {}, 物料ID: {}, 货主ID: {}", + log.info("通过料号查询到物料基础信息,料号: {}, 物料ID: {}, 货主ID: {}", r.getMaterialCode(), materialBaseInfoId, shipperId); } else { // 如果提供了料号但查询不到(或不属于该货主),直接报错,不允许导入 - String errorMsg = String.format("导入失败:该货主下不存在该料号(货主名称=%s,料号=%s)。请确保该料号已在物料管理中创建,且属于该货主", - order.getShipperName(), r.getMaterialCode()); + // 诊断对照查询(仅用于日志定位,不影响流程):去掉货主ID条件再查一次, + // 用于区分两类原因:A-按名称解析出的shipperId与物料档案shipper_id不一致(货主错配); + // B-登录人topOrganizationId与物料档案top_organization_id不一致(组织口径不一致) + try { + MaterialBaseInfoDO diagDO = new MaterialBaseInfoDO(); + diagDO.setMaterialCode(r.getMaterialCode()); + if (topOrganizationId != null) { + diagDO.setTopOrganizationId(topOrganizationId); + } + List diagList = materialBaseInfoService.queryList(diagDO); + if (diagList != null && !diagList.isEmpty()) { + MaterialBaseInfoPO diagPo = diagList.get(0); + log.error("导入料号校验诊断:去掉货主条件后可查到物料,判定为货主解析错配(原因A)。料号: [{}], 解析shipperId: {}, 登录topOrganizationId: {}, 物料ID: {}, 档案shipperId: {}, 档案shipperName: {}, 档案topOrganizationId: {}", + r.getMaterialCode(), shipperId, topOrganizationId, + diagPo.getMaterialBaseInfoId(), diagPo.getShipperId(), diagPo.getShipperName(), diagPo.getTopOrganizationId()); + } else { + log.error("导入料号校验诊断:去掉货主条件后仍查不到物料,判定为组织口径不一致(原因B)。料号: [{}], 解析shipperId: {}, 登录topOrganizationId: {}", + r.getMaterialCode(), shipperId, topOrganizationId); + } + } catch (Exception diagEx) { + log.warn("导入料号校验诊断查询异常,料号: [{}], 错误: {}", r.getMaterialCode(), diagEx.getMessage()); + } + String errorMsg = String.format("导入失败:该货主下不存在该料号(货主名称=%s,料号=%s,解析shipperId=%s,登录topOrganizationId=%s)。请确保该料号已在物料管理中创建,且属于该货主", + order.getShipperName(), r.getMaterialCode(), + shipperId == null ? "空" : shipperId, topOrganizationId == null ? "空" : topOrganizationId); log.error(errorMsg); throw new ServiceException(errorMsg); } // 校验料号与规格型号/SKU码一致性:按料号查到档案后逐项比对,任何一项不符直接报对应错误 - // 双方(trim后)必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错 + // 规格型号(trim后)双方必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错 + // SKU码:档案条码(barCode)为空时跳过比对(存量档案普遍未维护条码);档案有值时仍严格比对 String excelSpec = StringUtils.trimToEmpty(r.getSpecificationModel()); String dbSpec = StringUtils.trimToEmpty(materialBaseInfoPO.getSpecificationModel()); if (!excelSpec.equals(dbSpec)) { @@ -2064,7 +2114,7 @@ public class StockInOrderApplicationService { } String excelSku = StringUtils.trimToEmpty(r.getSkuCode()); String dbSku = StringUtils.trimToEmpty(materialBaseInfoPO.getBarCode()); - if (!excelSku.equals(dbSku)) { + if (StringUtils.isNotEmpty(dbSku) && !excelSku.equals(dbSku)) { throw new ServiceException(String.format("导入失败:料号[%s](商品名称:%s)SKU码与物料档案不一致(Excel:%s / 档案:%s)", r.getMaterialCode(), r.getMaterialName(), excelSku.isEmpty() ? "空" : excelSku, dbSku.isEmpty() ? "空" : dbSku)); @@ -2398,6 +2448,46 @@ public class StockInOrderApplicationService { return oid != null && loginOrganizationId.equals(oid); } + /** + * 导入校验:从按料号(SQL为LIKE模糊)查出的物料列表中挑选匹配记录。 + * 优先级:料号精确等值优先于模糊命中(避免子串料号误匹配); + * 同级内优先 shipperId 精确匹配,其次 shipperName 等值匹配,最后取排序第一条(与原 get(0) 行为一致)。 + */ + private MaterialBaseInfoPO pickMaterialByCode(List materialList, String materialCode, Long shipperId, String shipperName) { + if (materialList == null || materialList.isEmpty()) { + return null; + } + String code = StringUtils.trimToEmpty(materialCode); + String name = StringUtils.trimToEmpty(shipperName); + MaterialBaseInfoPO exactCodeFirst = null; + MaterialBaseInfoPO anyFirst = null; + // 第一轮:料号精确等值中优先 shipperId 精确匹配 + for (MaterialBaseInfoPO po : materialList) { + if (anyFirst == null) { + anyFirst = po; + } + if (StringUtils.isEmpty(code) || !code.equals(StringUtils.trimToEmpty(po.getMaterialCode()))) { + continue; + } + if (exactCodeFirst == null) { + exactCodeFirst = po; + } + if (shipperId != null && shipperId.equals(po.getShipperId())) { + return po; + } + } + // 第二轮:料号精确等值中按档案货主名称等值匹配 + if (StringUtils.isNotEmpty(name)) { + for (MaterialBaseInfoPO po : materialList) { + if (StringUtils.isNotEmpty(code) && code.equals(StringUtils.trimToEmpty(po.getMaterialCode())) + && name.equals(StringUtils.trimToEmpty(po.getShipperName()))) { + return po; + } + } + } + return exactCodeFirst != null ? exactCodeFirst : anyFirst; + } + /** * @description 根据货主名称或编号获取货主ID(用于导入时提前获取货主ID) * @param shipperName 货主名称