Commit b567632e121ee7f6ce95f3aa3a8329dd7ba9a160

Authored by YunaiV
1 parent 1f53c39c

refactor(mes-qc): 优化 IPQC/IQC 质检模块

  IPQC 优化:
  - 修复 TODO AI 项:模板检索方法、tool 字段重构、删除冗余字段
  - 新增废品数量字段(工废/料废/其他废品)及验证
  - 添加检测人员和物料的存在性验证

  IQC 优化:
  - 检测人员由后端自动设置改为前端传递
  - 添加检测人员存在性验证
Showing 14 changed files with 131 additions and 87 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/ipqc/MesQcIpqcLineController.java
@@ -85,13 +85,6 @@ public class MesQcIpqcLineController { @@ -85,13 +85,6 @@ public class MesQcIpqcLineController {
85 .setIndicatorType(indicator.getType())); 85 .setIndicatorType(indicator.getType()));
86 findAndThen(unitMeasureMap, vo.getUnitMeasureId(), 86 findAndThen(unitMeasureMap, vo.getUnitMeasureId(),
87 unit -> vo.setUnitMeasureName(unit.getName())); 87 unit -> vo.setUnitMeasureName(unit.getName()));
88 - // 逐个查询工具名称(工具数量通常较少)  
89 - if (vo.getToolId() != null) {  
90 - MesTmToolDO tool = toolService.getTool(vo.getToolId());  
91 - if (tool != null) {  
92 - vo.setToolName(tool.getName());  
93 - }  
94 - }  
95 }); 88 });
96 } 89 }
97 90
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/ipqc/vo/MesQcIpqcPageReqVO.java
@@ -26,9 +26,6 @@ public class MesQcIpqcPageReqVO extends PageParam { @@ -26,9 +26,6 @@ public class MesQcIpqcPageReqVO extends PageParam {
26 @Schema(description = "生产工单 ID", example = "10") 26 @Schema(description = "生产工单 ID", example = "10")
27 private Long workOrderId; 27 private Long workOrderId;
28 28
29 - @Schema(description = "工位 ID", example = "30")  
30 - private Long workstationId;  
31 -  
32 @Schema(description = "产品物料 ID", example = "50") 29 @Schema(description = "产品物料 ID", example = "50")
33 private Long itemId; 30 private Long itemId;
34 31
@@ -41,8 +38,4 @@ public class MesQcIpqcPageReqVO extends PageParam { @@ -41,8 +38,4 @@ public class MesQcIpqcPageReqVO extends PageParam {
41 @Schema(description = "检测人员用户 ID", example = "1") 38 @Schema(description = "检测人员用户 ID", example = "1")
42 private Long inspectorUserId; 39 private Long inspectorUserId;
43 40
44 - @Schema(description = "检测日期")  
45 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
46 - private LocalDateTime[] inspectDate;  
47 -  
48 } 41 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/ipqc/vo/MesQcIpqcSaveReqVO.java
1 package cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo; 1 package cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo;
2 2
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.AssertTrue;
  7 +import jakarta.validation.constraints.DecimalMin;
4 import jakarta.validation.constraints.NotEmpty; 8 import jakarta.validation.constraints.NotEmpty;
5 import jakarta.validation.constraints.NotNull; 9 import jakarta.validation.constraints.NotNull;
6 import lombok.Data; 10 import lombok.Data;
@@ -38,10 +42,6 @@ public class MesQcIpqcSaveReqVO { @@ -38,10 +42,6 @@ public class MesQcIpqcSaveReqVO {
38 @Schema(description = "来源单据 ID", example = "200") 42 @Schema(description = "来源单据 ID", example = "200")
39 private Long sourceDocId; 43 private Long sourceDocId;
40 44
41 - // TODO @AI:  
42 - @Schema(description = "来源单据编号", example = "FB20250101001")  
43 - private String sourceDocCode;  
44 -  
45 @Schema(description = "来源单据行 ID", example = "300") 45 @Schema(description = "来源单据行 ID", example = "300")
46 private Long sourceLineId; 46 private Long sourceLineId;
47 47
@@ -51,6 +51,7 @@ public class MesQcIpqcSaveReqVO { @@ -51,6 +51,7 @@ public class MesQcIpqcSaveReqVO {
51 @NotNull(message = "生产工单不能为空") 51 @NotNull(message = "生产工单不能为空")
52 private Long workOrderId; 52 private Long workOrderId;
53 53
  54 + // TODO @芋艿:【不确定】这里要怎么弄
54 @Schema(description = "生产任务 ID", example = "20") 55 @Schema(description = "生产任务 ID", example = "20")
55 private Long taskId; 56 private Long taskId;
56 57
@@ -58,6 +59,7 @@ public class MesQcIpqcSaveReqVO { @@ -58,6 +59,7 @@ public class MesQcIpqcSaveReqVO {
58 @NotNull(message = "工位不能为空") 59 @NotNull(message = "工位不能为空")
59 private Long workstationId; 60 private Long workstationId;
60 61
  62 + // TODO @芋艿:【不确定】这里要怎么弄
61 @Schema(description = "工序 ID", example = "40") 63 @Schema(description = "工序 ID", example = "40")
62 private Long processId; 64 private Long processId;
63 65
@@ -68,22 +70,34 @@ public class MesQcIpqcSaveReqVO { @@ -68,22 +70,34 @@ public class MesQcIpqcSaveReqVO {
68 70
69 // ========== 数量 ========== 71 // ========== 数量 ==========
70 72
71 - @Schema(description = "检测数量", example = "100") 73 + @Schema(description = "检测数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  74 + @NotNull(message = "检测数量不能为空")
  75 + @DecimalMin(value = "0", message = "检测数量不能小于 0")
72 private BigDecimal checkQuantity; 76 private BigDecimal checkQuantity;
73 77
74 - @Schema(description = "合格品数量", example = "95") 78 + @Schema(description = "合格品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "95")
  79 + @NotNull(message = "合格品数量不能为空")
  80 + @DecimalMin(value = "0", message = "合格品数量不能小于 0")
75 private BigDecimal qualifiedQuantity; 81 private BigDecimal qualifiedQuantity;
76 82
77 - @Schema(description = "不合格品数量", example = "5") 83 + @Schema(description = "不合格品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
  84 + @NotNull(message = "不合格品数量不能为空")
  85 + @DecimalMin(value = "0", message = "不合格品数量不能小于 0")
78 private BigDecimal unqualifiedQuantity; 86 private BigDecimal unqualifiedQuantity;
79 87
80 - @Schema(description = "工废数量", example = "2") 88 + @Schema(description = "工废数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  89 + @NotNull(message = "工废数量不能为空")
  90 + @DecimalMin(value = "0", message = "工废数量不能小于 0")
81 private BigDecimal laborScrapQuantity; 91 private BigDecimal laborScrapQuantity;
82 92
83 - @Schema(description = "料废数量", example = "2") 93 + @Schema(description = "料废数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  94 + @NotNull(message = "料废数量不能为空")
  95 + @DecimalMin(value = "0", message = "料废数量不能小于 0")
84 private BigDecimal materialScrapQuantity; 96 private BigDecimal materialScrapQuantity;
85 97
86 - @Schema(description = "其他废品数量", example = "1") 98 + @Schema(description = "其他废品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  99 + @NotNull(message = "其他废品数量不能为空")
  100 + @DecimalMin(value = "0", message = "其他废品数量不能小于 0")
87 private BigDecimal otherScrapQuantity; 101 private BigDecimal otherScrapQuantity;
88 102
89 // ========== 检验 ========== 103 // ========== 检验 ==========
@@ -100,4 +114,23 @@ public class MesQcIpqcSaveReqVO { @@ -100,4 +114,23 @@ public class MesQcIpqcSaveReqVO {
100 @Schema(description = "备注", example = "备注") 114 @Schema(description = "备注", example = "备注")
101 private String remark; 115 private String remark;
102 116
  117 + @AssertTrue(message = "检测数量必须等于合格品数量与不合格品数量之和")
  118 + @JsonIgnore
  119 + public boolean isQuantityValid() {
  120 + if (ObjUtil.hasNull(checkQuantity, qualifiedQuantity, unqualifiedQuantity)) {
  121 + return true; // @NotNull 会处理 null
  122 + }
  123 + return checkQuantity.compareTo(qualifiedQuantity.add(unqualifiedQuantity)) == 0;
  124 + }
  125 +
  126 + @AssertTrue(message = "工废、料废、其他废品数量之和不能超过不合格品数量")
  127 + @JsonIgnore
  128 + public boolean isScrapQuantityValid() {
  129 + if (ObjUtil.hasNull(unqualifiedQuantity, laborScrapQuantity, materialScrapQuantity, otherScrapQuantity)) {
  130 + return true; // @NotNull 会处理 null
  131 + }
  132 + BigDecimal scrapSum = laborScrapQuantity.add(materialScrapQuantity).add(otherScrapQuantity);
  133 + return scrapSum.compareTo(unqualifiedQuantity) <= 0;
  134 + }
  135 +
103 } 136 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/ipqc/vo/line/MesQcIpqcLineRespVO.java
@@ -30,11 +30,8 @@ public class MesQcIpqcLineRespVO { @@ -30,11 +30,8 @@ public class MesQcIpqcLineRespVO {
30 @Schema(description = "检测指标类型", example = "QUANTITATIVE") 30 @Schema(description = "检测指标类型", example = "QUANTITATIVE")
31 private String indicatorType; 31 private String indicatorType;
32 32
33 - @Schema(description = "检测工具 ID", example = "5")  
34 - private Long toolId;  
35 -  
36 - @Schema(description = "检测工具名称", example = "卡尺")  
37 - private String toolName; 33 + @Schema(description = "检测工具", example = "卡尺")
  34 + private String tool;
38 35
39 @Schema(description = "检测方法", example = "目测") 36 @Schema(description = "检测方法", example = "目测")
40 private String checkMethod; 37 private String checkMethod;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/MesQcIqcController.java
@@ -63,14 +63,14 @@ public class MesQcIqcController { @@ -63,14 +63,14 @@ public class MesQcIqcController {
63 @Operation(summary = "创建来料检验单") 63 @Operation(summary = "创建来料检验单")
64 @PreAuthorize("@ss.hasPermission('mes:qc-iqc:create')") 64 @PreAuthorize("@ss.hasPermission('mes:qc-iqc:create')")
65 public CommonResult<Long> createIqc(@Valid @RequestBody MesQcIqcSaveReqVO createReqVO) { 65 public CommonResult<Long> createIqc(@Valid @RequestBody MesQcIqcSaveReqVO createReqVO) {
66 - return success(iqcService.createIqc(createReqVO, getLoginUserId())); 66 + return success(iqcService.createIqc(createReqVO));
67 } 67 }
68 68
69 @PutMapping("/update") 69 @PutMapping("/update")
70 @Operation(summary = "更新来料检验单") 70 @Operation(summary = "更新来料检验单")
71 @PreAuthorize("@ss.hasPermission('mes:qc-iqc:update')") 71 @PreAuthorize("@ss.hasPermission('mes:qc-iqc:update')")
72 public CommonResult<Boolean> updateIqc(@Valid @RequestBody MesQcIqcSaveReqVO updateReqVO) { 72 public CommonResult<Boolean> updateIqc(@Valid @RequestBody MesQcIqcSaveReqVO updateReqVO) {
73 - iqcService.updateIqc(updateReqVO, getLoginUserId()); 73 + iqcService.updateIqc(updateReqVO);
74 return success(true); 74 return success(true);
75 } 75 }
76 76
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcSaveReqVO.java
@@ -71,6 +71,14 @@ public class MesQcIqcSaveReqVO { @@ -71,6 +71,14 @@ public class MesQcIqcSaveReqVO {
71 71
72 // ========== 检验 ========== 72 // ========== 检验 ==========
73 73
  74 + @Schema(description = "检测人员用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  75 + @NotNull(message = "检测人员不能为空")
  76 + private Long inspectorUserId;
  77 +
  78 + @Schema(description = "检测日期", requiredMode = Schema.RequiredMode.REQUIRED)
  79 + @NotNull(message = "检测日期不能为空")
  80 + private LocalDateTime inspectDate;
  81 +
74 @Schema(description = "检测结果", example = "1") 82 @Schema(description = "检测结果", example = "1")
75 private Integer checkResult; 83 private Integer checkResult;
76 84
@@ -78,10 +86,6 @@ public class MesQcIqcSaveReqVO { @@ -78,10 +86,6 @@ public class MesQcIqcSaveReqVO {
78 @NotNull(message = "来料日期不能为空") 86 @NotNull(message = "来料日期不能为空")
79 private LocalDateTime receiveDate; 87 private LocalDateTime receiveDate;
80 88
81 - @Schema(description = "检测日期", requiredMode = Schema.RequiredMode.REQUIRED)  
82 - @NotNull(message = "检测日期不能为空")  
83 - private LocalDateTime inspectDate;  
84 -  
85 @Schema(description = "备注", example = "备注") 89 @Schema(description = "备注", example = "备注")
86 private String remark; 90 private String remark;
87 91
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/ipqc/MesQcIpqcDO.java
@@ -65,11 +65,6 @@ public class MesQcIpqcDO extends BaseDO { @@ -65,11 +65,6 @@ public class MesQcIpqcDO extends BaseDO {
65 * 来源单据类型 65 * 来源单据类型
66 */ 66 */
67 private String sourceDocType; 67 private String sourceDocType;
68 - // TODO @AI:sourceDocCode 是不是不用存储?(晚点在处理,对应模块还没搞完)  
69 - /**  
70 - * 来源单据编号  
71 - */  
72 - private String sourceDocCode;  
73 /** 68 /**
74 * 来源单据行 ID 69 * 来源单据行 ID
75 */ 70 */
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/ipqc/MesQcIpqcLineDO.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc;
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.unitmeasure.MesMdUnitMeasureDO; 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
5 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; 5 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
6 -import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO;  
7 import com.baomidou.mybatisplus.annotation.KeySequence; 6 import com.baomidou.mybatisplus.annotation.KeySequence;
8 import com.baomidou.mybatisplus.annotation.TableId; 7 import com.baomidou.mybatisplus.annotation.TableId;
9 import com.baomidou.mybatisplus.annotation.TableName; 8 import com.baomidou.mybatisplus.annotation.TableName;
@@ -44,11 +43,11 @@ public class MesQcIpqcLineDO extends BaseDO { @@ -44,11 +43,11 @@ public class MesQcIpqcLineDO extends BaseDO {
44 */ 43 */
45 private Long indicatorId; 44 private Long indicatorId;
46 /** 45 /**
47 - * 检测工具 ID 46 + * 检测工具
48 * 47 *
49 - * 关联 {@link MesTmToolDO#getId()} 48 + * 冗余 {@link MesQcIndicatorDO#getTool()}
50 */ 49 */
51 - private Long toolId; 50 + private String tool;
52 /** 51 /**
53 * 检测方法 52 * 检测方法
54 */ 53 */
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/ipqc/MesQcIpqcMapper.java
@@ -20,11 +20,9 @@ public interface MesQcIpqcMapper extends BaseMapperX&lt;MesQcIpqcDO&gt; { @@ -20,11 +20,9 @@ public interface MesQcIpqcMapper extends BaseMapperX&lt;MesQcIpqcDO&gt; {
20 .likeIfPresent(MesQcIpqcDO::getCode, reqVO.getCode()) 20 .likeIfPresent(MesQcIpqcDO::getCode, reqVO.getCode())
21 .eqIfPresent(MesQcIpqcDO::getType, reqVO.getType()) 21 .eqIfPresent(MesQcIpqcDO::getType, reqVO.getType())
22 .eqIfPresent(MesQcIpqcDO::getWorkOrderId, reqVO.getWorkOrderId()) 22 .eqIfPresent(MesQcIpqcDO::getWorkOrderId, reqVO.getWorkOrderId())
23 - .eqIfPresent(MesQcIpqcDO::getWorkstationId, reqVO.getWorkstationId())  
24 .eqIfPresent(MesQcIpqcDO::getItemId, reqVO.getItemId()) 23 .eqIfPresent(MesQcIpqcDO::getItemId, reqVO.getItemId())
25 .eqIfPresent(MesQcIpqcDO::getCheckResult, reqVO.getCheckResult()) 24 .eqIfPresent(MesQcIpqcDO::getCheckResult, reqVO.getCheckResult())
26 .eqIfPresent(MesQcIpqcDO::getStatus, reqVO.getStatus()) 25 .eqIfPresent(MesQcIpqcDO::getStatus, reqVO.getStatus())
27 - .betweenIfPresent(MesQcIpqcDO::getInspectDate, reqVO.getInspectDate())  
28 .eqIfPresent(MesQcIpqcDO::getInspectorUserId, reqVO.getInspectorUserId()) 26 .eqIfPresent(MesQcIpqcDO::getInspectorUserId, reqVO.getInspectorUserId())
29 .orderByDesc(MesQcIpqcDO::getId)); 27 .orderByDesc(MesQcIpqcDO::getId));
30 } 28 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -261,6 +261,7 @@ public interface ErrorCodeConstants { @@ -261,6 +261,7 @@ public interface ErrorCodeConstants {
261 ErrorCode QC_IPQC_NOT_PREPARE = new ErrorCode(1_040_604_002, "只有草稿状态的检验单才可操作"); 261 ErrorCode QC_IPQC_NOT_PREPARE = new ErrorCode(1_040_604_002, "只有草稿状态的检验单才可操作");
262 ErrorCode QC_IPQC_QUANTITY_MISMATCH = new ErrorCode(1_040_604_004, "合格品与不合格品数量之和须等于检测数量"); 262 ErrorCode QC_IPQC_QUANTITY_MISMATCH = new ErrorCode(1_040_604_004, "合格品与不合格品数量之和须等于检测数量");
263 ErrorCode QC_IPQC_NO_TEMPLATE = new ErrorCode(1_040_604_005, "当前产品未配置 IPQC 检测模板"); 263 ErrorCode QC_IPQC_NO_TEMPLATE = new ErrorCode(1_040_604_005, "当前产品未配置 IPQC 检测模板");
  264 + ErrorCode QC_IPQC_CHECK_RESULT_EMPTY = new ErrorCode(1_040_604_006, "完成检验单前,检测结果必须填写");
264 // ========== MES 质量管理-过程检验行(1-040-604-100) ========== 265 // ========== MES 质量管理-过程检验行(1-040-604-100) ==========
265 ErrorCode QC_IPQC_LINE_NOT_EXISTS = new ErrorCode(1_040_604_100, "过程检验行不存在"); 266 ErrorCode QC_IPQC_LINE_NOT_EXISTS = new ErrorCode(1_040_604_100, "过程检验行不存在");
266 267
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcLineServiceImpl.java
@@ -5,21 +5,25 @@ import cn.hutool.core.util.ObjUtil; @@ -5,21 +5,25 @@ import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.line.MesQcIpqcLinePageReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.line.MesQcIpqcLinePageReqVO;
7 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; 7 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
8 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcLineDO; 9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcLineDO;
9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO;
10 import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcLineMapper; 11 import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcLineMapper;
11 import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateIndicatorMapper; 12 import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateIndicatorMapper;
12 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
  14 +import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService;
13 import jakarta.annotation.Resource; 15 import jakarta.annotation.Resource;
14 import org.springframework.stereotype.Service; 16 import org.springframework.stereotype.Service;
15 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
16 18
17 import java.util.ArrayList; 19 import java.util.ArrayList;
18 import java.util.List; 20 import java.util.List;
  21 +import java.util.Map;
19 import java.util.Objects; 22 import java.util.Objects;
20 23
21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
22 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 25 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  26 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
23 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; 27 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
24 28
25 /** 29 /**
@@ -36,6 +40,9 @@ public class MesQcIpqcLineServiceImpl implements MesQcIpqcLineService { @@ -36,6 +40,9 @@ public class MesQcIpqcLineServiceImpl implements MesQcIpqcLineService {
36 @Resource 40 @Resource
37 private MesQcTemplateIndicatorMapper templateIndicatorMapper; 41 private MesQcTemplateIndicatorMapper templateIndicatorMapper;
38 42
  43 + @Resource
  44 + private MesQcIndicatorService indicatorService;
  45 +
39 @Override 46 @Override
40 public MesQcIpqcLineDO getIpqcLine(Long id) { 47 public MesQcIpqcLineDO getIpqcLine(Long id) {
41 return ipqcLineMapper.selectById(id); 48 return ipqcLineMapper.selectById(id);
@@ -53,14 +60,22 @@ public class MesQcIpqcLineServiceImpl implements MesQcIpqcLineService { @@ -53,14 +60,22 @@ public class MesQcIpqcLineServiceImpl implements MesQcIpqcLineService {
53 60
54 @Override 61 @Override
55 public void createLinesFromTemplate(Long ipqcId, Long templateId) { 62 public void createLinesFromTemplate(Long ipqcId, Long templateId) {
56 - List<MesQcTemplateIndicatorDO> indicators = templateIndicatorMapper.selectListByTemplateId(templateId);  
57 - List<MesQcIpqcLineDO> lines = convertList(indicators, indicator -> new MesQcIpqcLineDO()  
58 - .setIpqcId(ipqcId).setIndicatorId(indicator.getIndicatorId())  
59 - .setToolId(null) // TODO @芋艿:模板指标暂无 toolId,后续可扩展  
60 - .setCheckMethod(indicator.getCheckMethod())  
61 - .setStandardValue(indicator.getStandardValue()).setUnitMeasureId(indicator.getUnitMeasureId())  
62 - .setMaxThreshold(indicator.getThresholdMax()).setMinThreshold(indicator.getThresholdMin())  
63 - .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0)); 63 + List<MesQcTemplateIndicatorDO> templateIndicators = templateIndicatorMapper.selectListByTemplateId(templateId);
  64 + if (CollUtil.isEmpty(templateIndicators)) {
  65 + return;
  66 + }
  67 + Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(
  68 + convertSet(templateIndicators, MesQcTemplateIndicatorDO::getIndicatorId));
  69 + List<MesQcIpqcLineDO> lines = convertList(templateIndicators, templateIndicator -> {
  70 + MesQcIndicatorDO indicator = indicatorMap.get(templateIndicator.getIndicatorId());
  71 + return new MesQcIpqcLineDO()
  72 + .setIpqcId(ipqcId).setIndicatorId(templateIndicator.getIndicatorId())
  73 + .setTool(indicator != null ? indicator.getTool() : null)
  74 + .setCheckMethod(templateIndicator.getCheckMethod())
  75 + .setStandardValue(templateIndicator.getStandardValue()).setUnitMeasureId(templateIndicator.getUnitMeasureId())
  76 + .setMaxThreshold(templateIndicator.getThresholdMax()).setMinThreshold(templateIndicator.getThresholdMin())
  77 + .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0);
  78 + });
64 ipqcLineMapper.insertBatch(lines); 79 ipqcLineMapper.insertBatch(lines);
65 } 80 }
66 81
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
@@ -8,15 +8,17 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcSaveReqV @@ -8,15 +8,17 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcSaveReqV
8 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; 8 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; 9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO;
10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO;
11 -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO; 11 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO;
12 import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcMapper; 12 import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcMapper;
13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
14 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusEnum; 14 import cn.iocoder.yudao.module.mes.enums.MesOrderStatusEnum;
15 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; 15 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  16 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
16 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; 17 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService;
17 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; 18 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
18 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; 19 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
19 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService; 20 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService;
  21 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
20 import jakarta.annotation.Resource; 22 import jakarta.annotation.Resource;
21 import org.springframework.context.annotation.Lazy; 23 import org.springframework.context.annotation.Lazy;
22 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
@@ -55,8 +57,14 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -55,8 +57,14 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
55 private MesMdWorkstationService workstationService; 57 private MesMdWorkstationService workstationService;
56 @Resource 58 @Resource
57 @Lazy 59 @Lazy
  60 + private MesMdItemService itemService;
  61 + @Resource
  62 + @Lazy
58 private MesQcDefectRecordService defectRecordService; 63 private MesQcDefectRecordService defectRecordService;
59 64
  65 + @Resource
  66 + private AdminUserApi adminUserApi;
  67 +
60 @Override 68 @Override
61 @Transactional(rollbackFor = Exception.class) 69 @Transactional(rollbackFor = Exception.class)
62 public Long createIpqc(MesQcIpqcSaveReqVO createReqVO) { 70 public Long createIpqc(MesQcIpqcSaveReqVO createReqVO) {
@@ -66,23 +74,24 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -66,23 +74,24 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
66 MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()); 74 MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
67 // 1.3 校验工位存在 75 // 1.3 校验工位存在
68 workstationService.validateWorkstationExists(createReqVO.getWorkstationId()); 76 workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
69 - // 1.4 根据产品 + 检验类型自动匹配模板  
70 - // TODO @AI:参考 iqc,应该通过 getRequiredTemplatesByItemIdAndType 方法;  
71 - MesQcTemplateDO template = templateDetailService.getTemplateByItemIdAndType( 77 + // 1.4 校验检测人员存在
  78 + adminUserApi.validateUser(createReqVO.getInspectorUserId());
  79 + // 1.5 校验物料存在
  80 + itemService.validateItemExists(createReqVO.getItemId());
  81 + // 1.6 根据产品 + 检验类型自动匹配模板
  82 + MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType(
72 workOrder.getProductId(), MesQcTypeEnum.IPQC.getType()); 83 workOrder.getProductId(), MesQcTypeEnum.IPQC.getType());
73 - if (template == null) {  
74 - throw exception(QC_IPQC_NO_TEMPLATE);  
75 - } 84 + Long templateId = templateItem.getTemplateId();
76 // TODO @AI:processId 不应该是前端传递,而是通过 workstation + work order + route 表,联合查询出来的; 85 // TODO @AI:processId 不应该是前端传递,而是通过 workstation + work order + route 表,联合查询出来的;
77 86
78 // 2. 插入主表 87 // 2. 插入主表
79 MesQcIpqcDO ipqc = BeanUtils.toBean(createReqVO, MesQcIpqcDO.class); 88 MesQcIpqcDO ipqc = BeanUtils.toBean(createReqVO, MesQcIpqcDO.class);
80 ipqc.setItemId(workOrder.getProductId()); 89 ipqc.setItemId(workOrder.getProductId());
81 - ipqc.setTemplateId(template.getId()).setStatus(MesOrderStatusEnum.DRAFT.getType()); 90 + ipqc.setTemplateId(templateId).setStatus(MesOrderStatusEnum.DRAFT.getType());
82 ipqcMapper.insert(ipqc); 91 ipqcMapper.insert(ipqc);
83 92
84 // 3. 从模板指标自动生成检验行 93 // 3. 从模板指标自动生成检验行
85 - ipqcLineService.createLinesFromTemplate(ipqc.getId(), template.getId()); 94 + ipqcLineService.createLinesFromTemplate(ipqc.getId(), templateId);
86 return ipqc.getId(); 95 return ipqc.getId();
87 } 96 }
88 97
@@ -92,6 +101,14 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -92,6 +101,14 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
92 validateIpqcStatusPrepare(updateReqVO.getId()); 101 validateIpqcStatusPrepare(updateReqVO.getId());
93 // 1.2 校验编号唯一 102 // 1.2 校验编号唯一
94 validateIpqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); 103 validateIpqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
  104 + // 1.3 校验工单存在
  105 + workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
  106 + // 1.4 校验工位存在
  107 + workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());
  108 + // 1.5 校验检测人员存在
  109 + adminUserApi.validateUser(updateReqVO.getInspectorUserId());
  110 + // 1.6 校验物料存在
  111 + itemService.validateItemExists(updateReqVO.getItemId());
95 112
96 // 2. 更新 113 // 2. 更新
97 MesQcIpqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIpqcDO.class); 114 MesQcIpqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIpqcDO.class);
@@ -102,13 +119,9 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -102,13 +119,9 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
102 public void completeIpqc(Long id) { 119 public void completeIpqc(Long id) {
103 // 1.1 校验存在 + 草稿状态 120 // 1.1 校验存在 + 草稿状态
104 MesQcIpqcDO ipqc = validateIpqcStatusPrepare(id); 121 MesQcIpqcDO ipqc = validateIpqcStatusPrepare(id);
105 - // 1.2 校验合格品 + 不合格品 = 检测数量  
106 - if (ipqc.getCheckQuantity() != null && ipqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) {  
107 - BigDecimal qualified = ipqc.getQualifiedQuantity() != null ? ipqc.getQualifiedQuantity() : BigDecimal.ZERO;  
108 - BigDecimal unqualified = ipqc.getUnqualifiedQuantity() != null ? ipqc.getUnqualifiedQuantity() : BigDecimal.ZERO;  
109 - if (qualified.add(unqualified).compareTo(ipqc.getCheckQuantity()) != 0) {  
110 - throw exception(QC_IPQC_QUANTITY_MISMATCH);  
111 - } 122 + // 1.2 校验检测结论必填
  123 + if (ipqc.getCheckResult() == null) {
  124 + throw exception(QC_IPQC_CHECK_RESULT_EMPTY);
112 } 125 }
113 126
114 // 2. 更新状态为已完成 127 // 2. 更新状态为已完成
@@ -179,11 +192,14 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -179,11 +192,14 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
179 192
180 @Override 193 @Override
181 public void recalculateDefectStats(Long ipqcId, List<MesQcDefectRecordDO> records) { 194 public void recalculateDefectStats(Long ipqcId, List<MesQcDefectRecordDO> records) {
  195 + MesQcIpqcDO ipqc = validateIpqcExists(ipqcId);
182 // 1. 行级缺陷统计 196 // 1. 行级缺陷统计
183 ipqcLineService.recalculateLineDefectStats(ipqcId, records); 197 ipqcLineService.recalculateLineDefectStats(ipqcId, records);
184 198
185 // 2.1 汇总主表的缺陷数量 199 // 2.1 汇总主表的缺陷数量
186 - int totalCritical = 0, totalMajor = 0, totalMinor = 0; 200 + int totalCritical = 0;
  201 + int totalMajor = 0;
  202 + int totalMinor = 0;
187 for (MesQcDefectRecordDO record : records) { 203 for (MesQcDefectRecordDO record : records) {
188 int quantity = ObjUtil.defaultIfNull(record.getQuantity(), 1); 204 int quantity = ObjUtil.defaultIfNull(record.getQuantity(), 1);
189 if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) { 205 if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {
@@ -196,8 +212,7 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -196,8 +212,7 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
196 throw exception(QC_DEFECT_RECORD_LEVEL_UNKNOWN); 212 throw exception(QC_DEFECT_RECORD_LEVEL_UNKNOWN);
197 } 213 }
198 } 214 }
199 - // 2.2 计算缺陷率(IPQC 的 checkQuantity 是 BigDecimal)  
200 - MesQcIpqcDO ipqc = validateIpqcExists(ipqcId); 215 + // 2.2 计算缺陷率
201 BigDecimal criticalRate = BigDecimal.ZERO; 216 BigDecimal criticalRate = BigDecimal.ZERO;
202 BigDecimal majorRate = BigDecimal.ZERO; 217 BigDecimal majorRate = BigDecimal.ZERO;
203 BigDecimal minorRate = BigDecimal.ZERO; 218 BigDecimal minorRate = BigDecimal.ZERO;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcService.java
@@ -22,18 +22,16 @@ public interface MesQcIqcService { @@ -22,18 +22,16 @@ public interface MesQcIqcService {
22 * 创建来料检验单 22 * 创建来料检验单
23 * 23 *
24 * @param createReqVO 创建信息 24 * @param createReqVO 创建信息
25 - * @param inspectorUserId 检测人员用户 ID  
26 * @return 编号 25 * @return 编号
27 */ 26 */
28 - Long createIqc(@Valid MesQcIqcSaveReqVO createReqVO, Long inspectorUserId); 27 + Long createIqc(@Valid MesQcIqcSaveReqVO createReqVO);
29 28
30 /** 29 /**
31 * 更新来料检验单 30 * 更新来料检验单
32 * 31 *
33 * @param updateReqVO 更新信息 32 * @param updateReqVO 更新信息
34 - * @param inspectorUserId 检测人员用户 ID  
35 */ 33 */
36 - void updateIqc(@Valid MesQcIqcSaveReqVO updateReqVO, Long inspectorUserId); 34 + void updateIqc(@Valid MesQcIqcSaveReqVO updateReqVO);
37 35
38 /** 36 /**
39 * 完成来料检验单 37 * 完成来料检验单
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcServiceImpl.java
@@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; @@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService;
20 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; 20 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
21 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService; 21 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService;
22 import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; 22 import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService;
  23 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
23 import jakarta.annotation.Resource; 24 import jakarta.annotation.Resource;
24 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
25 import org.springframework.transaction.annotation.Transactional; 26 import org.springframework.transaction.annotation.Transactional;
@@ -45,9 +46,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -45,9 +46,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
45 46
46 @Resource 47 @Resource
47 private MesQcIqcMapper iqcMapper; 48 private MesQcIqcMapper iqcMapper;
  49 +
48 @Resource 50 @Resource
49 private MesQcTemplateDetailService templateDetailService; 51 private MesQcTemplateDetailService templateDetailService;
50 -  
51 @Resource 52 @Resource
52 private MesQcIqcLineService iqcLineService; 53 private MesQcIqcLineService iqcLineService;
53 @Resource 54 @Resource
@@ -59,17 +60,22 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -59,17 +60,22 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
59 @Resource 60 @Resource
60 private MesMdItemService itemService; 61 private MesMdItemService itemService;
61 62
  63 + @Resource
  64 + private AdminUserApi adminUserApi;
  65 +
62 @Override 66 @Override
63 @Transactional(rollbackFor = Exception.class) 67 @Transactional(rollbackFor = Exception.class)
64 - public Long createIqc(MesQcIqcSaveReqVO createReqVO, Long inspectorUserId) { 68 + public Long createIqc(MesQcIqcSaveReqVO createReqVO) {
65 // 1.1 校验编号唯一 69 // 1.1 校验编号唯一
66 validateIqcCodeUnique(null, createReqVO.getCode()); 70 validateIqcCodeUnique(null, createReqVO.getCode());
67 // 1.2 校验供应商、物料存在 71 // 1.2 校验供应商、物料存在
68 vendorService.validateVendorExists(createReqVO.getVendorId()); 72 vendorService.validateVendorExists(createReqVO.getVendorId());
69 itemService.validateItemExists(createReqVO.getItemId()); 73 itemService.validateItemExists(createReqVO.getItemId());
70 - // 1.3 校验来源单据参数,并验证数据存在 74 + // 1.3 校验检测人员存在
  75 + adminUserApi.validateUser(createReqVO.getInspectorUserId());
  76 + // 1.4 校验来源单据参数,并验证数据存在
71 validateSourceDoc(createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId()); 77 validateSourceDoc(createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId());
72 - // 1.4 通过 itemId + IQC 类型自动查找模板 78 + // 1.5 通过 itemId + IQC 类型自动查找模板
73 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType( 79 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType(
74 createReqVO.getItemId(), MesQcTypeEnum.IQC.getType()); 80 createReqVO.getItemId(), MesQcTypeEnum.IQC.getType());
75 Long templateId = templateItem.getTemplateId(); 81 Long templateId = templateItem.getTemplateId();
@@ -78,7 +84,6 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -78,7 +84,6 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
78 MesQcIqcDO iqc = BeanUtils.toBean(createReqVO, MesQcIqcDO.class); 84 MesQcIqcDO iqc = BeanUtils.toBean(createReqVO, MesQcIqcDO.class);
79 iqc.setTemplateId(templateId); 85 iqc.setTemplateId(templateId);
80 iqc.setCheckQuantity(createReqVO.getQualifiedQuantity().add(createReqVO.getUnqualifiedQuantity())); 86 iqc.setCheckQuantity(createReqVO.getQualifiedQuantity().add(createReqVO.getUnqualifiedQuantity()));
81 - iqc.setInspectorUserId(inspectorUserId);  
82 iqc.setStatus(MesOrderStatusEnum.DRAFT.getType()); 87 iqc.setStatus(MesOrderStatusEnum.DRAFT.getType());
83 iqcMapper.insert(iqc); 88 iqcMapper.insert(iqc);
84 89
@@ -88,7 +93,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -88,7 +93,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
88 } 93 }
89 94
90 @Override 95 @Override
91 - public void updateIqc(MesQcIqcSaveReqVO updateReqVO, Long inspectorUserId) { 96 + public void updateIqc(MesQcIqcSaveReqVO updateReqVO) {
92 // 1.1 校验存在 + 草稿状态 97 // 1.1 校验存在 + 草稿状态
93 validateIqcStatusPrepare(updateReqVO.getId()); 98 validateIqcStatusPrepare(updateReqVO.getId());
94 // 1.2 校验编号唯一 99 // 1.2 校验编号唯一
@@ -96,13 +101,14 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -96,13 +101,14 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
96 // 1.3 校验供应商、物料存在 101 // 1.3 校验供应商、物料存在
97 vendorService.validateVendorExists(updateReqVO.getVendorId()); 102 vendorService.validateVendorExists(updateReqVO.getVendorId());
98 itemService.validateItemExists(updateReqVO.getItemId()); 103 itemService.validateItemExists(updateReqVO.getItemId());
  104 + // 1.4 校验检测人员存在
  105 + adminUserApi.validateUser(updateReqVO.getInspectorUserId());
99 106
100 // 2. 更新主表 107 // 2. 更新主表
101 MesQcIqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIqcDO.class); 108 MesQcIqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIqcDO.class);
102 updateObj.setSourceDocType(null).setSourceDocId(null).setSourceLineId(null); // 不允许修改来源单据 109 updateObj.setSourceDocType(null).setSourceDocId(null).setSourceLineId(null); // 不允许修改来源单据
103 updateObj.setTemplateId(null); // 不允许修改模板 110 updateObj.setTemplateId(null); // 不允许修改模板
104 updateObj.setCheckQuantity(updateReqVO.getQualifiedQuantity().add(updateReqVO.getUnqualifiedQuantity())); 111 updateObj.setCheckQuantity(updateReqVO.getQualifiedQuantity().add(updateReqVO.getUnqualifiedQuantity()));
105 - updateObj.setInspectorUserId(inspectorUserId);  
106 iqcMapper.updateById(updateObj); 112 iqcMapper.updateById(updateObj);
107 } 113 }
108 114
@@ -110,11 +116,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -110,11 +116,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
110 public void completeIqc(Long id) { 116 public void completeIqc(Long id) {
111 // 1.1 校验存在 + 草稿状态 117 // 1.1 校验存在 + 草稿状态
112 MesQcIqcDO iqc = validateIqcStatusPrepare(id); 118 MesQcIqcDO iqc = validateIqcStatusPrepare(id);
113 - // DONE @AI:已修复,增加 checkResult 必填校验  
114 if (iqc.getCheckResult() == null) { 119 if (iqc.getCheckResult() == null) {
115 throw exception(QC_IQC_CHECK_RESULT_EMPTY); 120 throw exception(QC_IQC_CHECK_RESULT_EMPTY);
116 } 121 }
117 - // DONE @AI:已修复,数量校验已在 MesQcIqcSaveReqVO 的 @AssertTrue 中保证,此处移除  
118 122
119 // 2. 更新状态为已完成 123 // 2. 更新状态为已完成
120 MesQcIqcDO updateObj = new MesQcIqcDO() 124 MesQcIqcDO updateObj = new MesQcIqcDO()
@@ -135,7 +139,6 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -135,7 +139,6 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
135 if (iqc.getSourceDocType() == null) { 139 if (iqc.getSourceDocType() == null) {
136 return; 140 return;
137 } 141 }
138 - // DONE @AI:已修复,使用 ObjectUtil.hasNull() 简化判断  
139 if (ObjectUtil.hasNull(iqc.getSourceLineId(), iqc.getSourceDocId())) { 142 if (ObjectUtil.hasNull(iqc.getSourceLineId(), iqc.getSourceDocId())) {
140 throw new IllegalArgumentException( 143 throw new IllegalArgumentException(
141 "IQC 单[" + iqc.getId() + "] sourceDocType 非空但 sourceLineId 或 sourceDocId 为空"); 144 "IQC 单[" + iqc.getId() + "] sourceDocType 非空但 sourceLineId 或 sourceDocId 为空");