Commit 8ac5704591f0fd6f6830c8ccbf4f935f5b09e6ac

Authored by YunaiV
1 parent 383e265e

✨ feat(mes): 增强退货单功能,新增行数据校验与删除逻辑

- 新增退货数量字段的校验,确保其大于 0
- 增加根据行 ID 删除明细的功能
- 新增退货单编码的定义
- 增强退货单状态校验,确保状态为草稿才能进行删除操作
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnvendor/vo/detail/MesWmReturnVendorDetailSaveReqVO.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.detail;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.DecimalMin;
4 5 import jakarta.validation.constraints.NotNull;
5 6 import lombok.Data;
6 7  
... ... @@ -27,6 +28,7 @@ public class MesWmReturnVendorDetailSaveReqVO {
27 28  
28 29 @Schema(description = "退货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "300.00")
29 30 @NotNull(message = "退货数量不能为空")
  31 + @DecimalMin(value = "0", inclusive = false, message = "退货数量必须大于 0")
30 32 private BigDecimal quantity;
31 33  
32 34 @Schema(description = "批次编号", example = "1")
... ... @@ -48,3 +50,4 @@ public class MesWmReturnVendorDetailSaveReqVO {
48 50 private String remark;
49 51  
50 52 }
  53 +
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnvendor/MesWmReturnVendorDetailMapper.java
... ... @@ -24,4 +24,8 @@ public interface MesWmReturnVendorDetailMapper extends BaseMapperX<MesWmReturnVe
24 24 delete(MesWmReturnVendorDetailDO::getReturnId, returnId);
25 25 }
26 26  
  27 + default void deleteByLineId(Long lineId) {
  28 + delete(MesWmReturnVendorDetailDO::getLineId, lineId);
  29 + }
  30 +
27 31 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnvendor/MesWmReturnVendorMapper.java
... ... @@ -26,4 +26,8 @@ public interface MesWmReturnVendorMapper extends BaseMapperX<MesWmReturnVendorDO
26 26 return selectCount(MesWmReturnVendorDO::getVendorId, vendorId);
27 27 }
28 28  
  29 + default MesWmReturnVendorDO selectByCode(String code) {
  30 + return selectOne(MesWmReturnVendorDO::getCode, code);
  31 + }
  32 +
29 33 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -473,8 +473,12 @@ public interface ErrorCodeConstants {
473 473 ErrorCode WM_RETURN_VENDOR_NO_LINE = new ErrorCode(1_040_711_002, "供应商退货单至少需要一条行数据");
474 474 ErrorCode WM_RETURN_VENDOR_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_711_003, "供应商退货单行数量与明细数量不一致");
475 475 ErrorCode WM_RETURN_VENDOR_CANCEL_NOT_ALLOWED = new ErrorCode(1_040_711_004, "供应商退货单已完成或已取消,无法取消");
  476 + ErrorCode WM_RETURN_VENDOR_CODE_DUPLICATE = new ErrorCode(1_040_711_005, "供应商退货单编号已存在");
  477 + ErrorCode WM_RETURN_VENDOR_NO_DETAIL = new ErrorCode(1_040_711_006, "供应商退货单没有拣货明细,无法执行退货");
  478 + ErrorCode WM_RETURN_VENDOR_DETAIL_ITEM_MISMATCH = new ErrorCode(1_040_711_007, "拣货明细的物料与退货单行的物料不一致");
476 479 ErrorCode WM_RETURN_VENDOR_LINE_NOT_EXISTS = new ErrorCode(1_040_711_100, "供应商退货单行不存在");
477 480 ErrorCode WM_RETURN_VENDOR_DETAIL_NOT_EXISTS = new ErrorCode(1_040_711_200, "供应商退货单明细不存在");
  481 + ErrorCode WM_RETURN_VENDOR_DETAIL_QUANTITY_INVALID = new ErrorCode(1_040_711_201, "退货明细数量必须大于 0");
478 482  
479 483 // ========== MES 仓库管理-产品收货单(1-040-712-000) ==========
480 484 ErrorCode WM_PRODUCT_RECPT_NOT_EXISTS = new ErrorCode(1_040_712_000, "产品收货单不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java
... ... @@ -19,6 +19,7 @@ public enum MesMdAutoCodeRuleCodeEnum {
19 19 TM_TOOL_TYPE_CODE("TM_TOOL_TYPE_CODE", "工具类型编码"),
20 20 WM_ARRIVAL_NOTICE_CODE("WM_ARRIVAL_NOTICE_CODE", "到货通知单编码"),
21 21 WM_ITEM_RECEIPT_CODE("WM_ITEM_RECEIPT_CODE", "采购入库单编码"),
  22 + WM_RETURN_VENDOR_CODE("WM_RETURN_VENDOR_CODE", "采购退货单编码"),
22 23 WM_SN_CODE("WM_SN_CODE", "SN 码"),
23 24 WM_PACKAGE_CODE("WM_PACKAGE_CODE", "装箱单编码"),
24 25 WM_BATCH_CODE("WM_BATCH_CODE", "批次编码"),
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorDetailService.java
... ... @@ -64,4 +64,11 @@ public interface MesWmReturnVendorDetailService {
64 64 */
65 65 void deleteReturnVendorDetailByReturnId(Long returnId);
66 66  
  67 + /**
  68 + * 根据行ID删除明细
  69 + *
  70 + * @param lineId 行ID
  71 + */
  72 + void deleteReturnVendorDetailByLineId(Long lineId);
  73 +
67 74 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorDetailServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.wm.returnvendor;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
3 4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 5 import cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.detail.MesWmReturnVendorDetailSaveReqVO;
5 6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorDetailDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorLineDO;
6 8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnvendor.MesWmReturnVendorDetailMapper;
7 9 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
8 10 import jakarta.annotation.Resource;
... ... @@ -13,6 +15,7 @@ import org.springframework.validation.annotation.Validated;
13 15 import java.util.List;
14 16  
15 17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  18 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_VENDOR_DETAIL_ITEM_MISMATCH;
16 19 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_VENDOR_DETAIL_NOT_EXISTS;
17 20  
18 21 /**
... ... @@ -35,9 +38,11 @@ public class MesWmReturnVendorDetailServiceImpl implements MesWmReturnVendorDeta
35 38 @Override
36 39 public Long createReturnVendorDetail(MesWmReturnVendorDetailSaveReqVO createReqVO) {
37 40 // 校验父数据存在
38   - returnVendorLineService.validateReturnVendorLineExists(createReqVO.getLineId());
  41 + MesWmReturnVendorLineDO line = returnVendorLineService.validateReturnVendorLineExists(createReqVO.getLineId());
39 42 // 校验物料存在
40 43 itemService.validateItemExists(createReqVO.getItemId());
  44 + // 校验物料与行物料一致
  45 + validateItemConsistency(createReqVO.getItemId(), line);
41 46  
42 47 // 插入
43 48 MesWmReturnVendorDetailDO detail = BeanUtils.toBean(createReqVO, MesWmReturnVendorDetailDO.class);
... ... @@ -50,9 +55,11 @@ public class MesWmReturnVendorDetailServiceImpl implements MesWmReturnVendorDeta
50 55 // 校验存在
51 56 validateReturnVendorDetailExists(updateReqVO.getId());
52 57 // 校验父数据存在
53   - returnVendorLineService.validateReturnVendorLineExists(updateReqVO.getLineId());
  58 + MesWmReturnVendorLineDO line = returnVendorLineService.validateReturnVendorLineExists(updateReqVO.getLineId());
54 59 // 校验物料存在
55 60 itemService.validateItemExists(updateReqVO.getItemId());
  61 + // 校验物料与行物料一致
  62 + validateItemConsistency(updateReqVO.getItemId(), line);
56 63  
57 64 // 更新
58 65 MesWmReturnVendorDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnVendorDetailDO.class);
... ... @@ -87,10 +94,24 @@ public class MesWmReturnVendorDetailServiceImpl implements MesWmReturnVendorDeta
87 94 returnVendorDetailMapper.deleteByReturnId(returnId);
88 95 }
89 96  
  97 + @Override
  98 + public void deleteReturnVendorDetailByLineId(Long lineId) {
  99 + returnVendorDetailMapper.deleteByLineId(lineId);
  100 + }
  101 +
90 102 private void validateReturnVendorDetailExists(Long id) {
91 103 if (returnVendorDetailMapper.selectById(id) == null) {
92 104 throw exception(WM_RETURN_VENDOR_DETAIL_NOT_EXISTS);
93 105 }
94 106 }
95 107  
  108 + /**
  109 + * 校验明细物料与行物料一致
  110 + */
  111 + private void validateItemConsistency(Long detailItemId, MesWmReturnVendorLineDO line) {
  112 + if (ObjUtil.notEqual(detailItemId, line.getItemId())) {
  113 + throw exception(WM_RETURN_VENDOR_DETAIL_ITEM_MISMATCH);
  114 + }
  115 + }
  116 +
96 117 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorLineServiceImpl.java
... ... @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
10 10 import jakarta.annotation.Resource;
11 11 import org.springframework.context.annotation.Lazy;
12 12 import org.springframework.stereotype.Service;
  13 +import org.springframework.transaction.annotation.Transactional;
13 14 import org.springframework.validation.annotation.Validated;
14 15  
15 16 import java.util.List;
... ... @@ -31,14 +32,15 @@ public class MesWmReturnVendorLineServiceImpl implements MesWmReturnVendorLineSe
31 32 @Lazy
32 33 private MesWmReturnVendorService returnVendorService;
33 34 @Resource
  35 + @Lazy
  36 + private MesWmReturnVendorDetailService returnVendorDetailService;
  37 + @Resource
34 38 private MesMdItemService itemService;
35 39  
36 40 @Override
37 41 public Long createReturnVendorLine(MesWmReturnVendorLineSaveReqVO createReqVO) {
38   - // 校验父数据存在
39   - returnVendorService.validateReturnVendorExists(createReqVO.getReturnId());
40   - // 校验物料存在
41   - itemService.validateItemExists(createReqVO.getItemId());
  42 + // 校验数据
  43 + validateReturnVendorLineSaveData(createReqVO);
42 44  
43 45 // 插入
44 46 MesWmReturnVendorLineDO line = BeanUtils.toBean(createReqVO, MesWmReturnVendorLineDO.class);
... ... @@ -50,10 +52,8 @@ public class MesWmReturnVendorLineServiceImpl implements MesWmReturnVendorLineSe
50 52 public void updateReturnVendorLine(MesWmReturnVendorLineSaveReqVO updateReqVO) {
51 53 // 校验存在
52 54 validateReturnVendorLineExists(updateReqVO.getId());
53   - // 校验父数据存在
54   - returnVendorService.validateReturnVendorExists(updateReqVO.getReturnId());
55   - // 校验物料存在
56   - itemService.validateItemExists(updateReqVO.getItemId());
  55 + // 校验数据
  56 + validateReturnVendorLineSaveData(updateReqVO);
57 57  
58 58 // 更新
59 59 MesWmReturnVendorLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnVendorLineDO.class);
... ... @@ -61,10 +61,16 @@ public class MesWmReturnVendorLineServiceImpl implements MesWmReturnVendorLineSe
61 61 }
62 62  
63 63 @Override
  64 + @Transactional(rollbackFor = Exception.class)
64 65 public void deleteReturnVendorLine(Long id) {
65   - // 校验存在
66   - validateReturnVendorLineExists(id);
67   - // 删除
  66 + // 1.1 校验存在
  67 + MesWmReturnVendorLineDO line = validateReturnVendorLineExists(id);
  68 + // 1.2 校验父数据为草稿状态
  69 + returnVendorService.validateReturnVendorExistsAndPrepare(line.getReturnId());
  70 +
  71 + // 2.1 级联删除该行下的明细
  72 + returnVendorDetailService.deleteReturnVendorDetailByLineId(id);
  73 + // 2.2 删除行
68 74 returnVendorLineMapper.deleteById(id);
69 75 }
70 76  
... ... @@ -97,4 +103,11 @@ public class MesWmReturnVendorLineServiceImpl implements MesWmReturnVendorLineSe
97 103 return line;
98 104 }
99 105  
  106 + private void validateReturnVendorLineSaveData(MesWmReturnVendorLineSaveReqVO reqVO) {
  107 + // 校验父数据存在且为草稿状态
  108 + returnVendorService.validateReturnVendorExistsAndPrepare(reqVO.getReturnId());
  109 + // 校验物料存在
  110 + itemService.validateItemExists(reqVO.getItemId());
  111 + }
  112 +
100 113 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorService.java
... ... @@ -101,4 +101,12 @@ public interface MesWmReturnVendorService {
101 101 */
102 102 Long getReturnVendorCountByVendorId(Long vendorId);
103 103  
  104 + /**
  105 + * 校验供应商退货单存在且为草稿状态
  106 + *
  107 + * @param id 编号
  108 + * @return 供应商退货单
  109 + */
  110 + MesWmReturnVendorDO validateReturnVendorExistsAndPrepare(Long id);
  111 +
104 112 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorServiceImpl.java
... ... @@ -52,8 +52,8 @@ public class MesWmReturnVendorServiceImpl implements MesWmReturnVendorService {
52 52 @Override
53 53 @Transactional(rollbackFor = Exception.class)
54 54 public Long createReturnVendor(MesWmReturnVendorSaveReqVO createReqVO) {
55   - // 1. 校验关联数据
56   - vendorService.validateVendorExists(createReqVO.getVendorId());
  55 + // 1. 校验数据
  56 + validateReturnVendorSaveData(createReqVO);
57 57  
58 58 // 2. 插入主表
59 59 MesWmReturnVendorDO returnVendor = BeanUtils.toBean(createReqVO, MesWmReturnVendorDO.class);
... ... @@ -65,10 +65,8 @@ public class MesWmReturnVendorServiceImpl implements MesWmReturnVendorService {
65 65 @Override
66 66 @Transactional(rollbackFor = Exception.class)
67 67 public void updateReturnVendor(MesWmReturnVendorSaveReqVO updateReqVO) {
68   - // 1.1 校验存在 + 准备中状态
69   - validateReturnVendorExistsAndPrepare(updateReqVO.getId());
70   - // 1.2 校验关联数据
71   - vendorService.validateVendorExists(updateReqVO.getVendorId());
  68 + // 1. 校验数据
  69 + validateReturnVendorSaveData(updateReqVO);
72 70  
73 71 // 2. 更新主表
74 72 MesWmReturnVendorDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnVendorDO.class);
... ... @@ -131,22 +129,26 @@ public class MesWmReturnVendorServiceImpl implements MesWmReturnVendorService {
131 129 @Override
132 130 @Transactional(rollbackFor = Exception.class)
133 131 public void finishReturnVendor(Long id) {
134   - // 1. 校验存在
  132 + // 1.1 校验存在
135 133 MesWmReturnVendorDO returnVendor = validateReturnVendorExists(id);
136 134 if (ObjUtil.notEqual(MesWmReturnVendorStatusEnum.APPROVED.getStatus(), returnVendor.getStatus())) {
137 135 throw exception(WM_RETURN_VENDOR_STATUS_INVALID);
138 136 }
  137 + // 1.2 校验明细不为空
  138 + List<MesWmReturnVendorDetailDO> details = returnVendorDetailService.getReturnVendorDetailListByReturnId(id);
  139 + if (CollUtil.isEmpty(details)) {
  140 + throw exception(WM_RETURN_VENDOR_NO_DETAIL);
  141 + }
139 142  
140 143 // 2. 遍历所有明细,创建库存事务(扣减库存 + 记录流水)
141   - createTransactionList(returnVendor);
  144 + createTransactionList(returnVendor, details);
142 145  
143 146 // 3. 更新退货单状态
144 147 returnVendorMapper.updateById(new MesWmReturnVendorDO()
145 148 .setId(id).setStatus(MesWmReturnVendorStatusEnum.FINISHED.getStatus()));
146 149 }
147 150  
148   - private void createTransactionList(MesWmReturnVendorDO returnVendor) {
149   - List<MesWmReturnVendorDetailDO> details = returnVendorDetailService.getReturnVendorDetailListByReturnId(returnVendor.getId());
  151 + private void createTransactionList(MesWmReturnVendorDO returnVendor, List<MesWmReturnVendorDetailDO> details) {
150 152 wmTransactionService.createTransactionList(convertList(details, detail -> new MesWmTransactionSaveReqDTO()
151 153 .setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(detail.getItemId())
152 154 .setQuantity(detail.getQuantity().negate()) // 出库数量为负数
... ... @@ -197,10 +199,8 @@ public class MesWmReturnVendorServiceImpl implements MesWmReturnVendorService {
197 199 return returnVendor;
198 200 }
199 201  
200   - /**
201   - * 校验供应商退货单存在且为准备中状态
202   - */
203   - private MesWmReturnVendorDO validateReturnVendorExistsAndPrepare(Long id) {
  202 + @Override
  203 + public MesWmReturnVendorDO validateReturnVendorExistsAndPrepare(Long id) {
204 204 MesWmReturnVendorDO returnVendor = validateReturnVendorExists(id);
205 205 if (ObjUtil.notEqual(MesWmReturnVendorStatusEnum.PREPARE.getStatus(), returnVendor.getStatus())) {
206 206 throw exception(WM_RETURN_VENDOR_STATUS_INVALID);
... ... @@ -208,6 +208,33 @@ public class MesWmReturnVendorServiceImpl implements MesWmReturnVendorService {
208 208 return returnVendor;
209 209 }
210 210  
  211 + /**
  212 + * 校验退货单创建/修改的公共数据
  213 + */
  214 + private void validateReturnVendorSaveData(MesWmReturnVendorSaveReqVO reqVO) {
  215 + // 校验存在 + 草稿状态(仅修改时)
  216 + if (reqVO.getId() != null) {
  217 + validateReturnVendorExistsAndPrepare(reqVO.getId());
  218 + }
  219 + // 校验供应商存在
  220 + vendorService.validateVendorExists(reqVO.getVendorId());
  221 + // 校验编码唯一
  222 + validateCodeUnique(reqVO.getId(), reqVO.getCode());
  223 + }
  224 +
  225 + /**
  226 + * 校验退货单编号唯一
  227 + */
  228 + private void validateCodeUnique(Long id, String code) {
  229 + MesWmReturnVendorDO existing = returnVendorMapper.selectByCode(code);
  230 + if (existing == null) {
  231 + return;
  232 + }
  233 + if (ObjUtil.notEqual(id, existing.getId())) {
  234 + throw exception(WM_RETURN_VENDOR_CODE_DUPLICATE);
  235 + }
  236 + }
  237 +
211 238 @Override
212 239 public Long getReturnVendorCountByVendorId(Long vendorId) {
213 240 return returnVendorMapper.selectCountByVendorId(vendorId);
... ...