From b209d8cb6d71b8fbb446d98615917fdba54ea114 Mon Sep 17 00:00:00 2001 From: rcx <3084692334@qq.com> Date: Fri, 21 Aug 2026 18:20:22 +0800 Subject: [PATCH] =?UTF-8?q?fix(oms):=E5=87=BA=E5=BA=93=E6=98=8E=E7=BB=86ma?= =?UTF-8?q?terialBaseInfoId=E8=87=AA=E5=8A=A8=E7=BA=A0=E6=AD=A3,=E6=9D=9C?= =?UTF-8?q?=E7=BB=9D=E8=84=8F=E7=89=A9=E6=96=99ID=E8=90=BD=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:客户端推单把materialInventoryId传进materialBaseInfoId字段(或漏传为0), 出库明细存脏ID,编辑/保存报"物料基础信息不存在"(如DCCK034存了库存ID477/444, 真实物料ID应为233/231)。预约端校验原先静默跳过,脏数据持续入库(7-15起200+行)。 一、新增MaterialBaseInfoResolveService三级解析: baseId直查 → 库存ID反查纠正 → 物料编码+组织兜底,全部失败返回null 二、三处setMaterialDetailInfo改为纠正+回填(预约/业务/执行出库单): 查不到抛错带定位信息(baseId/库存ID/物料编码/单号); 纠正后的ID随保存落库,旧脏单重新保存即自愈; 预约端由静默跳过改为抛错 三、两处pushOutOrderDetail推送入口(预约/业务)加纠正, 反查不到拒绝保存,脏数据不再入库 注:存量脏数据修复SQL另行手动执行;下发复制链(预约→业务→执行)不走校验, --- .../ExecutionStockOutOrderDomainService.java | 19 ++++++- .../MaterialBaseInfoResolveService.java | 57 +++++++++++++++++++ ...ReservationStockOutOrderDomainService.java | 33 ++++++++++- .../ReserveStockOutOrderDomainService.java | 34 ++++++++++- 4 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 mhd_oms/src/main/java/com/mhd/oms/domain/materialBaseInfo/service/MaterialBaseInfoResolveService.java diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockOutOrder/service/ExecutionStockOutOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockOutOrder/service/ExecutionStockOutOrderDomainService.java index 36603f13e..19d42bb59 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockOutOrder/service/ExecutionStockOutOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/executionStockOutOrder/service/ExecutionStockOutOrderDomainService.java @@ -31,6 +31,7 @@ import com.mhd.oms.domain.executionStockOutOrder.repository.facade.IExecutionSto import com.mhd.oms.domain.executionStockOutOrder.repository.mapper.ExecutionStockOutOrderMapper; import com.mhd.oms.domain.executionStockOutOrder.repository.po.ExecutionStockOutOrderPO; import com.mhd.oms.domain.executionStockOutOrder.repository.todo.ExecutionStockOutOrderDO; +import com.mhd.oms.domain.materialBaseInfo.service.MaterialBaseInfoResolveService; import com.mhd.oms.domain.reservationDeliveryDetailsLink.entity.ReservationDeliveryDetailsLink; import com.mhd.oms.domain.reservationDeliveryDetailsLink.repository.facade.IReservationDeliveryDetailsLinkService; //import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfoPO; @@ -102,6 +103,8 @@ public class ExecutionStockOutOrderDomainService { private ReservationStockInOrderMapper stockInOrderMapper; @Autowired private ReserveStockOutOrderMapper reserveStockOutOrderMapper; + @Autowired + private MaterialBaseInfoResolveService materialBaseInfoResolveService; /** * 分页查询出库单列表 */ @@ -902,10 +905,22 @@ public class ExecutionStockOutOrderDomainService { List outMaterialDetailDOList = stockOutOrderDO.getMaterialDetailList(); outMaterialDetailDOList.forEach(outMaterialDetailDO -> { // Long materialBaseInfoId = outMaterialDetailDO.getMaterialBaseInfoId(); - MaterialBaseInfoPO materialBaseInfoPO = reservationStockInOrderMapper.getinfo(outMaterialDetailDO.getMaterialBaseInfoId()); + // 物料ID自动纠正:baseId直查 → 库存ID反查 → 编码+组织兜底(修复客户端把库存ID传进baseId或漏传) + Long orgId = outMaterialDetailDO.getOrganizationId() != null + ? outMaterialDetailDO.getOrganizationId() : stockOutOrderDO.getOrganizationId(); + // 注意:解析器返回的是 reservationStockInOrder 包下的 MaterialBaseInfoPO,与本类 import 的同名PO不是同一类型,故用全限定名 + com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoResolveService.resolve( + outMaterialDetailDO.getMaterialBaseInfoId(), + outMaterialDetailDO.getMaterialInventoryId(), + outMaterialDetailDO.getMaterialCode(), orgId); if (materialBaseInfoPO == null){ - throw new ServiceException("物料基础信息不存在"); + throw new ServiceException("物料基础信息不存在:materialBaseInfoId=" + outMaterialDetailDO.getMaterialBaseInfoId() + + ",materialInventoryId=" + outMaterialDetailDO.getMaterialInventoryId() + + ",materialCode=" + outMaterialDetailDO.getMaterialCode() + + ",出库单号=" + stockOutOrderDO.getOutOrderNumber()); } + // 回填纠正后的物料ID,脏数据随保存落库自愈 + outMaterialDetailDO.setMaterialBaseInfoId(materialBaseInfoPO.getMaterialBaseInfoId()); outMaterialDetailDO.setMaterialCode(materialBaseInfoPO.getMaterialCode()); outMaterialDetailDO.setMaterialName(materialBaseInfoPO.getMaterialName()); outMaterialDetailDO.setBarCode(materialBaseInfoPO.getBarCode()); diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/materialBaseInfo/service/MaterialBaseInfoResolveService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/materialBaseInfo/service/MaterialBaseInfoResolveService.java new file mode 100644 index 000000000..510ca34b6 --- /dev/null +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/materialBaseInfo/service/MaterialBaseInfoResolveService.java @@ -0,0 +1,57 @@ +package com.mhd.oms.domain.materialBaseInfo.service; + +import com.mhd.common.core.utils.StringUtils; +import com.mhd.oms.domain.reservationMaterialInventory.entity.ReservationMaterialInventory; +import com.mhd.oms.domain.reservationMaterialInventory.repository.mapper.ReservationMaterialInventoryMapper; +import com.mhd.oms.domain.reservationStockInOrder.repository.mapper.ReservationStockInOrderMapper; +import com.mhd.oms.domain.reservationStockInOrder.repository.po.MaterialBaseInfoPO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 物料基础信息解析器(带自动纠正) + * 解决客户端推单把 materialInventoryId 传进 materialBaseInfoId 字段、或漏传导致明细存脏ID的问题。 + * 三级解析:1.按baseId直查 → 2.按库存ID反查纠正 → 3.按物料编码+组织兜底 + */ +@Service +public class MaterialBaseInfoResolveService { + + @Autowired + private ReservationStockInOrderMapper reservationStockInOrderMapper; + + @Autowired + private ReservationMaterialInventoryMapper reservationMaterialInventoryMapper; + + /** + * 解析物料基础信息,优先按 materialBaseInfoId 直查; + * 无效时用 materialInventoryId 反查库存表取正确 baseInfoId; + * 仍无效时按 物料编码+组织ID 兜底。 + * + * @return 解析成功返回物料信息(调用方需用 po.getMaterialBaseInfoId() 回填纠正后的ID);全部失败返回 null + */ + public MaterialBaseInfoPO resolve(Long materialBaseInfoId, Long materialInventoryId, String materialCode, Long organizationId) { + // 1. 优先按 baseId 直查(有效ID不受影响) + if (materialBaseInfoId != null && materialBaseInfoId > 0) { + MaterialBaseInfoPO po = reservationStockInOrderMapper.getinfo(materialBaseInfoId); + if (po != null) { + return po; + } + } + // 2. baseId 无效但带了库存ID → 反查库存表拿正确 baseInfoId(修复"库存ID传进baseId"场景) + if (materialInventoryId != null && materialInventoryId > 0) { + ReservationMaterialInventory inventory = reservationMaterialInventoryMapper.selectById(materialInventoryId); + if (inventory != null && inventory.getMaterialBaseInfoId() != null + && (inventory.getDelFlag() == null || inventory.getDelFlag() == 1)) { + MaterialBaseInfoPO po = reservationStockInOrderMapper.getinfo(inventory.getMaterialBaseInfoId()); + if (po != null) { + return po; + } + } + } + // 3. 兜底:按物料编码+组织查(修复 baseId=0 漏传场景) + if (StringUtils.isNotBlank(materialCode) && organizationId != null) { + return reservationStockInOrderMapper.getByCode(materialCode.trim(), organizationId); + } + return null; + } +} 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 91887172f..03be30fc3 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 @@ -30,6 +30,7 @@ import com.mhd.oms.domain.executionStockOutOrder.repository.facade.IExecutionSto import com.mhd.oms.domain.executionStockOutOrder.repository.mapper.ExecutionStockOutOrderMapper; import com.mhd.oms.domain.executionStockOutOrder.repository.todo.ExecutionStockOutOrderDO; import com.mhd.oms.domain.executionStockOutOrder.service.ExecutionStockOutOrderApplicationService; +import com.mhd.oms.domain.materialBaseInfo.service.MaterialBaseInfoResolveService; import com.mhd.oms.domain.reservationDeliveryDetailsLink.entity.ReservationDeliveryDetailsLink; import com.mhd.oms.domain.reservationDeliveryDetailsLink.repository.facade.IReservationDeliveryDetailsLinkService; import com.mhd.oms.domain.reservationInMaterialDetail.entity.ReservationInMaterialDetail; @@ -115,6 +116,8 @@ public class ReservationStockOutOrderDomainService { private ReservationStockOutOrderMapper reservationStockOutOrderMapper; @Autowired private ReserveStockOutOrderMapper reserveStockOutOrderMapper; + @Autowired + private MaterialBaseInfoResolveService materialBaseInfoResolveService; /** * 分页查询出库单列表 @@ -370,6 +373,21 @@ public class ReservationStockOutOrderDomainService { public Boolean pushOutOrderDetail(OutMaterialDetailTZPD outMaterialDetail) { ReservationOutMaterialDetail reservationOutMaterialDetail = new ReservationOutMaterialDetail(); BeanUtils.copyProperties(outMaterialDetail, reservationOutMaterialDetail); + // 推送数据物料ID纠正:客户端曾把库存ID传进 materialBaseInfoId 或漏传,纠正后再入库,查不到拒绝保存 + MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoResolveService.resolve( + reservationOutMaterialDetail.getMaterialBaseInfoId(), + reservationOutMaterialDetail.getMaterialInventoryId(), + reservationOutMaterialDetail.getMaterialCode(), + reservationOutMaterialDetail.getOrganizationId()); + if (materialBaseInfoPO == null){ + throw new ServiceException("推送出库明细物料无法识别,拒绝保存:materialBaseInfoId=" + reservationOutMaterialDetail.getMaterialBaseInfoId() + + ",materialInventoryId=" + reservationOutMaterialDetail.getMaterialInventoryId() + + ",materialCode=" + reservationOutMaterialDetail.getMaterialCode() + + ",出库单号=" + reservationOutMaterialDetail.getOutOrderNumber()); + } + reservationOutMaterialDetail.setMaterialBaseInfoId(materialBaseInfoPO.getMaterialBaseInfoId()); + reservationOutMaterialDetail.setMaterialCode(materialBaseInfoPO.getMaterialCode()); + reservationOutMaterialDetail.setMaterialName(materialBaseInfoPO.getMaterialName()); return outMaterialDetailService.save(reservationOutMaterialDetail); } @@ -1064,10 +1082,21 @@ public class ReservationStockOutOrderDomainService { List outMaterialDetailDOList = stockOutOrderDO.getMaterialDetailList(); outMaterialDetailDOList.forEach(outMaterialDetailDO -> { // Long materialBaseInfoId = outMaterialDetailDO.getMaterialBaseInfoId(); - MaterialBaseInfoPO materialBaseInfoPO = reservationStockInOrderMapper.getinfo(outMaterialDetailDO.getMaterialBaseInfoId()); + // 物料ID自动纠正:baseId直查 → 库存ID反查 → 编码+组织兜底(修复客户端把库存ID传进baseId或漏传) + Long orgId = outMaterialDetailDO.getOrganizationId() != null + ? outMaterialDetailDO.getOrganizationId() : stockOutOrderDO.getOrganizationId(); + MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoResolveService.resolve( + outMaterialDetailDO.getMaterialBaseInfoId(), + outMaterialDetailDO.getMaterialInventoryId(), + outMaterialDetailDO.getMaterialCode(), orgId); if (materialBaseInfoPO == null){ - throw new ServiceException("物料基础信息不存在"); + throw new ServiceException("物料基础信息不存在:materialBaseInfoId=" + outMaterialDetailDO.getMaterialBaseInfoId() + + ",materialInventoryId=" + outMaterialDetailDO.getMaterialInventoryId() + + ",materialCode=" + outMaterialDetailDO.getMaterialCode() + + ",出库单号=" + stockOutOrderDO.getOutOrderNumber()); } + // 回填纠正后的物料ID,脏数据随保存落库自愈 + outMaterialDetailDO.setMaterialBaseInfoId(materialBaseInfoPO.getMaterialBaseInfoId()); outMaterialDetailDO.setMaterialCode(materialBaseInfoPO.getMaterialCode()); outMaterialDetailDO.setMaterialName(materialBaseInfoPO.getMaterialName()); outMaterialDetailDO.setBarCode(materialBaseInfoPO.getBarCode()); diff --git a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java index 2c5b20546..5b81fafaa 100644 --- a/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java +++ b/mhd_oms/src/main/java/com/mhd/oms/domain/reserveStockOutOrder/service/ReserveStockOutOrderDomainService.java @@ -10,6 +10,7 @@ import com.mhd.common.core.utils.bean.BeanUtils; import com.mhd.common.core.web.domain.AjaxResult; import com.mhd.common.security.utils.SecurityUtils; import com.mhd.oms.domain.businessDocumentOrder.repository.mapper.BusinessDocumentOrderMapper; +import com.mhd.oms.domain.materialBaseInfo.service.MaterialBaseInfoResolveService; import com.mhd.oms.domain.reservationInMaterialDetail.entity.ReservationInMaterialDetail; import com.mhd.oms.domain.reservationOutMaterialDetail.entity.ReservationOutMaterialDetail; import com.mhd.oms.domain.reservationOutMaterialDetail.repository.facade.IReservationOutMaterialDetailService; @@ -80,6 +81,8 @@ public class ReserveStockOutOrderDomainService { private ReservationStockOutOrderDomainService reservationStockOutOrderDomainService; @Autowired private SystemServiceFeign systemServiceFeign; + @Autowired + private MaterialBaseInfoResolveService materialBaseInfoResolveService; /** * 分页查询出库单列表 @@ -324,6 +327,21 @@ public class ReserveStockOutOrderDomainService { public Boolean pushOutOrderDetail(OutMaterialDetailTZPD outMaterialDetail) { ReserveOutMaterialDetail reservationOutMaterialDetail = new ReserveOutMaterialDetail(); BeanUtils.copyProperties(outMaterialDetail, reservationOutMaterialDetail); + // 推送数据物料ID纠正:客户端曾把库存ID传进 materialBaseInfoId 或漏传,纠正后再入库,查不到拒绝保存 + MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoResolveService.resolve( + reservationOutMaterialDetail.getMaterialBaseInfoId(), + reservationOutMaterialDetail.getMaterialInventoryId(), + reservationOutMaterialDetail.getMaterialCode(), + reservationOutMaterialDetail.getOrganizationId()); + if (materialBaseInfoPO == null){ + throw new ServiceException("推送出库明细物料无法识别,拒绝保存:materialBaseInfoId=" + reservationOutMaterialDetail.getMaterialBaseInfoId() + + ",materialInventoryId=" + reservationOutMaterialDetail.getMaterialInventoryId() + + ",materialCode=" + reservationOutMaterialDetail.getMaterialCode() + + ",出库单号=" + reservationOutMaterialDetail.getOutOrderNumber()); + } + reservationOutMaterialDetail.setMaterialBaseInfoId(materialBaseInfoPO.getMaterialBaseInfoId()); + reservationOutMaterialDetail.setMaterialCode(materialBaseInfoPO.getMaterialCode()); + reservationOutMaterialDetail.setMaterialName(materialBaseInfoPO.getMaterialName()); return outMaterialDetailService.save(reservationOutMaterialDetail); } @@ -833,10 +851,22 @@ public class ReserveStockOutOrderDomainService { List outMaterialDetailDOList = stockOutOrderDO.getMaterialDetailList(); outMaterialDetailDOList.forEach(outMaterialDetailDO -> { // Long materialBaseInfoId = outMaterialDetailDO.getMaterialBaseInfoId(); - MaterialBaseInfoPO materialBaseInfoPO = reservationStockInOrderMapper.getinfo(outMaterialDetailDO.getMaterialBaseInfoId()); + // 物料ID自动纠正:baseId直查 → 库存ID反查 → 编码+组织兜底(修复客户端把库存ID传进baseId或漏传) + // 原逻辑查不到物料时静默跳过,导致物料信息缺失且脏ID落库,现改为纠正失败即抛错 + Long orgId = outMaterialDetailDO.getOrganizationId() != null + ? outMaterialDetailDO.getOrganizationId() : stockOutOrderDO.getOrganizationId(); + MaterialBaseInfoPO materialBaseInfoPO = materialBaseInfoResolveService.resolve( + outMaterialDetailDO.getMaterialBaseInfoId(), + outMaterialDetailDO.getMaterialInventoryId(), + outMaterialDetailDO.getMaterialCode(), orgId); if (materialBaseInfoPO == null){ - return; + throw new ServiceException("物料基础信息不存在:materialBaseInfoId=" + outMaterialDetailDO.getMaterialBaseInfoId() + + ",materialInventoryId=" + outMaterialDetailDO.getMaterialInventoryId() + + ",materialCode=" + outMaterialDetailDO.getMaterialCode() + + ",出库单号=" + stockOutOrderDO.getOutOrderNumber()); } + // 回填纠正后的物料ID,脏数据随保存落库自愈 + outMaterialDetailDO.setMaterialBaseInfoId(materialBaseInfoPO.getMaterialBaseInfoId()); outMaterialDetailDO.setMaterialCode(materialBaseInfoPO.getMaterialCode()); outMaterialDetailDO.setMaterialName(materialBaseInfoPO.getMaterialName()); outMaterialDetailDO.setBarCode(materialBaseInfoPO.getBarCode());