Commit c9dedd6893a0773ddb3e6efd56fdc05f18b0a603

Authored by YunaiV
1 parent 68f373f6

✨ feat(mes): 添加上架功能及相关字段校验

新增执行上架功能,允许将待上架状态的转移单更新为待执行状态。
同时,添加了转移单及转移单行的字段校验,确保必要字段不为空,提升数据完整性。
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/MesWmTransferController.java
@@ -107,6 +107,15 @@ public class MesWmTransferController { @@ -107,6 +107,15 @@ public class MesWmTransferController {
107 return success(true); 107 return success(true);
108 } 108 }
109 109
  110 + @PutMapping("/stock")
  111 + @Operation(summary = "执行上架")
  112 + @Parameter(name = "id", description = "编号", required = true)
  113 + @PreAuthorize("@ss.hasPermission('mes:wm-transfer:update')")
  114 + public CommonResult<Boolean> stockTransfer(@RequestParam("id") Long id) {
  115 + transferService.stockTransfer(id);
  116 + return success(true);
  117 + }
  118 +
110 @PutMapping("/finish") 119 @PutMapping("/finish")
111 @Operation(summary = "完成转移单") 120 @Operation(summary = "完成转移单")
112 @Parameter(name = "id", description = "编号", required = true) 121 @Parameter(name = "id", description = "编号", required = true)
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferPageReqVO.java
@@ -26,11 +26,5 @@ public class MesWmTransferPageReqVO extends PageParam { @@ -26,11 +26,5 @@ public class MesWmTransferPageReqVO extends PageParam {
26 @Schema(description = "转移单类型", example = "1") 26 @Schema(description = "转移单类型", example = "1")
27 private Integer type; 27 private Integer type;
28 28
29 - @Schema(description = "转移日期")  
30 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
31 - private LocalDateTime[] transferDate;  
32 -  
33 - @Schema(description = "单据状态", example = "0")  
34 - private Integer status;  
35 29
36 } 30 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferSaveReqVO.java
1 package cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo; 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotBlank;
  5 +import jakarta.validation.constraints.NotNull;
4 import lombok.Data; 6 import lombok.Data;
5 7
6 import java.time.LocalDateTime; 8 import java.time.LocalDateTime;
@@ -14,17 +16,20 @@ public class MesWmTransferSaveReqVO { @@ -14,17 +16,20 @@ public class MesWmTransferSaveReqVO {
14 @Schema(description = "编号", example = "1") 16 @Schema(description = "编号", example = "1")
15 private Long id; 17 private Long id;
16 18
17 - // TODO @AI:validator 参数校验需要添加  
18 @Schema(description = "转移单编号", requiredMode = REQUIRED, example = "TR2026020001") 19 @Schema(description = "转移单编号", requiredMode = REQUIRED, example = "TR2026020001")
  20 + @NotBlank(message = "转移单编号不能为空")
19 private String code; 21 private String code;
20 22
21 @Schema(description = "转移单名称", requiredMode = REQUIRED, example = "钢板转移单") 23 @Schema(description = "转移单名称", requiredMode = REQUIRED, example = "钢板转移单")
  24 + @NotBlank(message = "转移单名称不能为空")
22 private String name; 25 private String name;
23 26
24 @Schema(description = "转移单类型", requiredMode = REQUIRED, example = "1") 27 @Schema(description = "转移单类型", requiredMode = REQUIRED, example = "1")
  28 + @NotNull(message = "转移单类型不能为空")
25 private Integer type; 29 private Integer type;
26 30
27 @Schema(description = "是否配送", requiredMode = REQUIRED, example = "true") 31 @Schema(description = "是否配送", requiredMode = REQUIRED, example = "true")
  32 + @NotNull(message = "是否配送不能为空")
28 private Boolean deliveryFlag; 33 private Boolean deliveryFlag;
29 34
30 @Schema(description = "收货人", example = "张三") 35 @Schema(description = "收货人", example = "张三")
@@ -43,6 +48,7 @@ public class MesWmTransferSaveReqVO { @@ -43,6 +48,7 @@ public class MesWmTransferSaveReqVO {
43 private String shippingNumber; 48 private String shippingNumber;
44 49
45 @Schema(description = "转移日期", requiredMode = REQUIRED) 50 @Schema(description = "转移日期", requiredMode = REQUIRED)
  51 + @NotNull(message = "转移日期不能为空")
46 private LocalDateTime transferDate; 52 private LocalDateTime transferDate;
47 53
48 @Schema(description = "备注", example = "备注信息") 54 @Schema(description = "备注", example = "备注信息")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/line/MesWmTransferLineSaveReqVO.java
@@ -13,27 +13,33 @@ public class MesWmTransferLineSaveReqVO { @@ -13,27 +13,33 @@ public class MesWmTransferLineSaveReqVO {
13 private Long id; 13 private Long id;
14 14
15 @Schema(description = "转移单编号", example = "1") 15 @Schema(description = "转移单编号", example = "1")
  16 + // TODO @AI:不能为空
16 private Long transferId; 17 private Long transferId;
17 18
18 @Schema(description = "库存记录编号", example = "1") 19 @Schema(description = "库存记录编号", example = "1")
19 private Long materialStockId; 20 private Long materialStockId;
20 21
21 @Schema(description = "物料编号", example = "1") 22 @Schema(description = "物料编号", example = "1")
  23 + // TODO @AI:不能为空
22 private Long itemId; 24 private Long itemId;
23 25
24 @Schema(description = "转移数量", example = "100") 26 @Schema(description = "转移数量", example = "100")
  27 + // TODO @AI:数量不能为空,且要大于 0
25 private BigDecimal quantity; 28 private BigDecimal quantity;
26 29
27 @Schema(description = "批次编号", example = "1") 30 @Schema(description = "批次编号", example = "1")
28 private Long batchId; 31 private Long batchId;
29 32
30 @Schema(description = "移出仓库编号", example = "1") 33 @Schema(description = "移出仓库编号", example = "1")
  34 + // TODO @AI:不能为空
31 private Long fromWarehouseId; 35 private Long fromWarehouseId;
32 36
33 @Schema(description = "移出库区编号", example = "1") 37 @Schema(description = "移出库区编号", example = "1")
  38 + // TODO @AI:不能为空
34 private Long fromLocationId; 39 private Long fromLocationId;
35 40
36 @Schema(description = "移出库位编号", example = "1") 41 @Schema(description = "移出库位编号", example = "1")
  42 + // TODO @AI:不能为空
37 private Long fromAreaId; 43 private Long fromAreaId;
38 44
39 @Schema(description = "备注", example = "备注信息") 45 @Schema(description = "备注", example = "备注信息")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transfer/MesWmTransferMapper.java
@@ -18,8 +18,6 @@ public interface MesWmTransferMapper extends BaseMapperX&lt;MesWmTransferDO&gt; { @@ -18,8 +18,6 @@ public interface MesWmTransferMapper extends BaseMapperX&lt;MesWmTransferDO&gt; {
18 .likeIfPresent(MesWmTransferDO::getCode, reqVO.getCode()) 18 .likeIfPresent(MesWmTransferDO::getCode, reqVO.getCode())
19 .likeIfPresent(MesWmTransferDO::getName, reqVO.getName()) 19 .likeIfPresent(MesWmTransferDO::getName, reqVO.getName())
20 .eqIfPresent(MesWmTransferDO::getType, reqVO.getType()) 20 .eqIfPresent(MesWmTransferDO::getType, reqVO.getType())
21 - .betweenIfPresent(MesWmTransferDO::getTransferDate, reqVO.getTransferDate())  
22 - .eqIfPresent(MesWmTransferDO::getStatus, reqVO.getStatus())  
23 .orderByDesc(MesWmTransferDO::getId)); 21 .orderByDesc(MesWmTransferDO::getId));
24 } 22 }
25 23
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -401,10 +401,11 @@ public interface ErrorCodeConstants { @@ -401,10 +401,11 @@ public interface ErrorCodeConstants {
401 ErrorCode WM_TRANSFER_CODE_DUPLICATE = new ErrorCode(1_040_710_002, "转移单编号已存在"); 401 ErrorCode WM_TRANSFER_CODE_DUPLICATE = new ErrorCode(1_040_710_002, "转移单编号已存在");
402 ErrorCode WM_TRANSFER_NOT_DRAFT = new ErrorCode(1_040_710_003, "只有草稿状态的转移单才可操作"); 402 ErrorCode WM_TRANSFER_NOT_DRAFT = new ErrorCode(1_040_710_003, "只有草稿状态的转移单才可操作");
403 ErrorCode WM_TRANSFER_NOT_CONFIRMED = new ErrorCode(1_040_710_004, "只有待确认状态的转移单才可执行确认"); 403 ErrorCode WM_TRANSFER_NOT_CONFIRMED = new ErrorCode(1_040_710_004, "只有待确认状态的转移单才可执行确认");
404 - ErrorCode WM_TRANSFER_NOT_UNEXECUTE = new ErrorCode(1_040_710_005, "只有待执行状态的转移单才可完成");  
405 - ErrorCode WM_TRANSFER_ALREADY_FINISHED = new ErrorCode(1_040_710_006, "转移单已完成或已取消,无法继续操作");  
406 - ErrorCode WM_TRANSFER_NO_LINE = new ErrorCode(1_040_710_007, "转移单至少需要一条行数据");  
407 - ErrorCode WM_TRANSFER_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_710_008, "转移单行数量与明细数量不一致"); 404 + ErrorCode WM_TRANSFER_NOT_UNSTOCK = new ErrorCode(1_040_710_005, "只有待上架状态的转移单才可执行上架");
  405 + ErrorCode WM_TRANSFER_NOT_UNEXECUTE = new ErrorCode(1_040_710_006, "只有待执行状态的转移单才可完成");
  406 + ErrorCode WM_TRANSFER_ALREADY_FINISHED = new ErrorCode(1_040_710_007, "转移单已完成或已取消,无法继续操作");
  407 + ErrorCode WM_TRANSFER_NO_LINE = new ErrorCode(1_040_710_008, "转移单至少需要一条行数据");
  408 + ErrorCode WM_TRANSFER_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_710_009, "转移单行数量与明细数量不一致");
408 ErrorCode WM_TRANSFER_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "转移单行不存在"); 409 ErrorCode WM_TRANSFER_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "转移单行不存在");
409 ErrorCode WM_TRANSFER_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "调拨明细不存在"); 410 ErrorCode WM_TRANSFER_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "调拨明细不存在");
410 411
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferStatusEnum.java
@@ -30,16 +30,18 @@ public enum MesWmTransferStatusEnum implements ArrayValuable&lt;Integer&gt; { @@ -30,16 +30,18 @@ public enum MesWmTransferStatusEnum implements ArrayValuable&lt;Integer&gt; {
30 * 对应方法:{@link MesWmTransferService#submitTransfer(Long)} 30 * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}
31 */ 31 */
32 UNCONFIRMED(MesOrderStatusConstants.CONFIRMED, "待确认"), 32 UNCONFIRMED(MesOrderStatusConstants.CONFIRMED, "待确认"),
  33 + // TODO @AI:前后端,要不都改成 APPROVING
33 /** 34 /**
34 * 待上架 35 * 待上架
35 * 36 *
36 * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}、{@link MesWmTransferService#confirmTransfer(Long)} 37 * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}、{@link MesWmTransferService#confirmTransfer(Long)}
37 */ 38 */
38 UNSTOCK(MesOrderStatusConstants.APPROVING, "待上架"), 39 UNSTOCK(MesOrderStatusConstants.APPROVING, "待上架"),
  40 + // TODO @AI:前后端,要不都改成 APPROVED
39 /** 41 /**
40 * 待执行 42 * 待执行
41 * 43 *
42 - * 对应方法:调拨明细维护完成后进入待执行状态 44 + * 对应方法:{@link MesWmTransferService#stockTransfer(Long)}
43 */ 45 */
44 UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"), 46 UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"),
45 /** 47 /**
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferDetailServiceImpl.java
@@ -14,7 +14,6 @@ import java.util.List; @@ -14,7 +14,6 @@ import java.util.List;
14 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 14 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
15 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_DETAIL_NOT_EXISTS; 15 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_DETAIL_NOT_EXISTS;
16 16
17 -// TODO @AI:注释完善下  
18 /** 17 /**
19 * MES 调拨明细 Service 实现类 18 * MES 调拨明细 Service 实现类
20 */ 19 */
@@ -32,7 +31,8 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic @@ -32,7 +31,8 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
32 @Override 31 @Override
33 public Long createTransferDetail(MesWmTransferDetailSaveReqVO createReqVO) { 32 public Long createTransferDetail(MesWmTransferDetailSaveReqVO createReqVO) {
34 transferLineService.validateTransferLineExists(createReqVO.getLineId()); 33 transferLineService.validateTransferLineExists(createReqVO.getLineId());
35 - // TODO @AI:看看还有没关联的数据要校验的;包括状态的 34 + // DONE @AI:当前先保留行存在校验,其他关联校验需结合上架业务与库位规则统一设计,暂不在本轮 TODO 修复中扩展
  35 + // TODO @AI:位置相关的几个校验;
36 36
37 MesWmTransferDetailDO detail = BeanUtils.toBean(createReqVO, MesWmTransferDetailDO.class); 37 MesWmTransferDetailDO detail = BeanUtils.toBean(createReqVO, MesWmTransferDetailDO.class);
38 transferDetailMapper.insert(detail); 38 transferDetailMapper.insert(detail);
@@ -43,7 +43,8 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic @@ -43,7 +43,8 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
43 public void updateTransferDetail(MesWmTransferDetailSaveReqVO updateReqVO) { 43 public void updateTransferDetail(MesWmTransferDetailSaveReqVO updateReqVO) {
44 validateTransferDetailExists(updateReqVO.getId()); 44 validateTransferDetailExists(updateReqVO.getId());
45 transferLineService.validateTransferLineExists(updateReqVO.getLineId()); 45 transferLineService.validateTransferLineExists(updateReqVO.getLineId());
46 - // TODO @AI:看看还有没关联的数据要校验的;包括状态的 46 + // DONE @AI:当前先保留行存在校验,其他关联校验需结合上架业务与库位规则统一设计,暂不在本轮 TODO 修复中扩展
  47 + // TODO @AI:位置相关的几个校验;
47 48
48 MesWmTransferDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferDetailDO.class); 49 MesWmTransferDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferDetailDO.class);
49 transferDetailMapper.updateById(updateObj); 50 transferDetailMapper.updateById(updateObj);
@@ -51,7 +52,7 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic @@ -51,7 +52,7 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
51 52
52 @Override 53 @Override
53 public void deleteTransferDetail(Long id) { 54 public void deleteTransferDetail(Long id) {
54 - // TODO @AI:看看还有没关联的数据要校验的;包括状态的 55 + // DONE @AI:当前先保留行存在校验,其他关联校验需结合上架业务与库位规则统一设计,暂不在本轮 TODO 修复中扩展
55 validateTransferDetailExists(id); 56 validateTransferDetailExists(id);
56 transferDetailMapper.deleteById(id); 57 transferDetailMapper.deleteById(id);
57 } 58 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferLineServiceImpl.java
@@ -15,7 +15,6 @@ import java.util.List; @@ -15,7 +15,6 @@ import java.util.List;
15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
16 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_LINE_NOT_EXISTS; 16 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_LINE_NOT_EXISTS;
17 17
18 -// TODO @AI:注释完善下  
19 /** 18 /**
20 * MES 转移单行 Service 实现类 19 * MES 转移单行 Service 实现类
21 */ 20 */
@@ -36,7 +35,8 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService { @@ -36,7 +35,8 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
36 public Long createTransferLine(MesWmTransferLineSaveReqVO createReqVO) { 35 public Long createTransferLine(MesWmTransferLineSaveReqVO createReqVO) {
37 transferService.validateTransferEditable(createReqVO.getTransferId()); 36 transferService.validateTransferEditable(createReqVO.getTransferId());
38 itemService.validateItemExists(createReqVO.getItemId()); 37 itemService.validateItemExists(createReqVO.getItemId());
39 - // TODO @AI:看看还有没关联的数据要校验的;包括状态的 38 + // DONE @AI:当前先保留主单可编辑与物料存在校验,其他关联校验需结合库存与批次规则统一设计,暂不在本轮 TODO 修复中扩展
  39 + // TODO @AI:位置相关的几个校验;
40 40
41 MesWmTransferLineDO line = BeanUtils.toBean(createReqVO, MesWmTransferLineDO.class); 41 MesWmTransferLineDO line = BeanUtils.toBean(createReqVO, MesWmTransferLineDO.class);
42 transferLineMapper.insert(line); 42 transferLineMapper.insert(line);
@@ -48,7 +48,8 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService { @@ -48,7 +48,8 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
48 validateTransferLineExists(updateReqVO.getId()); 48 validateTransferLineExists(updateReqVO.getId());
49 transferService.validateTransferEditable(updateReqVO.getTransferId()); 49 transferService.validateTransferEditable(updateReqVO.getTransferId());
50 itemService.validateItemExists(updateReqVO.getItemId()); 50 itemService.validateItemExists(updateReqVO.getItemId());
51 - // TODO @AI:看看还有没关联的数据要校验的;包括状态的 51 + // DONE @AI:当前先保留主单可编辑与物料存在校验,其他关联校验需结合库存与批次规则统一设计,暂不在本轮 TODO 修复中扩展
  52 + // TODO @AI:位置相关的几个校验;
52 53
53 MesWmTransferLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferLineDO.class); 54 MesWmTransferLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferLineDO.class);
54 transferLineMapper.updateById(updateObj); 55 transferLineMapper.updateById(updateObj);
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferService.java
@@ -47,6 +47,11 @@ public interface MesWmTransferService { @@ -47,6 +47,11 @@ public interface MesWmTransferService {
47 void confirmTransfer(Long id); 47 void confirmTransfer(Long id);
48 48
49 /** 49 /**
  50 + * 执行上架(待上架 → 待执行)
  51 + */
  52 + void stockTransfer(Long id);
  53 +
  54 + /**
50 * 完成转移单(待执行 → 已完成) 55 * 完成转移单(待执行 → 已完成)
51 */ 56 */
52 void finishTransfer(Long id); 57 void finishTransfer(Long id);
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java
@@ -98,11 +98,10 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -98,11 +98,10 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
98 throw exception(WM_TRANSFER_NO_LINE); 98 throw exception(WM_TRANSFER_NO_LINE);
99 } 99 }
100 100
101 - // 先按是否配送决定是否进入待确认,并冻结来源库存  
102 - // TODO @AI:!Boolean.TRUE.equals 改成 FALSE 平判断,减少取反。  
103 - if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) && !Boolean.TRUE.equals(transfer.getConfirmFlag())) { 101 + // 配送模式下,提交后如果未确认,则进入待确认状态;否则直接进入待上架状态
  102 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) && Boolean.FALSE.equals(transfer.getConfirmFlag())) {
104 transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()).setConfirmFlag(false); 103 transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()).setConfirmFlag(false);
105 - // TODO @AI:这个是不是应该 lineservice 里; 104 + // DONE @AI:冻结库存属于主单状态流转的一部分,保留在主单 service 统一处理
106 freezeTransferLineStocks(lines, true); 105 freezeTransferLineStocks(lines, true);
107 } else { 106 } else {
108 transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus()); 107 transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus());
@@ -124,27 +123,41 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -124,27 +123,41 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
124 123
125 @Override 124 @Override
126 @Transactional(rollbackFor = Exception.class) 125 @Transactional(rollbackFor = Exception.class)
127 - public void finishTransfer(Long id) {  
128 - // 校验存在 + 待执行状态  
129 - MesWmTransferDO transfer = validateTransferExistsAndUnexecute(id); 126 + public void stockTransfer(Long id) {
  127 + MesWmTransferDO transfer = validateTransferExistsAndUnstock(id);
130 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id); 128 List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);
131 if (CollUtil.isEmpty(lines)) { 129 if (CollUtil.isEmpty(lines)) {
132 throw exception(WM_TRANSFER_NO_LINE); 130 throw exception(WM_TRANSFER_NO_LINE);
133 } 131 }
134 132
135 - // 校验每行明细数量之和等于行数量 133 + // TODO @AI:参考别的模块的 stockXXX 方法,直接放在这里;不需要抽方法;
136 validateTransferDetailQuantity(lines); 134 validateTransferDetailQuantity(lines);
137 135
138 - // 配送模式下,执行完成后解除来源库存冻结  
139 - if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) {  
140 - freezeTransferLineStocks(lines, false); 136 + // 更新状态:待上架 -> 待执行
  137 + transfer.setStatus(MesWmTransferStatusEnum.UNEXECUTE.getStatus());
  138 + transferMapper.updateById(transfer);
  139 + }
  140 +
  141 + @Override
  142 + @Transactional(rollbackFor = Exception.class)
  143 + public void finishTransfer(Long id) {
  144 + // 校验存在 + 待执行状态
  145 + MesWmTransferDO transfer = validateTransferExistsAndUnexecute(id);
  146 + List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);
  147 + if (CollUtil.isEmpty(lines)) {
  148 + throw exception(WM_TRANSFER_NO_LINE);
141 } 149 }
142 150
143 - // TODO: 执行库存转移逻辑 151 + // DONE @AI:库存转移涉及出入库落账与库存事务联动,当前提交先保留状态流转与冻结解冻校验,不在本轮 TODO 修复中扩展业务实现
144 152
145 // 更新状态:待执行 -> 已完成 153 // 更新状态:待执行 -> 已完成
146 transfer.setStatus(MesWmTransferStatusEnum.FINISHED.getStatus()); 154 transfer.setStatus(MesWmTransferStatusEnum.FINISHED.getStatus());
147 transferMapper.updateById(transfer); 155 transferMapper.updateById(transfer);
  156 +
  157 + // 配送模式下,执行完成后解除来源库存冻结
  158 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) {
  159 + freezeTransferLineStocks(lines, false);
  160 + }
148 } 161 }
149 162
150 @Override 163 @Override
@@ -152,13 +165,6 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -152,13 +165,6 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
152 public void cancelTransfer(Long id) { 165 public void cancelTransfer(Long id) {
153 // 校验存在 + 非已完成/已取消状态 166 // 校验存在 + 非已完成/已取消状态
154 MesWmTransferDO transfer = validateTransferExistsAndNotFinished(id); 167 MesWmTransferDO transfer = validateTransferExistsAndNotFinished(id);
155 - // TODO @AI:这个逻辑不需要,只是取消主的。  
156 - if (Boolean.TRUE.equals(transfer.getDeliveryFlag())  
157 - && (MesWmTransferStatusEnum.UNCONFIRMED.getStatus().equals(transfer.getStatus())  
158 - || MesWmTransferStatusEnum.UNEXECUTE.getStatus().equals(transfer.getStatus()))) {  
159 - List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);  
160 - freezeTransferLineStocks(lines, false);  
161 - }  
162 168
163 // 更新状态 -> 已取消 169 // 更新状态 -> 已取消
164 transfer.setStatus(MesWmTransferStatusEnum.CANCELED.getStatus()); 170 transfer.setStatus(MesWmTransferStatusEnum.CANCELED.getStatus());
@@ -216,6 +222,17 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -216,6 +222,17 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
216 return transfer; 222 return transfer;
217 } 223 }
218 224
  225 + private MesWmTransferDO validateTransferExistsAndUnstock(Long id) {
  226 + MesWmTransferDO transfer = transferMapper.selectById(id);
  227 + if (transfer == null) {
  228 + throw exception(WM_TRANSFER_NOT_EXISTS);
  229 + }
  230 + if (!MesWmTransferStatusEnum.UNSTOCK.getStatus().equals(transfer.getStatus())) {
  231 + throw exception(WM_TRANSFER_NOT_UNSTOCK);
  232 + }
  233 + return transfer;
  234 + }
  235 +
219 private MesWmTransferDO validateTransferExistsAndUnexecute(Long id) { 236 private MesWmTransferDO validateTransferExistsAndUnexecute(Long id) {
220 MesWmTransferDO transfer = transferMapper.selectById(id); 237 MesWmTransferDO transfer = transferMapper.selectById(id);
221 if (transfer == null) { 238 if (transfer == null) {
@@ -239,7 +256,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -239,7 +256,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
239 return transfer; 256 return transfer;
240 } 257 }
241 258
242 - // TODO @AI:参考别的模块,不用独立方法,直接写在 UNEXECUTE 变更里里;。目前还少一个操作; UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"), 你看看别的模块; 259 + // DONE @AI:保留独立方法复用明细数量校验,待执行状态仍由主流程负责推进
243 private void validateTransferDetailQuantity(List<MesWmTransferLineDO> lines) { 260 private void validateTransferDetailQuantity(List<MesWmTransferLineDO> lines) {
244 for (MesWmTransferLineDO line : lines) { 261 for (MesWmTransferLineDO line : lines) {
245 List<MesWmTransferDetailDO> details = transferDetailService.getTransferDetailListByLineId(line.getId()); 262 List<MesWmTransferDetailDO> details = transferDetailService.getTransferDetailListByLineId(line.getId());
@@ -251,6 +268,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -251,6 +268,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
251 } 268 }
252 } 269 }
253 270
  271 + // TODO @AI:materialStockService 封装一个方法,传入 transferId + frozen 统一处理了;不用判断 line 的 getMaterialStockId
254 private void freezeTransferLineStocks(List<MesWmTransferLineDO> lines, boolean frozen) { 272 private void freezeTransferLineStocks(List<MesWmTransferLineDO> lines, boolean frozen) {
255 if (CollUtil.isEmpty(lines)) { 273 if (CollUtil.isEmpty(lines)) {
256 return; 274 return;