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,11 +5,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
5 import lombok.Data; 5 import lombok.Data;
6 import lombok.EqualsAndHashCode; 6 import lombok.EqualsAndHashCode;
7 import lombok.ToString; 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 @Schema(description = "管理后台 - MES 出货检验单分页 Request VO") 9 @Schema(description = "管理后台 - MES 出货检验单分页 Request VO")
15 @Data 10 @Data
@@ -38,12 +33,4 @@ public class MesQcOqcPageReqVO extends PageParam { @@ -38,12 +33,4 @@ public class MesQcOqcPageReqVO extends PageParam {
38 @Schema(description = "检测人员用户 ID", example = "1") 33 @Schema(description = "检测人员用户 ID", example = "1")
39 private Long inspectorUserId; 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 package cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo; 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 import io.swagger.v3.oas.annotations.media.Schema; 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 import lombok.Data; 7 import lombok.Data;
7 8
8 import java.math.BigDecimal; 9 import java.math.BigDecimal;
@@ -23,10 +24,6 @@ public class MesQcOqcSaveReqVO { @@ -23,10 +24,6 @@ public class MesQcOqcSaveReqVO {
23 @NotEmpty(message = "检验单名称不能为空") 24 @NotEmpty(message = "检验单名称不能为空")
24 private String name; 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 @Schema(description = "来源单据 ID", example = "200") 29 @Schema(description = "来源单据 ID", example = "200")
@@ -58,43 +55,53 @@ public class MesQcOqcSaveReqVO { @@ -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 @Schema(description = "本次出货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") 58 @Schema(description = "本次出货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
69 @NotNull(message = "本次出货数量不能为空") 59 @NotNull(message = "本次出货数量不能为空")
  60 + @DecimalMin(value = "0", message = "本次出货数量不能小于 0")
70 private BigDecimal outQuantity; 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 private Integer checkQuantity; 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 private Integer qualifiedQuantity; 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 private Integer unqualifiedQuantity; 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 private LocalDateTime outDate; 86 private LocalDateTime outDate;
90 87
91 - @Schema(description = "检测日期") 88 + @Schema(description = "检测日期", requiredMode = Schema.RequiredMode.REQUIRED)
  89 + @NotNull(message = "检测日期不能为空")
92 private LocalDateTime inspectDate; 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 @Schema(description = "备注", example = "备注") 95 @Schema(description = "备注", example = "备注")
98 private String remark; 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,7 +2,10 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult;
2 2
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.item.MesMdItemDO; 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 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO; 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 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; 9 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
7 import com.baomidou.mybatisplus.annotation.KeySequence; 10 import com.baomidou.mybatisplus.annotation.KeySequence;
8 import com.baomidou.mybatisplus.annotation.TableId; 11 import com.baomidou.mybatisplus.annotation.TableId;
@@ -37,7 +40,9 @@ public class MesQcIndicatorResultDO extends BaseDO { @@ -37,7 +40,9 @@ public class MesQcIndicatorResultDO extends BaseDO {
37 * 关联质检单 ID(IQC/IPQC/OQC/RQC 的 id) 40 * 关联质检单 ID(IQC/IPQC/OQC/RQC 的 id)
38 * 41 *
39 * 关联 IQC {@link MesQcIqcDO#getId()} 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 private Long qcId; 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,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 private BigDecimal outQuantity; 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,6 +43,12 @@ public class MesQcOqcLineDO extends BaseDO {
43 */ 43 */
44 private Long indicatorId; 44 private Long indicatorId;
45 /** 45 /**
  46 + * 检测工具
  47 + *
  48 + * 冗余 {@link MesQcIndicatorDO#getTool()}
  49 + */
  50 + private String tool;
  51 + /**
46 * 检测方法 52 * 检测方法
47 */ 53 */
48 private String checkMethod; 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,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 * @param importClients 导入客户列表 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,7 +79,8 @@ public class MesMdClientServiceImpl implements MesMdClientService {
79 clientMapper.deleteById(id); 79 clientMapper.deleteById(id);
80 } 80 }
81 81
82 - private void validateClientExists(Long id) { 82 + @Override
  83 + public void validateClientExists(Long id) {
83 if (clientMapper.selectById(id) == null) { 84 if (clientMapper.selectById(id) == null) {
84 throw exception(MD_CLIENT_NOT_EXISTS); 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,15 +70,12 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
70 public Long createIpqc(MesQcIpqcSaveReqVO createReqVO) { 70 public Long createIpqc(MesQcIpqcSaveReqVO createReqVO) {
71 // 1.1 校验编号唯一 71 // 1.1 校验编号唯一
72 validateIpqcCodeUnique(null, createReqVO.getCode()); 72 validateIpqcCodeUnique(null, createReqVO.getCode());
73 - // 1.2 校验工单存在 73 + // 1.2 校验工单、工位、检测人员、物料存在
74 MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId()); 74 MesProWorkOrderDO workOrder = workOrderService.validateWorkOrderExists(createReqVO.getWorkOrderId());
75 - // 1.3 校验工位存在  
76 workstationService.validateWorkstationExists(createReqVO.getWorkstationId()); 75 workstationService.validateWorkstationExists(createReqVO.getWorkstationId());
77 - // 1.4 校验检测人员存在  
78 adminUserApi.validateUser(createReqVO.getInspectorUserId()); 76 adminUserApi.validateUser(createReqVO.getInspectorUserId());
79 - // 1.5 校验物料存在  
80 itemService.validateItemExists(createReqVO.getItemId()); 77 itemService.validateItemExists(createReqVO.getItemId());
81 - // 1.6 根据产品 + 检验类型自动匹配模板 78 + // 1.3 根据产品 + 检验类型自动匹配模板
82 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType( 79 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType(
83 workOrder.getProductId(), MesQcTypeEnum.IPQC.getType()); 80 workOrder.getProductId(), MesQcTypeEnum.IPQC.getType());
84 Long templateId = templateItem.getTemplateId(); 81 Long templateId = templateItem.getTemplateId();
@@ -101,13 +98,10 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -101,13 +98,10 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
101 validateIpqcStatusPrepare(updateReqVO.getId()); 98 validateIpqcStatusPrepare(updateReqVO.getId());
102 // 1.2 校验编号唯一 99 // 1.2 校验编号唯一
103 validateIpqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); 100 validateIpqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
104 - // 1.3 校验工单存在 101 + // 1.3 校验工单、工位、检测人员、物料存在
105 workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId()); 102 workOrderService.validateWorkOrderExists(updateReqVO.getWorkOrderId());
106 - // 1.4 校验工位存在  
107 workstationService.validateWorkstationExists(updateReqVO.getWorkstationId()); 103 workstationService.validateWorkstationExists(updateReqVO.getWorkstationId());
108 - // 1.5 校验检测人员存在  
109 adminUserApi.validateUser(updateReqVO.getInspectorUserId()); 104 adminUserApi.validateUser(updateReqVO.getInspectorUserId());
110 - // 1.6 校验物料存在  
111 itemService.validateItemExists(updateReqVO.getItemId()); 105 itemService.validateItemExists(updateReqVO.getItemId());
112 106
113 // 2. 更新 107 // 2. 更新
@@ -225,8 +219,7 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { @@ -225,8 +219,7 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
225 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100)) 219 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
226 .divide(checkQty, 2, RoundingMode.HALF_UP); 220 .divide(checkQty, 2, RoundingMode.HALF_UP);
227 } 221 }
228 -  
229 - // 3. 更新主表 222 + // 2.3 更新主表
230 MesQcIpqcDO updateIpqc = new MesQcIpqcDO().setId(ipqcId) 223 MesQcIpqcDO updateIpqc = new MesQcIpqcDO().setId(ipqcId)
231 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor) 224 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
232 .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate); 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,14 +68,13 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
68 public Long createIqc(MesQcIqcSaveReqVO createReqVO) { 68 public Long createIqc(MesQcIqcSaveReqVO createReqVO) {
69 // 1.1 校验编号唯一 69 // 1.1 校验编号唯一
70 validateIqcCodeUnique(null, createReqVO.getCode()); 70 validateIqcCodeUnique(null, createReqVO.getCode());
71 - // 1.2 校验供应商、物料存在 71 + // 1.2 校验供应商、物料、检测人员存在
72 vendorService.validateVendorExists(createReqVO.getVendorId()); 72 vendorService.validateVendorExists(createReqVO.getVendorId());
73 itemService.validateItemExists(createReqVO.getItemId()); 73 itemService.validateItemExists(createReqVO.getItemId());
74 - // 1.3 校验检测人员存在  
75 adminUserApi.validateUser(createReqVO.getInspectorUserId()); 74 adminUserApi.validateUser(createReqVO.getInspectorUserId());
76 - // 1.4 校验来源单据参数,并验证数据存在 75 + // 1.3 校验来源单据参数,并验证数据存在
77 validateSourceDoc(createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId()); 76 validateSourceDoc(createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId());
78 - // 1.5 通过 itemId + IQC 类型自动查找模板 77 + // 1.4 通过 itemId + IQC 类型自动查找模板
79 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType( 78 MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType(
80 createReqVO.getItemId(), MesQcTypeEnum.IQC.getType()); 79 createReqVO.getItemId(), MesQcTypeEnum.IQC.getType());
81 Long templateId = templateItem.getTemplateId(); 80 Long templateId = templateItem.getTemplateId();
@@ -98,10 +97,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -98,10 +97,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
98 validateIqcStatusPrepare(updateReqVO.getId()); 97 validateIqcStatusPrepare(updateReqVO.getId());
99 // 1.2 校验编号唯一 98 // 1.2 校验编号唯一
100 validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); 99 validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
101 - // 1.3 校验供应商、物料存在 100 + // 1.3 校验供应商、物料、检测人员存在
102 vendorService.validateVendorExists(updateReqVO.getVendorId()); 101 vendorService.validateVendorExists(updateReqVO.getVendorId());
103 itemService.validateItemExists(updateReqVO.getItemId()); 102 itemService.validateItemExists(updateReqVO.getItemId());
104 - // 1.4 校验检测人员存在  
105 adminUserApi.validateUser(updateReqVO.getInspectorUserId()); 103 adminUserApi.validateUser(updateReqVO.getInspectorUserId());
106 104
107 // 2. 更新主表 105 // 2. 更新主表
@@ -264,8 +262,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -264,8 +262,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
264 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100)) 262 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
265 .divide(checkQty, 2, RoundingMode.HALF_UP); 263 .divide(checkQty, 2, RoundingMode.HALF_UP);
266 } 264 }
267 -  
268 - // 3. 更新主表 265 + // 2.3 更新主表
269 MesQcIqcDO updateIqc = new MesQcIqcDO().setId(iqcId) 266 MesQcIqcDO updateIqc = new MesQcIqcDO().setId(iqcId)
270 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor) 267 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
271 .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate); 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,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.oqc.vo.line.MesQcOqcLinePageReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.line.MesQcOqcLinePageReqVO;
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.oqc.MesQcOqcLineDO; 9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcLineDO;
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.oqc.MesQcOqcLineMapper; 11 import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcLineMapper;
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 /**
@@ -35,6 +39,8 @@ public class MesQcOqcLineServiceImpl implements MesQcOqcLineService { @@ -35,6 +39,8 @@ public class MesQcOqcLineServiceImpl implements MesQcOqcLineService {
35 private MesQcOqcLineMapper oqcLineMapper; 39 private MesQcOqcLineMapper oqcLineMapper;
36 @Resource 40 @Resource
37 private MesQcTemplateIndicatorMapper templateIndicatorMapper; 41 private MesQcTemplateIndicatorMapper templateIndicatorMapper;
  42 + @Resource
  43 + private MesQcIndicatorService indicatorService;
38 44
39 @Override 45 @Override
40 public MesQcOqcLineDO validateOqcLineExists(Long id) { 46 public MesQcOqcLineDO validateOqcLineExists(Long id) {
@@ -57,14 +63,22 @@ public class MesQcOqcLineServiceImpl implements MesQcOqcLineService { @@ -57,14 +63,22 @@ public class MesQcOqcLineServiceImpl implements MesQcOqcLineService {
57 63
58 @Override 64 @Override
59 public void createLinesFromTemplate(Long oqcId, Long templateId) { 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 oqcLineMapper.insertBatch(lines); 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 package cn.iocoder.yudao.module.mes.service.qc.oqc; 1 package cn.iocoder.yudao.module.mes.service.qc.oqc;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 import cn.hutool.core.util.ObjUtil; 3 import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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,15 +7,16 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcPageReqVO;
8 import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcSaveReqVO; 7 import cn.iocoder.yudao.module.mes.controller.admin.qc.oqc.vo.MesQcOqcSaveReqVO;
9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; 8 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO;
10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO; 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 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; 10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO;
13 import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper; 11 import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper;
14 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; 12 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
15 import cn.iocoder.yudao.module.mes.enums.qc.MesQcOqcStatusEnum; 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcOqcStatusEnum;
16 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; 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 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; 17 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
18 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService; 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 import jakarta.annotation.Resource; 20 import jakarta.annotation.Resource;
21 import org.springframework.context.annotation.Lazy; 21 import org.springframework.context.annotation.Lazy;
22 import org.springframework.stereotype.Service; 22 import org.springframework.stereotype.Service;
@@ -43,45 +43,38 @@ public class MesQcOqcServiceImpl implements MesQcOqcService { @@ -43,45 +43,38 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
43 @Resource 43 @Resource
44 private MesQcOqcMapper oqcMapper; 44 private MesQcOqcMapper oqcMapper;
45 @Resource 45 @Resource
46 - private MesQcTemplateService templateService;  
47 - @Resource  
48 private MesQcTemplateDetailService templateDetailService; 46 private MesQcTemplateDetailService templateDetailService;
49 @Resource 47 @Resource
50 private MesQcOqcLineService oqcLineService; 48 private MesQcOqcLineService oqcLineService;
51 @Resource 49 @Resource
52 @Lazy 50 @Lazy
53 private MesQcDefectRecordService defectRecordService; 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 @Override 61 @Override
56 @Transactional(rollbackFor = Exception.class) 62 @Transactional(rollbackFor = Exception.class)
57 public Long createOqc(MesQcOqcSaveReqVO createReqVO) { 63 public Long createOqc(MesQcOqcSaveReqVO createReqVO) {
58 // 1.1 校验编号唯一 64 // 1.1 校验编号唯一
59 validateOqcCodeUnique(null, createReqVO.getCode()); 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 // 2. 插入主表 75 // 2. 插入主表
84 MesQcOqcDO oqc = BeanUtils.toBean(createReqVO, MesQcOqcDO.class); 76 MesQcOqcDO oqc = BeanUtils.toBean(createReqVO, MesQcOqcDO.class);
  77 + oqc.setTemplateId(templateId);
85 oqc.setStatus(MesQcOqcStatusEnum.PREPARE.getType()); 78 oqc.setStatus(MesQcOqcStatusEnum.PREPARE.getType());
86 oqcMapper.insert(oqc); 79 oqcMapper.insert(oqc);
87 80
@@ -96,6 +89,10 @@ public class MesQcOqcServiceImpl implements MesQcOqcService { @@ -96,6 +89,10 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
96 validateOqcStatusPrepare(updateReqVO.getId()); 89 validateOqcStatusPrepare(updateReqVO.getId());
97 // 1.2 校验编号唯一 90 // 1.2 校验编号唯一
98 validateOqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); 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 // 2. 更新 97 // 2. 更新
101 MesQcOqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcOqcDO.class); 98 MesQcOqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcOqcDO.class);
@@ -104,16 +101,8 @@ public class MesQcOqcServiceImpl implements MesQcOqcService { @@ -104,16 +101,8 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
104 101
105 @Override 102 @Override
106 public void completeOqc(Long id) { 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 // 2. 更新状态为已完成 107 // 2. 更新状态为已完成
119 MesQcOqcDO updateObj = new MesQcOqcDO() 108 MesQcOqcDO updateObj = new MesQcOqcDO()
@@ -210,8 +199,7 @@ public class MesQcOqcServiceImpl implements MesQcOqcService { @@ -210,8 +199,7 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
210 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100)) 199 minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
211 .divide(checkQty, 2, RoundingMode.HALF_UP); 200 .divide(checkQty, 2, RoundingMode.HALF_UP);
212 } 201 }
213 -  
214 - // 3. 更新主表 202 + // 2.3 更新主表
215 MesQcOqcDO updateOqc = new MesQcOqcDO().setId(oqcId) 203 MesQcOqcDO updateOqc = new MesQcOqcDO().setId(oqcId)
216 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor) 204 .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
217 .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate); 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,6 +162,8 @@ public class MesQcRqcServiceImpl implements MesQcRqcService {
162 public void recalculateDefectStats(Long rqcId, List<MesQcDefectRecordDO> records) { 162 public void recalculateDefectStats(Long rqcId, List<MesQcDefectRecordDO> records) {
163 // RQC 只更新行级缺陷统计,主表不存储缺陷统计字段 163 // RQC 只更新行级缺陷统计,主表不存储缺陷统计字段
164 rqcLineService.recalculateLineDefectStats(rqcId, records); 164 rqcLineService.recalculateLineDefectStats(rqcId, records);
  165 +
  166 + // TODO @AI:还是对齐其他的
165 } 167 }
166 168
167 } 169 }