Commit d6d6887bdffe1be5be08f00e27f7bedd41e77478

Authored by YunaiV
1 parent fa473f7d

✨ feat(mes): 将质量状态字段类型更新为整型,优化数据一致性

Showing 46 changed files with 970 additions and 127 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java
... ... @@ -33,8 +33,8 @@ public class MesQcOqcRespVO {
33 33 @Schema(description = "来源单据 ID", example = "200")
34 34 private Long sourceDocId;
35 35  
36   - @Schema(description = "来源单据类型", example = "SALES")
37   - private String sourceDocType;
  36 + @Schema(description = "来源单据类型", example = "118")
  37 + private Integer sourceDocType;
38 38  
39 39 @Schema(description = "来源单据编号", example = "SO20250101001")
40 40 private String sourceDocCode;
... ... @@ -88,15 +88,15 @@ public class MesQcOqcRespVO {
88 88  
89 89 @Schema(description = "本次检测数量", example = "10")
90 90 @ExcelProperty("检测数量")
91   - private Integer checkQuantity;
  91 + private BigDecimal checkQuantity;
92 92  
93 93 @Schema(description = "合格品数量", example = "9")
94 94 @ExcelProperty("合格品数量")
95   - private Integer qualifiedQuantity;
  95 + private BigDecimal qualifiedQuantity;
96 96  
97 97 @Schema(description = "不合格品数量", example = "1")
98 98 @ExcelProperty("不合格品数量")
99   - private Integer unqualifiedQuantity;
  99 + private BigDecimal unqualifiedQuantity;
100 100  
101 101 // ========== 缺陷统计 ==========
102 102  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcSaveReqVO.java
... ... @@ -29,8 +29,8 @@ public class MesQcOqcSaveReqVO {
29 29 @Schema(description = "来源单据 ID", example = "200")
30 30 private Long sourceDocId;
31 31  
32   - @Schema(description = "来源单据类型", example = "SALES")
33   - private String sourceDocType;
  32 + @Schema(description = "来源单据类型", example = "118")
  33 + private Integer sourceDocType;
34 34  
35 35 @Schema(description = "来源单据编号", example = "SO20250101001")
36 36 private String sourceDocCode;
... ... @@ -62,18 +62,18 @@ public class MesQcOqcSaveReqVO {
62 62  
63 63 @Schema(description = "本次检测数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
64 64 @NotNull(message = "本次检测数量不能为空")
65   - @Min(value = 1, message = "本次检测数量必须大于 0")
66   - private Integer checkQuantity;
  65 + @DecimalMin(value = "0", message = "本次检测数量不能小于 0")
  66 + private BigDecimal checkQuantity;
67 67  
68 68 @Schema(description = "合格品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "9")
69 69 @NotNull(message = "合格品数量不能为空")
70   - @Min(value = 0, message = "合格品数量不能小于 0")
71   - private Integer qualifiedQuantity;
  70 + @DecimalMin(value = "0", message = "合格品数量不能小于 0")
  71 + private BigDecimal qualifiedQuantity;
72 72  
73 73 @Schema(description = "不合格品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
74 74 @NotNull(message = "不合格品数量不能为空")
75   - @Min(value = 0, message = "不合格品数量不能小于 0")
76   - private Integer unqualifiedQuantity;
  75 + @DecimalMin(value = "0", message = "不合格品数量不能小于 0")
  76 + private BigDecimal unqualifiedQuantity;
77 77  
78 78 // ========== 检验 ==========
79 79  
... ... @@ -101,7 +101,7 @@ public class MesQcOqcSaveReqVO {
101 101 if (ObjUtil.hasNull(checkQuantity, qualifiedQuantity, unqualifiedQuantity)) {
102 102 return true; // @NotNull 会处理 null
103 103 }
104   - return checkQuantity.equals(qualifiedQuantity + unqualifiedQuantity);
  104 + return checkQuantity.compareTo(qualifiedQuantity.add(unqualifiedQuantity)) == 0;
105 105 }
106 106  
107 107 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java
... ... @@ -33,8 +33,8 @@ public class MesQcRqcRespVO {
33 33 @Schema(description = "来源单据 ID", example = "200")
34 34 private Long sourceDocId;
35 35  
36   - @Schema(description = "来源单据类型", example = "RTISSUE")
37   - private String sourceDocType;
  36 + @Schema(description = "来源单据类型", example = "116")
  37 + private Integer sourceDocType;
38 38  
39 39 @Schema(description = "来源单据行 ID", example = "300")
40 40 private Long sourceLineId;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcSaveReqVO.java
... ... @@ -35,8 +35,8 @@ public class MesQcRqcSaveReqVO {
35 35 @Schema(description = "来源单据 ID", example = "200")
36 36 private Long sourceDocId;
37 37  
38   - @Schema(description = "来源单据类型", example = "RTISSUE")
39   - private String sourceDocType;
  38 + @Schema(description = "来源单据类型", example = "116")
  39 + private Integer sourceDocType;
40 40  
41 41 @Schema(description = "来源单据行 ID", example = "300")
42 42 private Long sourceLineId;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchGenerateReqVO.java
... ... @@ -78,6 +78,6 @@ public class MesWmBatchGenerateReqVO {
78 78 /**
79 79 * 质量状态
80 80 */
81   - private String qualityStatus;
  81 + private Integer qualityStatus;
82 82  
83 83 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/batch/vo/MesWmBatchRespVO.java
... ... @@ -88,7 +88,7 @@ public class MesWmBatchRespVO {
88 88 private String lotNumber;
89 89  
90 90 @Schema(description = "质量状态", example = "1")
91   - private String qualityStatus;
  91 + private Integer qualityStatus;
92 92  
93 93 @Schema(description = "备注", example = "备注")
94 94 private String remark;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/line/MesWmReturnSalesLineRespVO.java
... ... @@ -46,7 +46,7 @@ public class MesWmReturnSalesLineRespVO {
46 46 private String batchCode;
47 47  
48 48 @Schema(description = "质量状态", example = "合格")
49   - private String qualityStatus;
  49 + private Integer qualityStatus;
50 50  
51 51 @Schema(description = "备注", example = "备注")
52 52 private String remark;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnsales/vo/line/MesWmReturnSalesLineSaveReqVO.java
... ... @@ -36,7 +36,7 @@ public class MesWmReturnSalesLineSaveReqVO {
36 36 private Long batchId;
37 37  
38 38 @Schema(description = "质量状态", example = "合格")
39   - private String qualityStatus;
  39 + private Integer qualityStatus;
40 40  
41 41 @Schema(description = "备注", example = "备注")
42 42 private String remark;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/oqc/MesQcOqcDO.java
... ... @@ -47,7 +47,7 @@ public class MesQcOqcDO extends BaseDO {
47 47 */
48 48 private Long templateId;
49 49  
50   - // ========== 来源单据(TODO @芋艿:WM 模块迁移后接入) ==========
  50 + // ========== 来源单据 ==========
51 51  
52 52 /**
53 53 * 来源单据 ID
... ... @@ -55,8 +55,10 @@ public class MesQcOqcDO extends BaseDO {
55 55 private Long sourceDocId;
56 56 /**
57 57 * 来源单据类型
  58 + *
  59 + * 关联 {@link cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants}
58 60 */
59   - private String sourceDocType;
  61 + private Integer sourceDocType;
60 62 /**
61 63 * 来源单据编号
62 64 */
... ... @@ -97,15 +99,15 @@ public class MesQcOqcDO extends BaseDO {
97 99 /**
98 100 * 本次检测数量
99 101 */
100   - private Integer checkQuantity;
  102 + private BigDecimal checkQuantity;
101 103 /**
102 104 * 合格品数量
103 105 */
104   - private Integer qualifiedQuantity;
  106 + private BigDecimal qualifiedQuantity;
105 107 /**
106 108 * 不合格品数量
107 109 */
108   - private Integer unqualifiedQuantity;
  110 + private BigDecimal unqualifiedQuantity;
109 111  
110 112 // ========== 缺陷统计 ==========
111 113  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcDO.java
... ... @@ -47,7 +47,7 @@ public class MesQcRqcDO extends BaseDO {
47 47 */
48 48 private Long templateId;
49 49  
50   - // ========== 来源单据(TODO @芋艿:WM 模块迁移后接入) ==========
  50 + // ========== 来源单据 ==========
51 51  
52 52 /**
53 53 * 来源单据 ID
... ... @@ -55,8 +55,10 @@ public class MesQcRqcDO extends BaseDO {
55 55 private Long sourceDocId;
56 56 /**
57 57 * 来源单据类型
  58 + *
  59 + * 关联 {@link cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants}
58 60 */
59   - private String sourceDocType;
  61 + private Integer sourceDocType;
60 62 /**
61 63 * 来源单据行 ID
62 64 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/batch/MesWmBatchDO.java
... ... @@ -113,7 +113,7 @@ public class MesWmBatchDO extends BaseDO {
113 113 /**
114 114 * 质量状态
115 115 */
116   - private String qualityStatus;
  116 + private Integer qualityStatus;
117 117 /**
118 118 * 备注
119 119 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/productsales/MesWmProductSalesLineDO.java
... ... @@ -68,7 +68,7 @@ public class MesWmProductSalesLineDO extends BaseDO {
68 68 *
69 69 * 枚举 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum}
70 70 */
71   - private String qualityStatus;
  71 + private Integer qualityStatus;
72 72 /**
73 73 * 备注
74 74 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnsales/MesWmReturnSalesLineDO.java
... ... @@ -54,7 +54,7 @@ public class MesWmReturnSalesLineDO extends BaseDO {
54 54 *
55 55 * 枚举 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum}
56 56 */
57   - private String qualityStatus;
  57 + private Integer qualityStatus;
58 58 /**
59 59 * 备注
60 60 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -312,6 +312,7 @@ public interface ErrorCodeConstants {
312 312 ErrorCode QC_OQC_NOT_PREPARE = new ErrorCode(1_040_607_002, "只有草稿状态的检验单才可操作");
313 313 ErrorCode QC_OQC_QUANTITY_MISMATCH = new ErrorCode(1_040_607_004, "合格品与不合格品数量之和须等于检测数量");
314 314 ErrorCode QC_OQC_NO_TEMPLATE = new ErrorCode(1_040_607_005, "当前产品未配置 OQC 检测模板");
  315 + ErrorCode QC_OQC_CHECK_RESULT_EMPTY = new ErrorCode(1_040_607_006, "完成检验单前,检测结果必须填写");
315 316 // ========== MES 质量管理-出货检验行(1-040-607-100) ==========
316 317 ErrorCode QC_OQC_LINE_NOT_EXISTS = new ErrorCode(1_040_607_100, "出货检验行不存在");
317 318  
... ... @@ -321,6 +322,7 @@ public interface ErrorCodeConstants {
321 322 ErrorCode QC_RQC_NOT_PREPARE = new ErrorCode(1_040_608_002, "只有草稿状态的检验单才可操作");
322 323 ErrorCode QC_RQC_QUANTITY_MISMATCH = new ErrorCode(1_040_608_004, "合格品与不合格品数量之和须等于检测数量");
323 324 ErrorCode QC_RQC_NO_TEMPLATE = new ErrorCode(1_040_608_005, "当前产品未配置 RQC 检测模板");
  325 + ErrorCode QC_RQC_CHECK_RESULT_EMPTY = new ErrorCode(1_040_608_006, "完成检验单前,检测结果必须填写");
324 326 // ========== MES 质量管理-退货检验行(1-040-608-100) ==========
325 327 ErrorCode QC_RQC_LINE_NOT_EXISTS = new ErrorCode(1_040_608_100, "退货检验行不存在");
326 328  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmArrivalNoticeStatusEnum.java
... ... @@ -36,7 +36,7 @@ public enum MesWmArrivalNoticeStatusEnum implements ArrayValuable<Integer> {
36 36 *
37 37 * 对应方法:
38 38 * 1. 不需要检验时:{@link MesWmArrivalNoticeService#submitArrivalNotice(Long)}
39   - * 2. 或检验完成时:{@link MesWmArrivalNoticeService#approveArrivalNoticeWhenIqcComplete(Long, Long, Long, BigDecimal)}
  39 + * 2. 或检验完成时:{@link MesWmArrivalNoticeService#updateArrivalNoticeWhenIqcFinish(Long, Long, Long, BigDecimal)}
40 40 */
41 41 PENDING_RECEIPT(MesOrderStatusConstants.APPROVED, "待入库"),
42 42 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java
... ... @@ -102,8 +102,8 @@ public interface MesProFeedbackService {
102 102 * @param materialScrapQty 料废数量
103 103 * @param otherScrapQty 其他废品数量
104 104 */
105   - void completeFeedbackFromIpqc(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty,
106   - BigDecimal laborScrapQty, BigDecimal materialScrapQty, BigDecimal otherScrapQty);
  105 + void updateProFeedbackWhenIpqcFinish(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty,
  106 + BigDecimal laborScrapQty, BigDecimal materialScrapQty, BigDecimal otherScrapQty);
107 107  
108 108 }
109 109  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
... ... @@ -285,8 +285,8 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService {
285 285  
286 286 @Override
287 287 @Transactional(rollbackFor = Exception.class)
288   - public void completeFeedbackFromIpqc(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty,
289   - BigDecimal laborScrapQty, BigDecimal materialScrapQty, BigDecimal otherScrapQty) {
  288 + public void updateProFeedbackWhenIpqcFinish(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty,
  289 + BigDecimal laborScrapQty, BigDecimal materialScrapQty, BigDecimal otherScrapQty) {
290 290 // 1. 校验报工单存在且为待检验状态
291 291 MesProFeedbackDO feedback = validateFeedbackExists(feedbackId);
292 292 if (ObjUtil.notEqual(feedback.getStatus(), MesProFeedbackStatusEnum.UNCHECK.getStatus())) {
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java
... ... @@ -155,7 +155,7 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService {
155 155 }
156 156  
157 157 if (Objects.equals(ipqc.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)) {
158   - feedbackService.completeFeedbackFromIpqc(ipqc.getSourceDocId(),
  158 + feedbackService.updateProFeedbackWhenIpqcFinish(ipqc.getSourceDocId(),
159 159 ObjectUtil.defaultIfNull(ipqc.getQualifiedQuantity(), BigDecimal.ZERO),
160 160 ObjectUtil.defaultIfNull(ipqc.getUnqualifiedQuantity(), BigDecimal.ZERO),
161 161 ObjectUtil.defaultIfNull(ipqc.getLaborScrapQuantity(), BigDecimal.ZERO),
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcServiceImpl.java
... ... @@ -148,10 +148,10 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
148 148  
149 149 // 根据不同的来源单据类型,回写不同的单据
150 150 if (Objects.equals(iqc.getSourceDocType(), MesBizTypeConstants.WM_ARRIVAL_NOTICE)) {
151   - arrivalNoticeService.approveArrivalNoticeWhenIqcComplete(iqc.getSourceDocId(), iqc.getSourceLineId(),
  151 + arrivalNoticeService.updateArrivalNoticeWhenIqcFinish(iqc.getSourceDocId(), iqc.getSourceLineId(),
152 152 iqc.getId(), iqc.getQualifiedQuantity());
153 153 } else if (Objects.equals(iqc.getSourceDocType(), MesBizTypeConstants.WM_OUTSOURCE_RECPT)) {
154   - outsourceReceiptService.approveOutsourceReceiptWhenIqcComplete(iqc.getSourceDocId(), iqc.getSourceLineId(),
  154 + outsourceReceiptService.updateOutsourceReceiptWhenIqcFinish(iqc.getSourceDocId(), iqc.getSourceLineId(),
155 155 iqc.getId(), iqc.getQualifiedQuantity(), iqc.getUnqualifiedQuantity());
156 156 } else {
157 157 throw new IllegalArgumentException(
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java
... ... @@ -12,10 +12,12 @@ import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper;
12 12 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
13 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
14 14 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  15 +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
15 16 import cn.iocoder.yudao.module.mes.service.md.client.MesMdClientService;
16 17 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
17 18 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
18 19 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService;
  20 +import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesLineService;
19 21 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
20 22 import jakarta.annotation.Resource;
21 23 import org.springframework.context.annotation.Lazy;
... ... @@ -56,6 +58,10 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
56 58 @Lazy
57 59 private MesMdItemService itemService;
58 60 @Resource
  61 + @Lazy
  62 + private MesWmProductSalesLineService productSalesLineService;
  63 +
  64 + @Resource
59 65 private AdminUserApi adminUserApi;
60 66  
61 67 @Override
... ... @@ -100,16 +106,47 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
100 106 }
101 107  
102 108 @Override
  109 + @Transactional(rollbackFor = Exception.class)
103 110 public void finishOqc(Long id) {
104   - // 1. 校验存在 + 草稿状态
105   - validateOqcStatusPrepare(id);
  111 + // 1.1 校验存在 + 草稿状态
  112 + MesQcOqcDO oqc = validateOqcStatusPrepare(id);
  113 + // 1.2 校验检测结论必填
  114 + if (oqc.getCheckResult() == null) {
  115 + throw exception(QC_OQC_CHECK_RESULT_EMPTY);
  116 + }
106 117  
107 118 // 2. 更新状态为已完成
108 119 MesQcOqcDO updateObj = new MesQcOqcDO()
109 120 .setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus());
110 121 oqcMapper.updateById(updateObj);
111 122  
112   - // TODO @芋艿:WM 模块迁移后,更新销售出库单行的检验结果
  123 + // 3. 回写来源单据
  124 + writeBackSourceDoc(oqc);
  125 + }
  126 +
  127 + /**
  128 + * 回写来源单据(OQC 完成后)
  129 + *
  130 + * <p>当来源为销售出库单时,回写行的 oqcId 和 qualityStatus
  131 + *
  132 + * @param oqc 出货检验单
  133 + */
  134 + private void writeBackSourceDoc(MesQcOqcDO oqc) {
  135 + if (oqc.getSourceDocType() == null) {
  136 + return;
  137 + }
  138 + if (oqc.getSourceLineId() == null) {
  139 + throw new IllegalArgumentException(
  140 + "OQC 单[" + oqc.getId() + "] sourceDocType 非空但 sourceLineId 为空");
  141 + }
  142 +
  143 + if (Objects.equals(oqc.getSourceDocType(), MesBizTypeConstants.WM_PRODUCT_SALES)) {
  144 + // 回写销售出库单行的 oqcId + qualityStatus
  145 + productSalesLineService.updateProductSalesLineWhenOqcFinish(oqc.getSourceLineId(), oqc.getId(), oqc.getCheckResult());
  146 + } else {
  147 + throw new IllegalArgumentException(
  148 + "OQC 单[" + oqc.getId() + "] sourceDocType=" + oqc.getSourceDocType() + " 无法识别,无法回写来源单据");
  149 + }
113 150 }
114 151  
115 152 @Override
... ... @@ -190,8 +227,8 @@ public class MesQcOqcServiceImpl implements MesQcOqcService {
190 227 BigDecimal criticalRate = BigDecimal.ZERO;
191 228 BigDecimal majorRate = BigDecimal.ZERO;
192 229 BigDecimal minorRate = BigDecimal.ZERO;
193   - if (oqc.getCheckQuantity() != null && oqc.getCheckQuantity() > 0) {
194   - BigDecimal checkQty = BigDecimal.valueOf(oqc.getCheckQuantity());
  230 + if (oqc.getCheckQuantity() != null && oqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) {
  231 + BigDecimal checkQty = oqc.getCheckQuantity();
195 232 criticalRate = BigDecimal.valueOf(totalCritical).multiply(BigDecimal.valueOf(100))
196 233 .divide(checkQty, 2, RoundingMode.HALF_UP);
197 234 majorRate = BigDecimal.valueOf(totalMajor).multiply(BigDecimal.valueOf(100))
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java
... ... @@ -12,9 +12,12 @@ import cn.iocoder.yudao.module.mes.dal.mysql.qc.rqc.MesQcRqcMapper;
12 12 import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
13 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
14 14 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  15 +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
15 16 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
16 17 import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
17 18 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService;
  19 +import cn.iocoder.yudao.module.mes.service.wm.returnissue.MesWmReturnIssueLineService;
  20 +import cn.iocoder.yudao.module.mes.service.wm.returnsales.MesWmReturnSalesLineService;
18 21 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
19 22 import jakarta.annotation.Resource;
20 23 import org.springframework.context.annotation.Lazy;
... ... @@ -51,6 +54,12 @@ public class MesQcRqcServiceImpl implements MesQcRqcService {
51 54 @Resource
52 55 @Lazy
53 56 private MesQcDefectRecordService defectRecordService;
  57 + @Resource
  58 + @Lazy
  59 + private MesWmReturnIssueLineService returnIssueLineService;
  60 + @Resource
  61 + @Lazy
  62 + private MesWmReturnSalesLineService returnSalesLineService;
54 63  
55 64 @Resource
56 65 private AdminUserApi adminUserApi;
... ... @@ -95,10 +104,15 @@ public class MesQcRqcServiceImpl implements MesQcRqcService {
95 104 }
96 105  
97 106 @Override
  107 + @Transactional(rollbackFor = Exception.class)
98 108 public void finishRqc(Long id) {
99 109 // 1.1 校验存在 + 草稿状态
100 110 MesQcRqcDO rqc = validateRqcStatusPrepare(id);
101   - // 1.2 校验合格品 + 不合格品 = 检测数量
  111 + // 1.2 校验检测结论必填
  112 + if (rqc.getCheckResult() == null) {
  113 + throw exception(QC_RQC_CHECK_RESULT_EMPTY);
  114 + }
  115 + // 1.3 校验合格品 + 不合格品 = 检测数量
102 116 if (rqc.getCheckQuantity() != null && rqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) {
103 117 BigDecimal qualified = rqc.getQualifiedQuantity() != null ? rqc.getQualifiedQuantity() : BigDecimal.ZERO;
104 118 BigDecimal unqualified = rqc.getUnqualifiedQuantity() != null ? rqc.getUnqualifiedQuantity() : BigDecimal.ZERO;
... ... @@ -111,7 +125,40 @@ public class MesQcRqcServiceImpl implements MesQcRqcService {
111 125 MesQcRqcDO updateObj = new MesQcRqcDO().setId(id).setStatus(MesQcStatusEnum.FINISHED.getStatus());
112 126 rqcMapper.updateById(updateObj);
113 127  
114   - // TODO @芋艿:WM 模块迁移后,更新来源退料/退货单行的质量状态
  128 + // 3. 回写来源单据
  129 + writeBackSourceDoc(rqc);
  130 + }
  131 +
  132 + /**
  133 + * 回写来源单据(RQC 完成后)
  134 + *
  135 + * <p>根据 sourceDocType 分发:
  136 + * <ul>
  137 + * <li>WM_RETURN_ISSUE(生产退料单)→ 回写行的 qualityStatus</li>
  138 + * <li>WM_RETURN_SALES(销售退货单)→ 回写行的 qualityStatus</li>
  139 + * </ul>
  140 + *
  141 + * @param rqc 退货检验单
  142 + */
  143 + private void writeBackSourceDoc(MesQcRqcDO rqc) {
  144 + if (rqc.getSourceDocType() == null) {
  145 + return;
  146 + }
  147 + if (rqc.getSourceLineId() == null) {
  148 + throw new IllegalArgumentException(
  149 + "RQC 单[" + rqc.getId() + "] sourceDocType 非空但 sourceLineId 为空");
  150 + }
  151 +
  152 + if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_ISSUE)) {
  153 + // 回写生产退料单行的 qualityStatus
  154 + returnIssueLineService.updateReturnIssueLineWhenRqcFinish(rqc.getSourceLineId(), rqc.getCheckResult());
  155 + } else if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_SALES)) {
  156 + // 回写销售退货单行的 qualityStatus
  157 + returnSalesLineService.updateReturnSalesLineWhenRqcFinish(rqc.getSourceLineId(), rqc.getCheckResult());
  158 + } else {
  159 + throw new IllegalArgumentException(
  160 + "RQC 单[" + rqc.getId() + "] sourceDocType=" + rqc.getSourceDocType() + " 无法识别,无法回写来源单据");
  161 + }
115 162 }
116 163  
117 164 @Override
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineService.java
... ... @@ -74,7 +74,7 @@ public interface MesWmArrivalNoticeLineService {
74 74 * @param iqcId IQC 检验单编号
75 75 * @param qualifiedQuantity 合格数量
76 76 */
77   - void updateByIqcComplete(Long lineId, Long iqcId, BigDecimal qualifiedQuantity);
  77 + void updateArrivalNoticeLineWhenIqcFinish(Long lineId, Long iqcId, BigDecimal qualifiedQuantity);
78 78  
79 79 /**
80 80 * 校验到货通知单行存在
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineServiceImpl.java
... ... @@ -63,7 +63,7 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine
63 63 /**
64 64 * 初始化合格品数量:
65 65 * 1. 如果不需要 IQC 检验,则合格品数量直接 = 接收数量;
66   - * 2. 否则,合格品数量由对应的 IQC 检验单负责更新(见 {@link #updateByIqcComplete})
  66 + * 2. 否则,合格品数量由对应的 IQC 检验单负责更新(见 {@link #updateArrivalNoticeLineWhenIqcFinish})
67 67 */
68 68 private void initQualifiedQuantityIfNoIqc(MesWmArrivalNoticeLineDO line) {
69 69 if (BooleanUtil.isFalse(line.getIqcCheckFlag())) {
... ... @@ -100,7 +100,7 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine
100 100 }
101 101  
102 102 @Override
103   - public void updateByIqcComplete(Long lineId, Long iqcId, BigDecimal qualifiedQuantity) {
  103 + public void updateArrivalNoticeLineWhenIqcFinish(Long lineId, Long iqcId, BigDecimal qualifiedQuantity) {
104 104 // 校验行存在
105 105 validateArrivalNoticeLineExists(lineId);
106 106 // 更新
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java
... ... @@ -71,7 +71,7 @@ public interface MesWmArrivalNoticeService {
71 71 * @param iqcId IQC 检验单编号
72 72 * @param qualifiedQuantity 合格数量
73 73 */
74   - void approveArrivalNoticeWhenIqcComplete(Long id, Long lineId, Long iqcId, BigDecimal qualifiedQuantity);
  74 + void updateArrivalNoticeWhenIqcFinish(Long id, Long lineId, Long iqcId, BigDecimal qualifiedQuantity);
75 75  
76 76 /**
77 77 * 完成到货通知单(待入库 → 已完成),内部调用
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java
... ... @@ -96,24 +96,23 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService
96 96 throw exception(WM_ARRIVAL_NOTICE_NO_LINE);
97 97 }
98 98  
99   - // 2. 检查所有行的 iqcCheckFlag:如果没有需要检验的行,则直接审批通过
  99 + // 2. 检查所有行的 iqcCheckFlag:如果有需要检验的行,进入待质检状态
100 100 boolean needCheck = CollectionUtils.anyMatch(lines,
101 101 line -> Boolean.TRUE.equals(line.getIqcCheckFlag()));
102   - // TODO @AI:if return;并且不要取反;
103   - if (!needCheck) {
104   - // 不需要检验,直接进入待入库
105   - arrivalNoticeMapper.updateById(new MesWmArrivalNoticeDO()
106   - .setId(id).setStatus(MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus()));
107   - } else {
  102 + if (needCheck) {
108 103 // 需要检验,进入待质检
109 104 arrivalNoticeMapper.updateById(new MesWmArrivalNoticeDO()
110 105 .setId(id).setStatus(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus()));
  106 + return;
111 107 }
  108 + // 不需要检验,直接进入待入库
  109 + arrivalNoticeMapper.updateById(new MesWmArrivalNoticeDO()
  110 + .setId(id).setStatus(MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus()));
112 111 }
113 112  
114 113 @Override
115 114 @Transactional(rollbackFor = Exception.class)
116   - public void approveArrivalNoticeWhenIqcComplete(Long id, Long lineId, Long iqcId, BigDecimal qualifiedQuantity) {
  115 + public void updateArrivalNoticeWhenIqcFinish(Long id, Long lineId, Long iqcId, BigDecimal qualifiedQuantity) {
117 116 // 1.1 校验到货通知单存在
118 117 MesWmArrivalNoticeDO notice = validateArrivalNoticeExists(id);
119 118 // 1.2 校验状态为待质检
... ... @@ -122,14 +121,14 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService
122 121 }
123 122  
124 123 // 2. 更新到货通知单行:绑定 iqcId + 合格数量
125   - arrivalNoticeLineService.updateByIqcComplete(lineId, iqcId, qualifiedQuantity);
  124 + arrivalNoticeLineService.updateArrivalNoticeLineWhenIqcFinish(lineId, iqcId, qualifiedQuantity);
126 125  
127 126 // 3.1 判断是否所有需检行都已完成
128 127 List<MesWmArrivalNoticeLineDO> lines = arrivalNoticeLineService.getArrivalNoticeLineListByNoticeId(id);
129 128 boolean hasUnchecked = CollectionUtils.anyMatch(lines,
130 129 line -> Boolean.TRUE.equals(line.getIqcCheckFlag()) && line.getIqcId() == null);
131 130 if (hasUnchecked) {
132   - log.info("[updateWhenIqcComplete][到货通知单({}) 还有未完成检验的行,暂不更新状态]", id);
  131 + log.info("[updateArrivalNoticeWhenIqcFinish][到货通知单({}) 还有未完成检验的行,暂不更新状态]", id);
133 132 return;
134 133 }
135 134 // 3.2 所有行检验完成,更新主表状态 PENDING_QC → PENDING_RECEIPT
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptService.java
... ... @@ -88,8 +88,8 @@ public interface MesWmOutsourceReceiptService {
88 88 * @param qualifiedQuantity 合格品数量
89 89 * @param unqualifiedQuantity 不合格品数量
90 90 */
91   - void approveOutsourceReceiptWhenIqcComplete(Long receiptId, Long lineId, Long iqcId,
92   - BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity);
  91 + void updateOutsourceReceiptWhenIqcFinish(Long receiptId, Long lineId, Long iqcId,
  92 + BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity);
93 93  
94 94 /**
95 95 * 校验外协入库单和行存在
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptServiceImpl.java
... ... @@ -209,8 +209,8 @@ public class MesWmOutsourceReceiptServiceImpl implements MesWmOutsourceReceiptSe
209 209  
210 210 @Override
211 211 @Transactional(rollbackFor = Exception.class)
212   - public void approveOutsourceReceiptWhenIqcComplete(Long receiptId, Long lineId, Long iqcId,
213   - BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity) {
  212 + public void updateOutsourceReceiptWhenIqcFinish(Long receiptId, Long lineId, Long iqcId,
  213 + BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity) {
214 214 // 1.1 校验入库单存在
215 215 MesWmOutsourceReceiptDO receipt = validateOutsourceReceiptExists(receiptId);
216 216 // 1.2 校验状态为待检验
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineService.java
1 1 package cn.iocoder.yudao.module.mes.service.wm.productsales;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 4 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLinePageReqVO;
4 5 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLineSaveReqVO;
5 6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO;
... ... @@ -65,7 +66,15 @@ public interface MesWmProductSalesLineService {
65 66 * @param pageReqVO 分页查询
66 67 * @return 销售出库单行分页
67 68 */
68   - cn.iocoder.yudao.framework.common.pojo.PageResult<MesWmProductSalesLineDO> getProductSalesLinePage(
69   - MesWmProductSalesLinePageReqVO pageReqVO);
  69 + PageResult<MesWmProductSalesLineDO> getProductSalesLinePage(MesWmProductSalesLinePageReqVO pageReqVO);
  70 +
  71 + /**
  72 + * OQC 检验完成后,更新销售出库单行的 OQC 质检状态
  73 + *
  74 + * @param id 行 ID
  75 + * @param oqcId 质检单 ID
  76 + * @param checkResult 检验结果
  77 + */
  78 + void updateProductSalesLineWhenOqcFinish(Long id, Long oqcId, Integer checkResult);
70 79  
71 80 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImpl.java
... ... @@ -5,15 +5,16 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesW
5 5 import cn.iocoder.yudao.module.mes.controller.admin.wm.productsales.vo.line.MesWmProductSalesLineSaveReqVO;
6 6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO;
7 7 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper;
  8 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
  9 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
8 10 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
9 11 import jakarta.annotation.Resource;
10   -import org.springframework.context.annotation.Lazy;
11 12 import org.springframework.stereotype.Service;
12 13 import org.springframework.transaction.annotation.Transactional;
13 14 import org.springframework.validation.annotation.Validated;
14 15  
15   -import java.math.BigDecimal;
16 16 import java.util.List;
  17 +import java.util.Objects;
17 18  
18 19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19 20 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_PRODUCT_SALES_LINE_NOT_EXISTS;
... ... @@ -29,14 +30,8 @@ public class MesWmProductSalesLineServiceImpl implements MesWmProductSalesLineSe
29 30  
30 31 @Resource
31 32 private MesWmProductSalesLineMapper productSalesLineMapper;
32   -
33   - @Resource
34   - @Lazy
35   - private MesWmProductSalesService productSalesService;
36   -
37 33 @Resource
38 34 private MesWmProductSalesDetailService productSalesDetailService;
39   -
40 35 @Resource
41 36 private MesMdItemService itemService;
42 37  
... ... @@ -104,4 +99,12 @@ public class MesWmProductSalesLineServiceImpl implements MesWmProductSalesLineSe
104 99 return line;
105 100 }
106 101  
  102 + @Override
  103 + public void updateProductSalesLineWhenOqcFinish(Long id, Long oqcId, Integer checkResult) {
  104 + Integer qualityStatus = Objects.equals(checkResult, MesQcCheckResultEnum.PASS.getType())
  105 + ? MesWmQualityStatusEnum.PASS.getStatus() : MesWmQualityStatusEnum.FAIL.getStatus();
  106 + productSalesLineMapper.updateById(new MesWmProductSalesLineDO()
  107 + .setId(id).setOqcId(oqcId).setQualityStatus(qualityStatus));
  108 + }
  109 +
107 110 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineService.java
... ... @@ -82,4 +82,12 @@ public interface MesWmReturnIssueLineService {
82 82 */
83 83 void updateReturnIssueQualityStatusByIssueId(Long issueId, Integer issueType);
84 84  
  85 + /**
  86 + * RQC 检验完成后,更新生产退料单行的质量状态
  87 + *
  88 + * @param id 行 ID
  89 + * @param checkResult 检验结果
  90 + */
  91 + void updateReturnIssueLineWhenRqcFinish(Long id, Integer checkResult);
  92 +
85 93 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImpl.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.line.MesWm
8 8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueDO;
9 9 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO;
10 10 import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnissue.MesWmReturnIssueLineMapper;
  11 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
11 12 import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
12 13 import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueTypeEnum;
13 14 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
... ... @@ -17,6 +18,7 @@ import org.springframework.stereotype.Service;
17 18 import org.springframework.validation.annotation.Validated;
18 19  
19 20 import java.util.List;
  21 +import java.util.Objects;
20 22  
21 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
22 24 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_ISSUE_LINE_NOT_EXISTS;
... ... @@ -134,4 +136,11 @@ public class MesWmReturnIssueLineServiceImpl implements MesWmReturnIssueLineServ
134 136 return MesWmQualityStatusEnum.FAIL.getStatus(); // 不合格
135 137 }
136 138  
  139 + @Override
  140 + public void updateReturnIssueLineWhenRqcFinish(Long id, Integer checkResult) {
  141 + Integer qualityStatus = Objects.equals(checkResult, MesQcCheckResultEnum.PASS.getType())
  142 + ? MesWmQualityStatusEnum.PASS.getStatus() : MesWmQualityStatusEnum.FAIL.getStatus();
  143 + issueLineMapper.updateById(new MesWmReturnIssueLineDO().setId(id).setQualityStatus(qualityStatus));
  144 + }
  145 +
137 146 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineService.java
... ... @@ -82,6 +82,14 @@ public interface MesWmReturnSalesLineService {
82 82 * @param returnId 退货单ID
83 83 * @param qualityStatus 质量状态
84 84 */
85   - void updateQualityStatusByReturnId(Long returnId, String qualityStatus);
  85 + void updateQualityStatusByReturnId(Long returnId, Integer qualityStatus);
  86 +
  87 + /**
  88 + * RQC 检验完成后,更新销售退货单行的质量状态
  89 + *
  90 + * @param id 行 ID
  91 + * @param checkResult 检验结果
  92 + */
  93 + void updateReturnSalesLineWhenRqcFinish(Long id, Integer checkResult);
86 94  
87 95 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java
... ... @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWm
7 7 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
8 8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO;
9 9 import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnsales.MesWmReturnSalesLineMapper;
  10 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
  11 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
10 12 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
11 13 import jakarta.annotation.Resource;
12 14 import org.springframework.context.annotation.Lazy;
... ... @@ -14,6 +16,7 @@ import org.springframework.stereotype.Service;
14 16 import org.springframework.validation.annotation.Validated;
15 17  
16 18 import java.util.List;
  19 +import java.util.Objects;
17 20  
18 21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
19 22 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_BATCH_REQUIRED;
... ... @@ -102,7 +105,7 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ
102 105 }
103 106  
104 107 @Override
105   - public void updateQualityStatusByReturnId(Long returnId, String qualityStatus) {
  108 + public void updateQualityStatusByReturnId(Long returnId, Integer qualityStatus) {
106 109 List<MesWmReturnSalesLineDO> lines = returnSalesLineMapper.selectListByReturnId(returnId);
107 110 for (MesWmReturnSalesLineDO line : lines) {
108 111 returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO()
... ... @@ -125,4 +128,12 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ
125 128 }
126 129 }
127 130  
  131 + @Override
  132 + public void updateReturnSalesLineWhenRqcFinish(Long id, Integer checkResult) {
  133 + Integer qualityStatus = Objects.equals(checkResult, MesQcCheckResultEnum.PASS.getType())
  134 + ? MesWmQualityStatusEnum.PASS.getStatus()
  135 + : MesWmQualityStatusEnum.FAIL.getStatus();
  136 + returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO().setId(id).setQualityStatus(qualityStatus));
  137 + }
  138 +
128 139 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesServiceImpl.java
... ... @@ -124,7 +124,7 @@ public class MesWmReturnSalesServiceImpl implements MesWmReturnSalesService {
124 124  
125 125 // DONE @AI:全部的行设置为待检验状态
126 126 returnSalesLineService.updateQualityStatusByReturnId(id,
127   - String.valueOf(MesWmQualityStatusEnum.PENDING.getStatus()));
  127 + MesWmQualityStatusEnum.PENDING.getStatus());
128 128 }
129 129  
130 130 @Override
... ...
yudao-module-mes/src/main/resources/mapper/qc/pendinginspect/MesQcPendingInspectMapper.xml
... ... @@ -3,11 +3,12 @@
3 3 <mapper namespace="cn.iocoder.yudao.module.mes.dal.mysql.qc.pendinginspect.MesQcPendingInspectMapper">
4 4  
5 5 <!--
6   - 待检任务查询(UNION ALL 多来源),目前已实现的来源:
  6 + 待检任务查询(UNION ALL 多来源),已实现的来源:
7 7 1. 到货通知单(IQC):状态=待质检(2),行的 iqc_check_flag=1 且 iqc_id IS NULL
8 8 2. 外协入库单(IQC/OIQC):状态=待检验(1),行的 iqc_check=1 且 iqc_id IS NULL
9   -
10   - TODO IPQC/OQC/RQC 来源待对应模块就绪后补充
  9 + 3. 生产报工(IPQC):状态=待检验(3)
  10 + 4. 销售出库单(OQC):行的 oqc_check=1 且 oqc_id IS NULL
  11 + 5. 生产退料单(RQC):状态=待检验(5),行的 qc_flag=1 且 quality_status=0(待检)
11 12 -->
12 13 <select id="selectQcPendingPage" resultType="cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectRespVO">
13 14 SELECT * FROM (
... ... @@ -50,6 +51,64 @@
50 51 AND rl.iqc_id IS NULL
51 52 AND r.deleted = 0
52 53 AND rl.deleted = 0
  54 +
  55 + UNION ALL
  56 +
  57 + <!-- 3. IPQC 来源:生产报工(状态=待检验) -->
  58 + SELECT
  59 + f.id AS sourceDocId,
  60 + ${@cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants@PRO_FEEDBACK} AS sourceDocType,
  61 + f.code AS sourceDocCode,
  62 + NULL AS sourceLineId,
  63 + f.feedback_time AS recordTime,
  64 + ${@cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum@IPQC.type} AS qcType,
  65 + f.item_id AS itemId,
  66 + f.uncheck_quantity AS quantity,
  67 + NULL AS vendorId
  68 + FROM mes_pro_feedback f
  69 + WHERE f.status = ${@cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum@UNCHECK.status}
  70 + AND f.deleted = 0
  71 +
  72 + UNION ALL
  73 +
  74 + <!-- 4. OQC 来源:销售出库单行(oqc_check=1 且 oqc_id IS NULL) -->
  75 + SELECT
  76 + s.id AS sourceDocId,
  77 + ${@cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants@WM_PRODUCT_SALES} AS sourceDocType,
  78 + s.code AS sourceDocCode,
  79 + sl.id AS sourceLineId,
  80 + s.sales_date AS recordTime,
  81 + ${@cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum@OQC.type} AS qcType,
  82 + sl.item_id AS itemId,
  83 + sl.quantity AS quantity,
  84 + NULL AS vendorId
  85 + FROM mes_wm_product_sales s
  86 + JOIN mes_wm_product_sales_line sl ON s.id = sl.sales_id
  87 + WHERE sl.oqc_check = 1
  88 + AND sl.oqc_id IS NULL
  89 + AND s.deleted = 0
  90 + AND sl.deleted = 0
  91 +
  92 + UNION ALL
  93 +
  94 + <!-- 5. RQC 来源:生产退料单行(状态=待检验,行的 qc_flag=1 且 quality_status=0) -->
  95 + SELECT
  96 + ri.id AS sourceDocId,
  97 + ${@cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants@WM_RETURN_ISSUE} AS sourceDocType,
  98 + ri.code AS sourceDocCode,
  99 + ril.id AS sourceLineId,
  100 + ri.return_date AS recordTime,
  101 + ${@cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum@RQC.type} AS qcType,
  102 + ril.item_id AS itemId,
  103 + ril.quantity AS quantity,
  104 + NULL AS vendorId
  105 + FROM mes_wm_return_issue ri
  106 + JOIN mes_wm_return_issue_line ril ON ri.id = ril.issue_id
  107 + WHERE ri.status = ${@cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueStatusEnum@CONFIRMED.status}
  108 + AND ril.qc_flag = 1
  109 + AND ril.quality_status = ${@cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum@PENDING.status}
  110 + AND ri.deleted = 0
  111 + AND ril.deleted = 0
53 112 ) t
54 113 <where>
55 114 <if test="sourceDocCode != null and sourceDocCode != ''">
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImplTest.java
... ... @@ -56,7 +56,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
56 56 private MesWmProductProduceLineService produceLineService;
57 57  
58 58 @Test
59   - public void testCompleteFeedbackFromIpqc_success_withUnqualified() {
  59 + public void testUpdateProFeedbackWhenIpqcFinish_success_withUnqualified() {
60 60 // 准备数据:插入一条待检验状态的报工单
61 61 Long taskId = randomLongId();
62 62 Long workOrderId = randomLongId();
... ... @@ -87,7 +87,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
87 87 BigDecimal materialScrapQty = BigDecimal.valueOf(10);
88 88 BigDecimal otherScrapQty = BigDecimal.valueOf(5);
89 89  
90   - feedbackService.completeFeedbackFromIpqc(feedback.getId(),
  90 + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(),
91 91 qualifiedQty, unqualifiedQty, laborScrapQty, materialScrapQty, otherScrapQty);
92 92  
93 93 // 断言 1:调用了 splitPendingAndFinishProduce
... ... @@ -115,7 +115,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
115 115 }
116 116  
117 117 @Test
118   - public void testCompleteFeedbackFromIpqc_success_allQualified() {
  118 + public void testUpdateProFeedbackWhenIpqcFinish_success_allQualified() {
119 119 // 准备数据:全部合格
120 120 Long taskId = randomLongId();
121 121 Long workOrderId = randomLongId();
... ... @@ -136,7 +136,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
136 136 .thenReturn(List.of(qualifiedLine));
137 137  
138 138 // 调用
139   - feedbackService.completeFeedbackFromIpqc(feedback.getId(),
  139 + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(),
140 140 BigDecimal.valueOf(50), BigDecimal.ZERO,
141 141 BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
142 142  
... ... @@ -151,17 +151,17 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
151 151 }
152 152  
153 153 @Test
154   - public void testCompleteFeedbackFromIpqc_feedbackNotExists() {
  154 + public void testUpdateProFeedbackWhenIpqcFinish_feedbackNotExists() {
155 155 // 调用不存在的 feedbackId,应该抛异常
156 156 Long feedbackId = randomLongId();
157 157 assertThrows(Exception.class, () ->
158   - feedbackService.completeFeedbackFromIpqc(feedbackId,
  158 + feedbackService.updateProFeedbackWhenIpqcFinish(feedbackId,
159 159 BigDecimal.TEN, BigDecimal.ZERO,
160 160 BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO));
161 161 }
162 162  
163 163 @Test
164   - public void testCompleteFeedbackFromIpqc_feedbackNotUncheck() {
  164 + public void testUpdateProFeedbackWhenIpqcFinish_feedbackNotUncheck() {
165 165 // 准备数据:草稿状态(不是 UNCHECK),应该报错
166 166 MesProFeedbackDO feedback = randomPojo(MesProFeedbackDO.class, o -> {
167 167 o.setStatus(MesProFeedbackStatusEnum.PREPARE.getStatus());
... ... @@ -170,7 +170,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
170 170  
171 171 // 调用,应该抛异常
172 172 assertThrows(Exception.class, () ->
173   - feedbackService.completeFeedbackFromIpqc(feedback.getId(),
  173 + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(),
174 174 BigDecimal.TEN, BigDecimal.ZERO,
175 175 BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO));
176 176  
... ... @@ -179,7 +179,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
179 179 }
180 180  
181 181 @Test
182   - public void testCompleteFeedbackFromIpqc_feedbackAlreadyFinished() {
  182 + public void testUpdateProFeedbackWhenIpqcFinish_feedbackAlreadyFinished() {
183 183 // 准备数据:已完成状态,不能再次完成
184 184 MesProFeedbackDO feedback = randomPojo(MesProFeedbackDO.class, o -> {
185 185 o.setStatus(MesProFeedbackStatusEnum.FINISHED.getStatus());
... ... @@ -188,7 +188,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest {
188 188  
189 189 // 调用,应该抛异常
190 190 assertThrows(Exception.class, () ->
191   - feedbackService.completeFeedbackFromIpqc(feedback.getId(),
  191 + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(),
192 192 BigDecimal.TEN, BigDecimal.ZERO,
193 193 BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO));
194 194 }
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImplTest.java
... ... @@ -88,7 +88,7 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest {
88 88  
89 89 // 断言 2:调用了 feedbackService.completeFeedbackFromIpqc,传递正确参数
90 90 // 注意:数量经过 DB 存取后 scale 可能变化(例如 80 → 80.00),所以用 any() 匹配
91   - verify(feedbackService).completeFeedbackFromIpqc(
  91 + verify(feedbackService).updateProFeedbackWhenIpqcFinish(
92 92 eq(sourceDocId),
93 93 any(BigDecimal.class),
94 94 any(BigDecimal.class),
... ... @@ -119,7 +119,7 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest {
119 119 ipqcService.finishIpqc(ipqc.getId());
120 120  
121 121 // 断言:所有数量参数都是 BigDecimal.ZERO(defaultIfNull 处理)
122   - verify(feedbackService).completeFeedbackFromIpqc(
  122 + verify(feedbackService).updateProFeedbackWhenIpqcFinish(
123 123 eq(sourceDocId),
124 124 eq(BigDecimal.ZERO),
125 125 eq(BigDecimal.ZERO),
... ... @@ -148,7 +148,7 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest {
148 148 assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedIpqc.getStatus());
149 149  
150 150 // 断言 2:不应该调用 feedbackService
151   - verify(feedbackService, never()).completeFeedbackFromIpqc(
  151 + verify(feedbackService, never()).updateProFeedbackWhenIpqcFinish(
152 152 anyLong(), any(), any(), any(), any(), any());
153 153 }
154 154  
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcServiceImplTest.java
... ... @@ -58,7 +58,7 @@ public class MesQcIqcServiceImplTest extends BaseDbUnitTest {
58 58  
59 59 @Test
60 60 public void testFinishIqc_writeBack_arrivalNotice() {
61   - // mock 数据:插入一条草稿状态的 IQC 单,来源为到货通知单
  61 + // 准备数据:插入一条草稿状态的 IQC 单,来源为到货通知单
62 62 Long sourceDocId = randomLongId();
63 63 Long sourceLineId = randomLongId();
64 64 MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> {
... ... @@ -79,16 +79,16 @@ public class MesQcIqcServiceImplTest extends BaseDbUnitTest {
79 79 MesQcIqcDO updatedIqc = iqcMapper.selectById(iqc.getId());
80 80 assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedIqc.getStatus());
81 81 // 断言:验证回写到货通知单(参数使用 any 避免 BigDecimal 精度问题)
82   - verify(arrivalNoticeService).approveArrivalNoticeWhenIqcComplete(
  82 + verify(arrivalNoticeService).updateArrivalNoticeWhenIqcFinish(
83 83 eq(sourceDocId), eq(sourceLineId), eq(iqc.getId()), any(BigDecimal.class));
84 84 // 断言:不应该调用外协入库单的回写
85   - verify(outsourceReceiptService, never()).approveOutsourceReceiptWhenIqcComplete(
  85 + verify(outsourceReceiptService, never()).updateOutsourceReceiptWhenIqcFinish(
86 86 anyLong(), anyLong(), anyLong(), any(), any());
87 87 }
88 88  
89 89 @Test
90 90 public void testFinishIqc_writeBack_outsourceReceipt() {
91   - // mock 数据:插入一条草稿状态的 IQC 单,来源为外协入库单
  91 + // 准备数据:插入一条草稿状态的 IQC 单,来源为外协入库单
92 92 Long sourceDocId = randomLongId();
93 93 Long sourceLineId = randomLongId();
94 94 MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> {
... ... @@ -109,16 +109,16 @@ public class MesQcIqcServiceImplTest extends BaseDbUnitTest {
109 109 MesQcIqcDO updatedIqc = iqcMapper.selectById(iqc.getId());
110 110 assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedIqc.getStatus());
111 111 // 断言:验证回写外协入库单(参数使用 any 避免 BigDecimal 精度问题)
112   - verify(outsourceReceiptService).approveOutsourceReceiptWhenIqcComplete(
  112 + verify(outsourceReceiptService).updateOutsourceReceiptWhenIqcFinish(
113 113 eq(sourceDocId), eq(sourceLineId), eq(iqc.getId()), any(BigDecimal.class), any(BigDecimal.class));
114 114 // 断言:不应该调用到货通知单的回写
115   - verify(arrivalNoticeService, never()).approveArrivalNoticeWhenIqcComplete(
  115 + verify(arrivalNoticeService, never()).updateArrivalNoticeWhenIqcFinish(
116 116 anyLong(), anyLong(), anyLong(), any());
117 117 }
118 118  
119 119 @Test
120 120 public void testFinishIqc_writeBack_noSourceDoc() {
121   - // mock 数据:sourceDocType 为空,不需要回写
  121 + // 准备数据:sourceDocType 为空,不需要回写
122 122 MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> {
123 123 o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
124 124 o.setCheckResult(1);
... ... @@ -135,15 +135,15 @@ public class MesQcIqcServiceImplTest extends BaseDbUnitTest {
135 135 MesQcIqcDO updatedIqc = iqcMapper.selectById(iqc.getId());
136 136 assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedIqc.getStatus());
137 137 // 断言:不应该调用任何回写
138   - verify(arrivalNoticeService, never()).approveArrivalNoticeWhenIqcComplete(
  138 + verify(arrivalNoticeService, never()).updateArrivalNoticeWhenIqcFinish(
139 139 anyLong(), anyLong(), anyLong(), any());
140   - verify(outsourceReceiptService, never()).approveOutsourceReceiptWhenIqcComplete(
  140 + verify(outsourceReceiptService, never()).updateOutsourceReceiptWhenIqcFinish(
141 141 anyLong(), anyLong(), anyLong(), any(), any());
142 142 }
143 143  
144 144 @Test
145 145 public void testFinishIqc_writeBack_sourceDocTypeDirtyData() {
146   - // mock 数据:sourceDocType 非空但 sourceLineId 为空,应该抛异常
  146 + // 准备数据:sourceDocType 非空但 sourceLineId 为空,应该抛异常
147 147 MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> {
148 148 o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
149 149 o.setCheckResult(1);
... ... @@ -159,7 +159,7 @@ public class MesQcIqcServiceImplTest extends BaseDbUnitTest {
159 159  
160 160 @Test
161 161 public void testFinishIqc_writeBack_unknownSourceDocType() {
162   - // mock 数据:sourceDocType 无法识别
  162 + // 准备数据:sourceDocType 无法识别
163 163 MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> {
164 164 o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
165 165 o.setCheckResult(1);
... ... @@ -173,4 +173,31 @@ public class MesQcIqcServiceImplTest extends BaseDbUnitTest {
173 173 assertThrows(IllegalArgumentException.class, () -> iqcService.finishIqc(iqc.getId()));
174 174 }
175 175  
  176 + @Test
  177 + public void testFinishIqc_checkResultEmpty() {
  178 + // 准备数据:checkResult 为空,应该报错
  179 + MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> {
  180 + o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
  181 + o.setCheckResult(null); // 检测结论为空
  182 + o.setSourceDocType(null);
  183 + });
  184 + iqcMapper.insert(iqc);
  185 +
  186 + // 调用,应该抛异常(检测结论必填)
  187 + assertThrows(Exception.class, () -> iqcService.finishIqc(iqc.getId()));
  188 + }
  189 +
  190 + @Test
  191 + public void testFinishIqc_notDraftStatus() {
  192 + // 准备数据:已完成状态,不能再次完成
  193 + MesQcIqcDO iqc = randomPojo(MesQcIqcDO.class, o -> {
  194 + o.setStatus(MesQcStatusEnum.FINISHED.getStatus());
  195 + o.setCheckResult(1);
  196 + });
  197 + iqcMapper.insert(iqc);
  198 +
  199 + // 调用,应该抛异常(不是草稿状态)
  200 + assertThrows(Exception.class, () -> iqcService.finishIqc(iqc.getId()));
  201 + }
  202 +
176 203 }
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.qc.oqc;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
  5 +import cn.iocoder.yudao.module.mes.dal.mysql.qc.oqc.MesQcOqcMapper;
  6 +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
  7 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
  8 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  9 +import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
  10 +import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService;
  11 +import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesLineService;
  12 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  13 +import jakarta.annotation.Resource;
  14 +import org.junit.jupiter.api.Test;
  15 +import org.springframework.context.annotation.Import;
  16 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  17 +
  18 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  19 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  20 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  21 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.QC_OQC_NOT_EXISTS;
  22 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.QC_OQC_NOT_PREPARE;
  23 +import static org.junit.jupiter.api.Assertions.assertEquals;
  24 +import static org.mockito.ArgumentMatchers.eq;
  25 +import static org.mockito.Mockito.verify;
  26 +
  27 +/**
  28 + * {@link MesQcOqcServiceImpl} 的单元测试类
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +@Import(MesQcOqcServiceImpl.class)
  33 +public class MesQcOqcServiceImplTest extends BaseDbUnitTest {
  34 +
  35 + @Resource
  36 + private MesQcOqcServiceImpl oqcService;
  37 +
  38 + @Resource
  39 + private MesQcOqcMapper oqcMapper;
  40 +
  41 + @MockitoBean
  42 + private MesWmProductSalesLineService productSalesLineService;
  43 + @MockitoBean
  44 + private MesQcOqcLineService oqcLineService;
  45 + @MockitoBean
  46 + private MesMdItemService itemService;
  47 + @MockitoBean
  48 + private MesQcTemplateDetailService templateDetailService;
  49 + @MockitoBean
  50 + private MesQcDefectRecordService defectRecordService;
  51 + @MockitoBean
  52 + private AdminUserApi adminUserApi;
  53 +
  54 + @Test
  55 + public void testFinishOqc_success() {
  56 + // 准备参数
  57 + Long sourceLineId = randomLongId();
  58 + Integer checkResult = 1;
  59 +
  60 + // mock 数据
  61 + MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> {
  62 + o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
  63 + o.setSourceDocType(MesBizTypeConstants.WM_PRODUCT_SALES);
  64 + o.setSourceLineId(sourceLineId);
  65 + o.setCheckResult(checkResult);
  66 + });
  67 + oqcMapper.insert(oqc);
  68 +
  69 + // 调用
  70 + oqcService.finishOqc(oqc.getId());
  71 +
  72 + // 断言:验证状态更新
  73 + MesQcOqcDO updatedOqc = oqcMapper.selectById(oqc.getId());
  74 + assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedOqc.getStatus());
  75 +
  76 + // 断言:验证回写调用
  77 + verify(productSalesLineService).updateProductSalesLineWhenOqcFinish(eq(sourceLineId), eq(oqc.getId()), eq(checkResult));
  78 + }
  79 +
  80 + @Test
  81 + public void testFinishOqc_notExists() {
  82 + // 准备参数
  83 + Long oqcId = randomLongId();
  84 +
  85 + // 调用,并断言异常
  86 + assertServiceException(() -> oqcService.finishOqc(oqcId), QC_OQC_NOT_EXISTS);
  87 + }
  88 +
  89 + @Test
  90 + public void testFinishOqc_statusNotDraft() {
  91 + // 准备参数
  92 + // mock 数据:状态为已完成
  93 + MesQcOqcDO oqc = randomPojo(MesQcOqcDO.class, o -> {
  94 + o.setStatus(MesQcStatusEnum.FINISHED.getStatus());
  95 + });
  96 + oqcMapper.insert(oqc);
  97 +
  98 + // 调用,并断言异常
  99 + assertServiceException(() -> oqcService.finishOqc(oqc.getId()), QC_OQC_NOT_PREPARE);
  100 + }
  101 +
  102 +}
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.qc.rqc;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcDO;
  5 +import cn.iocoder.yudao.module.mes.dal.mysql.qc.rqc.MesQcRqcMapper;
  6 +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
  7 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
  8 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  9 +import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService;
  10 +import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService;
  11 +import cn.iocoder.yudao.module.mes.service.wm.returnissue.MesWmReturnIssueLineService;
  12 +import cn.iocoder.yudao.module.mes.service.wm.returnsales.MesWmReturnSalesLineService;
  13 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  14 +import jakarta.annotation.Resource;
  15 +import org.junit.jupiter.api.Test;
  16 +import org.springframework.context.annotation.Import;
  17 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  18 +
  19 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  20 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  21 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  22 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.QC_RQC_NOT_EXISTS;
  23 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.QC_RQC_NOT_PREPARE;
  24 +import static org.junit.jupiter.api.Assertions.assertEquals;
  25 +import static org.mockito.ArgumentMatchers.anyInt;
  26 +import static org.mockito.ArgumentMatchers.anyLong;
  27 +import static org.mockito.ArgumentMatchers.eq;
  28 +import static org.mockito.Mockito.never;
  29 +import static org.mockito.Mockito.verify;
  30 +
  31 +/**
  32 + * {@link MesQcRqcServiceImpl} 的单元测试类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Import(MesQcRqcServiceImpl.class)
  37 +public class MesQcRqcServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private MesQcRqcServiceImpl rqcService;
  41 +
  42 + @Resource
  43 + private MesQcRqcMapper rqcMapper;
  44 +
  45 + @MockitoBean
  46 + private MesWmReturnIssueLineService returnIssueLineService;
  47 + @MockitoBean
  48 + private MesWmReturnSalesLineService returnSalesLineService;
  49 + @MockitoBean
  50 + private MesQcRqcLineService rqcLineService;
  51 + @MockitoBean
  52 + private MesMdItemService itemService;
  53 + @MockitoBean
  54 + private MesQcTemplateDetailService templateDetailService;
  55 + @MockitoBean
  56 + private MesQcDefectRecordService defectRecordService;
  57 + @MockitoBean
  58 + private AdminUserApi adminUserApi;
  59 +
  60 + @Test
  61 + public void testFinishRqc_successWithReturnIssue() {
  62 + // 准备参数
  63 + Long sourceLineId = randomLongId();
  64 + Integer checkResult = 1;
  65 +
  66 + // mock 数据
  67 + MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> {
  68 + o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
  69 + o.setSourceDocType(MesBizTypeConstants.WM_RETURN_ISSUE);
  70 + o.setSourceLineId(sourceLineId);
  71 + o.setCheckResult(checkResult);
  72 + // 设置数量通过 finishRqc 的数量校验:合格 + 不合格 = 检测数量
  73 + o.setCheckQuantity(new java.math.BigDecimal("100"));
  74 + o.setQualifiedQuantity(new java.math.BigDecimal("80"));
  75 + o.setUnqualifiedQuantity(new java.math.BigDecimal("20"));
  76 + });
  77 + rqcMapper.insert(rqc);
  78 +
  79 + // 调用
  80 + rqcService.finishRqc(rqc.getId());
  81 +
  82 + // 断言:验证状态更新
  83 + MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId());
  84 + assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus());
  85 +
  86 + // 断言:验证回写调用生产退料
  87 + verify(returnIssueLineService).updateReturnIssueLineWhenRqcFinish(eq(sourceLineId), eq(checkResult));
  88 + // 断言:未调用销售退货
  89 + verify(returnSalesLineService, never()).updateReturnSalesLineWhenRqcFinish(anyLong(), anyInt());
  90 + }
  91 +
  92 + @Test
  93 + public void testFinishRqc_successWithReturnSales() {
  94 + // 准备参数
  95 + Long sourceLineId = randomLongId();
  96 + Integer checkResult = 1;
  97 +
  98 + // mock 数据
  99 + MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> {
  100 + o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
  101 + o.setSourceDocType(MesBizTypeConstants.WM_RETURN_SALES);
  102 + o.setSourceLineId(sourceLineId);
  103 + o.setCheckResult(checkResult);
  104 + // 设置数量通过 finishRqc 的数量校验:合格 + 不合格 = 检测数量
  105 + o.setCheckQuantity(new java.math.BigDecimal("100"));
  106 + o.setQualifiedQuantity(new java.math.BigDecimal("90"));
  107 + o.setUnqualifiedQuantity(new java.math.BigDecimal("10"));
  108 + });
  109 + rqcMapper.insert(rqc);
  110 +
  111 + // 调用
  112 + rqcService.finishRqc(rqc.getId());
  113 +
  114 + // 断言:验证状态更新
  115 + MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId());
  116 + assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus());
  117 +
  118 + // 断言:验证回写调用销售退货
  119 + verify(returnSalesLineService).updateReturnSalesLineWhenRqcFinish(eq(sourceLineId), eq(checkResult));
  120 + // 断言:未调用生产退料
  121 + verify(returnIssueLineService, never()).updateReturnIssueLineWhenRqcFinish(anyLong(), anyInt());
  122 + }
  123 +
  124 + @Test
  125 + public void testFinishRqc_notExists() {
  126 + // 准备参数
  127 + Long rqcId = randomLongId();
  128 +
  129 + // 调用,并断言异常
  130 + assertServiceException(() -> rqcService.finishRqc(rqcId), QC_RQC_NOT_EXISTS);
  131 + }
  132 +
  133 + @Test
  134 + public void testFinishRqc_statusNotDraft() {
  135 + // 准备参数
  136 + // mock 数据:状态为已完成
  137 + MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> {
  138 + o.setStatus(MesQcStatusEnum.FINISHED.getStatus());
  139 + });
  140 + rqcMapper.insert(rqc);
  141 +
  142 + // 调用,并断言异常
  143 + assertServiceException(() -> rqcService.finishRqc(rqc.getId()), QC_RQC_NOT_PREPARE);
  144 + }
  145 +
  146 +}
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImplTest.java
... ... @@ -23,7 +23,7 @@ import static org.mockito.ArgumentMatchers.eq;
23 23 import static org.mockito.Mockito.*;
24 24  
25 25 /**
26   - * {@link MesWmArrivalNoticeServiceImpl#approveArrivalNoticeWhenIqcComplete} 的单元测试
  26 + * {@link MesWmArrivalNoticeServiceImpl} 的单元测试
27 27 *
28 28 * @author 芋道源码
29 29 */
... ... @@ -40,7 +40,7 @@ public class MesWmArrivalNoticeServiceImplTest extends BaseDbUnitTest {
40 40 private MesWmArrivalNoticeLineService arrivalNoticeLineService;
41 41  
42 42 @Test
43   - public void testApproveArrivalNoticeWhenIqcComplete_success_allLinesChecked() {
  43 + public void testUpdateArrivalNoticeWhenIqcFinish_success_allLinesChecked() {
44 44 // mock 数据:插入一条待质检的到货通知单
45 45 MesWmArrivalNoticeDO notice = randomPojo(MesWmArrivalNoticeDO.class, o -> {
46 46 o.setStatus(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus());
... ... @@ -67,17 +67,17 @@ public class MesWmArrivalNoticeServiceImplTest extends BaseDbUnitTest {
67 67 .thenReturn(Arrays.asList(line1, line2));
68 68  
69 69 // 调用
70   - arrivalNoticeService.approveArrivalNoticeWhenIqcComplete(noticeId, lineId, iqcId, qualifiedQuantity);
  70 + arrivalNoticeService.updateArrivalNoticeWhenIqcFinish(noticeId, lineId, iqcId, qualifiedQuantity);
71 71  
72 72 // 断言:行回写被调用
73   - verify(arrivalNoticeLineService).updateByIqcComplete(eq(lineId), eq(iqcId), eq(qualifiedQuantity));
  73 + verify(arrivalNoticeLineService).updateArrivalNoticeLineWhenIqcFinish(eq(lineId), eq(iqcId), eq(qualifiedQuantity));
74 74 // 断言:主表状态更新为待入库
75 75 MesWmArrivalNoticeDO updatedNotice = arrivalNoticeMapper.selectById(noticeId);
76 76 assertEquals(MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus(), updatedNotice.getStatus());
77 77 }
78 78  
79 79 @Test
80   - public void testApproveArrivalNoticeWhenIqcComplete_success_hasUncheckedLines() {
  80 + public void testUpdateArrivalNoticeWhenIqcFinish_success_hasUncheckedLines() {
81 81 // mock 数据:插入一条待质检的到货通知单
82 82 MesWmArrivalNoticeDO notice = randomPojo(MesWmArrivalNoticeDO.class, o -> {
83 83 o.setStatus(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus());
... ... @@ -104,17 +104,17 @@ public class MesWmArrivalNoticeServiceImplTest extends BaseDbUnitTest {
104 104 .thenReturn(Arrays.asList(line1, line2));
105 105  
106 106 // 调用
107   - arrivalNoticeService.approveArrivalNoticeWhenIqcComplete(noticeId, lineId, iqcId, qualifiedQuantity);
  107 + arrivalNoticeService.updateArrivalNoticeWhenIqcFinish(noticeId, lineId, iqcId, qualifiedQuantity);
108 108  
109 109 // 断言:行回写被调用
110   - verify(arrivalNoticeLineService).updateByIqcComplete(eq(lineId), eq(iqcId), eq(qualifiedQuantity));
  110 + verify(arrivalNoticeLineService).updateArrivalNoticeLineWhenIqcFinish(eq(lineId), eq(iqcId), eq(qualifiedQuantity));
111 111 // 断言:主表状态不变,仍然是待质检
112 112 MesWmArrivalNoticeDO updatedNotice = arrivalNoticeMapper.selectById(noticeId);
113 113 assertEquals(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus(), updatedNotice.getStatus());
114 114 }
115 115  
116 116 @Test
117   - public void testApproveArrivalNoticeWhenIqcComplete_noticeNotExists() {
  117 + public void testUpdateArrivalNoticeWhenIqcFinish_noticeNotExists() {
118 118 // 准备参数
119 119 Long noticeId = randomLongId();
120 120 Long lineId = randomLongId();
... ... @@ -123,12 +123,12 @@ public class MesWmArrivalNoticeServiceImplTest extends BaseDbUnitTest {
123 123  
124 124 // 调用,并断言异常
125 125 assertServiceException(
126   - () -> arrivalNoticeService.approveArrivalNoticeWhenIqcComplete(noticeId, lineId, iqcId, qualifiedQuantity),
  126 + () -> arrivalNoticeService.updateArrivalNoticeWhenIqcFinish(noticeId, lineId, iqcId, qualifiedQuantity),
127 127 WM_ARRIVAL_NOTICE_NOT_EXISTS);
128 128 }
129 129  
130 130 @Test
131   - public void testApproveArrivalNoticeWhenIqcComplete_statusNotPendingQc() {
  131 + public void testUpdateArrivalNoticeWhenIqcFinish_statusNotPendingQc() {
132 132 // mock 数据:插入一条草稿状态的到货通知单(非待质检)
133 133 MesWmArrivalNoticeDO notice = randomPojo(MesWmArrivalNoticeDO.class, o -> {
134 134 o.setStatus(MesWmArrivalNoticeStatusEnum.PREPARE.getStatus());
... ... @@ -142,7 +142,7 @@ public class MesWmArrivalNoticeServiceImplTest extends BaseDbUnitTest {
142 142  
143 143 // 调用,并断言异常
144 144 assertServiceException(
145   - () -> arrivalNoticeService.approveArrivalNoticeWhenIqcComplete(noticeId, lineId, iqcId, qualifiedQuantity),
  145 + () -> arrivalNoticeService.updateArrivalNoticeWhenIqcFinish(noticeId, lineId, iqcId, qualifiedQuantity),
146 146 WM_ARRIVAL_NOTICE_STATUS_NOT_PENDING_QC);
147 147 }
148 148  
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/outsourcereceipt/MesWmOutsourceReceiptServiceImplTest.java
... ... @@ -26,7 +26,7 @@ import static org.mockito.ArgumentMatchers.*;
26 26 import static org.mockito.Mockito.*;
27 27  
28 28 /**
29   - * {@link MesWmOutsourceReceiptServiceImpl#approveOutsourceReceiptWhenIqcComplete} 的单元测试
  29 + * {@link MesWmOutsourceReceiptServiceImpl} 的单元测试
30 30 *
31 31 * @author 芋道源码
32 32 */
... ... @@ -51,7 +51,7 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
51 51 private MesMdItemService itemService;
52 52  
53 53 @Test
54   - public void testApproveOutsourceReceiptWhenIqcComplete_success_bothQualifiedAndUnqualified() {
  54 + public void testUpdateOutsourceReceiptWhenIqcFinish_success_bothQualifiedAndUnqualified() {
55 55 // mock 数据:插入一条待检验状态的外协入库单
56 56 MesWmOutsourceReceiptDO receipt = randomPojo(MesWmOutsourceReceiptDO.class, o -> {
57 57 o.setStatus(MesWmOutsourceReceiptStatusEnum.CONFIRMED.getStatus());
... ... @@ -73,7 +73,7 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
73 73 when(outsourceReceiptLineService.getOutsourceReceiptLine(eq(lineId))).thenReturn(line);
74 74  
75 75 // 调用
76   - outsourceReceiptService.approveOutsourceReceiptWhenIqcComplete(
  76 + outsourceReceiptService.updateOutsourceReceiptWhenIqcFinish(
77 77 receiptId, lineId, iqcId, qualifiedQuantity, unqualifiedQuantity);
78 78  
79 79 // 断言:合格品行更新
... ... @@ -94,7 +94,7 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
94 94 }
95 95  
96 96 @Test
97   - public void testApproveOutsourceReceiptWhenIqcComplete_success_onlyQualified() {
  97 + public void testUpdateOutsourceReceiptWhenIqcFinish_success_onlyQualified() {
98 98 // mock 数据:插入一条待检验状态的外协入库单
99 99 MesWmOutsourceReceiptDO receipt = randomPojo(MesWmOutsourceReceiptDO.class, o -> {
100 100 o.setStatus(MesWmOutsourceReceiptStatusEnum.CONFIRMED.getStatus());
... ... @@ -115,7 +115,7 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
115 115 when(outsourceReceiptLineService.getOutsourceReceiptLine(eq(lineId))).thenReturn(line);
116 116  
117 117 // 调用
118   - outsourceReceiptService.approveOutsourceReceiptWhenIqcComplete(
  118 + outsourceReceiptService.updateOutsourceReceiptWhenIqcFinish(
119 119 receiptId, lineId, iqcId, qualifiedQuantity, unqualifiedQuantity);
120 120  
121 121 // 断言:合格品行更新
... ... @@ -129,7 +129,7 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
129 129 }
130 130  
131 131 @Test
132   - public void testApproveOutsourceReceiptWhenIqcComplete_receiptNotExists() {
  132 + public void testUpdateOutsourceReceiptWhenIqcFinish_receiptNotExists() {
133 133 // 准备参数
134 134 Long receiptId = randomLongId();
135 135 Long lineId = randomLongId();
... ... @@ -139,13 +139,13 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
139 139  
140 140 // 调用,并断言异常
141 141 assertServiceException(
142   - () -> outsourceReceiptService.approveOutsourceReceiptWhenIqcComplete(
  142 + () -> outsourceReceiptService.updateOutsourceReceiptWhenIqcFinish(
143 143 receiptId, lineId, iqcId, qualifiedQuantity, unqualifiedQuantity),
144 144 WM_OUTSOURCE_RECEIPT_NOT_EXISTS);
145 145 }
146 146  
147 147 @Test
148   - public void testApproveOutsourceReceiptWhenIqcComplete_statusNotConfirmed() {
  148 + public void testUpdateOutsourceReceiptWhenIqcFinish_statusNotConfirmed() {
149 149 // mock 数据:插入一条草稿状态的外协入库单(非待检验状态)
150 150 MesWmOutsourceReceiptDO receipt = randomPojo(MesWmOutsourceReceiptDO.class, o -> {
151 151 o.setStatus(MesWmOutsourceReceiptStatusEnum.PREPARE.getStatus());
... ... @@ -160,13 +160,13 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
160 160  
161 161 // 调用,并断言异常
162 162 assertServiceException(
163   - () -> outsourceReceiptService.approveOutsourceReceiptWhenIqcComplete(
  163 + () -> outsourceReceiptService.updateOutsourceReceiptWhenIqcFinish(
164 164 receiptId, lineId, iqcId, qualifiedQuantity, unqualifiedQuantity),
165 165 WM_OUTSOURCE_RECEIPT_STATUS_ERROR);
166 166 }
167 167  
168 168 @Test
169   - public void testApproveOutsourceReceiptWhenIqcComplete_lineNotExists() {
  169 + public void testUpdateOutsourceReceiptWhenIqcFinish_lineNotExists() {
170 170 // mock 数据:插入一条待检验状态的外协入库单
171 171 MesWmOutsourceReceiptDO receipt = randomPojo(MesWmOutsourceReceiptDO.class, o -> {
172 172 o.setStatus(MesWmOutsourceReceiptStatusEnum.CONFIRMED.getStatus());
... ... @@ -184,7 +184,7 @@ public class MesWmOutsourceReceiptServiceImplTest extends BaseDbUnitTest {
184 184  
185 185 // 调用,并断言异常
186 186 assertServiceException(
187   - () -> outsourceReceiptService.approveOutsourceReceiptWhenIqcComplete(
  187 + () -> outsourceReceiptService.updateOutsourceReceiptWhenIqcFinish(
188 188 receiptId, lineId, iqcId, qualifiedQuantity, unqualifiedQuantity),
189 189 WM_OUTSOURCE_RECEIPT_LINE_NOT_EXISTS);
190 190 }
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.productsales;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO;
  5 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper;
  6 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
  7 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
  8 +import jakarta.annotation.Resource;
  9 +import org.junit.jupiter.api.Test;
  10 +import org.springframework.context.annotation.Import;
  11 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  12 +
  13 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  14 +
  15 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  16 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  17 +import static org.junit.jupiter.api.Assertions.assertEquals;
  18 +
  19 +/**
  20 + * {@link MesWmProductSalesLineServiceImpl} 的单元测试类
  21 + *
  22 + * @author 芋道源码
  23 + */
  24 +@Import(MesWmProductSalesLineServiceImpl.class)
  25 +public class MesWmProductSalesLineServiceImplTest extends BaseDbUnitTest {
  26 +
  27 + @Resource
  28 + private MesWmProductSalesLineServiceImpl productSalesLineService;
  29 +
  30 + @Resource
  31 + private MesWmProductSalesLineMapper productSalesLineMapper;
  32 +
  33 + @MockitoBean
  34 + private MesWmProductSalesService productSalesService;
  35 +
  36 + @MockitoBean
  37 + private MesWmProductSalesDetailService productSalesDetailService;
  38 +
  39 + @MockitoBean
  40 + private MesMdItemService itemService;
  41 +
  42 + @Test
  43 + public void testUpdateProductSalesLineWhenOqcFinish_pass() {
  44 + // 准备参数
  45 + Long oqcId = randomLongId();
  46 + Integer checkResult = MesQcCheckResultEnum.PASS.getType();
  47 +
  48 + // mock 数据
  49 + MesWmProductSalesLineDO lineDO = randomPojo(MesWmProductSalesLineDO.class);
  50 + productSalesLineMapper.insert(lineDO);
  51 +
  52 + // 调用
  53 + productSalesLineService.updateProductSalesLineWhenOqcFinish(lineDO.getId(), oqcId, checkResult);
  54 +
  55 + // 断言:验证 mapper 更新参数正确
  56 + MesWmProductSalesLineDO updateLine = productSalesLineMapper.selectById(lineDO.getId());
  57 + assertEquals(oqcId, updateLine.getOqcId());
  58 + assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus());
  59 + }
  60 +
  61 + @Test
  62 + public void testUpdateProductSalesLineWhenOqcFinish_fail() {
  63 + // 准备参数
  64 + Long oqcId = randomLongId();
  65 + Integer checkResult = MesQcCheckResultEnum.FAIL.getType();
  66 +
  67 + // mock 数据
  68 + MesWmProductSalesLineDO lineDO = randomPojo(MesWmProductSalesLineDO.class);
  69 + productSalesLineMapper.insert(lineDO);
  70 +
  71 + // 调用
  72 + productSalesLineService.updateProductSalesLineWhenOqcFinish(lineDO.getId(), oqcId, checkResult);
  73 +
  74 + // 断言:验证 mapper 更新参数正确
  75 + MesWmProductSalesLineDO updateLine = productSalesLineMapper.selectById(lineDO.getId());
  76 + assertEquals(oqcId, updateLine.getOqcId());
  77 + assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus());
  78 + }
  79 +
  80 +}
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.returnissue;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO;
  5 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnissue.MesWmReturnIssueLineMapper;
  6 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
  7 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
  8 +import jakarta.annotation.Resource;
  9 +import org.junit.jupiter.api.Test;
  10 +import org.springframework.context.annotation.Import;
  11 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  12 +
  13 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  14 +
  15 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  16 +import static org.junit.jupiter.api.Assertions.assertEquals;
  17 +
  18 +/**
  19 + * {@link MesWmReturnIssueLineServiceImpl} 的单元测试类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Import(MesWmReturnIssueLineServiceImpl.class)
  24 +public class MesWmReturnIssueLineServiceImplTest extends BaseDbUnitTest {
  25 +
  26 + @Resource
  27 + private MesWmReturnIssueLineServiceImpl returnIssueLineService;
  28 +
  29 + @Resource
  30 + private MesWmReturnIssueLineMapper returnIssueLineMapper;
  31 +
  32 + @MockitoBean
  33 + private MesWmReturnIssueService issueService;
  34 +
  35 + @MockitoBean
  36 + private MesMdItemService itemService;
  37 +
  38 + @Test
  39 + public void testUpdateReturnIssueLineWhenRqcFinish_pass() {
  40 + // 准备参数
  41 + Integer checkResult = MesQcCheckResultEnum.PASS.getType();
  42 +
  43 + // mock 数据
  44 + MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class);
  45 + returnIssueLineMapper.insert(lineDO);
  46 +
  47 + // 调用
  48 + returnIssueLineService.updateReturnIssueLineWhenRqcFinish(lineDO.getId(), checkResult);
  49 +
  50 + // 断言:验证 mapper 更新参数正确
  51 + MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId());
  52 + assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus());
  53 + }
  54 +
  55 + @Test
  56 + public void testUpdateReturnIssueLineWhenRqcFinish_fail() {
  57 + // 准备参数
  58 + Integer checkResult = MesQcCheckResultEnum.FAIL.getType();
  59 +
  60 + // mock 数据
  61 + MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class);
  62 + returnIssueLineMapper.insert(lineDO);
  63 +
  64 + // 调用
  65 + returnIssueLineService.updateReturnIssueLineWhenRqcFinish(lineDO.getId(), checkResult);
  66 +
  67 + // 断言:验证 mapper 更新参数正确
  68 + MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId());
  69 + assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus());
  70 + }
  71 +
  72 +}
... ...
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.returnsales;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO;
  5 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnsales.MesWmReturnSalesLineMapper;
  6 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
  7 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
  8 +import jakarta.annotation.Resource;
  9 +import org.junit.jupiter.api.Test;
  10 +import org.springframework.context.annotation.Import;
  11 +import org.springframework.test.context.bean.override.mockito.MockitoBean;
  12 +
  13 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  14 +
  15 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  16 +import static org.junit.jupiter.api.Assertions.assertEquals;
  17 +
  18 +/**
  19 + * {@link MesWmReturnSalesLineServiceImpl} 的单元测试类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Import(MesWmReturnSalesLineServiceImpl.class)
  24 +public class MesWmReturnSalesLineServiceImplTest extends BaseDbUnitTest {
  25 +
  26 + @Resource
  27 + private MesWmReturnSalesLineServiceImpl returnSalesLineService;
  28 +
  29 + @Resource
  30 + private MesWmReturnSalesLineMapper returnSalesLineMapper;
  31 +
  32 + @MockitoBean
  33 + private MesWmReturnSalesService returnSalesService;
  34 +
  35 + @MockitoBean
  36 + private MesMdItemService itemService;
  37 +
  38 + @Test
  39 + public void testUpdateReturnSalesLineWhenRqcFinish_pass() {
  40 + // 准备参数
  41 + Integer checkResult = MesQcCheckResultEnum.PASS.getType();
  42 +
  43 + // mock 数据
  44 + MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class);
  45 + returnSalesLineMapper.insert(lineDO);
  46 +
  47 + // 调用
  48 + returnSalesLineService.updateReturnSalesLineWhenRqcFinish(lineDO.getId(), checkResult);
  49 +
  50 + // 断言:验证 mapper 更新参数正确
  51 + MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId());
  52 + assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus());
  53 + }
  54 +
  55 + @Test
  56 + public void testUpdateReturnSalesLineWhenRqcFinish_fail() {
  57 + // 准备参数
  58 + Integer checkResult = MesQcCheckResultEnum.FAIL.getType();
  59 +
  60 + // mock 数据
  61 + MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class);
  62 + returnSalesLineMapper.insert(lineDO);
  63 +
  64 + // 调用
  65 + returnSalesLineService.updateReturnSalesLineWhenRqcFinish(lineDO.getId(), checkResult);
  66 +
  67 + // 断言:验证 mapper 更新参数正确
  68 + MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId());
  69 + assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus());
  70 + }
  71 +
  72 +}
... ...
yudao-module-mes/src/test/resources/sql/create_tables.sql
... ... @@ -297,3 +297,151 @@ CREATE TABLE IF NOT EXISTS &quot;mes_wm_product_produce_detail&quot; (
297 297 "tenant_id" bigint NOT NULL DEFAULT 0,
298 298 PRIMARY KEY ("id")
299 299 );
  300 +
  301 +
  302 +-- ----------------------------
  303 +-- MES 出货检验单(OQC)
  304 +-- ----------------------------
  305 +CREATE TABLE IF NOT EXISTS "mes_qc_oqc" (
  306 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  307 + "code" varchar(64) NOT NULL,
  308 + "name" varchar(500) NOT NULL,
  309 + "template_id" bigint NOT NULL,
  310 + "source_doc_id" bigint DEFAULT NULL,
  311 + "source_doc_type" int DEFAULT NULL,
  312 + "source_doc_code" varchar(64) DEFAULT NULL,
  313 + "source_line_id" bigint DEFAULT NULL,
  314 + "client_id" bigint NOT NULL,
  315 + "batch_code" varchar(64) DEFAULT NULL,
  316 + "item_id" bigint NOT NULL,
  317 + "min_check_quantity" int DEFAULT 1,
  318 + "max_unqualified_quantity" int DEFAULT 0,
  319 + "out_quantity" decimal(14,2) NOT NULL,
  320 + "check_quantity" decimal(14,2) DEFAULT NULL,
  321 + "qualified_quantity" decimal(14,2) DEFAULT 0.00,
  322 + "unqualified_quantity" decimal(14,2) DEFAULT 0.00,
  323 + "critical_rate" decimal(14,2) DEFAULT 0.00,
  324 + "major_rate" decimal(14,2) DEFAULT 0.00,
  325 + "minor_rate" decimal(14,2) DEFAULT 0.00,
  326 + "critical_quantity" int DEFAULT 0,
  327 + "major_quantity" int DEFAULT 0,
  328 + "minor_quantity" int DEFAULT 0,
  329 + "check_result" tinyint DEFAULT NULL,
  330 + "out_date" timestamp DEFAULT NULL,
  331 + "inspect_date" timestamp DEFAULT NULL,
  332 + "inspector_user_id" bigint DEFAULT NULL,
  333 + "status" tinyint NOT NULL DEFAULT 0,
  334 + "remark" varchar(500) DEFAULT '',
  335 + "creator" varchar(64) DEFAULT '',
  336 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  337 + "updater" varchar(64) DEFAULT '',
  338 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  339 + "deleted" bit NOT NULL DEFAULT FALSE,
  340 + "tenant_id" bigint NOT NULL DEFAULT 0,
  341 + PRIMARY KEY ("id")
  342 +);
  343 +
  344 +-- ----------------------------
  345 +-- MES 退货检验单(RQC)
  346 +-- ----------------------------
  347 +CREATE TABLE IF NOT EXISTS "mes_qc_rqc" (
  348 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  349 + "code" varchar(64) NOT NULL,
  350 + "name" varchar(500) NOT NULL,
  351 + "template_id" bigint NOT NULL,
  352 + "source_doc_id" bigint DEFAULT NULL,
  353 + "source_doc_type" int DEFAULT NULL,
  354 + "source_doc_code" varchar(64) DEFAULT NULL,
  355 + "source_line_id" bigint DEFAULT NULL,
  356 + "type" int DEFAULT NULL,
  357 + "item_id" bigint NOT NULL,
  358 + "batch_code" varchar(128) DEFAULT NULL,
  359 + "check_quantity" decimal(14,2) DEFAULT NULL,
  360 + "qualified_quantity" decimal(14,2) DEFAULT 0.00,
  361 + "unqualified_quantity" decimal(14,2) DEFAULT 0.00,
  362 + "check_result" tinyint DEFAULT NULL,
  363 + "inspect_date" timestamp DEFAULT NULL,
  364 + "inspector_user_id" bigint DEFAULT NULL,
  365 + "status" tinyint NOT NULL DEFAULT 0,
  366 + "remark" varchar(500) DEFAULT '',
  367 + "critical_quantity" int DEFAULT 0,
  368 + "major_quantity" int DEFAULT 0,
  369 + "minor_quantity" int DEFAULT 0,
  370 + "critical_rate" decimal(5,2) DEFAULT 0.00,
  371 + "major_rate" decimal(5,2) DEFAULT 0.00,
  372 + "minor_rate" decimal(5,2) DEFAULT 0.00,
  373 + "creator" varchar(64) DEFAULT '',
  374 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  375 + "updater" varchar(64) DEFAULT '',
  376 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  377 + "deleted" bit NOT NULL DEFAULT FALSE,
  378 + "tenant_id" bigint NOT NULL DEFAULT 0,
  379 + PRIMARY KEY ("id")
  380 +);
  381 +
  382 +-- ----------------------------
  383 +-- MES 销售出库单行
  384 +-- ----------------------------
  385 +CREATE TABLE IF NOT EXISTS "mes_wm_product_sales_line" (
  386 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  387 + "sales_id" bigint NOT NULL,
  388 + "item_id" bigint NOT NULL,
  389 + "quantity" decimal(20,6) NOT NULL,
  390 + "batch_id" bigint DEFAULT NULL,
  391 + "material_stock_id" bigint DEFAULT NULL,
  392 + "oqc_check" tinyint DEFAULT NULL,
  393 + "oqc_id" bigint DEFAULT NULL,
  394 + "quality_status" int DEFAULT NULL,
  395 + "remark" varchar(500) DEFAULT NULL,
  396 + "creator" varchar(64) DEFAULT '',
  397 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  398 + "updater" varchar(64) DEFAULT '',
  399 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  400 + "deleted" bit NOT NULL DEFAULT FALSE,
  401 + "tenant_id" bigint NOT NULL DEFAULT 0,
  402 + PRIMARY KEY ("id")
  403 +);
  404 +
  405 +-- ----------------------------
  406 +-- MES 生产退料单行
  407 +-- ----------------------------
  408 +CREATE TABLE IF NOT EXISTS "mes_wm_return_issue_line" (
  409 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  410 + "issue_id" bigint NOT NULL,
  411 + "material_stock_id" bigint DEFAULT NULL,
  412 + "item_id" bigint NOT NULL,
  413 + "quantity" decimal(12,2) NOT NULL DEFAULT 0.00,
  414 + "batch_id" bigint DEFAULT NULL,
  415 + "ipqc_id" bigint DEFAULT NULL,
  416 + "qc_flag" bit NOT NULL DEFAULT FALSE,
  417 + "quality_status" int DEFAULT NULL,
  418 + "remark" varchar(500) DEFAULT '',
  419 + "creator" varchar(64) DEFAULT '',
  420 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  421 + "updater" varchar(64) DEFAULT '',
  422 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  423 + "deleted" bit NOT NULL DEFAULT FALSE,
  424 + "tenant_id" bigint NOT NULL DEFAULT 0,
  425 + PRIMARY KEY ("id")
  426 +);
  427 +
  428 +-- ----------------------------
  429 +-- MES 销售退货单行
  430 +-- ----------------------------
  431 +CREATE TABLE IF NOT EXISTS "mes_wm_return_sales_line" (
  432 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  433 + "return_id" bigint NOT NULL,
  434 + "item_id" bigint NOT NULL,
  435 + "quantity" decimal(12,2) NOT NULL DEFAULT 0.00,
  436 + "batch_id" bigint DEFAULT NULL,
  437 + "quality_status" int DEFAULT NULL,
  438 + "remark" varchar(500) DEFAULT '',
  439 + "creator" varchar(64) DEFAULT '',
  440 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  441 + "updater" varchar(64) DEFAULT '',
  442 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  443 + "deleted" bit NOT NULL DEFAULT FALSE,
  444 + "tenant_id" bigint NOT NULL DEFAULT 0,
  445 + PRIMARY KEY ("id")
  446 +);
  447 +
... ...