fix(oms,wms): 出库单下发WMS失败被静默吞掉,修复WMS出库拣货不显示OMS单据

- OMS建单/下发前校验明细数量>0且已关联库存
- OMS检查WMS自动分配/生成拣货单返回值,失败即报错回滚
- WMS自动分配各类失败场景抛带单号的明确异常,替代NPE
- WMS接单幂等保护,失败重试不产生重复数据
This commit is contained in:
rcx
2026-09-02 14:32:13 +08:00
parent 72cb1d8c07
commit 434348f972
3 changed files with 107 additions and 6 deletions
@@ -1122,8 +1122,20 @@ public class StockOutOrderApplicationService {
// throw new ServiceException("库存不存在:" + batchRefNo + " " + sheetRefNo + " " + boxPalletNo);
// }
Long materialInventoryId = detail.getMaterialInventoryId();
String materialDesc = detail.getMaterialCode() != null ? detail.getMaterialCode()
: (detail.getMaterialName() != null ? detail.getMaterialName() : String.valueOf(detail.getUniqueId()));
//OMS推送的库存ID缺失或在WMS不存在时明确报错(此前直接解引用空指针,异常被Feign降级吞掉后单据卡死)
if (materialInventoryId == null || materialInventoryId <= 0) {
throw new ServiceException("出库单[" + outOrderNumber + "]物料[" + materialDesc + "]未关联库存,无法自动分配");
}
MaterialInventory materialInventory = materialInventoryMapper.selectById(materialInventoryId);
if (materialInventory == null) {
throw new ServiceException("出库单[" + outOrderNumber + "]物料[" + materialDesc + "]库存不存在,库存ID=" + materialInventoryId + ",无法自动分配");
}
BigDecimal remainingQuantity = detail.getQuantity(); // 计划数量
if (remainingQuantity == null || remainingQuantity.compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException("出库单[" + outOrderNumber + "]物料[" + materialDesc + "]计划数量为0,无法自动分配");
}
// 当前物料的可用库存
BigDecimal availableStock = materialInventory.getAllocationQuantity();
@@ -1132,9 +1144,9 @@ public class StockOutOrderApplicationService {
continue;
}
if (availableStock.compareTo(remainingQuantity) < 0) {
throw new RuntimeException(
String.format("可用库存不足,计划数量:%s,当前可用库存:%s",
remainingQuantity, availableStock)
throw new ServiceException(
String.format("出库单[%s]物料[%s]可用库存不足,计划数量:%s,当前可用库存:%s",
outOrderNumber, materialDesc, remainingQuantity, availableStock)
);
}
// detail.setMaterialInventoryId(materialInventory.getMaterialInventoryId());
@@ -1148,6 +1160,10 @@ public class StockOutOrderApplicationService {
detail.setAllocationQuantity(remainingQuantity);
materialDetailList2.add(detail);
}
//全部明细因可用库存为0被跳过时明确报错(此前空明细落入batchAssignUpdate抛出笼统的"物料明细不能为空",难定位)
if (materialDetailList2.isEmpty()) {
throw new ServiceException("出库单[" + stockOutOrderDb.getOutOrderNumber() + "]所有物料明细的可用库存为0,无法自动分配");
}
stockOutOrderD.setMaterialDetailList(materialDetailList2);
StockOutOrderDO assembleStockOutOrderDO = assembleParamByOutOrder(stockOutOrderD);
Boolean assignResult = stockOutOrderDomainService.autoAssign(assembleStockOutOrderDO);
@@ -2542,6 +2542,13 @@ public class StockOutOrderDomainService {
private static final String OMS_AUTO_AUDIT_REMARK = "OMS下发自动审核";
public void omsOrderAdd(StockOutOrder stockOutOrder) {
//幂等保护:重复下发时同单号活动单已存在则跳过,避免插入重复出库单(下发失败重试场景此前会产生重复数据)
StockOutOrder existOrder = stockOutOrderService.getOne(new QueryWrapper<StockOutOrder>().lambda()
.eq(StockOutOrder::getOutOrderNumber, stockOutOrder.getOutOrderNumber())
.eq(StockOutOrder::getDelFlag, 1), false);
if (existOrder != null) {
return;
}
// 任务下发用户id
String userId = stockInOrderMapper.queryWarehouseUserId(stockOutOrder.getOrganizationId(), stockOutOrder.getWarehouseId(), stockOutOrder.getTopOrganizationId());
stockOutOrder.setTaskIssueUserId(userId);
@@ -2608,6 +2615,11 @@ public class StockOutOrderDomainService {
if (CollectionUtils.isEmpty(outMaterialDetails)) {
return;
}
//幂等保护:重复下发时先逻辑删除同单号已存在的活动明细,避免重复插入导致分配/拣货数据错乱
outMaterialDetailService.update(new UpdateWrapper<OutMaterialDetail>().lambda()
.set(OutMaterialDetail::getDelFlag, 2)
.eq(OutMaterialDetail::getOutOrderNumber, outMaterialDetails.get(0).getOutOrderNumber())
.eq(OutMaterialDetail::getDelFlag, 1));
outMaterialDetailService.saveBatch(outMaterialDetails);
autoAuditOmsOutOrder(outMaterialDetails.get(0).getOutOrderNumber());
}
@@ -2617,6 +2629,14 @@ public class StockOutOrderDomainService {
if (CollectionUtils.isEmpty(deliveryDetailsLinks)) {
return;
}
//幂等保护:重复下发时先逻辑删除同单号已存在的配送明细,避免重复插入
String firstOrderNumber = deliveryDetailsLinks.get(0).getOrderNumber();
if (StringUtils.isNotEmpty(firstOrderNumber)) {
deliveryDetailsLinkService.update(new UpdateWrapper<com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink>().lambda()
.set(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getDelFlag, 2)
.eq(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getOrderNumber, firstOrderNumber)
.eq(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getDelFlag, 1));
}
for (DeliveryDetailsLink deliveryDetailsLink : deliveryDetailsLinks) {
com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink deliveryDetailsLinkEntity = new com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink();
BeanUtils.copyProperties(deliveryDetailsLink, deliveryDetailsLinkEntity);