Commit 26507997c9072d9316bbf052acdd534e43280fa9

Authored by YunaiV
1 parent b567632e

refactor(mes-qc): 优化 OQC 出货检验单

  - 删除 minCheckQuantity、maxUnqualifiedQuantity、templateId(VO) 字段
  - 新增客户、物料、检测人员存在性校验
  - 新增数量关系校验:checkQuantity = qualifiedQuantity + unqualifiedQuantity
  - 模板改为后端自动匹配(产品 + 检验类型)
  - OQC 行新增 tool 字段(冗余存储)
  - MesMdClientService 新增 validateClientExists 公开方法
  - 删除分页查询中的出货日期、检测日期搜索字段
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcPageReqVO.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
... ... @@ -38,12 +33,4 @@ public class MesQcOqcPageReqVO extends PageParam {
38 33 @Schema(description = "检测人员用户 ID", example = "1")
39 34 private Long inspectorUserId;
40 35  
41   - @Schema(description = "出货日期")
42   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
43   - private LocalDateTime[] outDate;
44   -
45   - @Schema(description = "检测日期")
46   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
47   - private LocalDateTime[] inspectDate;
48   -
49 36 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcSaveReqVO.java
1 1 package cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 5 import io.swagger.v3.oas.annotations.media.Schema;
4   -import jakarta.validation.constraints.NotEmpty;
5   -import jakarta.validation.constraints.NotNull;
  6 +import jakarta.validation.constraints.*;
6 7 import lombok.Data;
7 8  
8 9 import java.math.BigDecimal;
... ... @@ -23,10 +24,6 @@ public class MesQcOqcSaveReqVO {
23 24 @NotEmpty(message = "检验单名称不能为空")
24 25 private String name;
25 26  
26   - @Schema(description = "检验模板 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
27   - @NotNull(message = "检验模板不能为空")
28   - private Long templateId;
29   -
30 27 // ========== 来源单据 ==========
31 28  
32 29 @Schema(description = "来源单据 ID", example = "200")
... ... @@ -58,43 +55,53 @@ public class MesQcOqcSaveReqVO {
58 55  
59 56 // ========== 数量 ==========
60 57  
61   - // TODO @AI:这 2 个字段去掉,minCheckQuantity、maxUnqualifiedQuantity;前后端都是;
62   - @Schema(description = "最低检测数", example = "5")
63   - private Integer minCheckQuantity;
64   -
65   - @Schema(description = "最大不合格数", example = "0")
66   - private Integer maxUnqualifiedQuantity;
67   -
68 58 @Schema(description = "本次出货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
69 59 @NotNull(message = "本次出货数量不能为空")
  60 + @DecimalMin(value = "0", message = "本次出货数量不能小于 0")
70 61 private BigDecimal outQuantity;
71 62  
72   - // TODO @AI:checkQuantity = qualifiedQuantity + unqualifiedQuantity;校验下相等;必须的;参考 iqc
73   -
74   - @Schema(description = "本次检测数量", example = "10")
  63 + @Schema(description = "本次检测数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  64 + @NotNull(message = "本次检测数量不能为空")
  65 + @Min(value = 1, message = "本次检测数量必须大于 0")
75 66 private Integer checkQuantity;
76 67  
77   - @Schema(description = "合格品数量", example = "9")
  68 + @Schema(description = "合格品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "9")
  69 + @NotNull(message = "合格品数量不能为空")
  70 + @Min(value = 0, message = "合格品数量不能小于 0")
78 71 private Integer qualifiedQuantity;
79 72  
80   - @Schema(description = "不合格品数量", example = "1")
  73 + @Schema(description = "不合格品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  74 + @NotNull(message = "不合格品数量不能为空")
  75 + @Min(value = 0, message = "不合格品数量不能小于 0")
81 76 private Integer unqualifiedQuantity;
82 77  
83 78 // ========== 检验 ==========
84 79  
85   - @Schema(description = "检测结果", example = "1")
86   - private Integer checkResult;
  80 + @Schema(description = "检测人员用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  81 + @NotNull(message = "检测人员不能为空")
  82 + private Long inspectorUserId;
87 83  
88   - @Schema(description = "出货日期")
  84 + @Schema(description = "出货日期", requiredMode = Schema.RequiredMode.REQUIRED)
  85 + @NotNull(message = "出货日期不能为空")
89 86 private LocalDateTime outDate;
90 87  
91   - @Schema(description = "检测日期")
  88 + @Schema(description = "检测日期", requiredMode = Schema.RequiredMode.REQUIRED)
  89 + @NotNull(message = "检测日期不能为空")
92 90 private LocalDateTime inspectDate;
93 91  
94   - @Schema(description = "检测人员用户 ID", example = "1")
95   - private Long inspectorUserId;
  92 + @Schema(description = "检测结果", example = "1")
  93 + private Integer checkResult;
96 94  
97 95 @Schema(description = "备注", example = "备注")
98 96 private String remark;
99 97  
  98 + @AssertTrue(message = "检测数量必须等于合格品数量与不合格品数量之和")
  99 + @JsonIgnore
  100 + public boolean isQuantityValid() {
  101 + if (ObjUtil.hasNull(checkQuantity, qualifiedQuantity, unqualifiedQuantity)) {
  102 + return true; // @NotNull 会处理 null
  103 + }
  104 + return checkQuantity.equals(qualifiedQuantity + unqualifiedQuantity);
  105 + }
  106 +
100 107 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/indicatorresult/MesQcIndicatorResultDO.java
... ... @@ -2,7 +2,10 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO;
5 6 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcDO;
6 9 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
7 10 import com.baomidou.mybatisplus.annotation.KeySequence;
8 11 import com.baomidou.mybatisplus.annotation.TableId;
... ... @@ -37,7 +40,9 @@ public class MesQcIndicatorResultDO extends BaseDO {
37 40 * 关联质检单 ID(IQC/IPQC/OQC/RQC 的 id)
38 41 *
39 42 * 关联 IQC {@link MesQcIqcDO#getId()}
40   - * TODO @芋艿:IPQC/OQC/RQC 关联补充
  43 + * 关联 IPQC {@link MesQcIpqcDO#getId()}
  44 + * 关联 OQC {@link MesQcOqcDO#getId()}
  45 + * 关联 RQC {@link MesQcRqcDO#getId()}
41 46 */
42 47 private Long qcId;
43 48 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcDO.java
... ... @@ -91,14 +91,6 @@ public class MesQcOqcDO extends BaseDO {
91 91 // ========== 数量 ==========
92 92  
93 93 /**
94   - * 最低检测数
95   - */
96   - private Integer minCheckQuantity;
97   - /**
98   - * 最大不合格数
99   - */
100   - private Integer maxUnqualifiedQuantity;
101   - /**
102 94 * 本次出货数量
103 95 */
104 96 private BigDecimal outQuantity;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcLineDO.java
... ... @@ -43,6 +43,12 @@ public class MesQcOqcLineDO extends BaseDO {
43 43 */
44 44 private Long indicatorId;
45 45 /**
  46 + * 检测工具
  47 + *
  48 + * 冗余 {@link MesQcIndicatorDO#getTool()}
  49 + */
  50 + private String tool;
  51 + /**
46 52 * 检测方法
47 53 */
48 54 private String checkMethod;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/client/MesMdClientService.java
... ... @@ -86,6 +86,13 @@ public interface MesMdClientService {
86 86 }
87 87  
88 88 /**
  89 + * 校验客户是否存在
  90 + *
  91 + * @param id 编号
  92 + */
  93 + void validateClientExists(Long id);
  94 +
  95 + /**
89 96 * 批量导入客户
90 97 *
91 98 * @param importClients 导入客户列表
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/client/MesMdClientServiceImpl.java
... ... @@ -79,7 +79,8 @@ public class MesMdClientServiceImpl implements MesMdClientService {
79 79 clientMapper.deleteById(id);
80 80 }
81 81  
82   - private void validateClientExists(Long id) {
  82 + @Override
  83 + public void validateClientExists(Long id) {
83 84 if (clientMapper.selectById(id) == null) {
84 85 throw exception(MD_CLIENT_NOT_EXISTS);
85 86 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
... ... @@ -70,15 +70,12 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
70 70 public Long createIpqc(MesQcIpqcSaveReqVO createReqVO) {
71 71 // 1.1 校验编号唯一
72 72 validateIpqcCodeUnique(null, createReqVO.getCode());
73   - // 1.2 校验工单存在
  73 + // 1.2 校验工单、工位、检测人员、物料存在
74 74 MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
75   - // 1.3 校验工位存在
76 75 workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
77   - // 1.4 校验检测人员存在
78 76 adminUserApi.validateUser(createReqVO.getInspectorUserId());
79   - // 1.5 校验物料存在
80 77 itemService.validateItemExists(createReqVO.getItemId());
81   - // 1.6 根据产品 + 检验类型自动匹配模板
  78 + // 1.3 根据产品 + 检验类型自动匹配模板
82 79 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType(
83 80 workOrder.getProductId(), MesQcTypeEnum.IPQC.getType());
84 81 Long templateId = templateItem.getTemplateId();
... ... @@ -101,13 +98,10 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
101 98 validateIpqcStatusPrepare(updateReqVO.getId());
102 99 // 1.2 校验编号唯一
103 100 validateIpqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
104   - // 1.3 校验工单存在
  101 + // 1.3 校验工单、工位、检测人员、物料存在
105 102 workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
106   - // 1.4 校验工位存在
107 103 workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());
108   - // 1.5 校验检测人员存在
109 104 adminUserApi.validateUser(updateReqVO.getInspectorUserId());
110   - // 1.6 校验物料存在
111 105 itemService.validateItemExists(updateReqVO.getItemId());
112 106  
113 107 // 2. 更新
... ... @@ -225,8 +219,7 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
225 219 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
226 220 .divide(checkQty, 2, RoundingMode.HALF_UP);
227 221 }
228   -
229   - // 3. 更新主表
  222 + // 2.3 更新主表
230 223 MesQcIpqcDO updateIpqc = new MesQcIpqcDO().setId(ipqcId)
231 224 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
232 225 .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcServiceImpl.java
... ... @@ -68,14 +68,13 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
68 68 public Long createIqc(MesQcIqcSaveReqVO createReqVO) {
69 69 // 1.1 校验编号唯一
70 70 validateIqcCodeUnique(null, createReqVO.getCode());
71   - // 1.2 校验供应商、物料存在
  71 + // 1.2 校验供应商、物料、检测人员存在
72 72 vendorService.validateVendorExists(createReqVO.getVendorId());
73 73 itemService.validateItemExists(createReqVO.getItemId());
74   - // 1.3 校验检测人员存在
75 74 adminUserApi.validateUser(createReqVO.getInspectorUserId());
76   - // 1.4 校验来源单据参数,并验证数据存在
  75 + // 1.3 校验来源单据参数,并验证数据存在
77 76 validateSourceDoc(createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId());
78   - // 1.5 通过 itemId + IQC 类型自动查找模板
  77 + // 1.4 通过 itemId + IQC 类型自动查找模板
79 78 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType(
80 79 createReqVO.getItemId(), MesQcTypeEnum.IQC.getType());
81 80 Long templateId = templateItem.getTemplateId();
... ... @@ -98,10 +97,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
98 97 validateIqcStatusPrepare(updateReqVO.getId());
99 98 // 1.2 校验编号唯一
100 99 validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
101   - // 1.3 校验供应商、物料存在
  100 + // 1.3 校验供应商、物料、检测人员存在
102 101 vendorService.validateVendorExists(updateReqVO.getVendorId());
103 102 itemService.validateItemExists(updateReqVO.getItemId());
104   - // 1.4 校验检测人员存在
105 103 adminUserApi.validateUser(updateReqVO.getInspectorUserId());
106 104  
107 105 // 2. 更新主表
... ... @@ -264,8 +262,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
264 262 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
265 263 .divide(checkQty, 2, RoundingMode.HALF_UP);
266 264 }
267   -
268   - // 3. 更新主表
  265 + // 2.3 更新主表
269 266 MesQcIqcDO updateIqc = new MesQcIqcDO().setId(iqcId)
270 267 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
271 268 .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcLineServiceImpl.java
... ... @@ -5,21 +5,25 @@ import cn.hutool.core.util.ObjUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.line.MesQcOqcLinePageReqVO;
7 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 9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcLineDO;
9 10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO;
10 11 import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcLineMapper;
11 12 import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateIndicatorMapper;
12 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
  14 +import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService;
13 15 import jakarta.annotation.Resource;
14 16 import org.springframework.stereotype.Service;
15 17 import org.springframework.validation.annotation.Validated;
16 18  
17 19 import java.util.ArrayList;
18 20 import java.util.List;
  21 +import java.util.Map;
19 22 import java.util.Objects;
20 23  
21 24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
22 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 27 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
24 28  
25 29 /**
... ... @@ -35,6 +39,8 @@ public class MesQcOqcLineServiceImpl implements MesQcOqcLineService {
35 39 private MesQcOqcLineMapper oqcLineMapper;
36 40 @Resource
37 41 private MesQcTemplateIndicatorMapper templateIndicatorMapper;
  42 + @Resource
  43 + private MesQcIndicatorService indicatorService;
38 44  
39 45 @Override
40 46 public MesQcOqcLineDO validateOqcLineExists(Long id) {
... ... @@ -57,14 +63,22 @@ public class MesQcOqcLineServiceImpl implements MesQcOqcLineService {
57 63  
58 64 @Override
59 65 public void createLinesFromTemplate(Long oqcId, Long templateId) {
60   - // TODO @AI:tool 存储
61   - List<MesQcTemplateIndicatorDO> indicators = templateIndicatorMapper.selectListByTemplateId(templateId);
62   - List<MesQcOqcLineDO> lines = convertList(indicators, indicator -> new MesQcOqcLineDO()
63   - .setOqcId(oqcId).setIndicatorId(indicator.getIndicatorId())
64   - .setCheckMethod(indicator.getCheckMethod())
65   - .setStandardValue(indicator.getStandardValue()).setUnitMeasureId(indicator.getUnitMeasureId())
66   - .setMaxThreshold(indicator.getThresholdMax()).setMinThreshold(indicator.getThresholdMin())
67   - .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0));
  66 + List<MesQcTemplateIndicatorDO> templateIndicators = templateIndicatorMapper.selectListByTemplateId(templateId);
  67 + if (CollUtil.isEmpty(templateIndicators)) {
  68 + return;
  69 + }
  70 + Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(
  71 + convertSet(templateIndicators, MesQcTemplateIndicatorDO::getIndicatorId));
  72 + List<MesQcOqcLineDO> lines = convertList(templateIndicators, templateIndicator -> {
  73 + MesQcIndicatorDO indicator = indicatorMap.get(templateIndicator.getIndicatorId());
  74 + return new MesQcOqcLineDO()
  75 + .setOqcId(oqcId).setIndicatorId(templateIndicator.getIndicatorId())
  76 + .setTool(indicator != null ? indicator.getTool() : null)
  77 + .setCheckMethod(templateIndicator.getCheckMethod())
  78 + .setStandardValue(templateIndicator.getStandardValue()).setUnitMeasureId(templateIndicator.getUnitMeasureId())
  79 + .setMaxThreshold(templateIndicator.getThresholdMax()).setMinThreshold(templateIndicator.getThresholdMin())
  80 + .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0);
  81 + });
68 82 oqcLineMapper.insertBatch(lines);
69 83 }
70 84  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java
1 1 package cn.iocoder.yudao.module.mes.service.qc.oqc;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.util.ObjUtil;
5 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
... ... @@ -8,15 +7,16 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcPageReqVO;
8 7 import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcSaveReqVO;
9 8 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO;
10 9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
11   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO;
12 10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO;
13 11 import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper;
14 12 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
15 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcOqcStatusEnum;
16 14 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  15 +import cn.iocoder.yudao.module.mes.service.md.client.MesMdClientService;
  16 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
17 17 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
18 18 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService;
19   -import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateService;
  19 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
20 20 import jakarta.annotation.Resource;
21 21 import org.springframework.context.annotation.Lazy;
22 22 import org.springframework.stereotype.Service;
... ... @@ -43,45 +43,38 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
43 43 @Resource
44 44 private MesQcOqcMapper oqcMapper;
45 45 @Resource
46   - private MesQcTemplateService templateService;
47   - @Resource
48 46 private MesQcTemplateDetailService templateDetailService;
49 47 @Resource
50 48 private MesQcOqcLineService oqcLineService;
51 49 @Resource
52 50 @Lazy
53 51 private MesQcDefectRecordService defectRecordService;
  52 + @Resource
  53 + @Lazy
  54 + private MesMdClientService clientService;
  55 + @Resource
  56 + @Lazy
  57 + private MesMdItemService itemService;
  58 + @Resource
  59 + private AdminUserApi adminUserApi;
54 60  
55 61 @Override
56 62 @Transactional(rollbackFor = Exception.class)
57 63 public Long createOqc(MesQcOqcSaveReqVO createReqVO) {
58 64 // 1.1 校验编号唯一
59 65 validateOqcCodeUnique(null, createReqVO.getCode());
60   - // TODO @AI:关联字段的校验!
61   - // 1.2 校验模板存在且包含 OQC 类型
62   - // TODO @AI:不用前端传递,而是类似 iqc 后端计算
63   - Long templateId = createReqVO.getTemplateId();
64   - MesQcTemplateDO template = templateService.validateTemplateExists(templateId);
65   - if (!CollUtil.contains(template.getTypes(), MesQcTypeEnum.OQC.getType())) {
66   - throw exception(QC_OQC_NO_TEMPLATE);
67   - }
68   -
69   - // 1.3 从模板的产品关联中获取检测参数
70   - // TODO @芋艿:【暂时不用删除】到底 miniCheckQuantity 和 maxUnqualifiedQuantity 是否有必要存储?
71   - // TODO @AI:去掉这 2 个字段的设置,包括数据的存储,也去掉!
72   - MesQcTemplateItemDO templateItem = templateDetailService.getTemplateItemByTemplateIdAndItemId(
73   - templateId, createReqVO.getItemId());
74   - if (templateItem != null) {
75   - if (createReqVO.getMinCheckQuantity() == null) {
76   - createReqVO.setMinCheckQuantity(templateItem.getQuantityCheck());
77   - }
78   - if (createReqVO.getMaxUnqualifiedQuantity() == null) {
79   - createReqVO.setMaxUnqualifiedQuantity(templateItem.getQuantityUnqualified());
80   - }
81   - }
  66 + // 1.2 校验客户、物料、检测人员存在
  67 + clientService.validateClientExists(createReqVO.getClientId());
  68 + itemService.validateItemExists(createReqVO.getItemId());
  69 + adminUserApi.validateUser(createReqVO.getInspectorUserId());
  70 + // 1.3 根据产品 + 检验类型自动匹配模板
  71 + MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType(
  72 + createReqVO.getItemId(), MesQcTypeEnum.OQC.getType());
  73 + Long templateId = templateItem.getTemplateId();
82 74  
83 75 // 2. 插入主表
84 76 MesQcOqcDO oqc = BeanUtils.toBean(createReqVO, MesQcOqcDO.class);
  77 + oqc.setTemplateId(templateId);
85 78 oqc.setStatus(MesQcOqcStatusEnum.PREPARE.getType());
86 79 oqcMapper.insert(oqc);
87 80  
... ... @@ -96,6 +89,10 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
96 89 validateOqcStatusPrepare(updateReqVO.getId());
97 90 // 1.2 校验编号唯一
98 91 validateOqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
  92 + // 1.3 校验客户、物料、检测人员存在
  93 + clientService.validateClientExists(updateReqVO.getClientId());
  94 + itemService.validateItemExists(updateReqVO.getItemId());
  95 + adminUserApi.validateUser(updateReqVO.getInspectorUserId());
99 96  
100 97 // 2. 更新
101 98 MesQcOqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcOqcDO.class);
... ... @@ -104,16 +101,8 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
104 101  
105 102 @Override
106 103 public void completeOqc(Long id) {
107   - // 1.1 校验存在 + 草稿状态
108   - MesQcOqcDO oqc = validateOqcStatusPrepare(id);
109   - // 1.2 校验合格品 + 不合格品 = 检测数量
110   - if (oqc.getCheckQuantity() != null && oqc.getCheckQuantity() > 0) {
111   - int total = (oqc.getQualifiedQuantity() != null ? oqc.getQualifiedQuantity() : 0)
112   - + (oqc.getUnqualifiedQuantity() != null ? oqc.getUnqualifiedQuantity() : 0);
113   - if (total != oqc.getCheckQuantity()) {
114   - throw exception(QC_OQC_QUANTITY_MISMATCH);
115   - }
116   - }
  104 + // 1. 校验存在 + 草稿状态
  105 + validateOqcStatusPrepare(id);
117 106  
118 107 // 2. 更新状态为已完成
119 108 MesQcOqcDO updateObj = new MesQcOqcDO()
... ... @@ -210,8 +199,7 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
210 199 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
211 200 .divide(checkQty, 2, RoundingMode.HALF_UP);
212 201 }
213   -
214   - // 3. 更新主表
  202 + // 2.3 更新主表
215 203 MesQcOqcDO updateOqc = new MesQcOqcDO().setId(oqcId)
216 204 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
217 205 .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java
... ... @@ -162,6 +162,8 @@ public class MesQcRqcServiceImpl implements MesQcRqcService {
162 162 public void recalculateDefectStats(Long rqcId, List<MesQcDefectRecordDO> records) {
163 163 // RQC 只更新行级缺陷统计,主表不存储缺陷统计字段
164 164 rqcLineService.recalculateLineDefectStats(rqcId, records);
  165 +
  166 + // TODO @AI:还是对齐其他的
165 167 }
166 168  
167 169 }
... ...