Commit a46f2b1f1aa2469a49210800f48f079f8edd73b8

Authored by YunaiV
1 parent 2f78c4df

✨ feat(mes): 新增单据状态字段,更新库存冻结状态批量处理

Showing 14 changed files with 188 additions and 78 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferPageReqVO.java
... ... @@ -5,11 +5,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
5 5 import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
8   -import org.springframework.format.annotation.DateTimeFormat;
9   -
10   -import java.time.LocalDateTime;
11   -
12   -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
13 8  
14 9 @Schema(description = "管理后台 - MES 转移单分页 Request VO")
15 10 @Data
... ... @@ -26,5 +21,7 @@ public class MesWmTransferPageReqVO extends PageParam {
26 21 @Schema(description = "转移单类型", example = "1")
27 22 private Integer type;
28 23  
  24 + @Schema(description = "单据状态", example = "0")
  25 + private Integer status;
29 26  
30 27 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
... ... @@ -49,6 +49,11 @@ public interface MesWmMaterialStockMapper extends BaseMapperX<MesWmMaterialStock
49 49 return selectByIds(ids);
50 50 }
51 51  
  52 + default void updateByIds(Collection<Long> ids, MesWmMaterialStockDO updateObj) {
  53 + update(updateObj, new LambdaUpdateWrapper<MesWmMaterialStockDO>()
  54 + .in(MesWmMaterialStockDO::getId, ids));
  55 + }
  56 +
52 57 /**
53 58 * 增量更新库存数量
54 59 *
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/transfer/MesWmTransferMapper.java
... ... @@ -18,6 +18,7 @@ public interface MesWmTransferMapper extends BaseMapperX&lt;MesWmTransferDO&gt; {
18 18 .likeIfPresent(MesWmTransferDO::getCode, reqVO.getCode())
19 19 .likeIfPresent(MesWmTransferDO::getName, reqVO.getName())
20 20 .eqIfPresent(MesWmTransferDO::getType, reqVO.getType())
  21 + .eqIfPresent(MesWmTransferDO::getStatus, reqVO.getStatus())
21 22 .orderByDesc(MesWmTransferDO::getId));
22 23 }
23 24  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -453,6 +453,7 @@ public interface ErrorCodeConstants {
453 453 ErrorCode WM_TRANSFER_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "转移单行不存在");
454 454 ErrorCode WM_TRANSFER_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "调拨明细不存在");
455 455 ErrorCode WM_TRANSFER_DETAIL_QUANTITY_EXCEED = new ErrorCode(1_040_710_201, "调拨明细总数量不能超过调拨单行数量");
  456 + ErrorCode WM_TRANSFER_DETAIL_MIXED_GOODS = new ErrorCode(1_040_710_202, "同一目标仓位下已存在其他物料的明细,不允许混货");
456 457  
457 458 // ========== MES 仓库管理-生产退料单(1-040-711-000) ==========
458 459 ErrorCode WM_RETURN_ISSUE_NOT_EXISTS = new ErrorCode(1_040_710_000, "生产退料单不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java
... ... @@ -33,7 +33,8 @@ public enum MesMdAutoCodeRuleCodeEnum {
33 33 WM_LOCATION_CODE("WM_LOCATION_CODE", "库区编码"),
34 34 WM_AREA_CODE("WM_AREA_CODE", "库位编码"),
35 35 WM_PRODUCT_SALES_CODE("WM_PRODUCT_SALES_CODE", "销售出库单编码"),
36   - WM_MISC_RECEIPT_CODE("WM_MISC_RECEIPT_CODE", "杂项入库单编码");
  36 + WM_MISC_RECEIPT_CODE("WM_MISC_RECEIPT_CODE", "杂项入库单编码"),
  37 + WM_TRANSFER_CODE("WM_TRANSFER_CODE", "转移调拨单编码");
37 38  
38 39 /**
39 40 * 规则代码
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductProduceStatusEnum.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.enums.wm;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4 4 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants;
  5 +import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceService;
5 6 import lombok.AllArgsConstructor;
6 7 import lombok.Getter;
7 8  
... ... @@ -16,13 +17,16 @@ import java.util.Arrays;
16 17 @AllArgsConstructor
17 18 public enum MesWmProductProduceStatusEnum implements ArrayValuable<Integer> {
18 19  
19   - // TODO @AI:对应的方法;参考别的 MesWmProductIssueStatusEnum
20 20 /**
21 21 * 草稿
  22 + *
  23 + * 对应方法:{@link MesWmProductProduceService#generateProductProduce}
22 24 */
23 25 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
24 26 /**
25 27 * 已完成
  28 + *
  29 + * 对应方法:{@link MesWmProductProduceService#finishProductProduce(Long)}
26 30 */
27 31 FINISHED(MesOrderStatusConstants.FINISHED, "已完成"),
28 32 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferTypeEnum.java
... ... @@ -6,7 +6,6 @@ import lombok.Getter;
6 6  
7 7 import java.util.Arrays;
8 8  
9   -// TODO @AI:没有 IntArrayValuable,你检查下;应该是另外个
10 9 /**
11 10 * MES 转移单类型枚举
12 11 *
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
... ... @@ -11,9 +11,6 @@ import java.math.BigDecimal;
11 11 import java.time.LocalDateTime;
12 12 import java.util.Collection;
13 13 import java.util.List;
14   -import java.util.Map;
15   -
16   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
17 14  
18 15 /**
19 16 * MES 库存台账 Service 接口
... ... @@ -52,6 +49,14 @@ public interface MesWmMaterialStockService {
52 49 void updateMaterialStockFrozen(@Valid MesWmMaterialStockFreezeReqVO updateReqVO);
53 50  
54 51 /**
  52 + * 批量更新库存冻结状态
  53 + *
  54 + * @param ids 库存记录编号列表
  55 + * @param frozen 是否冻结
  56 + */
  57 + void updateMaterialStockFrozen(Collection<Long> ids, boolean frozen);
  58 +
  59 + /**
55 60 * 获得仓库下库存记录数量
56 61 *
57 62 * @param warehouseId 仓库编号
... ... @@ -91,10 +96,6 @@ public interface MesWmMaterialStockService {
91 96 */
92 97 List<MesWmMaterialStockDO> getMaterialStockList(MesWmMaterialStockListReqVO reqVO);
93 98  
94   - default Map<Long, MesWmMaterialStockDO> getMaterialStockMap(Collection<Long> ids) {
95   - return convertMap(getMaterialStockList(ids), MesWmMaterialStockDO::getId);
96   - }
97   -
98 99 /**
99 100 * 获得库存精简列表(用于前端下拉选择)
100 101 *
... ... @@ -122,11 +123,11 @@ public interface MesWmMaterialStockService {
122 123 /**
123 124 * 更新库存数量
124 125 *
125   - * @param materialStockId 库存记录编号
  126 + * @param id 库存记录编号
126 127 * @param quantity 变动数量(正数=增加,负数=扣减)
127 128 * @param checkFlag 是否校验库存充足(为 true 且扣减后为负则报错)
128 129 */
129   - void updateMaterialStockQuantity(Long materialStockId, BigDecimal quantity, boolean checkFlag);
  130 + void updateMaterialStockQuantity(Long id, BigDecimal quantity, boolean checkFlag);
130 131  
131 132 /**
132 133 * 库位混放规则校验
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
... ... @@ -93,6 +93,14 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
93 93 }
94 94  
95 95 @Override
  96 + public void updateMaterialStockFrozen(Collection<Long> ids, boolean frozen) {
  97 + if (CollUtil.isEmpty(ids)) {
  98 + return;
  99 + }
  100 + materialStockMapper.updateByIds(ids, new MesWmMaterialStockDO().setFrozen(frozen));
  101 + }
  102 +
  103 + @Override
96 104 public Long getMaterialStockCountByWarehouseId(Long warehouseId) {
97 105 return materialStockMapper.selectCountByWarehouseId(warehouseId);
98 106 }
... ... @@ -153,9 +161,9 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
153 161 }
154 162  
155 163 @Override
156   - public void updateMaterialStockQuantity(Long materialStockId, BigDecimal quantity, boolean checkFlag) {
  164 + public void updateMaterialStockQuantity(Long id, BigDecimal quantity, boolean checkFlag) {
157 165 // 更新库存数量(Mapper 层 CAS 防负库存;checkFlag=false 时允许负数)
158   - int updatedRows = materialStockMapper.updateQuantity(materialStockId, quantity, checkFlag);
  166 + int updatedRows = materialStockMapper.updateQuantity(id, quantity, checkFlag);
159 167 if (updatedRows == 0) {
160 168 throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
161 169 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/salesnotice/MesWmSalesNoticeLineServiceImpl.java
... ... @@ -45,11 +45,8 @@ public class MesWmSalesNoticeLineServiceImpl implements MesWmSalesNoticeLineServ
45 45  
46 46 @Override
47 47 public Long createSalesNoticeLine(MesWmSalesNoticeLineSaveReqVO createReqVO) {
48   - // TODO @AI:增加 validateXXXSaveData 方法
49   - // 校验父单据存在且为草稿状态
50   - validateNoticeStatusDraft(createReqVO.getNoticeId());
51   - // 校验物料存在
52   - itemService.validateItemExists(createReqVO.getItemId());
  48 + // 校验数据
  49 + validateLineSaveData(createReqVO);
53 50  
54 51 // 插入
55 52 MesWmSalesNoticeLineDO line = BeanUtils.toBean(createReqVO, MesWmSalesNoticeLineDO.class);
... ... @@ -62,13 +59,9 @@ public class MesWmSalesNoticeLineServiceImpl implements MesWmSalesNoticeLineServ
62 59 public void updateSalesNoticeLine(MesWmSalesNoticeLineSaveReqVO updateReqVO) {
63 60 // 校验存在
64 61 MesWmSalesNoticeLineDO line = validateSalesNoticeLineExists(updateReqVO.getId());
65   - // TODO @AI:增加 validateXXXSaveData 方法
66   - // 校验父单据存在且为草稿状态
67   - validateNoticeStatusDraft(line.getNoticeId());
68   - // 校验物料存在
69   - if (updateReqVO.getItemId() != null) {
70   - itemService.validateItemExists(updateReqVO.getItemId());
71   - }
  62 + // 校验数据
  63 + updateReqVO.setNoticeId(line.getNoticeId());
  64 + validateLineSaveData(updateReqVO);
72 65  
73 66 // 更新
74 67 MesWmSalesNoticeLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmSalesNoticeLineDO.class);
... ... @@ -115,6 +108,15 @@ public class MesWmSalesNoticeLineServiceImpl implements MesWmSalesNoticeLineServ
115 108 return line;
116 109 }
117 110  
  111 + private void validateLineSaveData(MesWmSalesNoticeLineSaveReqVO reqVO) {
  112 + // 校验父单据存在且为草稿状态
  113 + validateNoticeStatusDraft(reqVO.getNoticeId());
  114 + // 校验物料存在
  115 + if (reqVO.getItemId() != null) {
  116 + itemService.validateItemExists(reqVO.getItemId());
  117 + }
  118 + }
  119 +
118 120 /**
119 121 * 校验父发货通知单存在且为草稿状态
120 122 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferDetailService.java
... ... @@ -64,4 +64,11 @@ public interface MesWmTransferDetailService {
64 64 */
65 65 void deleteTransferDetailByTransferId(Long transferId);
66 66  
  67 + /**
  68 + * 根据行 ID 删除明细
  69 + *
  70 + * @param lineId 行 ID
  71 + */
  72 + void deleteTransferDetailByLineId(Long lineId);
  73 +
67 74 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferDetailServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.wm.transfer;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
3 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.detail.MesWmTransferDetailSaveReqVO;
... ... @@ -18,6 +19,7 @@ import java.util.List;
18 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19 20 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_DETAIL_NOT_EXISTS;
20 21 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_DETAIL_QUANTITY_EXCEED;
  22 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_DETAIL_MIXED_GOODS;
21 23  
22 24 /**
23 25 * MES 调拨明细 Service 实现类
... ... @@ -31,6 +33,9 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
31 33  
32 34 @Resource
33 35 @Lazy
  36 + private MesWmTransferService transferService;
  37 + @Resource
  38 + @Lazy
34 39 private MesWmTransferLineService transferLineService;
35 40  
36 41 @Resource
... ... @@ -38,14 +43,8 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
38 43  
39 44 @Override
40 45 public Long createTransferDetail(MesWmTransferDetailSaveReqVO createReqVO) {
41   - // 校验父数据存在
42   - MesWmTransferLineDO line = transferLineService.validateTransferLineExists(createReqVO.getLineId());
43   - // 校验仓库、库区、库位的关联关系
44   - warehouseAreaService.validateWarehouseAreaExists(
45   - createReqVO.getToWarehouseId(), createReqVO.getToLocationId(), createReqVO.getToAreaId());
46   - // 校验明细总数量不超过行数量
47   - validateDetailQuantityNotExceed(createReqVO.getLineId(), createReqVO.getQuantity(), null, line);
48   - // TODO @芋艿:不能混货
  46 + // 校验
  47 + validateDetailSaveData(createReqVO, null);
49 48  
50 49 // 插入
51 50 MesWmTransferDetailDO detail = BeanUtils.toBean(createReqVO, MesWmTransferDetailDO.class);
... ... @@ -57,14 +56,8 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
57 56 public void updateTransferDetail(MesWmTransferDetailSaveReqVO updateReqVO) {
58 57 // 校验存在
59 58 validateTransferDetailExists(updateReqVO.getId());
60   - // 校验父数据存在
61   - MesWmTransferLineDO line = transferLineService.validateTransferLineExists(updateReqVO.getLineId());
62   - // 校验仓库、库区、库位的关联关系
63   - warehouseAreaService.validateWarehouseAreaExists(
64   - updateReqVO.getToWarehouseId(), updateReqVO.getToLocationId(), updateReqVO.getToAreaId());
65   - // 校验明细总数量不超过行数量(排除自身)
66   - validateDetailQuantityNotExceed(updateReqVO.getLineId(), updateReqVO.getQuantity(), updateReqVO.getId(), line);
67   - // TODO @芋艿:不能混货
  59 + // 校验
  60 + validateDetailSaveData(updateReqVO, updateReqVO.getId());
68 61  
69 62 // 更新
70 63 MesWmTransferDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferDetailDO.class);
... ... @@ -74,7 +67,13 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
74 67 @Override
75 68 public void deleteTransferDetail(Long id) {
76 69 // 校验存在
77   - validateTransferDetailExists(id);
  70 + MesWmTransferDetailDO detail = transferDetailMapper.selectById(id);
  71 + if (detail == null) {
  72 + throw exception(WM_TRANSFER_DETAIL_NOT_EXISTS);
  73 + }
  74 + // 校验父转移单可编辑(通过 line 找到 transfer)
  75 + MesWmTransferLineDO line = transferLineService.validateTransferLineExists(detail.getLineId());
  76 + transferService.validateTransferEditable(line.getTransferId());
78 77 // 删除
79 78 transferDetailMapper.deleteById(id);
80 79 }
... ... @@ -100,6 +99,13 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
100 99 .forEach(detail -> transferDetailMapper.deleteById(detail.getId()));
101 100 }
102 101  
  102 + @Override
  103 + public void deleteTransferDetailByLineId(Long lineId) {
  104 + // TODO @AI:不要 get;直接去 deletebylineId;
  105 + getTransferDetailListByLineId(lineId)
  106 + .forEach(detail -> transferDetailMapper.deleteById(detail.getId()));
  107 + }
  108 +
103 109 private void validateTransferDetailExists(Long id) {
104 110 if (transferDetailMapper.selectById(id) == null) {
105 111 throw exception(WM_TRANSFER_DETAIL_NOT_EXISTS);
... ... @@ -107,6 +113,25 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
107 113 }
108 114  
109 115 /**
  116 + * 校验明细保存数据
  117 + *
  118 + * @param reqVO 保存请求
  119 + * @param excludeDetailId 排除的明细 ID(更新时排除自身,新增时传 null)
  120 + */
  121 + private void validateDetailSaveData(MesWmTransferDetailSaveReqVO reqVO, Long excludeDetailId) {
  122 + // 校验父数据存在
  123 + MesWmTransferLineDO line = transferLineService.validateTransferLineExists(reqVO.getLineId());
  124 + // 校验仓库、库区、库位的关联关系
  125 + warehouseAreaService.validateWarehouseAreaExists(
  126 + reqVO.getToWarehouseId(), reqVO.getToLocationId(), reqVO.getToAreaId());
  127 + // 校验明细总数量不超过行数量
  128 + validateDetailQuantityNotExceed(reqVO.getLineId(), reqVO.getQuantity(), excludeDetailId, line);
  129 + // 校验不能混货:同一个目标仓位下,不能存在不同物料的明细
  130 + validateNoMixedGoods(reqVO.getLineId(), reqVO.getToWarehouseId(),
  131 + reqVO.getToLocationId(), reqVO.getToAreaId(), line.getItemId(), excludeDetailId);
  132 + }
  133 +
  134 + /**
110 135 * 校验明细总数量不超过行数量
111 136 *
112 137 * @param lineId 行 ID
... ... @@ -128,4 +153,45 @@ public class MesWmTransferDetailServiceImpl implements MesWmTransferDetailServic
128 153 }
129 154 }
130 155  
  156 + /**
  157 + * 校验不能混货:同一转移单下,同一个目标仓位(仓库+库区+库位)只能放同一个物料
  158 + *
  159 + * @param lineId 当前行 ID(用于排除同行明细,因为同行物料相同)
  160 + * @param toWarehouseId 目标仓库 ID
  161 + * @param toLocationId 目标库区 ID
  162 + * @param toAreaId 目标库位 ID
  163 + * @param itemId 当前物料 ID
  164 + * @param excludeDetailId 排除的明细 ID(更新时排除自身)
  165 + */
  166 + private void validateNoMixedGoods(Long lineId, Long toWarehouseId, Long toLocationId,
  167 + Long toAreaId, Long itemId, Long excludeDetailId) {
  168 + // 1. 获取当前转移单下的所有明细
  169 + // 说明:因为无法直接从参数拿到 transferId,所以先通过 lineId 查询当前行,进而获取 transferId 和所有明细
  170 + MesWmTransferLineDO currentLine = transferLineService.validateTransferLineExists(lineId);
  171 + List<MesWmTransferDetailDO> allDetails = transferDetailMapper.selectListByTransferId(currentLine.getTransferId());
  172 +
  173 + // 2. 遍历所有明细,校验同一个目标仓位不能有不同的物料
  174 + for (MesWmTransferDetailDO detail : allDetails) {
  175 + // 2.1 排除当前正在编辑的明细(更新时)
  176 + if (excludeDetailId != null && excludeDetailId.equals(detail.getId())) {
  177 + continue;
  178 + }
  179 + // 2.2 排除同行的明细(同行属于同一个转移单行,物料必定相同,无需校验)
  180 + if (detail.getLineId().equals(lineId)) {
  181 + continue;
  182 + }
  183 + // 2.3 目标仓位不同,则不会混货,直接跳过
  184 + if (ObjUtil.notEqual(detail.getToWarehouseId(), toWarehouseId)
  185 + || ObjUtil.notEqual(detail.getToLocationId(), toLocationId)
  186 + || ObjUtil.notEqual(detail.getToAreaId(), toAreaId)) {
  187 + continue;
  188 + }
  189 + // 2.4 重点:如果目标仓位相同,则必须保证物料也相同
  190 + MesWmTransferLineDO otherLine = transferLineService.validateTransferLineExists(detail.getLineId());
  191 + if (ObjUtil.notEqual(otherLine.getItemId(), itemId)) {
  192 + throw exception(WM_TRANSFER_DETAIL_MIXED_GOODS);
  193 + }
  194 + }
  195 + }
  196 +
131 197 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferLineServiceImpl.java
... ... @@ -5,15 +5,18 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.line.MesWmTra
5 5 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO;
6 6 import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferLineMapper;
7 7 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  8 +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
8 9 import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
9 10 import jakarta.annotation.Resource;
10 11 import org.springframework.context.annotation.Lazy;
11 12 import org.springframework.stereotype.Service;
  13 +import org.springframework.transaction.annotation.Transactional;
12 14 import org.springframework.validation.annotation.Validated;
13 15  
14 16 import java.util.List;
15 17  
16 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MATERIAL_STOCK_NOT_EXISTS;
17 20 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_TRANSFER_LINE_NOT_EXISTS;
18 21  
19 22 /**
... ... @@ -30,19 +33,19 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
30 33 @Lazy
31 34 private MesWmTransferService transferService;
32 35 @Resource
  36 + @Lazy
  37 + private MesWmTransferDetailService transferDetailService;
  38 + @Resource
33 39 private MesMdItemService itemService;
34 40 @Resource
35 41 private MesWmWarehouseAreaService warehouseAreaService;
  42 + @Resource
  43 + private MesWmMaterialStockService materialStockService;
36 44  
37 45 @Override
38 46 public Long createTransferLine(MesWmTransferLineSaveReqVO createReqVO) {
39   - // 校验父数据可编辑
40   - transferService.validateTransferEditable(createReqVO.getTransferId());
41   - // 校验产品存在
42   - itemService.validateItemExists(createReqVO.getItemId());
43   - // 校验来源仓库、库区、库位的关联关系
44   - warehouseAreaService.validateWarehouseAreaExists(createReqVO.getFromWarehouseId(),
45   - createReqVO.getFromLocationId(), createReqVO.getFromAreaId());
  47 + // 校验
  48 + validateLineSaveData(createReqVO);
46 49  
47 50 // 插入
48 51 MesWmTransferLineDO line = BeanUtils.toBean(createReqVO, MesWmTransferLineDO.class);
... ... @@ -54,13 +57,8 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
54 57 public void updateTransferLine(MesWmTransferLineSaveReqVO updateReqVO) {
55 58 // 校验存在
56 59 validateTransferLineExists(updateReqVO.getId());
57   - // 校验父数据可编辑
58   - transferService.validateTransferEditable(updateReqVO.getTransferId());
59   - // 校验产品存在
60   - itemService.validateItemExists(updateReqVO.getItemId());
61   - // 校验来源仓库、库区、库位的关联关系
62   - warehouseAreaService.validateWarehouseAreaExists(updateReqVO.getFromWarehouseId(),
63   - updateReqVO.getFromLocationId(), updateReqVO.getFromAreaId());
  60 + // 校验
  61 + validateLineSaveData(updateReqVO);
64 62  
65 63 // 更新
66 64 MesWmTransferLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmTransferLineDO.class);
... ... @@ -68,10 +66,16 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
68 66 }
69 67  
70 68 @Override
  69 + @Transactional(rollbackFor = Exception.class)
71 70 public void deleteTransferLine(Long id) {
72 71 // 校验存在
73   - validateTransferLineExists(id);
74   - // 删除
  72 + MesWmTransferLineDO line = validateTransferLineExists(id);
  73 + // 校验父数据可编辑
  74 + transferService.validateTransferEditable(line.getTransferId());
  75 +
  76 + // 级联删除该行下所有明细
  77 + transferDetailService.deleteTransferDetailByLineId(id);
  78 + // 删除行
75 79 transferLineMapper.deleteById(id);
76 80 }
77 81  
... ... @@ -100,4 +104,19 @@ public class MesWmTransferLineServiceImpl implements MesWmTransferLineService {
100 104 return line;
101 105 }
102 106  
  107 + private void validateLineSaveData(MesWmTransferLineSaveReqVO reqVO) {
  108 + // 校验父数据可编辑
  109 + transferService.validateTransferEditable(reqVO.getTransferId());
  110 + // 校验产品存在
  111 + itemService.validateItemExists(reqVO.getItemId());
  112 + // 校验来源仓库、库区、库位的关联关系
  113 + warehouseAreaService.validateWarehouseAreaExists(reqVO.getFromWarehouseId(),
  114 + reqVO.getFromLocationId(), reqVO.getFromAreaId());
  115 + // 校验库存记录存在
  116 + if (reqVO.getMaterialStockId() != null
  117 + && materialStockService.getMaterialStock(reqVO.getMaterialStockId()) == null) {
  118 + throw exception(WM_MATERIAL_STOCK_NOT_EXISTS);
  119 + }
  120 + }
  121 +
103 122 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java
... ... @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7   -import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
8 7 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferPageReqVO;
9 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferSaveReqVO;
10 9 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDO;
... ... @@ -27,6 +26,7 @@ import java.util.List;
27 26 import java.util.Map;
28 27  
29 28 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
30 30 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
31 31  
32 32 /**
... ... @@ -109,7 +109,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
109 109 if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) && !Boolean.TRUE.equals(transfer.getConfirmFlag())) {
110 110 transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()).setConfirmFlag(false);
111 111 // DONE @AI:冻结库存属于主单状态流转的一部分,保留在主单 service 统一处理
112   - freezeTransferLineStocks(lines, true);
  112 + freezeTransferLineStocks(id, true);
113 113 } else {
114 114 transfer.setStatus(MesWmTransferStatusEnum.APPROVING.getStatus());
115 115 }
... ... @@ -171,7 +171,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
171 171  
172 172 // 4. 配送模式下,执行完成后解除来源库存冻结
173 173 if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) {
174   - freezeTransferLineStocks(lines, false);
  174 + freezeTransferLineStocks(id, false);
175 175 }
176 176 }
177 177  
... ... @@ -215,6 +215,11 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
215 215 // 校验存在 + 非已完成/已取消状态
216 216 MesWmTransferDO transfer = validateTransferExistsAndNotFinished(id);
217 217  
  218 + // 配送模式下,取消时需解除冻结
  219 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) {
  220 + freezeTransferLineStocks(id, false);
  221 + }
  222 +
218 223 // 更新状态 -> 已取消
219 224 transfer.setStatus(MesWmTransferStatusEnum.CANCELED.getStatus());
220 225 transferMapper.updateById(transfer);
... ... @@ -305,20 +310,14 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
305 310 return transfer;
306 311 }
307 312  
308   - // TODO @芋艿:【后续弄】materialStockService 封装一个方法,传入 transferId + frozen 统一处理了;不用判断 line 的 getMaterialStockId
309   - private void freezeTransferLineStocks(List<MesWmTransferLineDO> lines, boolean frozen) {
  313 + private void freezeTransferLineStocks(Long transferId, boolean frozen) {
  314 + List<MesWmTransferLineDO> lines = transferLineService.getTransferLineListByTransferId(transferId);
310 315 if (CollUtil.isEmpty(lines)) {
311 316 return;
312 317 }
313   - for (MesWmTransferLineDO line : lines) {
314   - if (line.getMaterialStockId() == null) {
315   - continue;
316   - }
317   - MesWmMaterialStockFreezeReqVO freezeReqVO = new MesWmMaterialStockFreezeReqVO();
318   - freezeReqVO.setId(line.getMaterialStockId());
319   - freezeReqVO.setFrozen(frozen);
320   - materialStockService.updateMaterialStockFrozen(freezeReqVO);
321   - }
  318 + List<Long> materialStockIds = convertList(lines,
  319 + MesWmTransferLineDO::getMaterialStockId, line -> line.getMaterialStockId() != null);
  320 + materialStockService.updateMaterialStockFrozen(materialStockIds, frozen);
322 321 }
323 322  
324 323 }
... ...