fix(oms,wms):执行单重复下发致WMS收货明细翻倍修复,executeAndIssue获取仓库信息失败修复
一、收货明细翻倍(executionStockInOrderApi/issueOrder下发后,WMS收货管理详情明细×2): 根因:执行单下发接口无防重 + WMS接收端无幂等。executeAndIssue已自动下发过的执行单 仍可被手动再次下发(issueTime已置但无校验),重复推送使WMS插入同号入库主单+第二份 in_material_detail,再生成第二张同号收货单(收货单号"RV-"+入库单号确定性生成), 收货管理详情按单号查明细即双倍。四层防御: 1. OMS执行单issueOrder补防重:issueTime非空拒绝下发(与executeAndIssue对齐), inOrderIds去重防同请求重复推送 2. WMS omsOrderAdd主单幂等:同单号有效单(del_flag=1)已存在则跳过插入 3. WMS omsOrderAddDetail明细幂等:按oms_in_material_detail判重,已存在行不再插入; 未传ID的行保持原插入行为 4. WMS autoAuditOmsInOrder取单补orderByAsc(in_order_id)消除同号取单随机性; auditApprove生成收货单前按收货单号查重过滤,已生成过的单不再重复生成 二、executeAndIssue报"获取仓库信息失败": 1. 明细行warehouseId=0时兜底改用主表仓库(与下发issueOrder兜底逻辑对齐), 不再拿无效仓库ID调system服务 2. executeAndIssue/issueOrder两处报错增强为带仓库ID与错误信息,便于定位 存量已翻倍数据(重复入库单/明细/收货单)需另行软删清理,本次仅防新增
This commit is contained in:
+51
-2
@@ -676,6 +676,17 @@ public class StockInOrderDomainService {
|
||||
private static final String OMS_AUTO_AUDIT_REMARK = "OMS下发自动审核";
|
||||
|
||||
public void omsOrderAdd(StockInOrder stockInOrder) {
|
||||
// 幂等防御:OMS重复下发(下发接口防重缺失/请求重放)会以相同入库单号再次推送主单,
|
||||
// 同单号有效单已存在则跳过插入,防止WMS侧出现重复入库单、明细与收货单
|
||||
String inOrderNumber = stockInOrder.getInOrderNumber();
|
||||
if (!StringUtils.isEmpty(inOrderNumber)) {
|
||||
long exists = stockInOrderService.count(new QueryWrapper<StockInOrder>().lambda()
|
||||
.eq(StockInOrder::getInOrderNumber, inOrderNumber)
|
||||
.eq(StockInOrder::getDelFlag, 1));
|
||||
if (exists > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
stockInOrderService.save(stockInOrder);
|
||||
}
|
||||
|
||||
@@ -684,7 +695,29 @@ public class StockInOrderDomainService {
|
||||
if (CollectionUtils.isEmpty(inMaterialDetails)) {
|
||||
return;
|
||||
}
|
||||
materialDetailService.saveBatch(inMaterialDetails);
|
||||
// 幂等防御:OMS重复推送同单号明细(重复下发/请求重放)时,按OMS明细ID(omsInMaterialDetail)判重,
|
||||
// 已存在的行不再插入,防止WMS入库明细与下游收货明细翻倍;
|
||||
// omsInMaterialDetail为空(调用方未传)时无从判重,保持原插入行为
|
||||
String inOrderNumber = inMaterialDetails.get(0).getInOrderNumber();
|
||||
List<InMaterialDetail> toInsert = inMaterialDetails;
|
||||
if (!StringUtils.isEmpty(inOrderNumber)) {
|
||||
List<InMaterialDetail> existingDetails = materialDetailService.list(new QueryWrapper<InMaterialDetail>().lambda()
|
||||
.eq(InMaterialDetail::getInOrderNumber, inOrderNumber)
|
||||
.eq(InMaterialDetail::getDelFlag, 1));
|
||||
Set<String> existingOmsDetailIds = existingDetails.stream()
|
||||
.map(InMaterialDetail::getOmsInMaterialDetail)
|
||||
.filter(StringUtils::isNotEmpty)
|
||||
.collect(Collectors.toSet());
|
||||
if (!existingOmsDetailIds.isEmpty()) {
|
||||
toInsert = inMaterialDetails.stream()
|
||||
.filter(d -> StringUtils.isEmpty(d.getOmsInMaterialDetail())
|
||||
|| !existingOmsDetailIds.contains(d.getOmsInMaterialDetail()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
if (!toInsert.isEmpty()) {
|
||||
materialDetailService.saveBatch(toInsert);
|
||||
}
|
||||
autoAuditOmsInOrder(inMaterialDetails.get(0).getInOrderNumber());
|
||||
}
|
||||
|
||||
@@ -700,6 +733,9 @@ public class StockInOrderDomainService {
|
||||
StockInOrder stockInOrder = stockInOrderService.getOne(new QueryWrapper<StockInOrder>().lambda()
|
||||
.eq(StockInOrder::getInOrderNumber, inOrderNumber)
|
||||
.eq(StockInOrder::getDelFlag, 1)
|
||||
// 历史数据可能存在同号重复主单,固定取最早一张(首次下发那张),
|
||||
// 无排序时LIMIT 1返回行不确定,可能命中未审核的重复单导致重复生成同号收货单
|
||||
.orderByAsc(StockInOrder::getInOrderId)
|
||||
.last("LIMIT 1"));
|
||||
if (stockInOrder == null || AUDIT_STATUS_PASS == stockInOrder.getAuditStatus()) {
|
||||
return;
|
||||
@@ -1202,13 +1238,26 @@ public class StockInOrderDomainService {
|
||||
throw new ServiceException("出库单不存在或已审核通过");
|
||||
}
|
||||
List<String> inOrderNumberList = stockInOrderPOList.stream().map(StockInOrderPO::getInOrderNumber).collect(Collectors.toList());
|
||||
// 收货单防重:收货单号"RV-"+入库单号为确定性生成,该单号收货单已存在(历史重复下发/重复审核
|
||||
// 已生成过)时不再为对应入库单生成收货单,避免同号收货单叠加导致收货管理详情明细翻倍
|
||||
List<String> receiptNumbersToCheck = inOrderNumberList.stream().map(no -> "RV-" + no).collect(Collectors.toList());
|
||||
Set<String> existingReceiptNumbers = stockReceiptOrderService.list(new QueryWrapper<StockReceiptOrder>().lambda()
|
||||
.in(StockReceiptOrder::getReceiptOrderNumber, receiptNumbersToCheck)
|
||||
.eq(StockReceiptOrder::getDelFlag, 1))
|
||||
.stream().map(StockReceiptOrder::getReceiptOrderNumber).collect(Collectors.toSet());
|
||||
List<StockInOrderPO> pendingAuditOrders = stockInOrderPOList.stream()
|
||||
.filter(p -> !existingReceiptNumbers.contains("RV-" + p.getInOrderNumber()))
|
||||
.collect(Collectors.toList());
|
||||
if (pendingAuditOrders.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
InMaterialDetailDO inMaterialDetailDO = new InMaterialDetailDO();
|
||||
inMaterialDetailDO.setInOrderNumberList(inOrderNumberList);
|
||||
List<InMaterialDetailPO> inMaterialDetailPOList = materialDetailService.queryListChildren(inMaterialDetailDO);
|
||||
Map<String, List<InMaterialDetailPO>> inMaterialDetailListMap = inMaterialDetailPOList.stream().collect(Collectors.groupingBy(InMaterialDetailPO::getInOrderNumber));
|
||||
|
||||
List<StockReceiptOrderDO> stockReceiptOrderDOList = new ArrayList<>();
|
||||
stockInOrderPOList.forEach(p -> {
|
||||
pendingAuditOrders.forEach(p -> {
|
||||
StockReceiptOrderDO stockReceiptOrderDO = new StockReceiptOrderDO();
|
||||
BeanUtils.copyProperties(p, stockReceiptOrderDO);
|
||||
stockReceiptOrderDO.setReceiptOrderNumber("RV-"+p.getInOrderNumber());
|
||||
|
||||
Reference in New Issue
Block a user