Commit b486001c176e5585d5b5fcfcebee50c66dc01725

Authored by YunaiV
1 parent ff8aea9d

✨ feat(mes): 添加库存不足错误码及相关校验逻辑

新增库存不足的错误码,并在转移单相关服务中添加对仓库、库区、库位的校验逻辑,以确保数据的完整性和准确性。
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -330,6 +330,7 @@ public interface ErrorCodeConstants { @@ -330,6 +330,7 @@ public interface ErrorCodeConstants {
330 330
331 // ========== MES 仓库管理-库存(1-040-703-000) ========== 331 // ========== MES 仓库管理-库存(1-040-703-000) ==========
332 ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在"); 332 ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在");
  333 + ErrorCode WM_MATERIAL_STOCK_INSUFFICIENT = new ErrorCode(1_040_703_001, "库存数量不足");
333 334
334 // ========== MES 仓库管理-到货通知单(1-040-704-000) ========== 335 // ========== MES 仓库管理-到货通知单(1-040-704-000) ==========
335 ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "到货通知单不存在"); 336 ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "到货通知单不存在");
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferLineServiceImpl.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.line.MesWmTra @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.line.MesWmTra
5 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO; 5 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO;
6 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferLineMapper; 6 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferLineMapper;
7 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; 7 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  8 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
8 import jakarta.annotation.Resource; 9 import jakarta.annotation.Resource;
9 import org.springframework.context.annotation.Lazy; 10 import org.springframework.context.annotation.Lazy;
10 import org.springframework.stereotype.Service; 11 import org.springframework.stereotype.Service;
@@ -30,14 +31,20 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService { @@ -30,14 +31,20 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
30 private MesWmTransferService transferService; 31 private MesWmTransferService transferService;
31 @Resource 32 @Resource
32 private MesMdItemService itemService; 33 private MesMdItemService itemService;
  34 + @Resource
  35 + private MesWmWarehouseAreaService warehouseAreaService;
33 36
34 @Override 37 @Override
35 public Long createTransferLine(MesWmTransferLineSaveReqVO createReqVO) { 38 public Long createTransferLine(MesWmTransferLineSaveReqVO createReqVO) {
  39 + // 校验父数据可编辑
36 transferService.validateTransferEditable(createReqVO.getTransferId()); 40 transferService.validateTransferEditable(createReqVO.getTransferId());
  41 + // 校验产品存在
37 itemService.validateItemExists(createReqVO.getItemId()); 42 itemService.validateItemExists(createReqVO.getItemId());
38 - // DONE @AI:当前先保留主单可编辑与物料存在校验,其他关联校验需结合库存与批次规则统一设计,暂不在本轮 TODO 修复中扩展  
39 - // TODO @AI:位置相关的几个校验; 43 + // 校验来源仓库、库区、库位的关联关系
  44 + warehouseAreaService.validateWarehouseAreaExists(createReqVO.getFromWarehouseId(),
  45 + createReqVO.getFromLocationId(), createReqVO.getFromAreaId());
40 46
  47 + // 插入
41 MesWmTransferLineDO line = BeanUtils.toBean(createReqVO, MesWmTransferLineDO.class); 48 MesWmTransferLineDO line = BeanUtils.toBean(createReqVO, MesWmTransferLineDO.class);
42 transferLineMapper.insert(line); 49 transferLineMapper.insert(line);
43 return line.getId(); 50 return line.getId();
@@ -45,19 +52,26 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService { @@ -45,19 +52,26 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
45 52
46 @Override 53 @Override
47 public void updateTransferLine(MesWmTransferLineSaveReqVO updateReqVO) { 54 public void updateTransferLine(MesWmTransferLineSaveReqVO updateReqVO) {
  55 + // 校验存在
48 validateTransferLineExists(updateReqVO.getId()); 56 validateTransferLineExists(updateReqVO.getId());
  57 + // 校验父数据可编辑
49 transferService.validateTransferEditable(updateReqVO.getTransferId()); 58 transferService.validateTransferEditable(updateReqVO.getTransferId());
  59 + // 校验产品存在
50 itemService.validateItemExists(updateReqVO.getItemId()); 60 itemService.validateItemExists(updateReqVO.getItemId());
51 - // DONE @AI:当前先保留主单可编辑与物料存在校验,其他关联校验需结合库存与批次规则统一设计,暂不在本轮 TODO 修复中扩展  
52 - // TODO @AI:位置相关的几个校验; 61 + // 校验来源仓库、库区、库位的关联关系
  62 + warehouseAreaService.validateWarehouseAreaExists(updateReqVO.getFromWarehouseId(),
  63 + updateReqVO.getFromLocationId(), updateReqVO.getFromAreaId());
53 64
  65 + // 更新
54 MesWmTransferLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferLineDO.class); 66 MesWmTransferLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferLineDO.class);
55 transferLineMapper.updateById(updateObj); 67 transferLineMapper.updateById(updateObj);
56 } 68 }
57 69
58 @Override 70 @Override
59 public void deleteTransferLine(Long id) { 71 public void deleteTransferLine(Long id) {
  72 + // 校验存在
60 validateTransferLineExists(id); 73 validateTransferLineExists(id);
  74 + // 删除
61 transferLineMapper.deleteById(id); 75 transferLineMapper.deleteById(id);
62 } 76 }
63 77
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java
@@ -99,12 +99,12 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -99,12 +99,12 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
99 } 99 }
100 100
101 // 配送模式下,提交后如果未确认,则进入待确认状态;否则直接进入待上架状态 101 // 配送模式下,提交后如果未确认,则进入待确认状态;否则直接进入待上架状态
102 - if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) && Boolean.FALSE.equals(transfer.getConfirmFlag())) { 102 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) && !Boolean.TRUE.equals(transfer.getConfirmFlag())) {
103 transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()).setConfirmFlag(false); 103 transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()).setConfirmFlag(false);
104 // DONE @AI:冻结库存属于主单状态流转的一部分,保留在主单 service 统一处理 104 // DONE @AI:冻结库存属于主单状态流转的一部分,保留在主单 service 统一处理
105 freezeTransferLineStocks(lines, true); 105 freezeTransferLineStocks(lines, true);
106 } else { 106 } else {
107 - transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus()); 107 + transfer.setStatus(MesWmTransferStatusEnum.APPROVING.getStatus());
108 } 108 }
109 transferMapper.updateById(transfer); 109 transferMapper.updateById(transfer);
110 } 110 }
@@ -116,7 +116,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -116,7 +116,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
116 MesWmTransferDO transfer = validateTransferExistsAndConfirm(id); 116 MesWmTransferDO transfer = validateTransferExistsAndConfirm(id);
117 117
118 // 更新状态:待确认 -> 待上架 118 // 更新状态:待确认 -> 待上架
119 - transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus()); 119 + transfer.setStatus(MesWmTransferStatusEnum.APPROVING.getStatus());
120 transfer.setConfirmFlag(true); 120 transfer.setConfirmFlag(true);
121 transferMapper.updateById(transfer); 121 transferMapper.updateById(transfer);
122 } 122 }
@@ -124,17 +124,24 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -124,17 +124,24 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
124 @Override 124 @Override
125 @Transactional(rollbackFor = Exception.class) 125 @Transactional(rollbackFor = Exception.class)
126 public void stockTransfer(Long id) { 126 public void stockTransfer(Long id) {
127 - MesWmTransferDO transfer = validateTransferExistsAndUnstock(id); 127 + // 1.1 校验存在
  128 + MesWmTransferDO transfer = validateTransferExistsAndApproving(id);
128 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id); 129 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);
129 if (CollUtil.isEmpty(lines)) { 130 if (CollUtil.isEmpty(lines)) {
130 throw exception(WM_TRANSFER_NO_LINE); 131 throw exception(WM_TRANSFER_NO_LINE);
131 } 132 }
  133 + // 1.2 检查每个行的明细数量是否完成上架
  134 + for (MesWmTransferLineDO line : lines) {
  135 + List<MesWmTransferDetailDO> details = transferDetailService.getTransferDetailListByLineId(line.getId());
  136 + BigDecimal totalDetailQty = CollectionUtils.getSumValue(details,
  137 + MesWmTransferDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO);
  138 + if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) {
  139 + throw exception(WM_TRANSFER_DETAIL_QUANTITY_MISMATCH);
  140 + }
  141 + }
132 142
133 - // TODO @AI:参考别的模块的 stockXXX 方法,直接放在这里;不需要抽方法;  
134 - validateTransferDetailQuantity(lines);  
135 -  
136 - // 更新状态:待上架 -> 待执行  
137 - transfer.setStatus(MesWmTransferStatusEnum.UNEXECUTE.getStatus()); 143 + // 2. 更新状态:待上架 -> 待执行
  144 + transfer.setStatus(MesWmTransferStatusEnum.APPROVED.getStatus());
138 transferMapper.updateById(transfer); 145 transferMapper.updateById(transfer);
139 } 146 }
140 147
@@ -142,7 +149,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -142,7 +149,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
142 @Transactional(rollbackFor = Exception.class) 149 @Transactional(rollbackFor = Exception.class)
143 public void finishTransfer(Long id) { 150 public void finishTransfer(Long id) {
144 // 校验存在 + 待执行状态 151 // 校验存在 + 待执行状态
145 - MesWmTransferDO transfer = validateTransferExistsAndUnexecute(id); 152 + MesWmTransferDO transfer = validateTransferExistsAndApproved(id);
146 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id); 153 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);
147 if (CollUtil.isEmpty(lines)) { 154 if (CollUtil.isEmpty(lines)) {
148 throw exception(WM_TRANSFER_NO_LINE); 155 throw exception(WM_TRANSFER_NO_LINE);
@@ -222,24 +229,24 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -222,24 +229,24 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
222 return transfer; 229 return transfer;
223 } 230 }
224 231
225 - private MesWmTransferDO validateTransferExistsAndUnstock(Long id) { 232 + private MesWmTransferDO validateTransferExistsAndApproving(Long id) {
226 MesWmTransferDO transfer = transferMapper.selectById(id); 233 MesWmTransferDO transfer = transferMapper.selectById(id);
227 if (transfer == null) { 234 if (transfer == null) {
228 throw exception(WM_TRANSFER_NOT_EXISTS); 235 throw exception(WM_TRANSFER_NOT_EXISTS);
229 } 236 }
230 - if (!MesWmTransferStatusEnum.UNSTOCK.getStatus().equals(transfer.getStatus())) {  
231 - throw exception(WM_TRANSFER_NOT_UNSTOCK); 237 + if (!MesWmTransferStatusEnum.APPROVING.getStatus().equals(transfer.getStatus())) {
  238 + throw exception(WM_TRANSFER_NOT_APPROVING);
232 } 239 }
233 return transfer; 240 return transfer;
234 } 241 }
235 242
236 - private MesWmTransferDO validateTransferExistsAndUnexecute(Long id) { 243 + private MesWmTransferDO validateTransferExistsAndApproved(Long id) {
237 MesWmTransferDO transfer = transferMapper.selectById(id); 244 MesWmTransferDO transfer = transferMapper.selectById(id);
238 if (transfer == null) { 245 if (transfer == null) {
239 throw exception(WM_TRANSFER_NOT_EXISTS); 246 throw exception(WM_TRANSFER_NOT_EXISTS);
240 } 247 }
241 - if (!MesWmTransferStatusEnum.UNEXECUTE.getStatus().equals(transfer.getStatus())) {  
242 - throw exception(WM_TRANSFER_NOT_UNEXECUTE); 248 + if (!MesWmTransferStatusEnum.APPROVED.getStatus().equals(transfer.getStatus())) {
  249 + throw exception(WM_TRANSFER_NOT_APPROVED);
243 } 250 }
244 return transfer; 251 return transfer;
245 } 252 }
@@ -256,19 +263,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -256,19 +263,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
256 return transfer; 263 return transfer;
257 } 264 }
258 265
259 - // DONE @AI:保留独立方法复用明细数量校验,待执行状态仍由主流程负责推进  
260 - private void validateTransferDetailQuantity(List<MesWmTransferLineDO> lines) {  
261 - for (MesWmTransferLineDO line : lines) {  
262 - List<MesWmTransferDetailDO> details = transferDetailService.getTransferDetailListByLineId(line.getId());  
263 - BigDecimal totalDetailQty = CollectionUtils.getSumValue(details,  
264 - MesWmTransferDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO);  
265 - if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) {  
266 - throw exception(WM_TRANSFER_DETAIL_QUANTITY_MISMATCH);  
267 - }  
268 - }  
269 - }  
270 -  
271 - // TODO @AI:materialStockService 封装一个方法,传入 transferId + frozen 统一处理了;不用判断 line 的 getMaterialStockId 266 + // TODO @芋艿:【后续弄】materialStockService 封装一个方法,传入 transferId + frozen 统一处理了;不用判断 line 的 getMaterialStockId
272 private void freezeTransferLineStocks(List<MesWmTransferLineDO> lines, boolean frozen) { 267 private void freezeTransferLineStocks(List<MesWmTransferLineDO> lines, boolean frozen) {
273 if (CollUtil.isEmpty(lines)) { 268 if (CollUtil.isEmpty(lines)) {
274 return; 269 return;