Commit 4444478da4630f72d98559194fdbeb05c3e77367

Authored by YunaiV
1 parent 6332e59d

✨ feat(mes): 添加生产退料单确认功能及字段校验

新增确认生产退料单的接口,更新相关字段为必填项并添加数量校验逻辑。此变更旨在提升退料单的管理效率和数据准确性。
Showing 17 changed files with 290 additions and 54 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnissue/MesWmReturnIssueController.java
... ... @@ -115,6 +115,15 @@ public class MesWmReturnIssueController {
115 115 return success(true);
116 116 }
117 117  
  118 + @PutMapping("/confirm")
  119 + @Operation(summary = "确认生产退料单")
  120 + @Parameter(name = "id", description = "编号", required = true)
  121 + @PreAuthorize("@ss.hasPermission('mes:wm-return-issue:update')")
  122 + public CommonResult<Boolean> confirmReturnIssue(@RequestParam("id") Long id) {
  123 + issueService.confirmReturnIssue(id);
  124 + return success(true);
  125 + }
  126 +
118 127 @PutMapping("/submit")
119 128 @Operation(summary = "提交生产退料单")
120 129 @Parameter(name = "id", description = "编号", required = true)
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnissue/vo/MesWmReturnIssuePageReqVO.java
... ... @@ -27,8 +27,8 @@ public class MesWmReturnIssuePageReqVO extends PageParam {
27 27 @Schema(description = "生产工单 ID", example = "1")
28 28 private Long workOrderId;
29 29  
30   - @Schema(description = "退料类型", example = "RMR")
31   - private String returnType;
  30 + @Schema(description = "退料类型", example = "1")
  31 + private Integer type;
32 32  
33 33 @Schema(description = "状态", example = "0")
34 34 private Integer status;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnissue/vo/MesWmReturnIssueRespVO.java
... ... @@ -18,20 +18,20 @@ public class MesWmReturnIssueRespVO {
18 18 @Schema(description = "退料单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "生产退料")
19 19 private String name;
20 20  
21   - @Schema(description = "生产工单 ID", example = "1")
  21 + @Schema(description = "生产工单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
22 22 private Long workOrderId;
23 23  
24   - @Schema(description = "生产工单编号", example = "WO20250226001")
  24 + @Schema(description = "生产工单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "WO20250226001")
25 25 private String workOrderCode;
26 26  
27   - @Schema(description = "工作站 ID", example = "1")
  27 + @Schema(description = "工作站 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
28 28 private Long workstationId;
29 29  
30 30 @Schema(description = "工作站名称", example = "装配工作站")
31 31 private String workstationName;
32 32  
33   - @Schema(description = "退料类型", example = "RMR")
34   - private String returnType;
  33 + @Schema(description = "退料类型", example = "1")
  34 + private Integer type;
35 35  
36 36 @Schema(description = "退料日期")
37 37 private LocalDateTime returnDate;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnissue/vo/MesWmReturnIssueSaveReqVO.java
... ... @@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import jakarta.validation.constraints.NotBlank;
  5 +import jakarta.validation.constraints.NotNull;
5 6 import lombok.Data;
6 7  
7 8 import java.time.LocalDateTime;
8 9  
9   -// TODO @AI:需要检查下,哪些是必传字段。然后校验下;
10 10 @Schema(description = "管理后台 - MES 生产退料单新增/修改 Request VO")
11 11 @Data
12 12 public class MesWmReturnIssueSaveReqVO {
... ... @@ -22,14 +22,16 @@ public class MesWmReturnIssueSaveReqVO {
22 22 @NotBlank(message = "退料单名称不能为空")
23 23 private String name;
24 24  
25   - @Schema(description = "生产工单 ID", example = "1")
  25 + @Schema(description = "生产工单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  26 + @NotNull(message = "生产工单 ID 不能为空")
26 27 private Long workOrderId;
27 28  
28 29 @Schema(description = "工作站 ID", example = "1")
29 30 private Long workstationId;
30 31  
31   - @Schema(description = "退料类型", example = "RMR")
32   - private String returnType;
  32 + @Schema(description = "退料类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  33 + @NotNull(message = "退料类型不能为空")
  34 + private Integer type;
33 35  
34 36 @Schema(description = "退料日期")
35 37 private LocalDateTime returnDate;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnissue/vo/detail/MesWmReturnIssueDetailSaveReqVO.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.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 MesWmReturnIssueDetailSaveReqVO {
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")
... ... @@ -35,13 +37,16 @@ public class MesWmReturnIssueDetailSaveReqVO {
35 37 @Schema(description = "批次号", example = "BATCH20260101001")
36 38 private String batchCode;
37 39  
38   - @Schema(description = "仓库编号", example = "1")
  40 + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  41 + @NotNull(message = "仓库编号不能为空")
39 42 private Long warehouseId;
40 43  
41   - @Schema(description = "库区编号", example = "1")
  44 + @Schema(description = "库区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  45 + @NotNull(message = "库区编号不能为空")
42 46 private Long locationId;
43 47  
44   - @Schema(description = "库位编号", example = "1")
  48 + @Schema(description = "库位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  49 + @NotNull(message = "库位编号不能为空")
45 50 private Long areaId;
46 51  
47 52 @Schema(description = "备注", example = "备注")
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnissue/MesWmReturnIssueDO.java
... ... @@ -43,19 +43,19 @@ public class MesWmReturnIssueDO extends BaseDO {
43 43 * 关联 {@link MesProWorkOrderDO#getId()}
44 44 */
45 45 private Long workOrderId;
  46 + // TODO @芋艿:可能不需要这个字段。界面上没有;
46 47 /**
47 48 * 工作站 ID
48 49 *
49 50 * 关联 {@link MesMdWorkstationDO#getId()}
50 51 */
51 52 private Long workstationId;
52   - // TODO @AI:可以改成 type 字段;简化;
53 53 /**
54 54 * 退料类型
55 55 *
56   - * 字典 {@link cn.iocoder.yudao.module.mes.enums.DictTypeConstants#MES_WM_RETURN_ISSUE_TYPE}
  56 + * 枚举 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueTypeEnum}
57 57 */
58   - private String returnType;
  58 + private Integer type;
59 59 /**
60 60 * 退料日期
61 61 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnissue/MesWmReturnIssueLineDO.java
... ... @@ -59,12 +59,10 @@ public class MesWmReturnIssueLineDO extends BaseDO {
59 59 * 是否需要质检
60 60 */
61 61 private Boolean qcFlag;
62   - // TODO @AI:额外加个枚举类;
63   - // TODO @芋艿:是这些么?
64 62 /**
65 63 * 质量状态
66 64 *
67   - * 字典 {@link cn.iocoder.yudao.module.mes.enums.DictTypeConstants#MES_WM_QUALITY_STATUS}
  65 + * 枚举 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum}
68 66 */
69 67 private Integer qualityStatus;
70 68 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/returnissue/MesWmReturnIssueMapper.java
... ... @@ -19,7 +19,7 @@ public interface MesWmReturnIssueMapper extends BaseMapperX&lt;MesWmReturnIssueDO&gt;
19 19 .likeIfPresent(MesWmReturnIssueDO::getName, reqVO.getName())
20 20 .eqIfPresent(MesWmReturnIssueDO::getWorkstationId, reqVO.getWorkstationId())
21 21 .eqIfPresent(MesWmReturnIssueDO::getWorkOrderId, reqVO.getWorkOrderId())
22   - .eqIfPresent(MesWmReturnIssueDO::getReturnType, reqVO.getReturnType())
  22 + .eqIfPresent(MesWmReturnIssueDO::getType, reqVO.getType())
23 23 .eqIfPresent(MesWmReturnIssueDO::getStatus, reqVO.getStatus())
24 24 .betweenIfPresent(MesWmReturnIssueDO::getReturnDate, reqVO.getReturnDate())
25 25 .orderByDesc(MesWmReturnIssueDO::getId));
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -386,6 +386,8 @@ public interface ErrorCodeConstants {
386 386 ErrorCode WM_RETURN_ISSUE_CANCEL_NOT_ALLOWED = new ErrorCode(1_040_710_004, "生产退料单已完成或已取消,无法取消");
387 387 ErrorCode WM_RETURN_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "生产退料单行不存在");
388 388 ErrorCode WM_RETURN_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "生产退料单明细不存在");
  389 + ErrorCode WM_RETURN_ISSUE_DETAIL_QUANTITY_INVALID = new ErrorCode(1_040_710_201, "退料明细数量必须大于0");
  390 + ErrorCode WM_RETURN_ISSUE_DETAIL_QUANTITY_EXCEED = new ErrorCode(1_040_710_202, "退料明细总数量不能超过退料单行数量");
389 391  
390 392 // ========== MES 仓库管理-供应商退货单(1-040-711-000) ==========
391 393 ErrorCode WM_RETURN_VENDOR_NOT_EXISTS = new ErrorCode(1_040_711_000, "供应商退货单不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmQualityStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.enums.wm;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * MES 质量状态枚举
  11 + *
  12 + * 对应字典 mes_wm_quality_status
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Getter
  17 +@AllArgsConstructor
  18 +public enum MesWmQualityStatusEnum implements ArrayValuable<Integer> {
  19 +
  20 + /**
  21 + * 待检验
  22 + */
  23 + PENDING(0, "待检验"),
  24 + /**
  25 + * 合格
  26 + */
  27 + PASS(1, "合格"),
  28 + /**
  29 + * 不合格
  30 + */
  31 + FAIL(2, "不合格");
  32 +
  33 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmQualityStatusEnum::getStatus).toArray(Integer[]::new);
  34 +
  35 + /**
  36 + * 状态值
  37 + */
  38 + private final Integer status;
  39 + /**
  40 + * 状态名
  41 + */
  42 + private final String name;
  43 +
  44 + @Override
  45 + public Integer[] array() {
  46 + return ARRAYS;
  47 + }
  48 +
  49 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmReturnIssueStatusEnum.java
1 1 package cn.iocoder.yudao.module.mes.enums.wm;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.MesWmReturnIssueSaveReqVO;
4 5 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants;
  6 +import cn.iocoder.yudao.module.mes.service.wm.returnissue.MesWmReturnIssueService;
5 7 import lombok.AllArgsConstructor;
6 8 import lombok.Getter;
7 9  
... ... @@ -16,25 +18,40 @@ import java.util.Arrays;
16 18 @AllArgsConstructor
17 19 public enum MesWmReturnIssueStatusEnum 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/MesWmArrivalNoticeStatusEnum.java 增加注释
20 21 /**
21 22 * 草稿
  23 + *
  24 + * 对应方法:{@link MesWmReturnIssueService#createReturnIssue(MesWmReturnIssueSaveReqVO)}
22 25 */
23 26 PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
24 27 /**
25   - * 待入库(已提交,等待仓库上架入库)
  28 + * 待检验(已确认,等待质检)
  29 + *
  30 + * 对应方法:{@link MesWmReturnIssueService#confirmReturnIssue(Long)}
26 31 */
27   - APPROVING(MesOrderStatusConstants.APPROVING, "待入库"),
  32 + CONFIRMED(MesOrderStatusConstants.CONFIRMED, "待检验"), // "UNCHECK"
28 33 /**
29   - * 已入库(上架完成,等待最终确认)
  34 + * 待上架(检验完成,等待仓库上架)
  35 + *
  36 + * 对应方法:{@link MesWmReturnIssueService#submitReturnIssue(Long)}
30 37 */
31   - APPROVED(MesOrderStatusConstants.APPROVED, "已入库"),
  38 + APPROVING(MesOrderStatusConstants.APPROVING, "待上架"), // "UNSTOCK"
32 39 /**
33   - * 已完成
  40 + * 待执行退料(上架完成,等待执行退料操作)
  41 + *
  42 + * 对应方法:{@link MesWmReturnIssueService#stockReturnIssue(Long)}
  43 + */
  44 + APPROVED(MesOrderStatusConstants.APPROVED, "待执行退料"), // "UNEXECUTE"
  45 + /**
  46 + * 已完成(退料执行完成,库存已更新)
  47 + *
  48 + * 对应方法:{@link MesWmReturnIssueService#finishReturnIssue(Long)}
34 49 */
35 50 FINISHED(MesOrderStatusConstants.FINISHED, "已完成"),
36 51 /**
37 52 * 已取消
  53 + *
  54 + * 对应方法:{@link MesWmReturnIssueService#cancelReturnIssue(Long)}
38 55 */
39 56 CANCELED(MesOrderStatusConstants.CANCELLED, "已取消");
40 57  
... ... @@ -55,3 +72,5 @@ public enum MesWmReturnIssueStatusEnum implements ArrayValuable&lt;Integer&gt; {
55 72 }
56 73  
57 74 }
  75 +
  76 +// DONE @AI:状态流转逻辑已在 MesWmReturnIssueServiceImpl 中实现,参考 confirmReturnIssue、submitReturnIssue、stockReturnIssue、finishReturnIssue 方法
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmReturnIssueTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.enums.wm;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * MES 生产退料类型枚举
  11 + *
  12 + * 对应字典 mes_return_issue_type
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Getter
  17 +@AllArgsConstructor
  18 +public enum MesWmReturnIssueTypeEnum implements ArrayValuable<Integer> {
  19 +
  20 + /**
  21 + * 余料退料(余料退回,直接合格)
  22 + */
  23 + REMAINDER(1, "余料退料"),
  24 + /**
  25 + * 不良退料(不良品退回)
  26 + */
  27 + DEFECTIVE(2, "不良退料"),
  28 + /**
  29 + * 其他退料(其他原因退料)
  30 + */
  31 + OTHER(3, "其他退料");
  32 +
  33 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmReturnIssueTypeEnum::getType).toArray(Integer[]::new);
  34 +
  35 + /**
  36 + * 类型值
  37 + */
  38 + private final Integer type;
  39 + /**
  40 + * 类型名
  41 + */
  42 + private final String name;
  43 +
  44 + @Override
  45 + public Integer[] array() {
  46 + return ARRAYS;
  47 + }
  48 +
  49 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueDetailServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.wm.returnissue;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
3 4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 5 import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.detail.MesWmReturnIssueDetailSaveReqVO;
5 6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueDetailDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO;
6 8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnissue.MesWmReturnIssueDetailMapper;
  9 +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
7 10 import jakarta.annotation.Resource;
8 11 import org.springframework.context.annotation.Lazy;
9 12 import org.springframework.stereotype.Service;
10 13 import org.springframework.validation.annotation.Validated;
11 14  
  15 +import java.math.BigDecimal;
12 16 import java.util.List;
13 17  
14 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
15 19 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_ISSUE_DETAIL_NOT_EXISTS;
  20 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_ISSUE_DETAIL_QUANTITY_EXCEED;
16 21  
17 22 /**
18 23 * MES 生产退料明细 Service 实现类
... ... @@ -28,11 +33,19 @@ public class MesWmReturnIssueDetailServiceImpl implements MesWmReturnIssueDetail
28 33 @Lazy
29 34 private MesWmReturnIssueLineService issueLineService;
30 35  
  36 + @Resource
  37 + private MesWmWarehouseAreaService warehouseAreaService;
  38 +
31 39 @Override
32 40 public Long createReturnIssueDetail(MesWmReturnIssueDetailSaveReqVO createReqVO) {
33 41 // 校验父数据存在
34   - issueLineService.validateReturnIssueLineExists(createReqVO.getLineId());
35   - // TODO @AI:校验物料存在
  42 + MesWmReturnIssueLineDO line = issueLineService.validateReturnIssueLineExists(createReqVO.getLineId());
  43 + // 校验仓库、库区、库位的关联关系
  44 + warehouseAreaService.validateWarehouseAreaExists(
  45 + createReqVO.getWarehouseId(), createReqVO.getLocationId(), createReqVO.getAreaId());
  46 + // 校验明细总数量不超过行数量
  47 + validateDetailQuantityNotExceed(createReqVO.getLineId(), createReqVO.getQuantity(), null, line);
  48 + // TODO @芋艿:【后续搞】不允许物资混放
36 49  
37 50 // 插入
38 51 MesWmReturnIssueDetailDO detail = BeanUtils.toBean(createReqVO, MesWmReturnIssueDetailDO.class);
... ... @@ -45,8 +58,13 @@ public class MesWmReturnIssueDetailServiceImpl implements MesWmReturnIssueDetail
45 58 // 校验存在
46 59 validateReturnIssueDetailExists(updateReqVO.getId());
47 60 // 校验父数据存在
48   - issueLineService.validateReturnIssueLineExists(updateReqVO.getLineId());
49   - // TODO @AI:校验物料存在
  61 + MesWmReturnIssueLineDO line = issueLineService.validateReturnIssueLineExists(updateReqVO.getLineId());
  62 + // 校验仓库、库区、库位的关联关系
  63 + warehouseAreaService.validateWarehouseAreaExists(
  64 + updateReqVO.getWarehouseId(), updateReqVO.getLocationId(), updateReqVO.getAreaId());
  65 + // 校验明细总数量不超过行数量(排除自身)
  66 + validateDetailQuantityNotExceed(updateReqVO.getLineId(), updateReqVO.getQuantity(), updateReqVO.getId(), line);
  67 + // TODO @芋艿:【后续搞】不允许物资混放
50 68  
51 69 // 更新
52 70 MesWmReturnIssueDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnIssueDetailDO.class);
... ... @@ -87,4 +105,26 @@ public class MesWmReturnIssueDetailServiceImpl implements MesWmReturnIssueDetail
87 105 }
88 106 }
89 107  
  108 + /**
  109 + * 校验明细总数量不超过行数量
  110 + *
  111 + * @param lineId 行 ID
  112 + * @param newQuantity 本次新增/修改的数量
  113 + * @param excludeDetailId 排除的明细 ID(更新时排除自身,新增时传 null)
  114 + * @param line 退料单行
  115 + */
  116 + private void validateDetailQuantityNotExceed(Long lineId, BigDecimal newQuantity,
  117 + Long excludeDetailId, MesWmReturnIssueLineDO line) {
  118 + // 计算已有明细总数量(排除自身)
  119 + List<MesWmReturnIssueDetailDO> details = issueDetailMapper.selectListByLineId(lineId);
  120 + BigDecimal existingTotal = CollectionUtils.getSumValue(details,
  121 + detail -> excludeDetailId != null && excludeDetailId.equals(detail.getId())
  122 + ? BigDecimal.ZERO : detail.getQuantity(),
  123 + BigDecimal::add, BigDecimal.ZERO);
  124 + // 校验:已有 + 本次 <= 行数量
  125 + if (existingTotal.add(newQuantity).compareTo(line.getQuantity()) > 0) {
  126 + throw exception(WM_RETURN_ISSUE_DETAIL_QUANTITY_EXCEED);
  127 + }
  128 + }
  129 +
90 130 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineService.java
... ... @@ -74,4 +74,12 @@ public interface MesWmReturnIssueLineService {
74 74 */
75 75 MesWmReturnIssueLineDO validateReturnIssueLineExists(Long id);
76 76  
  77 + /**
  78 + * 刷新退料单下所有行的质量状态(退料类型变更时调用)
  79 + *
  80 + * @param issueId 退料单 ID
  81 + * @param issueType 退料类型
  82 + */
  83 + void updateReturnIssueQualityStatusByIssueId(Long issueId, Integer issueType);
  84 +
77 85 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.wm.returnissue;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.line.MesWmReturnIssueLinePageReqVO;
... ... @@ -7,6 +8,8 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.line.MesWm
7 8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueDO;
8 9 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO;
9 10 import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnissue.MesWmReturnIssueLineMapper;
  11 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
  12 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueTypeEnum;
10 13 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
11 14 import jakarta.annotation.Resource;
12 15 import org.springframework.context.annotation.Lazy;
... ... @@ -44,14 +47,7 @@ public class MesWmReturnIssueLineServiceImpl implements MesWmReturnIssueLineServ
44 47 // 插入
45 48 MesWmReturnIssueLineDO line = BeanUtils.toBean(createReqVO, MesWmReturnIssueLineDO.class);
46 49 // 质量状态自动赋值
47   - // TODO @AI:这里需要在 review 下 @芋艿;
48   - if (Boolean.TRUE.equals(createReqVO.getQcFlag())) {
49   - line.setQualityStatus(0); // 待检
50   - } else if ("RMR".equals(issue.getReturnType())) {
51   - line.setQualityStatus(1); // 合格(余料退回直接合格)
52   - } else {
53   - line.setQualityStatus(2); // 不合格
54   - }
  50 + line.setQualityStatus(calculateQualityStatus(line.getQcFlag(), issue.getType()));
55 51 issueLineMapper.insert(line);
56 52 return line.getId();
57 53 }
... ... @@ -61,12 +57,14 @@ public class MesWmReturnIssueLineServiceImpl implements MesWmReturnIssueLineServ
61 57 // 校验存在
62 58 validateReturnIssueLineExists(updateReqVO.getId());
63 59 // 校验父数据存在
64   - issueService.validateReturnIssueExists(updateReqVO.getIssueId());
  60 + MesWmReturnIssueDO issue = issueService.validateReturnIssueExists(updateReqVO.getIssueId());
65 61 // 校验物料存在
66 62 itemService.validateItemExists(updateReqVO.getItemId());
67 63  
68 64 // 更新
69 65 MesWmReturnIssueLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnIssueLineDO.class);
  66 + // 质量状态自动赋值
  67 + updateObj.setQualityStatus(calculateQualityStatus(updateObj.getQcFlag(), issue.getType()));
70 68 issueLineMapper.updateById(updateObj);
71 69 }
72 70  
... ... @@ -107,4 +105,33 @@ public class MesWmReturnIssueLineServiceImpl implements MesWmReturnIssueLineServ
107 105 return line;
108 106 }
109 107  
  108 + @Override
  109 + public void updateReturnIssueQualityStatusByIssueId(Long issueId, Integer issueType) {
  110 + List<MesWmReturnIssueLineDO> lines = issueLineMapper.selectListByIssueId(issueId);
  111 + for (MesWmReturnIssueLineDO line : lines) {
  112 + Integer newStatus = calculateQualityStatus(line.getQcFlag(), issueType);
  113 + if (ObjUtil.notEqual(newStatus, line.getQualityStatus())) {
  114 + issueLineMapper.updateById(new MesWmReturnIssueLineDO()
  115 + .setId(line.getId()).setQualityStatus(newStatus));
  116 + }
  117 + }
  118 + }
  119 +
  120 + /**
  121 + * 根据 qcFlag 和退料类型,计算质量状态
  122 + *
  123 + * @param qcFlag 是否需要质检
  124 + * @param issueType 退料类型
  125 + * @return 质量状态
  126 + */
  127 + private Integer calculateQualityStatus(Boolean qcFlag, Integer issueType) {
  128 + if (Boolean.TRUE.equals(qcFlag)) {
  129 + return MesWmQualityStatusEnum.PENDING.getStatus(); // 待检
  130 + }
  131 + if (MesWmReturnIssueTypeEnum.REMAINDER.getType().equals(issueType)) {
  132 + return MesWmQualityStatusEnum.PASS.getStatus(); // 合格(余料退回直接合格)
  133 + }
  134 + return MesWmQualityStatusEnum.FAIL.getStatus(); // 不合格
  135 + }
  136 +
110 137 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueService.java
... ... @@ -58,21 +58,28 @@ public interface MesWmReturnIssueService {
58 58 MesWmReturnIssueDO validateReturnIssueExists(Long id);
59 59  
60 60 /**
61   - * 提交生产退料单(草稿 → 待入库)
  61 + * 确认生产退料单(草稿 → 待检验)
  62 + *
  63 + * @param id 编号
  64 + */
  65 + void confirmReturnIssue(Long id);
  66 +
  67 + /**
  68 + * 提交生产退料单(待检验 → 待上架)
62 69 *
63 70 * @param id 编号
64 71 */
65 72 void submitReturnIssue(Long id);
66 73  
67 74 /**
68   - * 入库上架(待入库 → 已入库)
  75 + * 入库上架(待上架 → 待执行退料)
69 76 *
70 77 * @param id 编号
71 78 */
72 79 void stockReturnIssue(Long id);
73 80  
74 81 /**
75   - * 完成退料(已入库 → 已完成),更新库存台账
  82 + * 完成退料(待执行退料 → 已完成),更新库存台账
76 83 *
77 84 * @param id 编号
78 85 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueServiceImpl.java
... ... @@ -48,10 +48,8 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
48 48 @Override
49 49 @Transactional(rollbackFor = Exception.class)
50 50 public Long createReturnIssue(MesWmReturnIssueSaveReqVO createReqVO) {
51   - // 1. 校验关联数据(workOrderId 非必填)
52   - if (createReqVO.getWorkOrderId() != null) {
53   - workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
54   - }
  51 + // 1. 校验关联数据
  52 + workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
55 53 if (createReqVO.getWorkstationId() != null) {
56 54 workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
57 55 }
... ... @@ -67,11 +65,9 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
67 65 @Transactional(rollbackFor = Exception.class)
68 66 public void updateReturnIssue(MesWmReturnIssueSaveReqVO updateReqVO) {
69 67 // 1.1 校验存在 + 准备中状态
70   - validateReturnIssueExistsAndPrepare(updateReqVO.getId());
  68 + MesWmReturnIssueDO oldIssue = validateReturnIssueExistsAndPrepare(updateReqVO.getId());
71 69 // 1.2 校验关联数据
72   - if (updateReqVO.getWorkOrderId() != null) {
73   - workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
74   - }
  70 + workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
75 71 if (updateReqVO.getWorkstationId() != null) {
76 72 workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());
77 73 }
... ... @@ -79,6 +75,11 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
79 75 // 2. 更新主表
80 76 MesWmReturnIssueDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnIssueDO.class);
81 77 issueMapper.updateById(updateObj);
  78 +
  79 + // 3. 退料类型变更时,刷新所有行的质量状态
  80 + if (ObjUtil.notEqual(oldIssue.getType(), updateReqVO.getType())) {
  81 + issueLineService.updateReturnIssueQualityStatusByIssueId(updateReqVO.getId(), updateReqVO.getType());
  82 + }
82 83 }
83 84  
84 85 @Override
... ... @@ -107,7 +108,7 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
107 108  
108 109 @Override
109 110 @Transactional(rollbackFor = Exception.class)
110   - public void submitReturnIssue(Long id) {
  111 + public void confirmReturnIssue(Long id) {
111 112 // 校验存在 + 草稿状态
112 113 validateReturnIssueExistsAndPrepare(id);
113 114 // 校验至少有一条行
... ... @@ -116,7 +117,26 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
116 117 throw exception(WM_RETURN_ISSUE_NO_LINE);
117 118 }
118 119  
119   - // 提交(草稿 → 待入库)
  120 + // 确认(草稿 → 待检验)
  121 + issueMapper.updateById(new MesWmReturnIssueDO()
  122 + .setId(id).setStatus(MesWmReturnIssueStatusEnum.CONFIRMED.getStatus()));
  123 + }
  124 +
  125 + @Override
  126 + @Transactional(rollbackFor = Exception.class)
  127 + public void submitReturnIssue(Long id) {
  128 + // 校验存在 + 待检验状态
  129 + MesWmReturnIssueDO issue = validateReturnIssueExists(id);
  130 + if (ObjUtil.notEqual(MesWmReturnIssueStatusEnum.CONFIRMED.getStatus(), issue.getStatus())) {
  131 + throw exception(WM_RETURN_ISSUE_STATUS_INVALID);
  132 + }
  133 + // 校验至少有一条行
  134 + List<MesWmReturnIssueLineDO> lines = issueLineService.getReturnIssueLineListByIssueId(id);
  135 + if (CollUtil.isEmpty(lines)) {
  136 + throw exception(WM_RETURN_ISSUE_NO_LINE);
  137 + }
  138 +
  139 + // 提交(待检验 → 待上架)
120 140 issueMapper.updateById(new MesWmReturnIssueDO()
121 141 .setId(id).setStatus(MesWmReturnIssueStatusEnum.APPROVING.getStatus()));
122 142 }
... ... @@ -129,7 +149,7 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
129 149 if (ObjUtil.notEqual(MesWmReturnIssueStatusEnum.APPROVING.getStatus(), issue.getStatus())) {
130 150 throw exception(WM_RETURN_ISSUE_STATUS_INVALID);
131 151 }
132   - // 入库上架(待入库 → 已入库)
  152 + // 入库上架(待上架 → 待执行退料)
133 153 issueMapper.updateById(new MesWmReturnIssueDO()
134 154 .setId(id).setStatus(MesWmReturnIssueStatusEnum.APPROVED.getStatus()));
135 155 }
... ... @@ -143,6 +163,7 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
143 163 throw exception(WM_RETURN_ISSUE_STATUS_INVALID);
144 164 }
145 165  
  166 + // 完成退料(待执行退料 → 已完成),更新库存台账
146 167 // 遍历所有明细,更新库存台账(增加库存,与领料出库相反)
147 168 // TODO @芋艿:【后续在弄】这里可能有点问题;缺少库存更新;后面在弄;
148 169 List<MesWmReturnIssueDetailDO> details = issueDetailService.getReturnIssueDetailListByIssueId(id);
... ...