Compare commits
10
Commits
cae62e83a5
...
e60f22979c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e60f22979c | ||
|
|
84ff45b43d | ||
|
|
892cc30999 | ||
|
|
da76816533 | ||
|
|
b86ab75dcf | ||
|
|
796bb99a8b | ||
|
|
f9a50ae353 | ||
|
|
2094ea31cd | ||
|
|
788bae9a16 | ||
|
|
a65cca1cfa |
@@ -539,6 +539,13 @@ public interface WlhyServiceFeign {
|
||||
@GetMapping("/feign/order/cancelIssueDocuments")
|
||||
public AjaxResult cancelIssueDocuments(@RequestParam(name="executeOrderId") String executeOrderId);
|
||||
|
||||
/**
|
||||
* OMS出库业务单反审联动: 按执行单货源编号软删TMS整条链路(货源单->运单->运输作业单, is_delete=1), 幂等,
|
||||
* 与 cancelIssueDocuments(仅关闭货源单且有有效运单即拒绝)不同, 反审口径不留TMS数据
|
||||
*/
|
||||
@PostMapping("/feign/order/deleteChainByExecuteOrderNumber")
|
||||
public AjaxResult deleteChainByExecuteOrderNumber(@RequestParam(name="executeOrderNumber") String executeOrderNumber);
|
||||
|
||||
@GetMapping(value = "/ntocc/tmsSettlementExchangeRate/queryList")
|
||||
public AjaxResult<?> queryList(@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
||||
|
||||
@@ -74,21 +74,21 @@ public interface WmsServiceFeign {
|
||||
*/
|
||||
@ApiOperation("oms下发单保存")
|
||||
@PostMapping(value = "/stockOutOrderApi/omsOutOrderAdd")
|
||||
public void omsOutOrderAdd(@RequestBody StockOutOrder stockOutOrder);
|
||||
public AjaxResult omsOutOrderAdd(@RequestBody StockOutOrder stockOutOrder);
|
||||
|
||||
/**
|
||||
* oms下发单明细保存
|
||||
*/
|
||||
@ApiOperation("oms下发单明细保存")
|
||||
@PostMapping(value = "/stockOutOrderApi/omsOutOrderAddDetail")
|
||||
public void omsOutOrderAddDetail(@RequestBody List<OutMaterialDetail> outMaterialDetails);
|
||||
public AjaxResult omsOutOrderAddDetail(@RequestBody List<OutMaterialDetail> outMaterialDetails);
|
||||
|
||||
/**
|
||||
* oms下发单明细保存
|
||||
*/
|
||||
@ApiOperation("oms下发单明细保存")
|
||||
@PostMapping(value = "/stockOutOrderApi/omsOutOrderAddDeliveryDetailsLink")
|
||||
public void omsOutOrderAddDeliveryDetailsLink(@RequestBody List<DeliveryDetailsLink> deliveryDetailsLinks);
|
||||
public AjaxResult omsOutOrderAddDeliveryDetailsLink(@RequestBody List<DeliveryDetailsLink> deliveryDetailsLinks);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+6
@@ -551,6 +551,12 @@ public class RemoteWlhyFallbackFactory implements FallbackFactory<WlhyServiceFei
|
||||
return AjaxResult.error(cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AjaxResult deleteChainByExecuteOrderNumber(String executeOrderNumber) {
|
||||
//返回错误而非静默成功, 让OMS反审事务能感知失败并整体回滚
|
||||
return AjaxResult.error("TMS反审联动软删链路失败(服务降级):" + cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AjaxResult<?> queryList(Integer pageNo, Integer pageSize, String pushStatus, String organizationId) {
|
||||
return AjaxResult.error(cause.getMessage());
|
||||
|
||||
+7
-4
@@ -57,16 +57,19 @@ public class RemoteWmsFallbackFactory implements FallbackFactory<WmsServiceFeign
|
||||
}
|
||||
|
||||
@Override
|
||||
public void omsOutOrderAdd(StockOutOrder stockOutOrder) {
|
||||
public AjaxResult omsOutOrderAdd(StockOutOrder stockOutOrder) {
|
||||
//返回错误而非静默成功: 降级吞掉会让OMS继续走分配, 残留"有单无明细"的垃圾单
|
||||
return AjaxResult.error("WMS下发单保存失败(服务降级):" + cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void omsOutOrderAddDetail(List<OutMaterialDetail> outMaterialDetails) {
|
||||
public AjaxResult omsOutOrderAddDetail(List<OutMaterialDetail> outMaterialDetails) {
|
||||
return AjaxResult.error("WMS下发单明细保存失败(服务降级):" + cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void omsOutOrderAddDeliveryDetailsLink(List<DeliveryDetailsLink> deliveryDetailsLinks) {
|
||||
|
||||
public AjaxResult omsOutOrderAddDeliveryDetailsLink(List<DeliveryDetailsLink> deliveryDetailsLinks) {
|
||||
return AjaxResult.error("WMS下发单配送明细保存失败(服务降级):" + cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.mhd.oms.application.service;
|
||||
|
||||
import com.mhd.common.core.exception.ServiceException;
|
||||
import com.mhd.common.core.web.domain.AjaxResult;
|
||||
import com.mhd.oms.domain.reservationStockInOrder.repository.mapper.ReservationStockInOrderMapper;
|
||||
import com.mhd.system.api.SystemServiceFeign;
|
||||
import com.mhd.system.api.domain.WarehouseFeignPO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 仓库信息获取(带本地兜底): 下发/下单冻结/保存等流程原先直接 Feign 调 system 服务取仓库信息,
|
||||
* system 服务未启动/降级/返回非200时整个流程被"获取仓库信息失败"阻断。
|
||||
* 本组件统一收口: 优先 Feign, 失败时回退本地跨库直查 "NGWL_TEST_SYSTEM".WAREHOUSE(与 Feign 同库同表, OMS 库账号可读),
|
||||
* 两侧都取不到才抛错并带出 Feign 真实返回原因。
|
||||
*
|
||||
* @date 2026/9/11
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WarehouseInfoApplicationService {
|
||||
|
||||
@Autowired
|
||||
private SystemServiceFeign systemServiceFeign;
|
||||
@Autowired
|
||||
private ReservationStockInOrderMapper reservationStockInOrderMapper;
|
||||
|
||||
/**
|
||||
* 获取仓库信息: Feign 优先, 失败走本地兜底; 两边都取不到抛 ServiceException
|
||||
*
|
||||
* @param warehouseId 仓库id
|
||||
* @return 仓库信息(含编码/名称/单号生成规则/库存锁定模式等)
|
||||
*/
|
||||
public WarehouseFeignPO getWarehouseInfo(Long warehouseId) {
|
||||
if (warehouseId == null) {
|
||||
throw new ServiceException("仓库ID不能为空");
|
||||
}
|
||||
AjaxResult ajaxResult = null;
|
||||
try {
|
||||
ajaxResult = systemServiceFeign.getWarehouseInfoByWarehouseId(warehouseId);
|
||||
} catch (Exception e) {
|
||||
log.warn("获取仓库信息Feign调用异常, 走本地兜底查询, warehouseId={}, error={}", warehouseId, e.getMessage());
|
||||
}
|
||||
if (ajaxResult != null && "200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) {
|
||||
return com.alibaba.fastjson.JSON.parseObject(
|
||||
com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), WarehouseFeignPO.class);
|
||||
}
|
||||
String remoteMsg = ajaxResult == null ? "Feign调用异常" : String.valueOf(ajaxResult.get("msg"));
|
||||
log.warn("获取仓库信息Feign失败(返回: {}), 走本地兜底查询, warehouseId={}", remoteMsg, warehouseId);
|
||||
WarehouseFeignPO local = reservationStockInOrderMapper.getWarehouseInfoFallback(warehouseId);
|
||||
if (local == null) {
|
||||
throw new ServiceException("获取仓库信息失败(Feign返回:" + remoteMsg + "), 且本地未查到仓库[warehouseId="
|
||||
+ warehouseId + "], 请检查仓库是否存在/已启用");
|
||||
}
|
||||
return local;
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -46,6 +46,9 @@ public class OutEntrustOrderApplicationService {
|
||||
@Resource
|
||||
private SystemServiceFeign systemServiceFeign;
|
||||
|
||||
@Resource
|
||||
private com.mhd.oms.application.service.WarehouseInfoApplicationService warehouseInfoApplicationService;
|
||||
|
||||
@Resource
|
||||
private WmsServiceFeign wmsServiceFeign;
|
||||
|
||||
@@ -352,14 +355,10 @@ public class OutEntrustOrderApplicationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 仓库信息校验并回填编码/名称
|
||||
* 仓库信息校验并回填编码/名称 (Feign失败走本地跨库兜底)
|
||||
*/
|
||||
private void setWarehouseInfo(OutEntrustOrderDO outEntrustOrderDO) {
|
||||
AjaxResult ajaxResult = systemServiceFeign.getWarehouseInfoByWarehouseId(outEntrustOrderDO.getWarehouseId());
|
||||
if (ajaxResult == null || !"200".equals(String.valueOf(ajaxResult.get("code")))) {
|
||||
throw new ServiceException("获取仓库信息失败,请检查仓库是否有效");
|
||||
}
|
||||
WarehouseFeignPO warehouseFeignPO = JSONUtil.toBean(JSONUtil.toJsonStr(ajaxResult.get("data")), WarehouseFeignPO.class);
|
||||
WarehouseFeignPO warehouseFeignPO = warehouseInfoApplicationService.getWarehouseInfo(outEntrustOrderDO.getWarehouseId());
|
||||
if (warehouseFeignPO == null || Objects.isNull(warehouseFeignPO.getWarehouseId())) {
|
||||
throw new ServiceException("仓库不存在,请重新选择");
|
||||
}
|
||||
|
||||
+3
-3
@@ -39,8 +39,8 @@ public interface BusinessDocumentOrderMapper extends BaseMapper<BusinessDocument
|
||||
String getPushVerifyByOrgId(@Param("organizationId") Long organizationId);
|
||||
|
||||
/**
|
||||
* 统计指定日期前缀(yyMMdd)下已生成的新格式业务单号数量
|
||||
* 仅统计新格式(长度<=12),过滤历史16位旧数据,保证序号每日从001正确累计
|
||||
* 查询指定日期前缀(yyMMdd)下已生成的新格式业务单号列表
|
||||
* 仅查新格式(长度<=12),过滤历史16位旧数据,供取号器解析当日最大序号
|
||||
*/
|
||||
int countByGoodsNumberPrefix(@Param("prefix") String prefix);
|
||||
List<String> selectGoodsNumbersByPrefix(@Param("prefix") String prefix);
|
||||
}
|
||||
|
||||
+2
-5
@@ -237,11 +237,8 @@ public class BusinessDocumentOrderImpl extends ServiceImpl<BusinessDocumentOrder
|
||||
subOrder.setRecipientName(user.getUserName());
|
||||
|
||||
|
||||
//生成子单货源单号(yyMMdd + 当日顺序号)
|
||||
String orderCode = goodsNumberGenerator.generateUniqueGoodsNumber(subOrder.getDocumentDate());
|
||||
subOrder.setGoodsNumber(orderCode);
|
||||
|
||||
businessDocumentOrderMapper.insert(subOrder);
|
||||
//生成子单货源单号(yyMMdd + 当日顺序号)并落库, 撞唯一索引自动重新取号重试
|
||||
goodsNumberGenerator.insertWithUniqueGoodsNumber(subOrder);
|
||||
subOrderCount++; // 增加子单计数
|
||||
|
||||
// 保存子单的地址信息到BUSINESS_DOCUMENT_ADDRESS_MULTI表
|
||||
|
||||
+21
-19
@@ -285,24 +285,9 @@ public class BusinessDocumentOrderDomainService {
|
||||
}
|
||||
}
|
||||
|
||||
//生成货源单号(yyMMdd + 当日顺序号,每日重置)
|
||||
String orderCode = goodsNumberGenerator.generateUniqueGoodsNumber(tmsOrder.getDocumentDate());
|
||||
tmsOrder.setGoodsNumber(orderCode);
|
||||
|
||||
ReservationStockOutOrder reservationStockOutOrder = reservationStockOutOrderMapper.selectOne(new LambdaQueryWrapper<ReservationStockOutOrder>()
|
||||
.eq(ReservationStockOutOrder::getOutOrderNumber, tmsOrder.getInOrderNumber())
|
||||
.eq(ReservationStockOutOrder::getDelFlag, 1));
|
||||
if (reservationStockOutOrder != null){
|
||||
reservationStockOutOrder.setBusinessNumber(tmsOrder.getGoodsNumber());
|
||||
reservationStockOutOrderMapper.updateById(reservationStockOutOrder);
|
||||
}
|
||||
ReservationStockInOrder reservationStockInOrder = reservationStockInOrderMapper.selectOne(new LambdaQueryWrapper<ReservationStockInOrder>()
|
||||
.eq(ReservationStockInOrder::getInOrderNumber, tmsOrder.getInOrderNumber())
|
||||
.eq(ReservationStockInOrder::getDelFlag, 1));
|
||||
if (reservationStockInOrder != null){
|
||||
reservationStockInOrder.setBusinessNumber(tmsOrder.getGoodsNumber());
|
||||
reservationStockInOrderMapper.updateById(reservationStockInOrder);
|
||||
}
|
||||
//生成货源单号并落库见下方 insertWithUniqueGoodsNumber:
|
||||
//取号与插单合并为原子重试(撞goods_number唯一索引自动重新取号),
|
||||
//出库/入库业务单的单号回填也移至插单成功之后,避免插单失败留下脏回填
|
||||
|
||||
List<BusinessDocumentAddressMultiDTO> loadingAddressList = businessDocumentOrderDO.getLoadingAddressList();//装货地信息集合
|
||||
List<BusinessDocumentAddressMultiDTO> unloadAddressList = businessDocumentOrderDO.getUnloadAddressList();//卸货地信息集合
|
||||
@@ -426,7 +411,24 @@ public class BusinessDocumentOrderDomainService {
|
||||
//一天后
|
||||
tmsOrder.setDocumentDate(businessDocumentOrderDO.getDocumentDate());
|
||||
|
||||
boolean istrue = businessDocumentOrderMapper.insert(tmsOrder) > 0;
|
||||
//生成货源单号(yyMMdd + 当日顺序号,每日重置)并落库, 撞唯一索引自动重新取号重试
|
||||
boolean istrue = goodsNumberGenerator.insertWithUniqueGoodsNumber(tmsOrder);
|
||||
|
||||
//落库成功后将运输业务单号回填至关联的出库/入库业务单
|
||||
ReservationStockOutOrder reservationStockOutOrder = reservationStockOutOrderMapper.selectOne(new LambdaQueryWrapper<ReservationStockOutOrder>()
|
||||
.eq(ReservationStockOutOrder::getOutOrderNumber, tmsOrder.getInOrderNumber())
|
||||
.eq(ReservationStockOutOrder::getDelFlag, 1));
|
||||
if (reservationStockOutOrder != null){
|
||||
reservationStockOutOrder.setBusinessNumber(tmsOrder.getGoodsNumber());
|
||||
reservationStockOutOrderMapper.updateById(reservationStockOutOrder);
|
||||
}
|
||||
ReservationStockInOrder reservationStockInOrder = reservationStockInOrderMapper.selectOne(new LambdaQueryWrapper<ReservationStockInOrder>()
|
||||
.eq(ReservationStockInOrder::getInOrderNumber, tmsOrder.getInOrderNumber())
|
||||
.eq(ReservationStockInOrder::getDelFlag, 1));
|
||||
if (reservationStockInOrder != null){
|
||||
reservationStockInOrder.setBusinessNumber(tmsOrder.getGoodsNumber());
|
||||
reservationStockInOrderMapper.updateById(reservationStockInOrder);
|
||||
}
|
||||
|
||||
if (hasDetails) {
|
||||
for (BusinessDeliveryDetailsLinkDTO businessDeliveryDetailsLinkDTO : businessDeliveryDetailsLinkDTOList) {
|
||||
|
||||
+90
-4
@@ -5,23 +5,44 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.mhd.common.core.exception.ServiceException;
|
||||
import com.mhd.oms.domain.businessDocumentOrder.entity.BusinessDocumentOrder;
|
||||
import com.mhd.oms.domain.businessDocumentOrder.repository.mapper.BusinessDocumentOrderMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 业务单据订单(goodsNumber)单号生成器
|
||||
* 规则: yyMMdd(取自单据日期) + 当日顺序号(每日重置, 3位起步, 超999自动扩位)
|
||||
* 示例: 260804001、260804999、2608041000
|
||||
*
|
||||
* 唯一性保障(不依赖唯一索引, 三层防线):
|
||||
* 1) 取号: 当日已生成单号 MAX+1 作为基线 + 候选号存在性校验后移收敛
|
||||
* (对齐入库单号修复先例 ReservationStockInOrderDomainService#generateReserveOrderNumber)
|
||||
* 2) 落库: 按日期前缀分段的JVM锁串行化"取号+插单", 消除本实例内并发审核/
|
||||
* 批量取号的check-then-act竞态(多实例部署时本层只覆盖各自实例)
|
||||
* 3) 自检自愈: 插单后立即校验同号数量, >1 说明与并发插入撞号, 给本单重新
|
||||
* 取号改号, 兜住跨实例残余竞态
|
||||
* 若日后补建goods_number唯一索引(见 sql/20260906_oms_business_goods_number_unique.sql),
|
||||
* 撞号将抛DuplicateKeyException由重试逻辑接住, 与上述防线叠加互不冲突
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class GoodsNumberGenerator {
|
||||
|
||||
private static final int MAX_RETRY = 100;
|
||||
|
||||
/**
|
||||
* 取号+插单分段锁: 按单号日期前缀(yyMMdd)分段, 同日串行、跨日并行,
|
||||
* 锁对象常驻(每日新增1个, 增量可忽略)
|
||||
*/
|
||||
private static final Map<String, Object> LOCK_STRIPES = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private BusinessDocumentOrderMapper businessDocumentOrderMapper;
|
||||
|
||||
@@ -33,8 +54,21 @@ public class GoodsNumberGenerator {
|
||||
Date date = (documentDate == null) ? new Date() : documentDate;
|
||||
String datePart = DateUtil.format(date, "yyMMdd");
|
||||
|
||||
// count 只查一次作为序号基线
|
||||
long seq = (long) businessDocumentOrderMapper.countByGoodsNumberPrefix(datePart) + 1;
|
||||
// 当日已生成单号的最大序号作为基线(MAX+1而非COUNT+1, 防脏数据/序号错位导致回退复用)
|
||||
List<String> existNumbers = businessDocumentOrderMapper.selectGoodsNumbersByPrefix(datePart);
|
||||
long seq = 0;
|
||||
for (String existNumber : existNumbers) {
|
||||
if (existNumber == null || existNumber.length() <= datePart.length()) {
|
||||
continue;
|
||||
}
|
||||
String numStr = existNumber.substring(datePart.length());
|
||||
if (!numStr.matches("\\d+")) {
|
||||
continue; // 防脏数据(非纯数字后缀)导致解析失败
|
||||
}
|
||||
seq = Math.max(seq, Long.parseLong(numStr));
|
||||
}
|
||||
seq = seq + 1;
|
||||
|
||||
int retryCount = 0;
|
||||
while (retryCount < MAX_RETRY) {
|
||||
String orderCode = datePart + String.format("%03d", seq);
|
||||
@@ -46,8 +80,60 @@ public class GoodsNumberGenerator {
|
||||
if (CollectionUtils.isEmpty(exist)) {
|
||||
return orderCode;
|
||||
}
|
||||
seq++; // ← 关键:查重失败,序号往后递增找空位,而不是重新count
|
||||
seq++; // ← 关键:查重失败,序号往后递增找空位,而不是重新取基线
|
||||
}
|
||||
throw new ServiceException("生成唯一业务单号失败,已达到最大重试次数:" + MAX_RETRY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一业务单号并落库: JVM分段锁内完成"取号+插单",
|
||||
* 插入撞goods_number唯一索引时自动重新取号重试(索引为可选兜底),
|
||||
* 插单成功后自检同号并自愈改号。
|
||||
* 供业务单创建入口(手动/审核新增、审核拆单、预约确认)统一使用。
|
||||
* @return 是否插入成功(mapper.insert结果)
|
||||
*/
|
||||
public boolean insertWithUniqueGoodsNumber(BusinessDocumentOrder order) {
|
||||
Date date = (order.getDocumentDate() == null) ? new Date() : order.getDocumentDate();
|
||||
String lockKey = DateUtil.format(date, "yyMMdd");
|
||||
synchronized (LOCK_STRIPES.computeIfAbsent(lockKey, k -> new Object())) {
|
||||
int retryCount = 0;
|
||||
while (retryCount < MAX_RETRY) {
|
||||
retryCount++;
|
||||
order.setGoodsNumber(generateUniqueGoodsNumber(order.getDocumentDate()));
|
||||
try {
|
||||
boolean inserted = businessDocumentOrderMapper.insert(order) > 0;
|
||||
// 插单后自检自愈: 无唯一索引时跨实例并发窗口内的撞号双方都能落库,
|
||||
// 同号数量>1说明本单撞号, 给本单重新取号改号, 防止单号重复扩散
|
||||
healIfDuplicated(order);
|
||||
return inserted;
|
||||
} catch (DuplicateKeyException e) {
|
||||
// 已建唯一索引时的兜底: 仅业务单号撞唯一索引时重试, 其他唯一约束冲突原样抛出
|
||||
String message = e.getMessage();
|
||||
if (message == null || !message.toLowerCase().contains("goods_number")) {
|
||||
throw e;
|
||||
}
|
||||
log.warn("业务单号[{}]撞号, 自动重新取号重试(第{}次): {}", order.getGoodsNumber(), retryCount, message);
|
||||
}
|
||||
}
|
||||
throw new ServiceException("生成唯一业务单号失败,已达到最大重试次数:" + MAX_RETRY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插单后自检自愈: 查同号数量, >1 说明有并发插入撞号(本单为后插入方),
|
||||
* 保持先落库单据单号不变, 重新取号给本单改号
|
||||
*/
|
||||
private void healIfDuplicated(BusinessDocumentOrder order) {
|
||||
List<BusinessDocumentOrder> sameNumber = businessDocumentOrderMapper.selectList(
|
||||
new QueryWrapper<BusinessDocumentOrder>().eq("goods_number", order.getGoodsNumber())
|
||||
);
|
||||
if (sameNumber != null && sameNumber.size() > 1) {
|
||||
String oldNumber = order.getGoodsNumber();
|
||||
String newNumber = generateUniqueGoodsNumber(order.getDocumentDate());
|
||||
order.setGoodsNumber(newNumber);
|
||||
businessDocumentOrderMapper.updateById(order);
|
||||
log.warn("业务单号[{}]与并发插入撞号(无唯一索引兜底), 已自愈改号为[{}], orderId={}",
|
||||
oldNumber, newNumber, order.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -29,6 +29,8 @@ public class ExecutionStockOutOrderPO extends BaseVOEntity {
|
||||
|
||||
@ApiModelProperty("出库单id")
|
||||
private Long outOrderId;
|
||||
@ApiModelProperty("反审标记: 1-已反审(反审软删归档, 【已反审】tab按 delFlag=2+reverseFlag=1 查询)")
|
||||
private Integer reverseFlag;
|
||||
@ApiModelProperty("总价")
|
||||
@Excel(name = "总价")
|
||||
private BigDecimal amount;
|
||||
|
||||
+3
@@ -29,6 +29,9 @@ public class ExecutionStockOutOrderDO extends BaseVOEntity {
|
||||
@ApiModelProperty("出库单id")
|
||||
private Long outOrderId;
|
||||
|
||||
@ApiModelProperty("反审标记查询: 1-已反审(与delFlag=2成对传, 查【已反审】tab归档数据)")
|
||||
private Integer reverseFlag;
|
||||
|
||||
@ApiModelProperty("组织表ID")
|
||||
@Excel(name = "组织表ID")
|
||||
private Long organizationId;
|
||||
|
||||
+3
@@ -27,6 +27,9 @@ public class ExecutionStockOutOrderDTO extends ExecutionStockOutOrderBaseDTO {
|
||||
@ApiModelProperty("出库单id")
|
||||
private Long outOrderId;
|
||||
|
||||
@ApiModelProperty("反审标记查询: 1-已反审(与delFlag=2成对传, 查【已反审】tab归档数据)")
|
||||
private Integer reverseFlag;
|
||||
|
||||
@ApiModelProperty("组织表ID")
|
||||
@Excel(name = "组织表ID")
|
||||
private Long organizationId;
|
||||
|
||||
+4
-5
@@ -66,6 +66,8 @@ import java.util.stream.Collectors;
|
||||
public class ExecutionStockOutOrderApplicationService {
|
||||
@Autowired
|
||||
private ExecutionStockOutOrderDomainService stockOutOrderDomainService;
|
||||
@Autowired
|
||||
private com.mhd.oms.application.service.WarehouseInfoApplicationService warehouseInfoApplicationService;
|
||||
// @Autowired
|
||||
// private ExecutionOutMaterialDetailDomainService outMaterialDetailDomainService;
|
||||
// @Autowired
|
||||
@@ -862,11 +864,8 @@ public class ExecutionStockOutOrderApplicationService {
|
||||
if (stockOutOrderDO.getWarehouseId() == null) {
|
||||
throw new ServiceException("仓库ID不能为空");
|
||||
}
|
||||
AjaxResult ajaxResult = systemServiceFeign.getWarehouseInfoByWarehouseId(stockOutOrderDO.getWarehouseId());
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取仓库信息失败");
|
||||
}
|
||||
WarehouseFeignPO warehouseFeignPO = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), WarehouseFeignPO.class);
|
||||
// Feign失败走本地跨库兜底, 避免保存被"获取仓库信息失败"阻断
|
||||
WarehouseFeignPO warehouseFeignPO = warehouseInfoApplicationService.getWarehouseInfo(stockOutOrderDO.getWarehouseId());
|
||||
stockOutOrderDO.setWarehouseCode(warehouseFeignPO.getWarehouseCode());
|
||||
stockOutOrderDO.setWarehouseName(warehouseFeignPO.getWarehouseName());
|
||||
}
|
||||
|
||||
+23
-17
@@ -71,6 +71,8 @@ public class ExecutionStockOutOrderDomainService {
|
||||
@Autowired
|
||||
private IExecutionStockOutOrderService stockOutOrderService;
|
||||
@Autowired
|
||||
private com.mhd.oms.application.service.WarehouseInfoApplicationService warehouseInfoApplicationService;
|
||||
@Autowired
|
||||
private IExecutionOutMaterialDetailService outMaterialDetailService;
|
||||
@Autowired
|
||||
private IReservationDeliveryDetailsLinkService deliveryDetailsLinkService;
|
||||
@@ -148,14 +150,9 @@ public class ExecutionStockOutOrderDomainService {
|
||||
public Boolean insert(ExecutionStockOutOrderDO stockOutOrderDO) {
|
||||
//建单校验:明细数量必须大于0(0数量单下发WMS后自动分配必失败,出库单会卡死在已审核状态)
|
||||
validateMaterialDetailQuantity(stockOutOrderDO.getMaterialDetailList());
|
||||
//设置单号
|
||||
//设置单号(仓库信息: Feign优先, system服务失败/降级时本地跨库兜底)
|
||||
Long warehouseId = stockOutOrderDO.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);
|
||||
WarehouseFeignPO warehouseFeignPO = warehouseInfoApplicationService.getWarehouseInfo(warehouseId);
|
||||
String orderNoGenerateRule = warehouseFeignPO.getOrderNoGenerateRule();
|
||||
String prefix = warehouseFeignPO.getOutOrderNoPrefix();
|
||||
if ("yang_pin_chu_ku".equals(stockOutOrderDO.getBusinessType())) {
|
||||
@@ -218,14 +215,9 @@ public class ExecutionStockOutOrderDomainService {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchInsert(List<ExecutionStockOutOrderDO> stockOutOrderDOList) {
|
||||
for (ExecutionStockOutOrderDO stockOutOrderDO : stockOutOrderDOList){
|
||||
//设置单号
|
||||
//设置单号(仓库信息: Feign优先, system服务失败/降级时本地跨库兜底)
|
||||
Long warehouseId = stockOutOrderDO.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);
|
||||
WarehouseFeignPO warehouseFeignPO = warehouseInfoApplicationService.getWarehouseInfo(warehouseId);
|
||||
String orderNoGenerateRule = warehouseFeignPO.getOrderNoGenerateRule();
|
||||
String prefix = warehouseFeignPO.getOutOrderNoPrefix();
|
||||
if ("yang_pin_chu_ku".equals(stockOutOrderDO.getBusinessType())) {
|
||||
@@ -542,7 +534,12 @@ public class ExecutionStockOutOrderDomainService {
|
||||
stockOutOrder.setOrganizationId(orgId);
|
||||
stockOutOrder.setOrganizationName(orgName);
|
||||
stockOutOrder.setTopOrganizationId(topOrgId);
|
||||
wmsServiceFeign.omsOutOrderAdd(stockOutOrder);
|
||||
//单头/配送明细推送同样校验返回值: 降级吞掉会残留"有单无明细"等半截单
|
||||
AjaxResult orderAddResult = wmsServiceFeign.omsOutOrderAdd(stockOutOrder);
|
||||
if (orderAddResult == null || !"200".equals(String.valueOf(orderAddResult.get("code")))) {
|
||||
throw new ServiceException("出库单[" + currentOrderNumber + "]WMS出库单推送失败:"
|
||||
+ (orderAddResult == null ? "WMS服务不可用或已降级" : orderAddResult.get("msg")));
|
||||
}
|
||||
|
||||
List<ReservationDeliveryDetailsLink> list = deliveryDetailsLinkService.list(new QueryWrapper<ReservationDeliveryDetailsLink>().lambda().eq(ReservationDeliveryDetailsLink::getOrderNumber, byId.getOutOrderNumber()));
|
||||
List<DeliveryDetailsLink> deliveryDetailsLinkList = new ArrayList<>();
|
||||
@@ -552,7 +549,11 @@ public class ExecutionStockOutOrderDomainService {
|
||||
deliveryDetailsLink.setOmsId(reservationDeliveryDetailsLink.getId());
|
||||
deliveryDetailsLinkList.add(deliveryDetailsLink);
|
||||
}
|
||||
wmsServiceFeign.omsOutOrderAddDeliveryDetailsLink(deliveryDetailsLinkList);
|
||||
AjaxResult linkAddResult = wmsServiceFeign.omsOutOrderAddDeliveryDetailsLink(deliveryDetailsLinkList);
|
||||
if (linkAddResult == null || !"200".equals(String.valueOf(linkAddResult.get("code")))) {
|
||||
throw new ServiceException("出库单[" + currentOrderNumber + "]WMS配送明细推送失败:"
|
||||
+ (linkAddResult == null ? "WMS服务不可用或已降级" : linkAddResult.get("msg")));
|
||||
}
|
||||
|
||||
|
||||
String inOrderNumber = stockOutOrder.getOutOrderNumber();
|
||||
@@ -566,7 +567,12 @@ public class ExecutionStockOutOrderDomainService {
|
||||
outMaterialDetail.setTopOrganizationId(topOrgId);
|
||||
outMaterialDetailList.add(outMaterialDetail);
|
||||
}
|
||||
wmsServiceFeign.omsOutOrderAddDetail(outMaterialDetailList);
|
||||
//明细推送必须校验返回值: 失败被降级吞掉时WMS会残留"有单无明细"的出库单, 自动分配报"可用库存为0"难定位
|
||||
AjaxResult detailAddResult = wmsServiceFeign.omsOutOrderAddDetail(outMaterialDetailList);
|
||||
if (detailAddResult == null || !"200".equals(String.valueOf(detailAddResult.get("code")))) {
|
||||
throw new ServiceException("出库单[" + currentOrderNumber + "]WMS出库明细推送失败:"
|
||||
+ (detailAddResult == null ? "WMS服务不可用或已降级" : detailAddResult.get("msg")));
|
||||
}
|
||||
|
||||
String outOrderNumber = byId.getOutOrderNumber();
|
||||
com.mhd.system.api.domain.StockOutOrderDTO stockOutOrderDTO = new com.mhd.system.api.domain.StockOutOrderDTO();
|
||||
|
||||
+7
@@ -54,6 +54,13 @@ public interface ReservationStockInOrderMapper extends BaseMapper<ReservationSto
|
||||
|
||||
public String getWarehouseName(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 本地跨库直查仓库信息(编码/名称/单号生成规则),
|
||||
* 供下发等流程在 system 服务 Feign 失败/降级时兜底, 与 getWarehouseInfoByWarehouseId Feign 接口同数据源。
|
||||
* 不含 STOCK_LOCK_MODE(冻结功能列, 各环境库结构不一致), 兜底时 stockLockMode 为 null 即默认分配库存冻结模式
|
||||
*/
|
||||
public com.mhd.system.api.domain.WarehouseFeignPO getWarehouseInfoFallback(@Param("id") Long id);
|
||||
|
||||
List<ReservationStockInOrderPO> queryNoticePrint(ReservationStockInOrderDO stockInOrderDO);
|
||||
List<ReservationInMaterialDetailPO> queryNoticePrintDetail(ReservationStockInOrderDO stockInOrderDO);
|
||||
public void updateByTransportationNumber(@Param("transportationNumber") String transportationNumber);
|
||||
|
||||
+8
-2
@@ -176,6 +176,10 @@ public class ReservationStockInOrderDomainService {
|
||||
// //统计总体积
|
||||
// BigDecimal volumeLimit = stockInOrderDO.getMaterialDetailList().stream().map(ReservationInMaterialDetailDO::getVolumeLimit).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
// stockInOrderDO.setVolumeLimit(volumeLimit);
|
||||
// 订单来源为空时兜底为手动创建(导入/预约下发等路径已显式设置,不受影响),下发执行单时随业务单继承
|
||||
if (stockInOrderDO.getReservationOrderSource() == null || stockInOrderDO.getReservationOrderSource().isEmpty()) {
|
||||
stockInOrderDO.setReservationOrderSource("手动创建");
|
||||
}
|
||||
stockInOrderService.insert(stockInOrderDO);
|
||||
return materialDetailService.batchInsert(stockInOrderDO.getInOrderNumber(), stockInOrderDO.getMaterialDetailList());
|
||||
}
|
||||
@@ -614,7 +618,6 @@ public class ReservationStockInOrderDomainService {
|
||||
reservationStockInOrder.setOrderTypeName("普通入库");
|
||||
reservationStockInOrder.setBusinessType("pu_tong_ru_ku");
|
||||
}
|
||||
reservationStockInOrder.setReservationOrderSource("客户预约");
|
||||
reservationStockInOrder.setWarehouseId(warehouseId);
|
||||
if (warehouseId == null || warehouseId == 0L){
|
||||
reservationStockInOrder.setWarehouseId(byId.getWarehouseId());
|
||||
@@ -897,6 +900,10 @@ public class ReservationStockInOrderDomainService {
|
||||
.set(ReservationStockInOrder::getIssueStatus, 3)
|
||||
//清空下发/执行时间(前端"是否执行"列按执行时间判断,不清会仍显示已执行,与取消下发 cancelIssueOrder 同口径)
|
||||
.set(ReservationStockInOrder::getIssueTime, null)
|
||||
//入库进度状态(1-已创建 2-已审核 3-收货中 4-上架中 5-已入库):首轮"完成上架"会经WMS回传写成5,
|
||||
//不重置的话重新下发时copy给执行单→W入库单→收货单,收货单带着"已完成"状态导致前端不给收货按钮;
|
||||
//重置为1(已创建),与手工新单首次下发链路一致(W入库单/收货单起点=1-待收货)
|
||||
.set(ReservationStockInOrder::getStatus, 1)
|
||||
.set(ReservationStockInOrder::getInQuantity, BigDecimal.ZERO)
|
||||
.set(ReservationStockInOrder::getStorageTime, null)
|
||||
.set(ReservationStockInOrder::getExecutionInOrderNumber, null)
|
||||
@@ -1038,7 +1045,6 @@ public class ReservationStockInOrderDomainService {
|
||||
reservationStockInOrder.setOrderTypeName("普通入库");
|
||||
reservationStockInOrder.setBusinessType("pu_tong_ru_ku");
|
||||
}
|
||||
reservationStockInOrder.setReservationOrderSource("客户预约");
|
||||
reservationStockInOrder.setWarehouseId(warehouseId);
|
||||
// reservationStockInOrder.setOrganizationId(orgId);
|
||||
// reservationStockInOrder.setOrganizationName(orgName);
|
||||
|
||||
+4
-5
@@ -85,6 +85,8 @@ import java.util.stream.Collectors;
|
||||
public class ReservationStockOutOrderApplicationService {
|
||||
@Autowired
|
||||
private ReservationStockOutOrderDomainService stockOutOrderDomainService;
|
||||
@Autowired
|
||||
private com.mhd.oms.application.service.WarehouseInfoApplicationService warehouseInfoApplicationService;
|
||||
// @Autowired
|
||||
// private ReservationOutMaterialDetailDomainService outMaterialDetailDomainService;
|
||||
// @Autowired
|
||||
@@ -913,11 +915,8 @@ public class ReservationStockOutOrderApplicationService {
|
||||
if (stockOutOrderDO.getWarehouseId() == null) {
|
||||
throw new ServiceException("仓库ID不能为空");
|
||||
}
|
||||
AjaxResult ajaxResult = systemServiceFeign.getWarehouseInfoByWarehouseId(stockOutOrderDO.getWarehouseId());
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取仓库信息失败");
|
||||
}
|
||||
WarehouseFeignPO warehouseFeignPO = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), WarehouseFeignPO.class);
|
||||
// Feign失败走本地跨库兜底, 避免新增/编辑保存被"获取仓库信息失败"阻断
|
||||
WarehouseFeignPO warehouseFeignPO = warehouseInfoApplicationService.getWarehouseInfo(stockOutOrderDO.getWarehouseId());
|
||||
stockOutOrderDO.setWarehouseCode(warehouseFeignPO.getWarehouseCode());
|
||||
stockOutOrderDO.setWarehouseName(warehouseFeignPO.getWarehouseName());
|
||||
}
|
||||
|
||||
+167
-23
@@ -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;
|
||||
|
||||
/**
|
||||
* 分页查询出库单列表
|
||||
@@ -219,6 +232,10 @@ public class ReservationStockOutOrderDomainService {
|
||||
if (stockOutOrderDO.getCheckTaskDistribution() == null) {
|
||||
stockOutOrderDO.setCheckTaskDistribution(2);
|
||||
}
|
||||
// 订单来源为空时兜底为手动创建(导入/预约下发等路径已显式设置,不受影响),下发执行单时随业务单继承
|
||||
if (stockOutOrderDO.getReservationOrderSource() == null || stockOutOrderDO.getReservationOrderSource().isEmpty()) {
|
||||
stockOutOrderDO.setReservationOrderSource("手动创建");
|
||||
}
|
||||
stockOutOrderService.insert(stockOutOrderDO);
|
||||
List<ReservationDeliveryDetailsLink> reservationDeliveryDetailsLinkList = stockOutOrderDO.getReservationDeliveryDetailsLinkList();
|
||||
if (reservationDeliveryDetailsLinkList != null && !reservationDeliveryDetailsLinkList.isEmpty()){
|
||||
@@ -491,6 +508,125 @@ 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 反审联动软删运输链路(编辑"是否运输"=是 且审核通过后生成的链), 真实层级:
|
||||
* 运输业务单-主单(splicingOrderType=4, business_document_order)
|
||||
* -> 审核运输业务单按配送明细生成子单(splicingOrderType=3, mainOrderId=主单id, 每明细一单)
|
||||
* -> 下发每个子单各生成一个运输执行单(execute_order.businessDocumentId=【子单id】, goodsNumber=子单货源号, 主单下无直接执行单)
|
||||
* -> 每个执行单各推一单TMS(tms_order.execute_order_number=执行单货源号) -> TMS运单/运输作业单(wlhy外部服务)。
|
||||
* 定位运输业务单: ①出库单.businessNumber(创建运输业务单时回填的货源单号) ②inOrderNumber=出库单号兜底
|
||||
* (businessNumber缺失/已清空场景); 均不滤del_flag——此前被旧版反审漏删或手工删过的主单,
|
||||
* 其子单/执行单/TMS链可能仍存活, 同样要清理(幂等)。配送明细链的invoiceNumber存的是送货单号而非出库单号, 不能作为定位条件。
|
||||
* 执行单逐个调 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()))
|
||||
.forEach(order -> transportOrderIds.add(order.getId()));
|
||||
}
|
||||
businessDocumentOrderMapper.selectList(new LambdaQueryWrapper<BusinessDocumentOrder>()
|
||||
.eq(BusinessDocumentOrder::getInOrderNumber, outOrderNumber))
|
||||
.forEach(order -> transportOrderIds.add(order.getId()));
|
||||
if (transportOrderIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Long transportOrderId : transportOrderIds) {
|
||||
BusinessDocumentOrder transportOrder = businessDocumentOrderMapper.selectById(transportOrderId);
|
||||
if (transportOrder == null) {
|
||||
continue;
|
||||
}
|
||||
// 0. 拆单主单自身无执行单: 收集主单+全部子单id, 执行单/货品/地址明细按全量id清理
|
||||
List<BusinessDocumentOrder> subOrders = businessDocumentOrderMapper.selectList(new LambdaQueryWrapper<BusinessDocumentOrder>()
|
||||
.eq(BusinessDocumentOrder::getMainOrderId, String.valueOf(transportOrderId))
|
||||
.eq(BusinessDocumentOrder::getDelFlag, 1));
|
||||
Set<Long> chainDocIds = new HashSet<>();
|
||||
chainDocIds.add(transportOrderId);
|
||||
subOrders.forEach(subOrder -> chainDocIds.add(subOrder.getId()));
|
||||
// 1. 执行单: 不滤del_flag——历史周期已归档执行单的TMS链也幂等补清(防"执行单已删TMS残留"),
|
||||
// 先逐个软删TMS侧整链(货源单->运单->作业单), 再软删本地执行单(已归档的跳过更新)
|
||||
List<ExecuteOrder> executeOrders = executeOrderMapper.selectList(new LambdaQueryWrapper<ExecuteOrder>()
|
||||
.in(ExecuteOrder::getBusinessDocumentId, chainDocIds));
|
||||
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")));
|
||||
}
|
||||
}
|
||||
if (!Integer.valueOf(2).equals(executeOrder.getDelFlag())) {
|
||||
executeOrder.setDelFlag(2);
|
||||
executeOrderMapper.updateById(executeOrder);
|
||||
}
|
||||
}
|
||||
// 2. 软删运输业务单(主单+子单)及其货品/地址明细(主单已软删的只补清理子单/明细, 不重复更新主单)
|
||||
if (!Integer.valueOf(2).equals(transportOrder.getDelFlag())) {
|
||||
transportOrder.setDelFlag(2);
|
||||
businessDocumentOrderMapper.updateById(transportOrder);
|
||||
}
|
||||
for (BusinessDocumentOrder subOrder : subOrders) {
|
||||
subOrder.setDelFlag(2);
|
||||
businessDocumentOrderMapper.updateById(subOrder);
|
||||
}
|
||||
List<String> chainDocIdStrings = chainDocIds.stream().map(String::valueOf).collect(Collectors.toList());
|
||||
businessDocumentCargoMultiMapper.update(null, new LambdaUpdateWrapper<BusinessDocumentCargoMulti>()
|
||||
.set(BusinessDocumentCargoMulti::getDelFlag, 2)
|
||||
.in(BusinessDocumentCargoMulti::getOrderId, chainDocIdStrings)
|
||||
.eq(BusinessDocumentCargoMulti::getDelFlag, 1));
|
||||
businessDocumentAddressMultiMapper.update(null, new LambdaUpdateWrapper<BusinessDocumentAddressMulti>()
|
||||
.set(BusinessDocumentAddressMulti::getDelFlag, 2)
|
||||
.in(BusinessDocumentAddressMulti::getOrderId, chainDocIdStrings)
|
||||
.eq(BusinessDocumentAddressMulti::getDelFlag, 1));
|
||||
}
|
||||
// 3. 配送明细链软删: 链的orderId固定指向运输业务单-主单, 按本次命中的主单id清理(含历史周期残留链)
|
||||
businessDeliveryDetailsLinkService.update(null, new LambdaUpdateWrapper<BusinessDeliveryDetailsLink>()
|
||||
.set(BusinessDeliveryDetailsLink::getDelFlag, 2)
|
||||
.in(BusinessDeliveryDetailsLink::getOrderId, transportOrderIds)
|
||||
.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,8 +667,14 @@ 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));
|
||||
// 下发明细必须过滤软删行(del_flag=1):编辑对账软删的旧行仍留表内,
|
||||
// 不滤会参与按仓库分组/数量汇总,多生成执行单且数量叠加(入库侧同查询已过滤)
|
||||
List<ReservationOutMaterialDetail> materialDetailList = outMaterialDetailService.list(new QueryWrapper<ReservationOutMaterialDetail>().lambda()
|
||||
.eq(ReservationOutMaterialDetail::getOutOrderNumber, inOrderNumber)
|
||||
.eq(ReservationOutMaterialDetail::getDelFlag, 1));
|
||||
|
||||
// 按照 warehouseId 分组
|
||||
Map<Long, List<ReservationOutMaterialDetail>> materialDetailGroupByWarehouse = materialDetailList.stream()
|
||||
@@ -550,7 +692,6 @@ public class ReservationStockOutOrderDomainService {
|
||||
reservationStockInOrder.setOrderTypeCode("pu_tong_chu_ku");
|
||||
reservationStockInOrder.setOrderTypeName("普通出库");
|
||||
reservationStockInOrder.setBusinessType("pu_tong_chu_ku");
|
||||
reservationStockInOrder.setReservationOrderSource("客户预约");
|
||||
reservationStockInOrder.setWarehouseId(warehouseId);
|
||||
reservationStockInOrder.setWarehouseCode(warehouseCode);
|
||||
reservationStockInOrder.setWarehouseName(warehouseName);
|
||||
@@ -566,14 +707,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 +797,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 +813,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 +876,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 +890,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,7 +961,13 @@ public class ReservationStockOutOrderDomainService {
|
||||
String warehouseCode1 = byId.getWarehouseCode();
|
||||
String warehouseName1 = byId.getWarehouseName();
|
||||
String inOrderNumber = byId.getOutOrderNumber();
|
||||
List<ReservationOutMaterialDetail> materialDetailList = outMaterialDetailService.list(new QueryWrapper<ReservationOutMaterialDetail>().lambda().eq(ReservationOutMaterialDetail::getOutOrderNumber, inOrderNumber));
|
||||
// 自愈: 历史版本反审/取消下发的归档明细可能仍占用unique_id, 先置空释放键位再重新下发
|
||||
releaseArchivedDetailUniqueId(inOrderNumber);
|
||||
// 下发明细必须过滤软删行(del_flag=1):编辑对账软删的旧行仍留表内,
|
||||
// 不滤会参与按仓库分组/数量汇总,多生成执行单且数量叠加(入库侧同查询已过滤)
|
||||
List<ReservationOutMaterialDetail> materialDetailList = outMaterialDetailService.list(new QueryWrapper<ReservationOutMaterialDetail>().lambda()
|
||||
.eq(ReservationOutMaterialDetail::getOutOrderNumber, inOrderNumber)
|
||||
.eq(ReservationOutMaterialDetail::getDelFlag, 1));
|
||||
|
||||
// 按照 warehouseId 分组
|
||||
Map<Long, List<ReservationOutMaterialDetail>> materialDetailGroupByWarehouse = materialDetailList.stream()
|
||||
@@ -880,7 +1031,6 @@ public class ReservationStockOutOrderDomainService {
|
||||
reservationStockInOrder.setOrderTypeCode("pu_tong_chu_ku");
|
||||
reservationStockInOrder.setOrderTypeName("普通出库");
|
||||
reservationStockInOrder.setBusinessType("pu_tong_chu_ku");
|
||||
reservationStockInOrder.setReservationOrderSource("客户预约");
|
||||
reservationStockInOrder.setWarehouseId(warehouseId);
|
||||
reservationStockInOrder.setOrganizationId(orgId);
|
||||
reservationStockInOrder.setOrganizationName(orgName);
|
||||
@@ -890,14 +1040,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())) {
|
||||
|
||||
+4
-5
@@ -68,6 +68,8 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
public class ReserveStockOutOrderApplicationService {
|
||||
@Autowired
|
||||
private ReserveStockOutOrderDomainService stockOutOrderDomainService;
|
||||
@Autowired
|
||||
private com.mhd.oms.application.service.WarehouseInfoApplicationService warehouseInfoApplicationService;
|
||||
// @Autowired
|
||||
// private ReserveOutMaterialDetailDomainService outMaterialDetailDomainService;
|
||||
// @Autowired
|
||||
@@ -895,11 +897,8 @@ public class ReserveStockOutOrderApplicationService {
|
||||
if (stockOutOrderDO.getWarehouseId() == null) {
|
||||
throw new ServiceException("仓库ID不能为空");
|
||||
}
|
||||
AjaxResult ajaxResult = systemServiceFeign.getWarehouseInfoByWarehouseId(stockOutOrderDO.getWarehouseId());
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取仓库信息失败");
|
||||
}
|
||||
WarehouseFeignPO warehouseFeignPO = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), WarehouseFeignPO.class);
|
||||
// Feign失败走本地跨库兜底, 避免保存被"获取仓库信息失败"阻断
|
||||
WarehouseFeignPO warehouseFeignPO = warehouseInfoApplicationService.getWarehouseInfo(stockOutOrderDO.getWarehouseId());
|
||||
stockOutOrderDO.setWarehouseCode(warehouseFeignPO.getWarehouseCode());
|
||||
stockOutOrderDO.setWarehouseName(warehouseFeignPO.getWarehouseName());
|
||||
}
|
||||
|
||||
+2
-2
@@ -1278,8 +1278,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
select PUSH_VERIFY from NGWL_TEST_PRODUCT.SYS_ORGANIZATION where ORGANIZATION_ID = #{organizationId}
|
||||
</select>
|
||||
|
||||
<select id="countByGoodsNumberPrefix" resultType="java.lang.Integer">
|
||||
SELECT COUNT(1)
|
||||
<select id="selectGoodsNumbersByPrefix" resultType="java.lang.String">
|
||||
SELECT goods_number
|
||||
FROM business_document_order
|
||||
WHERE goods_number LIKE concat(#{prefix}, '%')
|
||||
AND LENGTH(goods_number) <= 12
|
||||
|
||||
@@ -42,6 +42,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<sql id="selectExecuteOrderPo1">
|
||||
<where>
|
||||
<!-- 默认只查正常单(del_flag=1); 反审/删除的归档行需显式传delFlag=2(已反审tab) -->
|
||||
<choose>
|
||||
<when test="delFlag != null">and eo.DEL_FLAG = #{delFlag}</when>
|
||||
<otherwise>and eo.DEL_FLAG = 1</otherwise>
|
||||
</choose>
|
||||
<if test="createStartTime != null">
|
||||
and eo.CREATE_TIME >= #{createStartTime}
|
||||
</if>
|
||||
|
||||
+4
-1
@@ -52,6 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateByName" column="update_by_name" />
|
||||
<result property="delFlag" column="del_flag" />
|
||||
<result property="reverseFlag" column="reverse_flag" />
|
||||
<result property="overStockId" column="over_stock_id" />
|
||||
<result property="overStockStatus" column="over_stock_status" />
|
||||
<result property="overStockType" column="over_stock_type" />
|
||||
@@ -127,7 +128,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
a.cancel_time, a.close_order, a.close_remark, a.close_by, a.close_by_name, a.close_time, a.check_status,a.BUSINESS_ORDER_NO,
|
||||
a.check_task_distribution, a.check_task_distribution_time, a.check_operators_by, a.check_operators_name, a.mobilize_code,
|
||||
a.remark, a.create_time, a.create_by, a.create_by_name,a.business_number,a.train_no,a.amount,a.business_out_order_number,
|
||||
a.update_time, a.update_by, a.update_by_name, a.del_flag, a.over_stock_id, a.over_stock_status, a.over_stock_type,a."TO",
|
||||
a.update_time, a.update_by, a.update_by_name, a.del_flag, a.reverse_flag, a.over_stock_id, a.over_stock_status, a.over_stock_type,a."TO",
|
||||
a.CONTACT_PERSON,a.VEHICLE_MODEL_PLATE,a.ENTRUST_NO,a.TEL,a.DRIVER_SIGN,a.FAX,a.DECLARE_CUSTOMS,a.MANUFACTURER,
|
||||
a.CUSTOMS_DECLARER_INFO,a.DELIVERY_ADDR,a.ENTRY_EXIT_CUSTOMS,a.DEPARTURE_ARRIVAL_COUNTRY,a.CARRIER,a.CONTAINER_NO,a.CONTAINER_NO_NAME,a.OUTBOUND_DATE,
|
||||
a.COMPLETE_TIME,a.ORDER_DATE,a.TRANSPORT_MODE_CODE,a.TRANSPORT_MODE_NAME,a.SUPERVISION_MODE_CODE,a.SUPERVISION_MODE_NAME,
|
||||
@@ -401,6 +402,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<when test="delFlag != null"> and a.del_flag = #{delFlag} </when>
|
||||
<otherwise> and a.del_flag = 1 </otherwise>
|
||||
</choose>
|
||||
<!-- 反审标记查询: OMS执行单【已反审】tab 前端传 delFlag=2 + reverseFlag=1 (与WMS四列表同口径, 两参数须成对传) -->
|
||||
<if test="reverseFlag != null"> and a.reverse_flag = #{reverseFlag} </if>
|
||||
</sql>
|
||||
|
||||
<select id="queryList" parameterType="com.mhd.oms.domain.executionStockOutOrder.repository.todo.ExecutionStockOutOrderDO" resultMap="StockOutOrderResult">
|
||||
|
||||
+13
@@ -592,6 +592,19 @@
|
||||
select WAREHOUSE_CODE from "NGWL_TEST_SYSTEM".WAREHOUSE where 1 = 1 and DEL_FLAG = 1 and WAREHOUSE_ID = #{id} limit 1
|
||||
</select>
|
||||
|
||||
<!-- 本地跨库直查仓库信息: 下发/保存等流程 Feign 获取仓库信息失败/降级时兜底(与 system 服务同库同表)。
|
||||
注意不含 STOCK_LOCK_MODE(冻结功能列, 各环境库结构不一致, 兜底路径不依赖冻结功能的列;
|
||||
stockLockMode 走 Feign 正常路径获取, 兜底时为 null 即默认"分配库存冻结"模式) -->
|
||||
<select id="getWarehouseInfoFallback" parameterType="java.lang.Long" resultType="com.mhd.system.api.domain.WarehouseFeignPO">
|
||||
select WAREHOUSE_CODE as warehouseCode,
|
||||
WAREHOUSE_NAME as warehouseName,
|
||||
ORDER_NO_GENERATE_RULE as orderNoGenerateRule,
|
||||
OUT_ORDER_NO_PREFIX as outOrderNoPrefix,
|
||||
SAMPLE_OUT_ORDER_NO_PREFIX as sampleOutOrderNoPrefix
|
||||
from "NGWL_TEST_SYSTEM".WAREHOUSE
|
||||
where 1 = 1 and DEL_FLAG = 1 and WAREHOUSE_ID = #{id} limit 1
|
||||
</select>
|
||||
|
||||
|
||||
<!-- 入仓通知单打印-表头查询 -->
|
||||
<select id="queryNoticePrint" resultMap="StockInOrderResult">
|
||||
|
||||
+22
-1
@@ -201,9 +201,22 @@ public class StockReceiptOrderApplicationService {
|
||||
*/
|
||||
public StockReceiptOrderPO getInfo(Long receiptOrderId)
|
||||
{
|
||||
StockReceiptOrderPO stockReceiptOrderPO = stockReceiptOrderDomainService.getInfo(receiptOrderId);
|
||||
return getInfo(receiptOrderId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收货单详情
|
||||
* @param archive true-查询【已反审】tab 归档数据(已软删+已反审标记,明细放行软删行)
|
||||
*/
|
||||
public StockReceiptOrderPO getInfo(Long receiptOrderId, boolean archive)
|
||||
{
|
||||
StockReceiptOrderPO stockReceiptOrderPO = stockReceiptOrderDomainService.getInfo(receiptOrderId, archive);
|
||||
ReceiptMaterialDetailDO receiptMaterialDetailDO = new ReceiptMaterialDetailDO();
|
||||
receiptMaterialDetailDO.setReceiptOrderNumber(stockReceiptOrderPO.getReceiptOrderNumber());
|
||||
if (archive) {
|
||||
//归档明细已随主单软删,放行软删行
|
||||
receiptMaterialDetailDO.setDelFlag(2);
|
||||
}
|
||||
List<ReceiptMaterialDetailPO> receiptMaterialDetailPOList = receiptMaterialDetailDomainService.queryListChildren(receiptMaterialDetailDO);
|
||||
|
||||
// 性能优化:批量获取批次属性,避免N+1查询问题
|
||||
@@ -306,6 +319,14 @@ public class StockReceiptOrderApplicationService {
|
||||
totalNetWeight, totalGrossWeight, totalVolume, totalArea);
|
||||
return stockReceiptOrderPO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询收货单【已反审】tab 归档详情(已软删+已反审标记的数据,含软删明细)
|
||||
*/
|
||||
public StockReceiptOrderPO getReverseAuditInfo(Long receiptOrderId)
|
||||
{
|
||||
return getInfo(receiptOrderId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据物料基础信息ID获取批次属性(更多属性),只返回isDisplay=1的属性
|
||||
|
||||
+13
-6
@@ -134,12 +134,12 @@ public class StockShelfOrderApplicationService {
|
||||
private static final String VERIFY = "ESLuxAmB6VXCgbqP1eFzxTPVRagkQ62BUkfhElrgQ6XmE/g2reHVflY/SiCSU7JD";
|
||||
|
||||
/** 仅这些仓库的上架单在PC上传页默认填充上架库位(按仓库名匹配;需放开其他仓库时在此追加)。
|
||||
* 生产环境:维他奶仓(warehouseId=14,已对照线上库位树验证:库区id=20,库位id=33);测试环境为 青洲仓(warehouseId=13),需测试时切换 */
|
||||
private static final Set<String> DEFAULT_STORAGE_LOCATION_WAREHOUSE_NAMES = new HashSet<>(Collections.singletonList("维他奶仓"));
|
||||
/** 默认上架库位:指定库区名→库位名(精确匹配,须与基础资料名称完全一致,注意含繁体字)。
|
||||
* 生产环境:維他奶2层冷凍A區 → 2层冷凍A區A01;测试环境为 4楼A区 → 4A-01-01,需测试时切换 */
|
||||
private static final String DEFAULT_SHELF_STORAGE_NAME = "維他奶2层冷凍A區";
|
||||
private static final String DEFAULT_SHELF_STORAGE_LOCATION_NAME = "2层冷凍A區A01";
|
||||
* 测试环境:青洲仓(warehouseId=13);生产环境为 维他奶仓(warehouseId=14,已对照线上库位树验证:库区id=20,库位id=33),发版前需切换 */
|
||||
private static final Set<String> DEFAULT_STORAGE_LOCATION_WAREHOUSE_NAMES = new HashSet<>(Collections.singletonList("青洲仓"));
|
||||
/** 默认上架库位:指定库区名→库位名(精确匹配,须与基础资料名称完全一致)。
|
||||
* 测试环境:4楼A区 → 4A-01-01;生产环境为 維他奶2层冷凍A區 → 2层冷凍A區A01(含繁体字),发版前需切换 */
|
||||
private static final String DEFAULT_SHELF_STORAGE_NAME = "4楼A区";
|
||||
private static final String DEFAULT_SHELF_STORAGE_LOCATION_NAME = "4A-01-01";
|
||||
/** 仅这些组织的上架单在PC上传页默认填充上架库位(按组织id精确匹配;测试与生产均为 谷丰=2842,若不一致需按环境切换) */
|
||||
private static final Set<Long> DEFAULT_STORAGE_LOCATION_ORGANIZATION_IDS = new HashSet<>(Collections.singletonList(2842L));
|
||||
|
||||
@@ -243,6 +243,13 @@ public class StockShelfOrderApplicationService {
|
||||
return getInfo(shelfOrderId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询上架单【已反审】tab 归档详情(已软删+已反审标记的数据,含软删明细)
|
||||
*/
|
||||
public StockShelfOrderPO getReverseAuditInfo(Long shelfOrderId) {
|
||||
return stockShelfOrderDomainService.getInfo(shelfOrderId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上架单详细信息
|
||||
*
|
||||
|
||||
+6
@@ -187,6 +187,8 @@ public class InOrderAbnormalImpl extends ServiceImpl<InOrderAbnormalMapper, InOr
|
||||
inOrderAbnormal.setAbnormalNumber(OrderSequence.getOrderCode("FSYC"));
|
||||
inOrderAbnormal.setType(3);
|
||||
inOrderAbnormal.setAbnormalType(6);
|
||||
//del_flag 不显式置1时 insert 不含该列,列无默认值则落库为NULL,会被列表的 del_flag=1 过滤掉导致记录永远不可见
|
||||
inOrderAbnormal.setDelFlag(1);
|
||||
if (inOrderAbnormal.getCreateTime() == null) {
|
||||
inOrderAbnormal.setCreateTime(new Date());
|
||||
}
|
||||
@@ -242,6 +244,8 @@ public class InOrderAbnormalImpl extends ServiceImpl<InOrderAbnormalMapper, InOr
|
||||
inOrderAbnormal.setCreateByName(userRealName);
|
||||
inOrderAbnormal.setCreateTime(new Date());
|
||||
inOrderAbnormal.setType(2);
|
||||
//del_flag 不显式置1时 insert 不含该列,列无默认值则落库为NULL,会被列表的 del_flag=1 过滤掉导致记录永远不可见
|
||||
inOrderAbnormal.setDelFlag(1);
|
||||
inOrderAbnormalList.add(inOrderAbnormal);
|
||||
}
|
||||
}
|
||||
@@ -287,6 +291,8 @@ public class InOrderAbnormalImpl extends ServiceImpl<InOrderAbnormalMapper, InOr
|
||||
inOrderAbnormal.setCreateByName(userRealName);
|
||||
inOrderAbnormal.setCreateTime(new Date());
|
||||
inOrderAbnormal.setType(1);
|
||||
//del_flag 不显式置1时 insert 不含该列,列无默认值则落库为NULL,会被列表的 del_flag=1 过滤掉导致记录永远不可见
|
||||
inOrderAbnormal.setDelFlag(1);
|
||||
inOrderAbnormalList.add(inOrderAbnormal);
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -26,6 +26,12 @@ public interface PickingMaterialDetailMapper extends BaseMapper<PickingMaterialD
|
||||
|
||||
public PickingMaterialDetailPO queryTotalsByOutNumberAndBaseId(@Param("outUniqueId") Long outUniqueId);
|
||||
|
||||
/**
|
||||
* 归档汇总(已反审): 同 queryTotalsByOutNumberAndBaseId, 但按 DEL_FLAG=2 统计软删归档的拣货明细,
|
||||
* 供交接单归档详情 getReverseInfo 使用(反审时拣货明细均已软删, 按 del_flag=1 统计恒为0会丢行)
|
||||
*/
|
||||
public PickingMaterialDetailPO queryTotalsByOutNumberAndBaseIdReverse(@Param("outUniqueId") Long outUniqueId);
|
||||
|
||||
/**
|
||||
* 按出库单号汇总拣货完成数量(实际下发/拣货完成的数量)
|
||||
*/
|
||||
|
||||
+19
-1
@@ -2632,6 +2632,8 @@ public class StockOutOrderDomainService {
|
||||
.eq(InventoryAdjustmentRecord::getRelateNo, relateNo));
|
||||
//逻辑删除出库单明细
|
||||
materialDetail.setDelFlag(2);
|
||||
// 归档行置空uniqueId: 明细表唯一约束不含del_flag, 保留原值会与重新下发推单时同一uniqueId的新明细撞键
|
||||
materialDetail.setUniqueId(null);
|
||||
outMaterialDetailService.updateById(materialDetail);
|
||||
}
|
||||
//逻辑删除出库单(用按单号查出的DB对象更新:OMS补偿清理只传单号,传入对象无主键,直接updateById不生效)
|
||||
@@ -2772,6 +2774,8 @@ public class StockOutOrderDomainService {
|
||||
}
|
||||
//逻辑删除出库单明细
|
||||
materialDetail.setDelFlag(2);
|
||||
// 归档行置空uniqueId: 明细表唯一约束不含del_flag, 保留原值会与重新下发推单时同一uniqueId的新明细撞键
|
||||
materialDetail.setUniqueId(null);
|
||||
materialDetail.setReverseFlag(1);
|
||||
outMaterialDetailService.updateById(materialDetail);
|
||||
}
|
||||
@@ -2845,11 +2849,25 @@ public class StockOutOrderDomainService {
|
||||
if (CollectionUtils.isEmpty(outMaterialDetails)) {
|
||||
return;
|
||||
}
|
||||
//幂等保护:重复下发时先逻辑删除同单号已存在的活动明细,避免重复插入导致分配/拣货数据错乱
|
||||
//幂等保护:重复下发时本单已有活动明细统一软删(1→2)并置空uniqueId
|
||||
outMaterialDetailService.update(new UpdateWrapper<OutMaterialDetail>().lambda()
|
||||
.set(OutMaterialDetail::getDelFlag, 2)
|
||||
.set(OutMaterialDetail::getUniqueId, null)
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, outMaterialDetails.get(0).getOutOrderNumber())
|
||||
.eq(OutMaterialDetail::getDelFlag, 1));
|
||||
//自愈:反审/取消下发的历史归档明细(del_flag=2, 含其他执行单残留)若仍占用本次推送的uniqueId, 置空释放键位
|
||||
//(表唯一约束不含del_flag; 反审后重新下发会复用同一库存行的uniqueId, 跨执行单也要清, 否则明细插入撞唯一约束)
|
||||
List<Long> pushedUniqueIds = outMaterialDetails.stream()
|
||||
.map(OutMaterialDetail::getUniqueId)
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (!pushedUniqueIds.isEmpty()) {
|
||||
outMaterialDetailService.update(new UpdateWrapper<OutMaterialDetail>().lambda()
|
||||
.set(OutMaterialDetail::getUniqueId, null)
|
||||
.eq(OutMaterialDetail::getDelFlag, 2)
|
||||
.in(OutMaterialDetail::getUniqueId, pushedUniqueIds));
|
||||
}
|
||||
outMaterialDetailService.saveBatch(outMaterialDetails);
|
||||
autoAuditOmsOutOrder(outMaterialDetails.get(0).getOutOrderNumber());
|
||||
}
|
||||
|
||||
+20
-1
@@ -261,7 +261,26 @@ public class StockReceiptOrderDomainService {
|
||||
* 获取收货单详细信息
|
||||
*/
|
||||
public StockReceiptOrderPO getInfo(Long receiptOrderId) {
|
||||
return stockReceiptOrderService.getInfo(receiptOrderId);
|
||||
return getInfo(receiptOrderId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收货单详情
|
||||
* @param archive true-查询【已反审】tab 归档数据(已软删+已反审标记)
|
||||
*/
|
||||
public StockReceiptOrderPO getInfo(Long receiptOrderId, boolean archive) {
|
||||
if (!archive) {
|
||||
return stockReceiptOrderService.getInfo(receiptOrderId);
|
||||
}
|
||||
//归档主单已软删,用 MP getById(不过滤 del_flag)并校验已反审标记
|
||||
StockReceiptOrder order = stockReceiptOrderService.getById(receiptOrderId);
|
||||
if (order == null || order.getDelFlag() == null || order.getDelFlag() != 2
|
||||
|| !Integer.valueOf(1).equals(order.getReverseAuditStatus())) {
|
||||
throw new ServiceException("收货单非已反审归档数据,无法查看归档详情");
|
||||
}
|
||||
StockReceiptOrderPO po = new StockReceiptOrderPO();
|
||||
org.springframework.beans.BeanUtils.copyProperties(order, po);
|
||||
return po;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
-1
@@ -243,9 +243,34 @@ public class StockShelfOrderDomainService {
|
||||
*/
|
||||
public StockShelfOrderPO getInfo(Long shelfOrderId)
|
||||
{
|
||||
StockShelfOrderPO stockShelfOrderPO = stockShelfOrderService.getInfo(shelfOrderId);
|
||||
return getInfo(shelfOrderId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上架单详情
|
||||
* @param archive true-查询【已反审】tab 归档数据(已软删+已反审标记,明细放行软删行)
|
||||
*/
|
||||
public StockShelfOrderPO getInfo(Long shelfOrderId, boolean archive)
|
||||
{
|
||||
StockShelfOrderPO stockShelfOrderPO;
|
||||
if (archive) {
|
||||
//归档主单已软删,用 MP getById(不过滤 del_flag)并校验已反审标记
|
||||
StockShelfOrder order = stockShelfOrderService.getById(shelfOrderId);
|
||||
if (order == null || order.getDelFlag() == null || order.getDelFlag() != 2
|
||||
|| !Integer.valueOf(1).equals(order.getReverseAuditStatus())) {
|
||||
throw new ServiceException("上架单非已反审归档数据,无法查看归档详情");
|
||||
}
|
||||
stockShelfOrderPO = new StockShelfOrderPO();
|
||||
org.springframework.beans.BeanUtils.copyProperties(order, stockShelfOrderPO);
|
||||
} else {
|
||||
stockShelfOrderPO = stockShelfOrderService.getInfo(shelfOrderId);
|
||||
}
|
||||
ShelfMaterialDetailDO shelfMaterialDetailDO = new ShelfMaterialDetailDO();
|
||||
shelfMaterialDetailDO.setShelfOrderNumber(stockShelfOrderPO.getShelfOrderNumber());
|
||||
if (archive) {
|
||||
//归档明细已随主单软删,放行软删行
|
||||
shelfMaterialDetailDO.setDelFlag(2);
|
||||
}
|
||||
List<ShelfMaterialDetailPO> inMaterialDetailPOList = shelfMaterialDetailService.queryListChildren(shelfMaterialDetailDO);
|
||||
stockShelfOrderPO.setMaterialDetailList(inMaterialDetailPOList);
|
||||
return stockShelfOrderPO;
|
||||
|
||||
+6
-3
@@ -521,8 +521,9 @@ public class StockOutOrderApi extends BaseController {
|
||||
*/
|
||||
@ApiOperation("oms下发单保存")
|
||||
@PostMapping(value = "/omsOutOrderAdd")
|
||||
public void omsOutOrderAdd(@RequestBody StockOutOrder stockOutOrder) {
|
||||
public AjaxResult omsOutOrderAdd(@RequestBody StockOutOrder stockOutOrder) {
|
||||
stockOutOrderApplicationService.omsOrderAdd(stockOutOrder);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -550,8 +551,9 @@ public class StockOutOrderApi extends BaseController {
|
||||
*/
|
||||
@ApiOperation("oms下发单明细保存")
|
||||
@PostMapping(value = "/omsOutOrderAddDetail")
|
||||
public void omsOutOrderAddDetail(@RequestBody List<OutMaterialDetail> outMaterialDetails) {
|
||||
public AjaxResult omsOutOrderAddDetail(@RequestBody List<OutMaterialDetail> outMaterialDetails) {
|
||||
stockOutOrderApplicationService.omsOrderAddDetail(outMaterialDetails);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,8 +589,9 @@ public class StockOutOrderApi extends BaseController {
|
||||
*/
|
||||
@ApiOperation("oms下发单配送明细保存")
|
||||
@PostMapping(value = "/omsOutOrderAddDeliveryDetailsLink")
|
||||
public void omsOutOrderAddDeliveryDetailsLink(@RequestBody List<DeliveryDetailsLink> deliveryDetailLinks) {
|
||||
public AjaxResult omsOutOrderAddDeliveryDetailsLink(@RequestBody List<DeliveryDetailsLink> deliveryDetailLinks) {
|
||||
stockOutOrderApplicationService.omsOrderAddDeliveryDetailsLink(deliveryDetailLinks);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@ApiOperation("出库单提货单打印")
|
||||
|
||||
+10
@@ -64,6 +64,16 @@ public class StockReceiptOrderApi extends BaseController {
|
||||
return AjaxResult.success(stockReceiptOrderApplicationService.getInfo(receiptOrderId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询收货单【已反审】tab 归档详情(已软删+已反审标记的数据,含软删明细)
|
||||
*/
|
||||
@ApiOperation("查询收货单已反审归档详情")
|
||||
@GetMapping(value = "/getReverseAuditInfo/{receiptOrderId}")
|
||||
public AjaxResult getReverseAuditInfo(@PathVariable("receiptOrderId") Long receiptOrderId)
|
||||
{
|
||||
return AjaxResult.success(stockReceiptOrderApplicationService.getReverseAuditInfo(receiptOrderId));
|
||||
}
|
||||
|
||||
@ApiOperation("分配月台")
|
||||
@PostMapping("/allocationPlatform")
|
||||
public AjaxResult allocationPlatform(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) {
|
||||
|
||||
+10
@@ -64,6 +64,16 @@ public class StockShelfOrderApi extends BaseController {
|
||||
return AjaxResult.success(stockShelfOrderApplicationService.getInfo(shelfOrderId, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询上架单【已反审】tab 归档详情(已软删+已反审标记的数据,含软删明细)
|
||||
*/
|
||||
@ApiOperation("查询上架单已反审归档详情")
|
||||
@GetMapping(value = "/getReverseAuditInfo/{shelfOrderId}")
|
||||
public AjaxResult getReverseAuditInfo(@PathVariable("shelfOrderId") Long shelfOrderId)
|
||||
{
|
||||
return AjaxResult.success(stockShelfOrderApplicationService.getReverseAuditInfo(shelfOrderId));
|
||||
}
|
||||
|
||||
@ApiOperation("任务下发")
|
||||
@PostMapping("/taskDistribution")
|
||||
public AjaxResult taskDistribution(@RequestBody StockShelfOrderDTO stockShelfOrderDTO) {
|
||||
|
||||
@@ -91,7 +91,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<include refid="selectInOrderAbnormalPo"/>
|
||||
<include refid="com.mhd.wms.domain.stockInOrder.repository.mapper.StockInOrderMapper.joinStockInOrderPo"/>
|
||||
from in_order_abnormal a
|
||||
LEFT JOIN stock_in_order b ON a.in_order_number = b.in_order_number and a.DEL_FLAG = 1 and b.DEL_FLAG = 1
|
||||
<!-- 反审记录(a.TYPE=3)关联的W入库单已被反审软删(del_flag=2),仍按 b.DEL_FLAG=1 关联会匹配不上:
|
||||
LEFT JOIN 下 b 全为 NULL,仓库/货主等基于 b 的过滤条件(warehouseId等)随之恒为 false,反审记录列表恒为空;
|
||||
故按 a.TYPE 切换关联状态:type=3 关联已软删的入库单,其余(收货/上架异常)关联正常入库单。
|
||||
b.IN_ORDER_ID 取同状态最新一张:历史重复下发会产生同号多张入库单,不限定会JOIN出重复行 -->
|
||||
LEFT JOIN stock_in_order b ON a.in_order_number = b.in_order_number
|
||||
and a.DEL_FLAG = 1
|
||||
and b.DEL_FLAG = (case when a.TYPE = 3 then 2 else 1 end)
|
||||
and b.IN_ORDER_ID = (select max(c.IN_ORDER_ID) from stock_in_order c
|
||||
where c.IN_ORDER_NUMBER = a.in_order_number
|
||||
and c.DEL_FLAG = (case when a.TYPE = 3 then 2 else 1 end))
|
||||
<where>
|
||||
<include refid="selectInOrderAbnormalPo1"/>
|
||||
<include refid="com.mhd.wms.domain.stockInOrder.repository.mapper.StockInOrderMapper.joinStockInOrderPoWhere"/>
|
||||
|
||||
@@ -101,10 +101,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="orderTypeCode != null and orderTypeCode != ''">
|
||||
and b.order_type_code = #{orderTypeCode}
|
||||
</if>
|
||||
<choose>
|
||||
<when test="delFlag != null"> and b.del_flag = #{delFlag} </when>
|
||||
<otherwise> and b.del_flag = 1 </otherwise>
|
||||
</choose>
|
||||
<!-- 不默认过滤 b.del_flag: 反审后出库单已软删(del_flag=2), 默认 b.del_flag=1 会让反审生成的异常记录在列表中消失;
|
||||
仅当前端显式传 delFlag 时才过滤 -->
|
||||
<if test="delFlag != null"> and b.del_flag = #{delFlag} </if>
|
||||
</sql>
|
||||
|
||||
<select id="queryList" parameterType="com.mhd.wms.domain.outOrderAbnormal.repository.todo.OutOrderAbnormalDO" resultMap="OutOrderAbnormalResult">
|
||||
@@ -112,7 +111,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<include refid="selectOutOrderAbnormalPo11"/>
|
||||
<include refid="com.mhd.wms.domain.stockOutOrder.repository.mapper.StockOutOrderMapper.joinStockOutOrderPoYc"/>
|
||||
from out_order_abnormal a
|
||||
left join stock_out_order b on a.out_order_number = b.out_order_number and b.del_flag = 1
|
||||
<!-- 不按 b.del_flag 限定: 出库单号唯一, 关联活动单或反审归档单均按单号取数, 保证反审异常记录能带出出库单信息 -->
|
||||
left join stock_out_order b on a.out_order_number = b.out_order_number
|
||||
<where>
|
||||
<include refid="selectOutOrderAbnormalPo1"/>
|
||||
<include refid="joinStockOutOrderPoWhere"/>
|
||||
|
||||
+15
@@ -248,6 +248,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
AND b.DEL_FLAG = 1
|
||||
</select>
|
||||
|
||||
<!-- 归档汇总(已反审): 反审时拣货明细已软删(del_flag=2), 按 del_flag=1 统计恒为0会丢行, 供交接单归档详情使用 -->
|
||||
<select id="queryTotalsByOutNumberAndBaseIdReverse" resultType="com.mhd.wms.domain.pickingMaterialDetail.repository.po.PickingMaterialDetailPO">
|
||||
SELECT
|
||||
COALESCE(SUM(b.PICKING_QUANTITY), 0) AS picking_quantity,
|
||||
COALESCE(SUM(b.TOTAL_AREA), 0) AS total_area,
|
||||
COALESCE(SUM(b.TOTAL_VOLUME), 0) AS total_volume,
|
||||
COALESCE(SUM(b.TOTAL_NET_WEIGHT), 0) AS total_net_weight,
|
||||
COALESCE(SUM(b.TOTAL_GROSS_WEIGHT), 0) AS total_gross_weight
|
||||
FROM
|
||||
PICKING_MATERIAL_DETAIL b
|
||||
WHERE
|
||||
b.OUT_UNIQUE_ID = #{outUniqueId}
|
||||
AND b.DEL_FLAG = 2
|
||||
</select>
|
||||
|
||||
<select id="sumPickingQuantityByOutOrderNumber" resultType="java.math.BigDecimal">
|
||||
SELECT COALESCE(SUM(pmd.PICKING_QUANTITY), 0)
|
||||
FROM picking_material_detail pmd
|
||||
|
||||
@@ -46,13 +46,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<sql id="selectPickingOrderPo">
|
||||
a.picking_order_id, a.organization_id, a.organization_name, a.top_organization_id, a.order_number, a.picking_order_number,
|
||||
a.status, a.type, a.warehouse_id, a.warehouse_code, a.warehouse_name, a.shipper_id, a.shipper_name, a.quantity, a.weight_limit, a.volume_limit, a.material_quantity,
|
||||
IFNULL((SELECT SUM(b.picking_quantity) FROM picking_material_detail b WHERE b.picking_order_number = a.picking_order_number AND b.del_flag = 1), 0) AS picking_quantity,
|
||||
<!-- 拣货数量/货物类型按行自身生命周期聚合(del_flag=a.del_flag): 活动行统计活动明细, 已反审归档行(del_flag=2)统计归档明细;
|
||||
固定 del_flag=1 会导致【已反审】tab 及归档详情(queryOutOrderByIdReverse 复用本片段)拣货数量恒为0 -->
|
||||
IFNULL((SELECT SUM(b.picking_quantity) FROM picking_material_detail b WHERE b.picking_order_number = a.picking_order_number AND b.del_flag = a.del_flag), 0) AS picking_quantity,
|
||||
a.picking_material_quantity, a.abnormal, a.task_distribution, a.remark, a.create_time, a.create_by, a.create_by_name, a.update_time,b.out_order_id,
|
||||
a.update_by, a.update_by_name, a.del_flag, a.reverse_flag, a.out_order_number, a.business_order_no, a.order_type_code, a.order_type_name, a.priority_level_code, a.priority_level_name
|
||||
,a.push_status,a.push_time,a.push_by,a.push_by_name,
|
||||
(SELECT m.goods_type FROM PICKING_MATERIAL_DETAIL d
|
||||
JOIN material_base_info m ON d.material_base_info_id = m.material_base_info_id
|
||||
WHERE d.PICKING_ORDER_NUMBER = a.PICKING_ORDER_NUMBER and d.del_flag = 1
|
||||
WHERE d.PICKING_ORDER_NUMBER = a.PICKING_ORDER_NUMBER and d.del_flag = a.del_flag
|
||||
LIMIT 1) AS goods_type
|
||||
</sql>
|
||||
|
||||
|
||||
@@ -204,7 +204,8 @@
|
||||
sum(ifnull(d.material_plan_qty, ifnull(d.pending_review_qty, 0) + ifnull(d.reviewed_qty, 0))) as total_plan_qty,
|
||||
sum(ifnull(d.reviewed_qty, 0)) as total_reviewed_qty
|
||||
from review_material_detail d
|
||||
where d.del_flag = 1
|
||||
<!-- 不滤 del_flag: 复核明细仅随整单反审统一软删(全库唯一软删路径), 不滤才能让【已反审】tab 行汇总到归档明细;
|
||||
活动单明细恒为 del_flag=1, 汇总口径不变 -->
|
||||
group by d.review_order_id
|
||||
) agg on a.review_order_id = agg.review_order_id
|
||||
<where>
|
||||
|
||||
@@ -173,9 +173,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<choose>
|
||||
<when test="reverseAuditStatus != null">
|
||||
and a.DEL_FLAG = 2 and b.DEL_FLAG = 2
|
||||
<!-- 历史重复下发会产生同号多张入库单,限定只关联同状态最新一张,防止列表出现重复行 -->
|
||||
and b.IN_ORDER_ID = (select max(c.IN_ORDER_ID) from stock_in_order c
|
||||
where c.IN_ORDER_NUMBER = a.in_order_number and c.DEL_FLAG = 2)
|
||||
</when>
|
||||
<otherwise>
|
||||
and a.DEL_FLAG = 1 and b.DEL_FLAG = 1
|
||||
and b.IN_ORDER_ID = (select max(c.IN_ORDER_ID) from stock_in_order c
|
||||
where c.IN_ORDER_NUMBER = a.in_order_number and c.DEL_FLAG = 1)
|
||||
</otherwise>
|
||||
</choose>
|
||||
<where>
|
||||
|
||||
@@ -164,9 +164,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<choose>
|
||||
<when test="reverseAuditStatus != null">
|
||||
and a.DEL_FLAG = 2 and b.DEL_FLAG = 2
|
||||
<!-- 历史重复下发会产生同号多张入库单,限定只关联同状态最新一张,防止列表出现重复行 -->
|
||||
and b.IN_ORDER_ID = (select max(c.IN_ORDER_ID) from stock_in_order c
|
||||
where c.IN_ORDER_NUMBER = a.in_order_number and c.DEL_FLAG = 2)
|
||||
</when>
|
||||
<otherwise>
|
||||
and a.DEL_FLAG = 1 and b.DEL_FLAG = 1
|
||||
and b.IN_ORDER_ID = (select max(c.IN_ORDER_ID) from stock_in_order c
|
||||
where c.IN_ORDER_NUMBER = a.in_order_number and c.DEL_FLAG = 1)
|
||||
</otherwise>
|
||||
</choose>
|
||||
<where>
|
||||
|
||||
Reference in New Issue
Block a user