Commit a682efdbcf491b73d266e350c4a469ce55fefbcc

Authored by YunaiV
1 parent 6a9c2c25

✨ feat(mes): 添加库存调拨事务创建逻辑,支持出入库操作

yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java
@@ -11,8 +11,12 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDO; @@ -11,8 +11,12 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDO;
11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDetailDO; 11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDetailDO;
12 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO; 12 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO;
13 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferMapper; 13 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferMapper;
  14 +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
  15 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
14 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransferStatusEnum; 16 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransferStatusEnum;
15 import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; 17 import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
  18 +import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
  19 +import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
16 import jakarta.annotation.Resource; 20 import jakarta.annotation.Resource;
17 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
18 import org.springframework.transaction.annotation.Transactional; 22 import org.springframework.transaction.annotation.Transactional;
@@ -20,6 +24,7 @@ import org.springframework.validation.annotation.Validated; @@ -20,6 +24,7 @@ import org.springframework.validation.annotation.Validated;
20 24
21 import java.math.BigDecimal; 25 import java.math.BigDecimal;
22 import java.util.List; 26 import java.util.List;
  27 +import java.util.Map;
23 28
24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 29 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; 30 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -40,6 +45,8 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -40,6 +45,8 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
40 private MesWmTransferDetailService transferDetailService; 45 private MesWmTransferDetailService transferDetailService;
41 @Resource 46 @Resource
42 private MesWmMaterialStockService materialStockService; 47 private MesWmMaterialStockService materialStockService;
  48 + @Resource
  49 + private MesWmTransactionService wmTransactionService;
43 50
44 @Override 51 @Override
45 public Long createTransfer(MesWmTransferSaveReqVO createReqVO) { 52 public Long createTransfer(MesWmTransferSaveReqVO createReqVO) {
@@ -148,25 +155,60 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -148,25 +155,60 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
148 @Override 155 @Override
149 @Transactional(rollbackFor = Exception.class) 156 @Transactional(rollbackFor = Exception.class)
150 public void finishTransfer(Long id) { 157 public void finishTransfer(Long id) {
151 - // 校验存在 + 待执行状态 158 + // 1. 校验存在 + 待执行状态
152 MesWmTransferDO transfer = validateTransferExistsAndApproved(id); 159 MesWmTransferDO transfer = validateTransferExistsAndApproved(id);
153 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id); 160 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);
154 if (CollUtil.isEmpty(lines)) { 161 if (CollUtil.isEmpty(lines)) {
155 throw exception(WM_TRANSFER_NO_LINE); 162 throw exception(WM_TRANSFER_NO_LINE);
156 } 163 }
157 164
158 - // DONE @AI:库存转移涉及出入库落账与库存事务联动,当前提交先保留状态流转与冻结解冻校验,不在本轮 TODO 修复中扩展业务实现 165 + // 2. 创建库存事务(调拨移出 + 调拨移入)
  166 + createTransferTransactions(transfer, lines);
159 167
160 - // 更新状态:待执行 -> 已完成 168 + // 3. 更新状态:待执行 -> 已完成
161 transfer.setStatus(MesWmTransferStatusEnum.FINISHED.getStatus()); 169 transfer.setStatus(MesWmTransferStatusEnum.FINISHED.getStatus());
162 transferMapper.updateById(transfer); 170 transferMapper.updateById(transfer);
163 171
164 - // 配送模式下,执行完成后解除来源库存冻结 172 + // 4. 配送模式下,执行完成后解除来源库存冻结
165 if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) { 173 if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) {
166 freezeTransferLineStocks(lines, false); 174 freezeTransferLineStocks(lines, false);
167 } 175 }
168 } 176 }
169 177
  178 + /**
  179 + * 创建调拨事务:基于 detail (明细) 的视角,不是纯粹的 line(行)的视角。
  180 + * 因为明细才代表了实际调往各个目标仓位的动作,所以每条明細产生一笔出库(MOVE_OUT)和一笔入库(MOVE_IN)。
  181 + */
  182 + private void createTransferTransactions(MesWmTransferDO transfer, List<MesWmTransferLineDO> lines) {
  183 + // 1. 预加载所有明细,按 lineId 分组,避免 N+1 查询
  184 + List<MesWmTransferDetailDO> allDetails = transferDetailService.getTransferDetailListByTransferId(transfer.getId());
  185 + Map<Long, List<MesWmTransferDetailDO>> detailMap = CollectionUtils.convertMultiMap(
  186 + allDetails, MesWmTransferDetailDO::getLineId);
  187 + // 2. 遍历行和对应的明细,创建事务
  188 + for (MesWmTransferLineDO line : lines) {
  189 + List<MesWmTransferDetailDO> details = detailMap.getOrDefault(line.getId(), List.of());
  190 + for (MesWmTransferDetailDO detail : details) {
  191 + // 2.1 先执行出库:调拨移出(从源仓库扣减库存),出库数量基于当前明细的数量
  192 + Long outTransactionId = wmTransactionService.createTransaction(new MesWmTransactionSaveReqDTO()
  193 + .setType(MesWmTransactionTypeEnum.MOVE_OUT.getType()).setItemId(line.getItemId())
  194 + .setQuantity(detail.getQuantity().negate()) // 库存减少(按 detail 的数量出)
  195 + .setBatchId(line.getBatchId())
  196 + .setWarehouseId(line.getFromWarehouseId()).setLocationId(line.getFromLocationId()).setAreaId(line.getFromAreaId())
  197 + .setBizType(MesBizTypeConstants.WM_TRANSFER_OUT).setBizId(transfer.getId())
  198 + .setBizCode(transfer.getCode()).setBizLineId(line.getId()));
  199 + // 2.2 再执行入库:调拨移入(向目标仓库增加库存),入库数量等于相同明细的数量
  200 + wmTransactionService.createTransaction(new MesWmTransactionSaveReqDTO()
  201 + .setType(MesWmTransactionTypeEnum.MOVE_IN.getType()).setItemId(line.getItemId()) // 物料信息来自 line
  202 + .setQuantity(detail.getQuantity()) // 库存增加(按 detail 的数量入)
  203 + .setBatchId(line.getBatchId()) // 批次信息来自 line
  204 + .setWarehouseId(detail.getToWarehouseId()).setLocationId(detail.getToLocationId()).setAreaId(detail.getToAreaId())
  205 + .setBizType(MesBizTypeConstants.WM_TRANSFER_IN).setBizId(transfer.getId())
  206 + .setBizCode(transfer.getCode()).setBizLineId(line.getId())
  207 + .setRelatedTransactionId(outTransactionId)); // 关联本次的具体出库事务
  208 + }
  209 + }
  210 + }
  211 +
170 @Override 212 @Override
171 @Transactional(rollbackFor = Exception.class) 213 @Transactional(rollbackFor = Exception.class)
172 public void cancelTransfer(Long id) { 214 public void cancelTransfer(Long id) {