fix(oms,wms): 入库执行单取消下发完整回退WMS数据,修复重复下发数据致取消阻断

一、取消下发回退不完整/阻断:原OMS跨库仅软删4张表,收货任务/收货作业单/质检单/电子签名残留;且getWShOrder在重复下发产生多张同号收货单时抛TooManyResultsException,取消下发整体回滚失败。WMS新增/stockInOrderApi/omsCancelInOrder:单事务软删下发链路全部8张表(入库单/明细、收货单/明细、收货任务、收货作业单/明细、质检单),幂等可重试,已开始收货报错拦截;OMS执行单取消下发改调该接口并清理待签名电子签名;预约单取消下发补齐WMS清理

二、下发失败被静默吞掉:omsInOrderAdd/omsInOrderAddDetail原返回void、Feign降级静默,OMS已下发但WMS无数据。改返回AjaxResult、fallback报错,执行单/预约单下发逐一校验返回值,失败回滚下发标记(WMS侧幂等,重下发安全)

三、下发防重原子化:issueOrder下发标记改条件更新(issue_time IS NULL)+影响行数校验,关闭并发/双击重复推送WMS的窗口
This commit is contained in:
rcx
2026-09-07 09:20:37 +08:00
parent be8ba45067
commit 627f63cbd3
7 changed files with 272 additions and 22 deletions
@@ -947,6 +947,14 @@ public class StockInOrderApplicationService {
stockInOrderDomainService.omsOrderAddDetail(inMaterialDetails);
}
/**
* OMS取消下发入库执行单:清理WMS侧下发链路产生的全部数据
* (入库单/明细、收货单/明细、收货任务、收货作业单/明细、质检单),已开始收货则报错拦截
*/
public void omsCancelInOrder(StockInOrder stockInOrder){
stockInOrderDomainService.cancelExecutionOrder(stockInOrder);
}
/**
* @description 取消入库单
* @author ZhouGY
@@ -23,6 +23,8 @@ import com.mhd.system.api.domain.ElectronicSignatureSyncDTO;
import com.mhd.system.api.domain.PackDetailFeignPO;
import com.mhd.system.api.domain.WarehouseFeignPO;
import com.mhd.system.api.model.LoginUser;
import com.mhd.wms.domain.deliveTask.entity.DeliveTask;
import com.mhd.wms.domain.deliveTask.repository.facade.IDeliveTaskService;
import com.mhd.wms.domain.inMaterialDetail.entity.InMaterialDetail;
import com.mhd.wms.domain.inMaterialDetail.repository.facade.IInMaterialDetailService;
import com.mhd.wms.domain.inMaterialDetail.repository.po.InMaterialDetailPO;
@@ -49,6 +51,8 @@ import com.mhd.wms.domain.stockInOrder.repository.facade.IStockInOrderService;
import com.mhd.wms.domain.stockInOrder.repository.mapper.StockInOrderMapper;
import com.mhd.wms.domain.stockInOrder.repository.po.StockInOrderPO;
import com.mhd.wms.domain.stockInOrder.repository.todo.StockInOrderDO;
import com.mhd.wms.domain.stockInTaskOrder.entity.StockInTaskOrder;
import com.mhd.wms.domain.stockInTaskOrder.repository.facade.IStockInTaskOrderService;
import com.mhd.wms.domain.stockReceiptOrder.entity.StockReceiptOrder;
import com.mhd.wms.domain.stockReceiptOrder.repository.facade.IStockReceiptOrderService;
import com.mhd.wms.domain.stockReceiptOrder.repository.po.StockReceiptOrderPO;
@@ -59,6 +63,8 @@ import com.mhd.wms.domain.stockShelfOrder.repository.facade.IStockShelfOrderServ
import com.mhd.wms.domain.stockShelfOrder.repository.po.StockShelfOrderPO;
import com.mhd.wms.domain.stockShelfOrder.repository.todo.StockShelfOrderDO;
import com.mhd.wms.domain.stockShelfOrder.service.StockShelfOrderDomainService;
import com.mhd.wms.domain.taskReceiptMaterialDetail.entity.TaskReceiptMaterialDetail;
import com.mhd.wms.domain.taskReceiptMaterialDetail.repository.facade.ITaskReceiptMaterialDetailService;
import com.mhd.wms.interfaces.dto.stockInOrder.StockInOrderDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -115,6 +121,12 @@ public class StockInOrderDomainService {
@Autowired
private IStockShelfOrderService stockShelfOrderService;
@Autowired
private IDeliveTaskService deliveTaskService;
@Autowired
private IStockInTaskOrderService stockInTaskOrderService;
@Autowired
private ITaskReceiptMaterialDetailService taskReceiptMaterialDetailService;
@Autowired
private IdGenerator idGenerator;
/**
@@ -721,6 +733,117 @@ public class StockInOrderDomainService {
autoAuditOmsInOrder(inMaterialDetails.get(0).getInOrderNumber());
}
/**
* OMS取消下发入库执行单:WMS侧补偿清理(与下发链路 omsOrderAdd→omsOrderAddDetail→自动审核→生成收货单/任务 对称)
* <p>下发链路在WMS落库的表(按清理顺序):</p>
* <ul>
* <li>task_receipt_material_detail 收货作业单明细(按收货作业单号)</li>
* <li>stock_in_task_order 收货作业单(按入库单号)</li>
* <li>delive_task 收货任务(按收货单号 tracking_number</li>
* <li>quality_inspection 质检单(按入库单号)</li>
* <li>receipt_material_detail 收货单明细(按收货单号)</li>
* <li>stock_receipt_order 收货单(按入库单号)</li>
* <li>in_material_detail 入库单明细(按入库单号)</li>
* <li>stock_in_order 入库单(按入库单号)</li>
* </ul>
* <p>历史缺陷:OMS侧只跨库删除4张表,收货任务/收货作业单/质检单残留;且按单号取收货单号
* 在重复下发产生多张同号收货单时会 TooManyResultsException,取消下发整体失败(流程阻断)。</p>
*/
@Transactional(rollbackFor = Exception.class)
public void cancelExecutionOrder(StockInOrder stockInOrder) {
String inOrderNumber = stockInOrder.getInOrderNumber();
if (StringUtils.isEmpty(inOrderNumber)) {
throw new ServiceException("取消下发失败:入库单号为空");
}
List<StockInOrder> stockInOrders = stockInOrderService.list(new LambdaQueryWrapper<StockInOrder>()
.eq(StockInOrder::getInOrderNumber, inOrderNumber)
.eq(StockInOrder::getDelFlag, 1));
if (CollectionUtils.isEmpty(stockInOrders)) {
//幂等:WMS无该单数据(从未下发成功或已清理过),直接成功,保证OMS取消下发可重试
return;
}
//收货进度拦截:已开始收货(3)/上架中(4)/已入库(5)的数据不允许取消,否则会删掉真实收货与库存依据
for (StockInOrder order : stockInOrders) {
if (order.getStatus() != null && order.getStatus() >= 3) {
throw new ServiceException("入库单[" + inOrderNumber + "]已在WMS开始收货/上架,无法取消下发");
}
}
//收货单(含历史重复下发产生的多张同号收货单,全部查出统一清理,避免按单号取一条漏删/报错)
List<StockReceiptOrder> receiptOrders = stockReceiptOrderService.list(new LambdaQueryWrapper<StockReceiptOrder>()
.eq(StockReceiptOrder::getInOrderNumber, inOrderNumber)
.eq(StockReceiptOrder::getDelFlag, 1));
List<String> receiptOrderNumbers = receiptOrders.stream()
.map(StockReceiptOrder::getReceiptOrderNumber)
.filter(StringUtils::isNotEmpty)
.distinct()
.collect(Collectors.toList());
for (StockReceiptOrder receiptOrder : receiptOrders) {
if (receiptOrder.getStatus() != null && receiptOrder.getStatus() > 2) {
throw new ServiceException("入库单[" + inOrderNumber + "]对应收货单已完成收货,无法取消下发");
}
}
//收货作业单(type=1收货,入库单号关联),先记下任务号用于删作业单明细
List<StockInTaskOrder> taskOrders = stockInTaskOrderService.list(new LambdaQueryWrapper<StockInTaskOrder>()
.eq(StockInTaskOrder::getInOrderNumber, inOrderNumber)
.eq(StockInTaskOrder::getDelFlag, 1));
List<String> taskNumbers = taskOrders.stream()
.map(StockInTaskOrder::getTaskNumber)
.filter(StringUtils::isNotEmpty)
.distinct()
.collect(Collectors.toList());
//1.收货作业单明细
if (!taskNumbers.isEmpty()) {
taskReceiptMaterialDetailService.update(new UpdateWrapper<TaskReceiptMaterialDetail>().lambda()
.set(TaskReceiptMaterialDetail::getDelFlag, 2)
.in(TaskReceiptMaterialDetail::getTaskNumber, taskNumbers)
.eq(TaskReceiptMaterialDetail::getDelFlag, 1));
}
//2.收货作业单
if (!taskOrders.isEmpty()) {
stockInTaskOrderService.update(new UpdateWrapper<StockInTaskOrder>().lambda()
.set(StockInTaskOrder::getDelFlag, 2)
.eq(StockInTaskOrder::getInOrderNumber, inOrderNumber)
.eq(StockInTaskOrder::getDelFlag, 1));
}
//3.收货任务(tracking_number=收货单号;补"RV-"+入库单号兜底历史同号收货单)
if (!receiptOrderNumbers.isEmpty()) {
Set<String> trackingNumbers = new HashSet<>(receiptOrderNumbers);
trackingNumbers.add("RV-" + inOrderNumber);
deliveTaskService.update(new UpdateWrapper<DeliveTask>().lambda()
.set(DeliveTask::getDelFlag, 2)
.in(DeliveTask::getTrackingNumber, trackingNumbers)
.eq(DeliveTask::getTaskType, 1)
.eq(DeliveTask::getDelFlag, 1));
}
//4.质检单
qualityInspectionService.update(new UpdateWrapper<com.mhd.wms.domain.qualityInspection.entity.QualityInspection>().lambda()
.set(com.mhd.wms.domain.qualityInspection.entity.QualityInspection::getDelFlag, 2)
.eq(com.mhd.wms.domain.qualityInspection.entity.QualityInspection::getInOrderNumber, inOrderNumber)
.eq(com.mhd.wms.domain.qualityInspection.entity.QualityInspection::getDelFlag, 1));
//5.收货单明细
if (!receiptOrderNumbers.isEmpty()) {
receiptMaterialDetailService.update(new UpdateWrapper<ReceiptMaterialDetail>().lambda()
.set(ReceiptMaterialDetail::getDelFlag, 2)
.in(ReceiptMaterialDetail::getReceiptOrderNumber, receiptOrderNumbers)
.eq(ReceiptMaterialDetail::getDelFlag, 1));
}
//6.收货单
stockReceiptOrderService.update(new UpdateWrapper<StockReceiptOrder>().lambda()
.set(StockReceiptOrder::getDelFlag, 2)
.eq(StockReceiptOrder::getInOrderNumber, inOrderNumber)
.eq(StockReceiptOrder::getDelFlag, 1));
//7.入库单明细
materialDetailService.update(new UpdateWrapper<InMaterialDetail>().lambda()
.set(InMaterialDetail::getDelFlag, 2)
.eq(InMaterialDetail::getInOrderNumber, inOrderNumber)
.eq(InMaterialDetail::getDelFlag, 1));
//8.入库单
stockInOrderService.update(new UpdateWrapper<StockInOrder>().lambda()
.set(StockInOrder::getDelFlag, 2)
.eq(StockInOrder::getInOrderNumber, inOrderNumber)
.eq(StockInOrder::getDelFlag, 1));
}
/**
* OMS下发入库单明细保存后自动审核通过(生成收货单并更新审核状态)
*/
@@ -199,8 +199,10 @@ public class StockInOrderApi extends BaseController {
*/
@ApiOperation("oms下发单保存")
@PostMapping(value = "/omsInOrderAdd")
public void omsInOrderAdd(@RequestBody StockInOrder stockInOrder) {
public AjaxResult omsInOrderAdd(@RequestBody StockInOrder stockInOrder) {
//返回执行结果而非void:OMS侧需感知保存失败(此前Feign降级被静默吞掉,OMS显示下发成功但WMS无数据,流程阻断)
stockInOrderApplicationService.omsOrderAdd(stockInOrder);
return AjaxResult.success();
}
/**
@@ -311,8 +313,20 @@ public class StockInOrderApi extends BaseController {
*/
@ApiOperation("oms下发单明细保存")
@PostMapping(value = "/omsInOrderAddDetail")
public void omsInOrderAddDetail(@RequestBody List<InMaterialDetail> inMaterialDetails) {
public AjaxResult omsInOrderAddDetail(@RequestBody List<InMaterialDetail> inMaterialDetails) {
//返回执行结果而非void:明细保存含自动审核链路,失败必须让OMS感知并回滚下发标记
stockInOrderApplicationService.omsOrderAddDetail(inMaterialDetails);
return AjaxResult.success();
}
/**
* oms取消下发入库执行单:清理WMS侧下发生成的入库单及下游收货链路数据(逻辑删除)
*/
@ApiOperation("oms取消下发入库单清理")
@PostMapping(value = "/omsCancelInOrder")
public AjaxResult omsCancelInOrder(@RequestBody StockInOrder stockInOrder) {
stockInOrderApplicationService.omsCancelInOrder(stockInOrder);
return AjaxResult.success();
}
@ApiOperation("查询入库信息(通过入库单号)")