Commit 68f373f6c962aa73583186b86bf6515d13e09797

Authored by YunaiV
1 parent f004611c

✨ feat(mes): 添加转移单及转移单行的字段校验和状态管理

新增转移单及转移单行相关功能,包含字段的必填校验和状态管理逻辑。更新了相关数据结构,确保在创建和提交转移单时进行必要的验证,提升系统的稳定性和数据一致性。

- 添加转移单字段的必填校验
- 更新转移单状态管理逻辑
- 增强数据结构的完整性
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferSaveReqVO.java
@@ -5,6 +5,8 @@ import lombok.Data; @@ -5,6 +5,8 @@ import lombok.Data;
5 5
6 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
7 7
  8 +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
  9 +
8 @Schema(description = "管理后台 - MES 转移单 Save Request VO") 10 @Schema(description = "管理后台 - MES 转移单 Save Request VO")
9 @Data 11 @Data
10 public class MesWmTransferSaveReqVO { 12 public class MesWmTransferSaveReqVO {
@@ -12,16 +14,17 @@ public class MesWmTransferSaveReqVO { @@ -12,16 +14,17 @@ public class MesWmTransferSaveReqVO {
12 @Schema(description = "编号", example = "1") 14 @Schema(description = "编号", example = "1")
13 private Long id; 15 private Long id;
14 16
15 - @Schema(description = "转移单编号", example = "TR2026020001") 17 + // TODO @AI:validator 参数校验需要添加
  18 + @Schema(description = "转移单编号", requiredMode = REQUIRED, example = "TR2026020001")
16 private String code; 19 private String code;
17 20
18 - @Schema(description = "转移单名称", example = "钢板转移单") 21 + @Schema(description = "转移单名称", requiredMode = REQUIRED, example = "钢板转移单")
19 private String name; 22 private String name;
20 23
21 - @Schema(description = "转移单类型", example = "1") 24 + @Schema(description = "转移单类型", requiredMode = REQUIRED, example = "1")
22 private Integer type; 25 private Integer type;
23 26
24 - @Schema(description = "是否配送", example = "true") 27 + @Schema(description = "是否配送", requiredMode = REQUIRED, example = "true")
25 private Boolean deliveryFlag; 28 private Boolean deliveryFlag;
26 29
27 @Schema(description = "收货人", example = "张三") 30 @Schema(description = "收货人", example = "张三")
@@ -39,15 +42,9 @@ public class MesWmTransferSaveReqVO { @@ -39,15 +42,9 @@ public class MesWmTransferSaveReqVO {
39 @Schema(description = "运输单号", example = "SF123456789") 42 @Schema(description = "运输单号", example = "SF123456789")
40 private String shippingNumber; 43 private String shippingNumber;
41 44
42 - @Schema(description = "是否已确认", example = "false")  
43 - private Boolean confirmFlag;  
44 -  
45 - @Schema(description = "转移日期") 45 + @Schema(description = "转移日期", requiredMode = REQUIRED)
46 private LocalDateTime transferDate; 46 private LocalDateTime transferDate;
47 47
48 - @Schema(description = "单据状态", example = "0")  
49 - private Integer status;  
50 -  
51 @Schema(description = "备注", example = "备注信息") 48 @Schema(description = "备注", example = "备注信息")
52 private String remark; 49 private String remark;
53 50
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferDetailDO.java
@@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer; @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
5 import com.baomidou.mybatisplus.annotation.KeySequence; 8 import com.baomidou.mybatisplus.annotation.KeySequence;
6 import com.baomidou.mybatisplus.annotation.TableId; 9 import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 10 import com.baomidou.mybatisplus.annotation.TableName;
@@ -57,17 +60,22 @@ public class MesWmTransferDetailDO extends BaseDO { @@ -57,17 +60,22 @@ public class MesWmTransferDetailDO extends BaseDO {
57 */ 60 */
58 private Long batchId; 61 private Long batchId;
59 62
60 - // TODO @AI:需要 @  
61 /** 63 /**
62 * 移入仓库编号 64 * 移入仓库编号
  65 + *
  66 + * 关联 {@link MesWmWarehouseDO#getId()}
63 */ 67 */
64 private Long toWarehouseId; 68 private Long toWarehouseId;
65 /** 69 /**
66 * 移入库区编号 70 * 移入库区编号
  71 + *
  72 + * 关联 {@link MesWmWarehouseLocationDO#getId()}
67 */ 73 */
68 private Long toLocationId; 74 private Long toLocationId;
69 /** 75 /**
70 * 移入库位编号 76 * 移入库位编号
  77 + *
  78 + * 关联 {@link MesWmWarehouseAreaDO#getId()}
71 */ 79 */
72 private Long toAreaId; 80 private Long toAreaId;
73 81
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferLineDO.java
@@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer; @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
5 import com.baomidou.mybatisplus.annotation.KeySequence; 8 import com.baomidou.mybatisplus.annotation.KeySequence;
6 import com.baomidou.mybatisplus.annotation.TableId; 9 import com.baomidou.mybatisplus.annotation.TableId;
7 import com.baomidou.mybatisplus.annotation.TableName; 10 import com.baomidou.mybatisplus.annotation.TableName;
@@ -54,17 +57,22 @@ public class MesWmTransferLineDO extends BaseDO { @@ -54,17 +57,22 @@ public class MesWmTransferLineDO extends BaseDO {
54 */ 57 */
55 private Long batchId; 58 private Long batchId;
56 59
57 - // TODO @AI:需要 @  
58 /** 60 /**
59 * 移出仓库编号 61 * 移出仓库编号
  62 + *
  63 + * 关联 {@link MesWmWarehouseDO#getId()}
60 */ 64 */
61 private Long fromWarehouseId; 65 private Long fromWarehouseId;
62 /** 66 /**
63 * 移出库区编号 67 * 移出库区编号
  68 + *
  69 + * 关联 {@link MesWmWarehouseLocationDO#getId()}
64 */ 70 */
65 private Long fromLocationId; 71 private Long fromLocationId;
66 /** 72 /**
67 * 移出库位编号 73 * 移出库位编号
  74 + *
  75 + * 关联 {@link MesWmWarehouseAreaDO#getId()}
68 */ 76 */
69 private Long fromAreaId; 77 private Long fromAreaId;
70 78
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -403,6 +403,8 @@ public interface ErrorCodeConstants { @@ -403,6 +403,8 @@ public interface ErrorCodeConstants {
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, "只有待执行状态的转移单才可完成"); 404 ErrorCode WM_TRANSFER_NOT_UNEXECUTE = new ErrorCode(1_040_710_005, "只有待执行状态的转移单才可完成");
405 ErrorCode WM_TRANSFER_ALREADY_FINISHED = new ErrorCode(1_040_710_006, "转移单已完成或已取消,无法继续操作"); 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, "转移单行数量与明细数量不一致");
406 ErrorCode WM_TRANSFER_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "转移单行不存在"); 408 ErrorCode WM_TRANSFER_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "转移单行不存在");
407 ErrorCode WM_TRANSFER_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "调拨明细不存在"); 409 ErrorCode WM_TRANSFER_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "调拨明细不存在");
408 410
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferStatusEnum.java
1 package cn.iocoder.yudao.module.mes.enums.wm; 1 package cn.iocoder.yudao.module.mes.enums.wm;
2 2
3 import cn.iocoder.yudao.framework.common.core.ArrayValuable; 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferSaveReqVO;
4 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants; 5 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants;
  6 +import cn.iocoder.yudao.module.mes.service.wm.transfer.MesWmTransferService;
5 import lombok.AllArgsConstructor; 7 import lombok.AllArgsConstructor;
6 import lombok.Getter; 8 import lombok.Getter;
7 9
@@ -16,29 +18,40 @@ import java.util.Arrays; @@ -16,29 +18,40 @@ import java.util.Arrays;
16 @AllArgsConstructor 18 @AllArgsConstructor
17 public enum MesWmTransferStatusEnum implements ArrayValuable<Integer> { 19 public enum MesWmTransferStatusEnum implements ArrayValuable<Integer> {
18 20
19 - // TODO @AI:/Users/yunai/Java/yudao-all-in-one/ruoyi-vue-pro/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmOutsourceReceiptStatusEnum.java,增加 “对应方法”  
20 /** 21 /**
21 * 草稿 22 * 草稿
  23 + *
  24 + * 对应方法:{@link MesWmTransferService#createTransfer(MesWmTransferSaveReqVO)}
22 */ 25 */
23 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), 26 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
24 /** 27 /**
25 * 待确认(仅配送模式) 28 * 待确认(仅配送模式)
  29 + *
  30 + * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}
26 */ 31 */
27 UNCONFIRMED(MesOrderStatusConstants.CONFIRMED, "待确认"), 32 UNCONFIRMED(MesOrderStatusConstants.CONFIRMED, "待确认"),
28 /** 33 /**
29 * 待上架 34 * 待上架
  35 + *
  36 + * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}、{@link MesWmTransferService#confirmTransfer(Long)}
30 */ 37 */
31 UNSTOCK(MesOrderStatusConstants.APPROVING, "待上架"), 38 UNSTOCK(MesOrderStatusConstants.APPROVING, "待上架"),
32 /** 39 /**
33 * 待执行 40 * 待执行
  41 + *
  42 + * 对应方法:调拨明细维护完成后进入待执行状态
34 */ 43 */
35 UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"), 44 UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"),
36 /** 45 /**
37 * 已完成 46 * 已完成
  47 + *
  48 + * 对应方法:{@link MesWmTransferService#finishTransfer(Long)}
38 */ 49 */
39 FINISHED(MesOrderStatusConstants.FINISHED, "已完成"), 50 FINISHED(MesOrderStatusConstants.FINISHED, "已完成"),
40 /** 51 /**
41 * 已取消 52 * 已取消
  53 + *
  54 + * 对应方法:{@link MesWmTransferService#cancelTransfer(Long)}
42 */ 55 */
43 CANCELED(MesOrderStatusConstants.CANCELLED, "已取消"); 56 CANCELED(MesOrderStatusConstants.CANCELLED, "已取消");
44 57
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java
1 package cn.iocoder.yudao.module.mes.service.wm.transfer; 1 package cn.iocoder.yudao.module.mes.service.wm.transfer;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
5 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferPageReqVO; 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferPageReqVO;
6 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferSaveReqVO; 9 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferSaveReqVO;
7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDetailDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO;
8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferMapper; 13 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferMapper;
9 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransferStatusEnum; 14 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransferStatusEnum;
10 -import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransferTypeEnum; 15 +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
11 import jakarta.annotation.Resource; 16 import jakarta.annotation.Resource;
12 import org.springframework.stereotype.Service; 17 import org.springframework.stereotype.Service;
  18 +import org.springframework.transaction.annotation.Transactional;
13 import org.springframework.validation.annotation.Validated; 19 import org.springframework.validation.annotation.Validated;
14 20
  21 +import java.math.BigDecimal;
  22 +import java.util.List;
  23 +
15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
16 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; 25 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
17 26
@@ -25,11 +34,12 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -25,11 +34,12 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
25 @Resource 34 @Resource
26 private MesWmTransferMapper transferMapper; 35 private MesWmTransferMapper transferMapper;
27 36
28 - // TODO @AI:MesWmTransferLineService、MesWmTransferDetailService 类不存在;  
29 @Resource 37 @Resource
30 private MesWmTransferLineService transferLineService; 38 private MesWmTransferLineService transferLineService;
31 @Resource 39 @Resource
32 private MesWmTransferDetailService transferDetailService; 40 private MesWmTransferDetailService transferDetailService;
  41 + @Resource
  42 + private MesWmMaterialStockService materialStockService;
33 43
34 @Override 44 @Override
35 public Long createTransfer(MesWmTransferSaveReqVO createReqVO) { 45 public Long createTransfer(MesWmTransferSaveReqVO createReqVO) {
@@ -55,8 +65,8 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -55,8 +65,8 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
55 transferMapper.updateById(updateObj); 65 transferMapper.updateById(updateObj);
56 } 66 }
57 67
58 - // TODO @AI:少了事务;  
59 @Override 68 @Override
  69 + @Transactional(rollbackFor = Exception.class)
60 public void deleteTransfer(Long id) { 70 public void deleteTransfer(Long id) {
61 // 校验存在 + 草稿状态 71 // 校验存在 + 草稿状态
62 validateTransferExistsAndDraft(id); 72 validateTransferExistsAndDraft(id);
@@ -79,23 +89,29 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -79,23 +89,29 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
79 } 89 }
80 90
81 @Override 91 @Override
  92 + @Transactional(rollbackFor = Exception.class)
82 public void submitTransfer(Long id) { 93 public void submitTransfer(Long id) {
83 // 校验存在 + 草稿状态 94 // 校验存在 + 草稿状态
84 MesWmTransferDO transfer = validateTransferExistsAndDraft(id); 95 MesWmTransferDO transfer = validateTransferExistsAndDraft(id);
  96 + List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);
  97 + if (CollUtil.isEmpty(lines)) {
  98 + throw exception(WM_TRANSFER_NO_LINE);
  99 + }
85 100
86 - // TODO @芋艿:这里的逻辑对齐不对;需要再次看看;  
87 - // 根据转移单类型设置状态  
88 - // 内部调拨:草稿 -> 待上架  
89 - // 外部调拨:草稿 -> 待确认  
90 - if (MesWmTransferTypeEnum.INNER.getType().equals(transfer.getType())) {  
91 - transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus()); 101 + // 先按是否配送决定是否进入待确认,并冻结来源库存
  102 + // TODO @AI:!Boolean.TRUE.equals 改成 FALSE 平判断,减少取反。
  103 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) && !Boolean.TRUE.equals(transfer.getConfirmFlag())) {
  104 + transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()).setConfirmFlag(false);
  105 + // TODO @AI:这个是不是应该 lineservice 里;
  106 + freezeTransferLineStocks(lines, true);
92 } else { 107 } else {
93 - transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()); 108 + transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus());
94 } 109 }
95 transferMapper.updateById(transfer); 110 transferMapper.updateById(transfer);
96 } 111 }
97 112
98 @Override 113 @Override
  114 + @Transactional(rollbackFor = Exception.class)
99 public void confirmTransfer(Long id) { 115 public void confirmTransfer(Long id) {
100 // 校验存在 + 待确认状态 116 // 校验存在 + 待确认状态
101 MesWmTransferDO transfer = validateTransferExistsAndConfirm(id); 117 MesWmTransferDO transfer = validateTransferExistsAndConfirm(id);
@@ -107,9 +123,22 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -107,9 +123,22 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
107 } 123 }
108 124
109 @Override 125 @Override
  126 + @Transactional(rollbackFor = Exception.class)
110 public void finishTransfer(Long id) { 127 public void finishTransfer(Long id) {
111 // 校验存在 + 待执行状态 128 // 校验存在 + 待执行状态
112 MesWmTransferDO transfer = validateTransferExistsAndUnexecute(id); 129 MesWmTransferDO transfer = validateTransferExistsAndUnexecute(id);
  130 + List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(id);
  131 + if (CollUtil.isEmpty(lines)) {
  132 + throw exception(WM_TRANSFER_NO_LINE);
  133 + }
  134 +
  135 + // 校验每行明细数量之和等于行数量
  136 + validateTransferDetailQuantity(lines);
  137 +
  138 + // 配送模式下,执行完成后解除来源库存冻结
  139 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) {
  140 + freezeTransferLineStocks(lines, false);
  141 + }
113 142
114 // TODO: 执行库存转移逻辑 143 // TODO: 执行库存转移逻辑
115 144
@@ -119,9 +148,17 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -119,9 +148,17 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
119 } 148 }
120 149
121 @Override 150 @Override
  151 + @Transactional(rollbackFor = Exception.class)
122 public void cancelTransfer(Long id) { 152 public void cancelTransfer(Long id) {
123 // 校验存在 + 非已完成/已取消状态 153 // 校验存在 + 非已完成/已取消状态
124 MesWmTransferDO transfer = validateTransferExistsAndNotFinished(id); 154 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 + }
125 162
126 // 更新状态 -> 已取消 163 // 更新状态 -> 已取消
127 transfer.setStatus(MesWmTransferStatusEnum.CANCELED.getStatus()); 164 transfer.setStatus(MesWmTransferStatusEnum.CANCELED.getStatus());
@@ -131,7 +168,6 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -131,7 +168,6 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
131 @Override 168 @Override
132 public MesWmTransferDO validateTransferEditable(Long id) { 169 public MesWmTransferDO validateTransferEditable(Long id) {
133 MesWmTransferDO transfer = transferMapper.selectById(id); 170 MesWmTransferDO transfer = transferMapper.selectById(id);
134 - // TODO @AI:错误码缺少;是不是少了 WM_  
135 if (transfer == null) { 171 if (transfer == null) {
136 throw exception(WM_TRANSFER_NOT_EXISTS); 172 throw exception(WM_TRANSFER_NOT_EXISTS);
137 } 173 }
@@ -203,4 +239,31 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -203,4 +239,31 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
203 return transfer; 239 return transfer;
204 } 240 }
205 241
  242 + // TODO @AI:参考别的模块,不用独立方法,直接写在 UNEXECUTE 变更里里;。目前还少一个操作; UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"), 你看看别的模块;
  243 + private void validateTransferDetailQuantity(List<MesWmTransferLineDO> lines) {
  244 + for (MesWmTransferLineDO line : lines) {
  245 + List<MesWmTransferDetailDO> details = transferDetailService.getTransferDetailListByLineId(line.getId());
  246 + BigDecimal totalDetailQty = CollectionUtils.getSumValue(details,
  247 + MesWmTransferDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO);
  248 + if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) {
  249 + throw exception(WM_TRANSFER_DETAIL_QUANTITY_MISMATCH);
  250 + }
  251 + }
  252 + }
  253 +
  254 + private void freezeTransferLineStocks(List<MesWmTransferLineDO> lines, boolean frozen) {
  255 + if (CollUtil.isEmpty(lines)) {
  256 + return;
  257 + }
  258 + for (MesWmTransferLineDO line : lines) {
  259 + if (line.getMaterialStockId() == null) {
  260 + continue;
  261 + }
  262 + MesWmMaterialStockFreezeReqVO freezeReqVO = new MesWmMaterialStockFreezeReqVO();
  263 + freezeReqVO.setId(line.getMaterialStockId());
  264 + freezeReqVO.setFrozen(frozen);
  265 + materialStockService.updateMaterialStockFrozen(freezeReqVO);
  266 + }
  267 + }
  268 +
206 } 269 }