fix(oms,wms): 下单冻结推送OMS镜像丢loginUser致NPE静默失败——O侧库存查询冻结不同步根因修复

- 根因: WMS pushOmsMirror 用 MaterialInventoryParamDO(无loginUser字段)copyProperties到OMS参数, loginUser=null 致 OMS kctzjl 写调整记录时 NPE(先于xgkc执行)→镜像不更新+无调整记录, 异常被 Feign @Async+fallback(return null) 完全吞掉, WMS 侧静默无感知
- 修复1(WMS): pushOmsMirror 显式 setLoginUser, 3 个调用点传入登录态兜底后的 loginUser
- 修复2(OMS): kctzjl 补三个文案分支——下单冻结(并入库存冻结:可用-冻结+库存不变, adjustType=3)、下单解冻(并入取消分配:可用+冻结-库存不变)、出库反审-还原冻结(新增:实物+冻结+可用不变, 合并快照两步推送)
- 修复3(OMS): omsEdit try-catch 失败 log.error 带 type/kctzType/relateNo/全部匹配键后原样抛出, 推送失败不再无痕(此前连错误日志都没有)
- 存量: 在途冻结单 R260915004 镜像需按 16.7 节 SQL 补同步; R260915003 因 RQZ260723005 入库镜像行缺失需先补建镜像行(存量对账问题单独排查)
This commit is contained in:
rcx
2026-09-15 16:54:02 +08:00
parent a473387574
commit 6f43bed5d4
2 changed files with 52 additions and 8 deletions
@@ -25,6 +25,7 @@ import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.domain.MaterialInventoryOmsParamDO;
import com.mhd.system.api.domain.MaterialInventoryPO;
import com.mhd.system.api.model.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -43,6 +44,7 @@ import java.util.stream.Collectors;
* @author gen
* @date 2024-05-29
*/
@Slf4j
@Service
public class ReservationMaterialInventoryImpl extends ServiceImpl<ReservationMaterialInventoryMapper, ReservationMaterialInventory> implements IReservationMaterialInventoryService {
@Autowired
@@ -131,6 +133,22 @@ public class ReservationMaterialInventoryImpl extends ServiceImpl<ReservationMat
@Override
public Boolean omsEdit(MaterialInventoryOmsParamDO materialInventoryOmsParamDO) {
// ★推送处理异常必须留痕:WMS 侧 omsEdit 为 @Async+fallback 静默(失败连 error 日志都没有),
// 这里若不记日志,失败将完全无痕(历史 bug:下单冻结推送 loginUser=null 在 kctzjl NPE
// 镜像未更新且全程无日志)。记录匹配键便于定位,记录后原样抛出保持语义
try {
return doOmsEdit(materialInventoryOmsParamDO);
} catch (Exception e) {
log.error("omsEdit库存镜像更新失败:type={}, kctzType={}, relateNo={}, 匹配键: materialBaseInfoId={}, warehouseId={}, inOrderNumber={}, lotNumber={}, batchNumber={}, purchaseDate={}",
materialInventoryOmsParamDO.getType(), materialInventoryOmsParamDO.getKctzType(), materialInventoryOmsParamDO.getRelateNo(),
materialInventoryOmsParamDO.getMaterialBaseInfoId(), materialInventoryOmsParamDO.getWarehouseId(),
materialInventoryOmsParamDO.getInOrderNumber(), materialInventoryOmsParamDO.getLotNumber(),
materialInventoryOmsParamDO.getBatchNumber(), materialInventoryOmsParamDO.getPurchaseDate(), e);
throw e;
}
}
private Boolean doOmsEdit(MaterialInventoryOmsParamDO materialInventoryOmsParamDO) {
String inOrderNumber = materialInventoryOmsParamDO.getInOrderNumber();
String lotNumber = materialInventoryOmsParamDO.getLotNumber();
String batchNumber = materialInventoryOmsParamDO.getBatchNumber();
@@ -293,7 +311,7 @@ public class ReservationMaterialInventoryImpl extends ServiceImpl<ReservationMat
}
inventoryAdjustmentRecord.setMaterialBaseInfoId(materialInventory.getMaterialBaseInfoId());
inventoryAdjustmentRecord.setAdjustType(1L);
if ("库存冻结".equals(adjustAction)) {
if ("库存冻结".equals(adjustAction) || "下单冻结".equals(adjustAction)) {
inventoryAdjustmentRecord.setAdjustType(3L);
}
inventoryAdjustmentRecord.setOrganizationId(materialInventory.getOrganizationId());
@@ -339,8 +357,8 @@ public class ReservationMaterialInventoryImpl extends ServiceImpl<ReservationMat
inventoryAdjustmentRecord.setAdjustedGrossWeight(nz(materialInventory.getGrossWeight()));//毛重
inventoryAdjustmentRecord.setAdjustedVolume(nz(materialInventory.getVolume()));//体积
inventoryAdjustmentRecord.setAdjustedArea(nz(materialInventory.getArea()));//积
} else if ("取消分配".equals(adjustAction)) {
// 与分配相反:可用增加、冻结减少,总库存不变
} else if ("取消分配".equals(adjustAction) || "下单解冻".equals(adjustAction)) {
// 与分配相反:可用增加、冻结减少,总库存不变"下单解冻":OMS下单冻结后的取消/编辑重锁释放,同数学)
BigDecimal invBefore = nz(materialInventory.getInventoryQuantity());
BigDecimal allocBefore = nz(materialInventory.getAllocationQuantity());
BigDecimal freezeBefore = nz(materialInventory.getFreezeQuantity());
@@ -434,7 +452,8 @@ public class ReservationMaterialInventoryImpl extends ServiceImpl<ReservationMat
inventoryAdjustmentRecord.setAdjustedGrossWeight(materialInventory.getGrossWeight());
inventoryAdjustmentRecord.setAdjustedVolume(materialInventory.getVolume());
inventoryAdjustmentRecord.setAdjustedArea(materialInventory.getArea());
} else if ("库存冻结".equals(adjustAction)) {
} else if ("库存冻结".equals(adjustAction) || "下单冻结".equals(adjustAction)) {
// "下单冻结"(OMS防超卖):总库存不变;可用减少、冻结增加——与"库存冻结"同数学
inventoryAdjustmentRecord.setAllocationBeforeQuantity(nz(materialInventory.getAllocationQuantity()));
inventoryAdjustmentRecord.setAllocationAfterQuantity(nz(materialInventory.getAllocationQuantity()).subtract(qty));
inventoryAdjustmentRecord.setFreezeBeforeQuantity(nz(materialInventory.getFreezeQuantity()));
@@ -488,6 +507,27 @@ public class ReservationMaterialInventoryImpl extends ServiceImpl<ReservationMat
inventoryAdjustmentRecord.setAdjustedGrossWeight(materialInventory.getGrossWeight());
inventoryAdjustmentRecord.setAdjustedVolume(materialInventory.getVolume());
inventoryAdjustmentRecord.setAdjustedArea(materialInventory.getArea());
} else if ("出库反审-还原冻结".equals(adjustAction)) {
// OMS下单冻结模式出库反审:还原为"下单已冻结待出库"——实物增加、冻结增加、可用不变,
// 与交接扣减 ckjj(库存-冻结-)互逆;WMS 侧以 type=1+type=7 两步推送合成,此处记录一步合并快照
BigDecimal invBefore = nz(materialInventory.getInventoryQuantity());
BigDecimal allocBefore = nz(materialInventory.getAllocationQuantity());
BigDecimal freezeBefore = nz(materialInventory.getFreezeQuantity());
inventoryAdjustmentRecord.setInventoryBeforeQuantity(invBefore);
inventoryAdjustmentRecord.setInventoryAfterQuantity(invBefore.add(qty));
inventoryAdjustmentRecord.setAllocationBeforeQuantity(allocBefore);
inventoryAdjustmentRecord.setAllocationAfterQuantity(allocBefore);
inventoryAdjustmentRecord.setFreezeBeforeQuantity(freezeBefore);
inventoryAdjustmentRecord.setFreezeAfterQuantity(freezeBefore.add(qty));
inventoryAdjustmentRecord.setAdjustType(3L);
inventoryAdjustmentRecord.setNetWeight(nz(materialInventory.getNetWeight()));
inventoryAdjustmentRecord.setGrossWeight(nz(materialInventory.getGrossWeight()));
inventoryAdjustmentRecord.setVolume(nz(materialInventory.getVolume()));
inventoryAdjustmentRecord.setArea(nz(materialInventory.getArea()));
inventoryAdjustmentRecord.setAdjustedNetWeight(nz(materialInventory.getNetWeight()));
inventoryAdjustmentRecord.setAdjustedGrossWeight(nz(materialInventory.getGrossWeight()));
inventoryAdjustmentRecord.setAdjustedVolume(nz(materialInventory.getVolume()));
inventoryAdjustmentRecord.setAdjustedArea(nz(materialInventory.getArea()));
}
@@ -382,7 +382,7 @@ public class OutOrderFreezeRecordDomainService {
for (PendingFreeze pending : pendingFreezes) {
insertFreezeRecord(pending.row, pending.quantity, businessOrderNumber, pending.uniqueId, pending.relateNo, holder);
MaterialInventoryParamDO paramDO = buildParamDO(pending.row, pending.quantity, "7", pending.relateNo);
pushOmsMirror(paramDO, "下单冻结");
pushOmsMirror(paramDO, "下单冻结", holder.loginUser);
}
}
@@ -405,7 +405,7 @@ public class OutOrderFreezeRecordDomainService {
record.setFreezeStatus(OutOrderFreezeRecord.STATUS_RELEASED);
record.setUpdateTime(new Date());
outOrderFreezeRecordService.updateById(record);
pushOmsMirror(buildParamDO(row, record.getFreezeQuantity(), "3", record.getRelateNo()), "下单解冻");
pushOmsMirror(buildParamDO(row, record.getFreezeQuantity(), "3", record.getRelateNo()), "下单解冻", holder.loginUser);
}
/**
@@ -454,13 +454,17 @@ public class OutOrderFreezeRecordDomainService {
}
/**
* 推送OMS镜像库存(type=7下单冻结:可用-冻结+ / type=3下单解冻:可用+冻结-),与分配/交接推送同模式
* 推送OMS镜像库存(type=7下单冻结:可用-冻结+ / type=3下单解冻:可用+冻结-),与分配/交接推送同模式
* ★loginUser 必须显式传入:MaterialInventoryParamDO 无 loginUser 字段,copyProperties 不会带过去,
* 推过去为 null 时 OMS 侧 kctzjl 写调整记录 loginUser.getUserid() 直接 NPE——
* kctzjl 先于 xgkc 执行,NPE 导致镜像完全不更新且异常被 Feign 异步/fallback 吞掉(历史静默失败根因)
*/
private void pushOmsMirror(MaterialInventoryParamDO paramDO, String kctzType) {
private void pushOmsMirror(MaterialInventoryParamDO paramDO, String kctzType, LoginUser loginUser) {
try {
MaterialInventoryOmsParamDO omsParamDO = new MaterialInventoryOmsParamDO();
BeanUtils.copyProperties(paramDO, omsParamDO);
omsParamDO.setKctzType(kctzType);
omsParamDO.setLoginUser(loginUser);
omsServiceFeign.omsEdit(omsParamDO);
} catch (Exception e) {
// 镜像推送失败不阻断冻结主流程(与分配/交接链路同口径),由OMS侧定时对账兜底