fix(oms): 出库反审核心改动(下发自愈/运输链路软删/issueStatus已驳回/uniqueId置空/仓库兜底切换)
This commit is contained in:
+150
-19
@@ -18,6 +18,10 @@ import com.mhd.oms.domain.businessDeliveryDetailsLink.repository.facade.IBusines
|
||||
import com.mhd.oms.domain.businessDeliveryDetailsLink.repository.mapper.BusinessDeliveryDetailsLinkMapper;
|
||||
import com.mhd.oms.domain.businessDocumentOrder.entity.BusinessDocumentOrder;
|
||||
import com.mhd.oms.domain.businessDocumentOrder.repository.mapper.BusinessDocumentOrderMapper;
|
||||
import com.mhd.oms.domain.businessDocumentCargoMulti.entity.BusinessDocumentCargoMulti;
|
||||
import com.mhd.oms.domain.businessDocumentCargoMulti.repository.mapper.BusinessDocumentCargoMultiMapper;
|
||||
import com.mhd.oms.domain.businessDocumentAddressMulti.entity.BusinessDocumentAddressMulti;
|
||||
import com.mhd.oms.domain.businessDocumentAddressMulti.repository.mapper.BusinessDocumentAddressMultiMapper;
|
||||
import com.mhd.oms.domain.executeOrder.entity.ExecuteOrder;
|
||||
import com.mhd.oms.domain.executeOrder.repository.mapper.ExecuteOrderMapper;
|
||||
import com.mhd.oms.domain.executionInMaterialDetail.entity.ExecutionInMaterialDetail;
|
||||
@@ -57,6 +61,7 @@ import com.mhd.oms.domain.reservationStockOutOrder.repository.todo.ReservationSt
|
||||
import com.mhd.oms.domain.reserveStockOutOrder.repository.mapper.ReserveStockOutOrderMapper;
|
||||
import com.mhd.system.api.SystemServiceFeign;
|
||||
import com.mhd.system.api.WmsServiceFeign;
|
||||
import com.mhd.system.api.WlhyServiceFeign;
|
||||
import com.mhd.system.api.domain.*;
|
||||
import com.mhd.system.api.model.LoginUser;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -122,6 +127,14 @@ public class ReservationStockOutOrderDomainService {
|
||||
private MaterialBaseInfoResolveService materialBaseInfoResolveService;
|
||||
@Resource
|
||||
private ReservationInventoryAdjustmentRecordMapper inventoryAdjustmentRecordMapper;
|
||||
@Resource
|
||||
private WlhyServiceFeign wlhyServiceFeign;
|
||||
@Autowired
|
||||
private BusinessDocumentCargoMultiMapper businessDocumentCargoMultiMapper;
|
||||
@Autowired
|
||||
private BusinessDocumentAddressMultiMapper businessDocumentAddressMultiMapper;
|
||||
@Autowired
|
||||
private com.mhd.oms.application.service.WarehouseInfoApplicationService warehouseInfoApplicationService;
|
||||
|
||||
/**
|
||||
* 分页查询出库单列表
|
||||
@@ -491,6 +504,122 @@ public class ReservationStockOutOrderDomainService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新下发前自愈清理: 历史版本反审/取消下发软删的执行明细(del_flag=2)仍占用unique_id
|
||||
* (EXECUTION_OUT_MATERIAL_DETAIL 唯一约束不含del_flag), 重新下发从预留明细复制同一unique_id会撞键;
|
||||
* 归档行的unique_id无功能用途(仅活动明细展示反查批号用到), 统一置空释放键位, 幂等可重复执行
|
||||
*/
|
||||
private void releaseArchivedDetailUniqueId(String businessOutOrderNumber) {
|
||||
List<String> executionOrderNumbers = executionStockOutOrderService.list(new QueryWrapper<ExecutionStockOutOrder>().lambda()
|
||||
.eq(ExecutionStockOutOrder::getBusinessOutOrderNumber, businessOutOrderNumber))
|
||||
.stream()
|
||||
.map(ExecutionStockOutOrder::getOutOrderNumber)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (executionOrderNumbers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
executionOutMaterialDetailService.update(null, new UpdateWrapper<ExecutionOutMaterialDetail>().lambda()
|
||||
.set(ExecutionOutMaterialDetail::getUniqueId, null)
|
||||
.eq(ExecutionOutMaterialDetail::getDelFlag, 2)
|
||||
.in(ExecutionOutMaterialDetail::getOutOrderNumber, executionOrderNumbers));
|
||||
}
|
||||
|
||||
/**
|
||||
* 反审联动软删运输链路(编辑"是否运输"=是 且审核通过后生成的链):
|
||||
* 运输业务单(business_document_order) -> 运输执行单(execute_order) -> TMS货源单/运单/运输作业单(wlhy外部服务)。
|
||||
* 定位: 出库单.businessNumber(货源单号) + business_delivery_details_link.invoiceNumber=出库单号(orderId/拆单subOrderId);
|
||||
* 执行单逐个调 TMS deleteChainByExecuteOrderNumber 软删TMS侧整链(未下发过则TMS无数据, 幂等空操作), 失败抛异常整批回滚;
|
||||
* 本地软删执行单/运输业务单及其货品/地址明细/配送明细链; 无关联运输单时直接跳过。
|
||||
*/
|
||||
private void reverseTransportChain(ReservationStockOutOrder byId) {
|
||||
String outOrderNumber = byId.getOutOrderNumber();
|
||||
Set<Long> transportOrderIds = new HashSet<>();
|
||||
if (StringUtils.isNotBlank(byId.getBusinessNumber())) {
|
||||
businessDocumentOrderMapper.selectList(new LambdaQueryWrapper<BusinessDocumentOrder>()
|
||||
.eq(BusinessDocumentOrder::getGoodsNumber, byId.getBusinessNumber())
|
||||
.eq(BusinessDocumentOrder::getDelFlag, 1))
|
||||
.forEach(order -> transportOrderIds.add(order.getId()));
|
||||
}
|
||||
for (BusinessDeliveryDetailsLink link : businessDeliveryDetailsLinkService.list(new LambdaQueryWrapper<BusinessDeliveryDetailsLink>()
|
||||
.eq(BusinessDeliveryDetailsLink::getInvoiceNumber, outOrderNumber)
|
||||
.eq(BusinessDeliveryDetailsLink::getDelFlag, 1))) {
|
||||
if (link.getOrderId() != null) {
|
||||
transportOrderIds.add(link.getOrderId());
|
||||
}
|
||||
if (StringUtils.isNotBlank(link.getSubOrderId())) {
|
||||
try {
|
||||
transportOrderIds.add(Long.valueOf(link.getSubOrderId()));
|
||||
} catch (NumberFormatException ignore) {
|
||||
//拆单子单id非纯数字的历史脏数据, 忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
if (transportOrderIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Long transportOrderId : transportOrderIds) {
|
||||
BusinessDocumentOrder transportOrder = businessDocumentOrderMapper.selectById(transportOrderId);
|
||||
if (transportOrder == null) {
|
||||
continue;
|
||||
}
|
||||
// 1. 执行单: 先软删TMS侧整链(货源单->运单->作业单), 再软删本地执行单
|
||||
// (运输业务单已被手工删除时其执行单/TMS链可能仍存活, 同样需要清理)
|
||||
List<ExecuteOrder> executeOrders = executeOrderMapper.selectList(new LambdaQueryWrapper<ExecuteOrder>()
|
||||
.eq(ExecuteOrder::getBusinessDocumentId, transportOrderId)
|
||||
.eq(ExecuteOrder::getDelFlag, 1));
|
||||
for (ExecuteOrder executeOrder : executeOrders) {
|
||||
if (StringUtils.isNotBlank(executeOrder.getGoodsNumber())) {
|
||||
AjaxResult tmsResult = wlhyServiceFeign.deleteChainByExecuteOrderNumber(executeOrder.getGoodsNumber());
|
||||
if (tmsResult == null || !"200".equals(String.valueOf(tmsResult.get("code")))) {
|
||||
throw new ServiceException("出库单[" + outOrderNumber + "]反审失败: 运输执行单货源单号["
|
||||
+ executeOrder.getGoodsNumber() + "]TMS链路软删失败: "
|
||||
+ (tmsResult == null ? "TMS服务不可用" : tmsResult.get("msg")));
|
||||
}
|
||||
}
|
||||
executeOrder.setDelFlag(2);
|
||||
executeOrderMapper.updateById(executeOrder);
|
||||
}
|
||||
// 2. 软删运输业务单及其货品/地址明细(已软删的跳过更新)
|
||||
if (!Integer.valueOf(2).equals(transportOrder.getDelFlag())) {
|
||||
transportOrder.setDelFlag(2);
|
||||
businessDocumentOrderMapper.updateById(transportOrder);
|
||||
businessDocumentCargoMultiMapper.update(null, new LambdaUpdateWrapper<BusinessDocumentCargoMulti>()
|
||||
.set(BusinessDocumentCargoMulti::getDelFlag, 2)
|
||||
.eq(BusinessDocumentCargoMulti::getOrderId, String.valueOf(transportOrderId))
|
||||
.eq(BusinessDocumentCargoMulti::getDelFlag, 1));
|
||||
businessDocumentAddressMultiMapper.update(null, new LambdaUpdateWrapper<BusinessDocumentAddressMulti>()
|
||||
.set(BusinessDocumentAddressMulti::getDelFlag, 2)
|
||||
.eq(BusinessDocumentAddressMulti::getOrderId, String.valueOf(transportOrderId))
|
||||
.eq(BusinessDocumentAddressMulti::getDelFlag, 1));
|
||||
}
|
||||
}
|
||||
// 3. 配送明细链软删(仅限指向本次删除的运输业务单, 保留指向其他运输单的链路)
|
||||
List<String> transportOrderIdStrings = transportOrderIds.stream().map(String::valueOf).collect(Collectors.toList());
|
||||
businessDeliveryDetailsLinkService.update(null, new LambdaUpdateWrapper<BusinessDeliveryDetailsLink>()
|
||||
.set(BusinessDeliveryDetailsLink::getDelFlag, 2)
|
||||
.eq(BusinessDeliveryDetailsLink::getInvoiceNumber, outOrderNumber)
|
||||
.and(wrapper -> wrapper.in(BusinessDeliveryDetailsLink::getOrderId, transportOrderIds)
|
||||
.or().in(BusinessDeliveryDetailsLink::getSubOrderId, transportOrderIdStrings))
|
||||
.eq(BusinessDeliveryDetailsLink::getDelFlag, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仓库信息(Feign优先, system服务失败/降级时本地跨库兜底), 统一委托共享组件
|
||||
*/
|
||||
private WarehouseFeignPO getWarehouseInfoWithFallback(Long warehouseId) {
|
||||
return warehouseInfoApplicationService.getWarehouseInfo(warehouseId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取仓库单号生成规则(下发生成执行单号用): 优先 Feign 调 system 服务;
|
||||
* Feign 异常/降级/返回非200时回退本地跨库直查 NGWL_TEST_SYSTEM.WAREHOUSE(同库同表, 与 getWarehouseCode 等查询同数据源),
|
||||
* 避免 system 服务抖动阻断下发; 两侧都取不到才报错并带出 Feign 真实返回原因。
|
||||
*/
|
||||
private WarehouseFeignPO getWarehouseOrderNoRule(Long warehouseId) {
|
||||
return getWarehouseInfoWithFallback(warehouseId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 审核出库单
|
||||
* @author ZhouGY
|
||||
@@ -531,6 +660,8 @@ public class ReservationStockOutOrderDomainService {
|
||||
if (activeExecutionCount > 0) {
|
||||
throw new ServiceException("出库单[" + inOrderNumber + "]已下发,请勿重复下发;如需重新下发请先取消下发");
|
||||
}
|
||||
// 自愈: 历史版本反审/取消下发的归档明细可能仍占用unique_id, 先置空释放键位再重新下发
|
||||
releaseArchivedDetailUniqueId(inOrderNumber);
|
||||
List<String> executionInOrderNumbers = new ArrayList<>();
|
||||
List<ReservationOutMaterialDetail> materialDetailList = outMaterialDetailService.list(new QueryWrapper<ReservationOutMaterialDetail>().lambda().eq(ReservationOutMaterialDetail::getOutOrderNumber, inOrderNumber));
|
||||
|
||||
@@ -566,14 +697,8 @@ public class ReservationStockOutOrderDomainService {
|
||||
reservationStockInOrder.setBusinessOutOrderNumber(inOrderNumber);
|
||||
// reservationStockInOrder.setOutOrderNumber(generateExecutionOrderNumber(warehouseCode));
|
||||
|
||||
//设置单号
|
||||
Long warehouseId1 = reservationStockInOrder.getWarehouseId();
|
||||
AjaxResult ajaxResult = systemServiceFeign.getWarehouseInfoByWarehouseId(warehouseId1);
|
||||
if (!"200".equals(String.valueOf(ajaxResult.get("code")))) {
|
||||
throw new ServiceException("获取仓库信息失败");
|
||||
}
|
||||
//仓库信息
|
||||
WarehouseFeignPO warehouseFeignPO = com.alibaba.fastjson.JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), WarehouseFeignPO.class);
|
||||
//设置单号(仓库单号规则: Feign优先, system服务失败/降级时本地跨库兜底)
|
||||
WarehouseFeignPO warehouseFeignPO = getWarehouseOrderNoRule(reservationStockInOrder.getWarehouseId());
|
||||
String orderNoGenerateRule = warehouseFeignPO.getOrderNoGenerateRule();
|
||||
String prefix = warehouseFeignPO.getOutOrderNoPrefix();
|
||||
if ("yang_pin_chu_ku".equals(stockOutOrderDO.getBusinessType())) {
|
||||
@@ -662,6 +787,8 @@ public class ReservationStockOutOrderDomainService {
|
||||
materialDetails.forEach(executionOutMaterialDetail -> {
|
||||
executionOutMaterialDetailService.update(null, new UpdateWrapper<ExecutionOutMaterialDetail>().lambda()
|
||||
.set(ExecutionOutMaterialDetail::getDelFlag, 2)
|
||||
// 归档行置空uniqueId: 明细表唯一约束不含del_flag, 保留原值会与重新下发时从预留明细复制的同一uniqueId撞键
|
||||
.set(ExecutionOutMaterialDetail::getUniqueId, null)
|
||||
.eq(ExecutionOutMaterialDetail::getMaterialDetailId, executionOutMaterialDetail.getMaterialDetailId()));
|
||||
});
|
||||
executionStockOutOrderService.update(null, new UpdateWrapper<ExecutionStockOutOrder>().lambda()
|
||||
@@ -676,7 +803,8 @@ public class ReservationStockOutOrderDomainService {
|
||||
* @description 反审出库业务单(按前端展示字段 issueStatus 判断可反审范围: 2-已审核(未出库) / 4-已出库 均可反审;
|
||||
* 0-已创建无需反审、3-已驳回可直接编辑; status 字段在出库完成后不一定同步为9, 故不作为判断依据,
|
||||
* 仅兜底排除 10-已取消/11-已关闭)。
|
||||
* 反审将单据回退到最原始状态(1-已创建, issueStatus=0)并打上反审标记:
|
||||
* 反审将单据回退到已创建(status=1)且审核状态置为已驳回(issueStatus=3, 与入库侧反审同口径, 可编辑→重新审核→重新下发)
|
||||
* 并打上反审标记:
|
||||
* WMS 侧按出库单实际状态分支还原库存(已出库: 实物库存还原+推OMS; 未出库: 仅还原分配/冻结占用)、
|
||||
* 清理执行单据(出库单/明细/拣货/复核/交接/配送, 软删+reverseFlag=1 划归【已反审】tab)、
|
||||
* 每个执行出库单生成1条出库异常记录【反审记录】(out_order_abnormal, abnormalType=3);
|
||||
@@ -738,6 +866,8 @@ public class ReservationStockOutOrderDomainService {
|
||||
executionOutMaterialDetailService.update(null, new UpdateWrapper<ExecutionOutMaterialDetail>().lambda()
|
||||
.set(ExecutionOutMaterialDetail::getDelFlag, 2)
|
||||
.set(ExecutionOutMaterialDetail::getReverseFlag, 1)
|
||||
// 归档行置空uniqueId: 明细表唯一约束不含del_flag, 保留原值会与重新下发时从预留明细复制的同一uniqueId撞键
|
||||
.set(ExecutionOutMaterialDetail::getUniqueId, null)
|
||||
.eq(ExecutionOutMaterialDetail::getMaterialDetailId, executionOutMaterialDetail.getMaterialDetailId()));
|
||||
});
|
||||
executionStockOutOrderService.update(null, new UpdateWrapper<ExecutionStockOutOrder>().lambda()
|
||||
@@ -750,15 +880,20 @@ public class ReservationStockOutOrderDomainService {
|
||||
.eq(ReservationInventoryAdjustmentRecord::getExecutionOrderNumber, executionOutOrderNumber)
|
||||
.eq(ReservationInventoryAdjustmentRecord::getDelFlag, 1));
|
||||
}
|
||||
// 反审联动: 软删关联运输链路(运输业务单/运输执行单/TMS货源单-运单-作业单), 无关联运输单时跳过
|
||||
reverseTransportChain(byId);
|
||||
}
|
||||
|
||||
// 主单回退到已创建并打反审标记; 更新条件带 issueStatus in (2,4) + 排除已取消/已关闭 兜底防并发重复反审
|
||||
// issueStatus 回退到 0-已创建(前端展示映射: 0-已创建 2-已审核 3-已驳回 4-已出库);
|
||||
// issueStatus 回退到 3-已驳回(前端展示映射: 0-已创建 2-已审核 3-已驳回 4-已出库; 与入库侧反审同口径,
|
||||
// 已驳回态可编辑→重新审核→重新下发, 重新审核通过时 reverse_status 自动复位 0 离开已反审tab);
|
||||
// 清空执行出库单号——执行单已随反审软删, 前端"是否执行"列由该字段有无值推导, 不清空会仍显示已执行
|
||||
return stockOutOrderService.update(null, new UpdateWrapper<ReservationStockOutOrder>().lambda()
|
||||
.set(ReservationStockOutOrder::getStatus, 1)
|
||||
.set(ReservationStockOutOrder::getIssueStatus, 0)
|
||||
.set(ReservationStockOutOrder::getIssueStatus, 3)
|
||||
.set(ReservationStockOutOrder::getExecutionOutOrderNumber, null)
|
||||
// 运输业务单已随反审软删, 货源单号一并清空, 重新审核后重建运输链路时自动回填
|
||||
.set(ReservationStockOutOrder::getBusinessNumber, null)
|
||||
.set(ReservationStockOutOrder::getIssueId, null)
|
||||
.set(ReservationStockOutOrder::getIssueName, null)
|
||||
.set(ReservationStockOutOrder::getIssueTime, null)
|
||||
@@ -816,6 +951,8 @@ public class ReservationStockOutOrderDomainService {
|
||||
String warehouseCode1 = byId.getWarehouseCode();
|
||||
String warehouseName1 = byId.getWarehouseName();
|
||||
String inOrderNumber = byId.getOutOrderNumber();
|
||||
// 自愈: 历史版本反审/取消下发的归档明细可能仍占用unique_id, 先置空释放键位再重新下发
|
||||
releaseArchivedDetailUniqueId(inOrderNumber);
|
||||
List<ReservationOutMaterialDetail> materialDetailList = outMaterialDetailService.list(new QueryWrapper<ReservationOutMaterialDetail>().lambda().eq(ReservationOutMaterialDetail::getOutOrderNumber, inOrderNumber));
|
||||
|
||||
// 按照 warehouseId 分组
|
||||
@@ -890,14 +1027,8 @@ public class ReservationStockOutOrderDomainService {
|
||||
reservationStockInOrder.setBusinessOutOrderNumber(inOrderNumber);
|
||||
|
||||
|
||||
//设置单号
|
||||
// Long warehouseId1 = reservationStockInOrder.getWarehouseId();
|
||||
AjaxResult ajaxResult = systemServiceFeign.getWarehouseInfoByWarehouseId(warehouseId);
|
||||
if (!"200".equals(String.valueOf(ajaxResult.get("code")))) {
|
||||
throw new ServiceException("获取仓库信息失败");
|
||||
}
|
||||
//仓库信息
|
||||
WarehouseFeignPO warehouseFeignPO = com.alibaba.fastjson.JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), WarehouseFeignPO.class);
|
||||
//设置单号(仓库单号规则: Feign优先, system服务失败/降级时本地跨库兜底)
|
||||
WarehouseFeignPO warehouseFeignPO = getWarehouseOrderNoRule(warehouseId);
|
||||
String orderNoGenerateRule = warehouseFeignPO.getOrderNoGenerateRule();
|
||||
String prefix = warehouseFeignPO.getOutOrderNoPrefix();
|
||||
if ("yang_pin_chu_ku".equals(stockOutOrderDO.getBusinessType())) {
|
||||
|
||||
Reference in New Issue
Block a user