From d415f7740533e5d7883506986f9f979e71d97b42 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 10 Apr 2026 14:24:15 +0800 Subject: [PATCH] ✨ feat(mes): 添加 IPQC 相关错误码和更新反馈处理逻辑 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 2 ++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java | 4 +++- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java | 5 +++-- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java | 27 +++++++++++++-------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java | 8 ++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java | 12 ++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java | 4 +++- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java | 12 ++++-------- yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImplTest.java | 16 ++++++++-------- yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImplTest.java | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImplTest.java | 69 ++++++++++++++++++++++++++++++++++++--------------------------------- 11 files changed, 315 insertions(+), 72 deletions(-) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index e61dd25..4b4e697 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -353,6 +353,8 @@ public interface ErrorCodeConstants { ErrorCode QC_IPQC_SOURCE_DOC_TYPE_UNKNOWN = new ErrorCode(1_040_604_007, "未知的 IPQC 来源单据类型"); ErrorCode QC_IPQC_SOURCE_DOC_NO_PENDING_LINE = new ErrorCode(1_040_604_008, "来源报工单不存在待检产出行,无法创建 IPQC"); ErrorCode QC_IPQC_SOURCE_LINE_NOT_BELONG = new ErrorCode(1_040_604_009, "来源单据行不属于该报工单"); + ErrorCode QC_IPQC_SOURCE_LINE_REQUIRED = new ErrorCode(1_040_604_010, "来源单据类型为报工时,来源产出行 ID 不能为空"); + ErrorCode QC_IPQC_SOURCE_LINE_NOT_PENDING = new ErrorCode(1_040_604_011, "来源产出行不是待检验状态"); // ========== MES 质量管理-过程检验行(1-040-604-100) ========== ErrorCode QC_IPQC_LINE_NOT_EXISTS = new ErrorCode(1_040_604_100, "过程检验行不存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java index 9df980c..0dfd9fd 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java @@ -104,13 +104,15 @@ public interface MesProFeedbackService { * 并根据检验结果回写合格/不合格/废品数量,同时更新任务/工单的已生产数量。 * * @param feedbackId 报工记录 ID + * @param sourceLineId 来源产出行 ID(用于直接定位待检行) * @param qualifiedQty 合格品数量 * @param unqualifiedQty 不合格品数量 * @param laborScrapQty 工废数量 * @param materialScrapQty 料废数量 * @param otherScrapQty 其他废品数量 */ - void updateProFeedbackWhenIpqcFinish(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty, + void updateProFeedbackWhenIpqcFinish(Long feedbackId, Long sourceLineId, + BigDecimal qualifiedQty, BigDecimal unqualifiedQty, BigDecimal laborScrapQty, BigDecimal materialScrapQty, BigDecimal otherScrapQty); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java index 34faee5..4cf0f9a 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java @@ -313,7 +313,8 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService { @Override @Transactional(rollbackFor = Exception.class) - public void updateProFeedbackWhenIpqcFinish(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty, + public void updateProFeedbackWhenIpqcFinish(Long feedbackId, Long sourceLineId, + BigDecimal qualifiedQty, BigDecimal unqualifiedQty, BigDecimal laborScrapQty, BigDecimal materialScrapQty, BigDecimal otherScrapQty) { // 1. 校验报工单存在且为待检验状态 MesProFeedbackDO feedback = validateFeedbackExists(feedbackId); @@ -322,7 +323,7 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService { } // 2. 拆分待检产出行(合格/不合格),生成明细,完成产出入库 - productProduceService.splitPendingAndFinishProduce(feedbackId, qualifiedQty, unqualifiedQty); + productProduceService.splitPendingAndFinishProduce(feedbackId, sourceLineId, qualifiedQty, unqualifiedQty); // 3. 回写合格/不合格/废品数量,更新状态为已完成 feedbackMapper.updateById(new MesProFeedbackDO().setId(feedbackId) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java index 36def60..2119765 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java @@ -221,7 +221,7 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { } if (Objects.equals(ipqc.getSourceDocType(), MesBizTypeConstants.PRO_FEEDBACK)) { - feedbackService.updateProFeedbackWhenIpqcFinish(ipqc.getSourceDocId(), + feedbackService.updateProFeedbackWhenIpqcFinish(ipqc.getSourceDocId(), ipqc.getSourceLineId(), ObjectUtil.defaultIfNull(ipqc.getQualifiedQuantity(), BigDecimal.ZERO), ObjectUtil.defaultIfNull(ipqc.getUnqualifiedQuantity(), BigDecimal.ZERO), ObjectUtil.defaultIfNull(ipqc.getLaborScrapQuantity(), BigDecimal.ZERO), @@ -286,20 +286,19 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { } if (Objects.equals(sourceDocType, MesBizTypeConstants.PRO_FEEDBACK)) { MesProFeedbackDO feedback = feedbackService.validateFeedbackExists(sourceDocId); - // 校验该报工存在待检产出行 - List lines = productProduceLineService - .getProductProduceLineListByFeedbackId(sourceDocId); - boolean hasPending = lines.stream().anyMatch( - l -> Objects.equals(l.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())); - if (!hasPending) { - throw exception(QC_IPQC_SOURCE_DOC_NO_PENDING_LINE); + // 校验 sourceLineId 必填 + if (sourceLineId == null) { + throw exception(QC_IPQC_SOURCE_LINE_REQUIRED); } - // 校验 sourceLineId 属于该报工的产出行 - if (sourceLineId != null) { - boolean belongs = lines.stream().anyMatch(l -> Objects.equals(l.getId(), sourceLineId)); - if (!belongs) { - throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG); - } + // 校验 sourceLineId 存在,且属于该报工的产出行 + MesWmProductProduceLineDO targetLine = productProduceLineService + .validateProductProduceLineExists(sourceLineId); + if (ObjUtil.notEqual(targetLine.getFeedbackId(), sourceDocId)) { + throw exception(QC_IPQC_SOURCE_LINE_NOT_BELONG); + } + // 校验该产出行为待检验状态 + if (ObjUtil.notEqual(targetLine.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())) { + throw exception(QC_IPQC_SOURCE_LINE_NOT_PENDING); } return feedback.getCode(); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java index 3623070..874ed3d 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java @@ -19,6 +19,14 @@ public interface MesWmProductProduceLineService { void createProductProduceLine(MesWmProductProduceLineDO line); /** + * 校验生产入库单行存在 + * + * @param id 行 ID + * @return 行数据 + */ + MesWmProductProduceLineDO validateProductProduceLineExists(Long id); + + /** * 更新生产入库单行(内部使用) * * @param line 行数据 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java index e88a352..77e6f9f 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java @@ -10,6 +10,9 @@ import org.springframework.validation.annotation.Validated; import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + /** * MES 生产入库单行 Service 实现类 */ @@ -26,6 +29,15 @@ public class MesWmProductProduceLineServiceImpl implements MesWmProductProduceLi } @Override + public MesWmProductProduceLineDO validateProductProduceLineExists(Long id) { + MesWmProductProduceLineDO line = productProduceLineMapper.selectById(id); + if (line == null) { + throw exception(WM_PRODUCT_PRODUCE_LINE_NOT_EXISTS); + } + return line; + } + + @Override public void updateProductProduceLine(MesWmProductProduceLineDO line) { productProduceLineMapper.updateById(line); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java index d612272..76188cf 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java @@ -41,9 +41,11 @@ public interface MesWmProductProduceService { * 待检产出({@code checkFlag=true})按检验结果拆分行,并执行入库。 * * @param feedbackId 报工记录 ID + * @param sourceLineId 来源产出行 ID(直接定位待检行) * @param qualifiedQty 合格品数量 * @param unqualifiedQty 不合格品数量 */ - void splitPendingAndFinishProduce(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty); + void splitPendingAndFinishProduce(Long feedbackId, Long sourceLineId, + BigDecimal qualifiedQty, BigDecimal unqualifiedQty); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java index f4a1f15..fd6f98a 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java @@ -222,7 +222,8 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic @Override @Transactional(rollbackFor = Exception.class) - public void splitPendingAndFinishProduce(Long feedbackId, BigDecimal qualifiedQty, BigDecimal unqualifiedQty) { + public void splitPendingAndFinishProduce(Long feedbackId, Long sourceLineId, + BigDecimal qualifiedQty, BigDecimal unqualifiedQty) { // 1.1 查询产出单 MesWmProductProduceDO produce = productProduceMapper.selectByFeedbackId(feedbackId); if (produce == null) { @@ -233,13 +234,8 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic MesWmWarehouseLocationDO virtualLocation = locationService.getWarehouseLocationByCode(MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION); MesWmWarehouseAreaDO virtualArea = areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA); - // 2. 查找待检验行(checkFlag=true 时只有一行 PENDING) - List lines = productProduceLineService.getProductProduceLineListByProduceId(produce.getId()); - MesWmProductProduceLineDO pendingLine = CollUtil.findOne(lines, - l -> ObjUtil.equal(l.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())); - if (pendingLine == null) { - throw exception(WM_PRODUCT_PRODUCE_LINE_NOT_EXISTS); - } + // 2. 通过 sourceLineId 直接定位待检验行 + MesWmProductProduceLineDO pendingLine = productProduceLineService.validateProductProduceLineExists(sourceLineId); // 3A. 情况一:存在不合格品数量,需要拆分行 if (unqualifiedQty != null && unqualifiedQty.compareTo(BigDecimal.ZERO) > 0) { diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImplTest.java index 8c24869..d379b75 100644 --- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImplTest.java +++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImplTest.java @@ -61,6 +61,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest { // 准备数据:插入一条待检验状态的报工单 Long taskId = randomLongId(); Long workOrderId = randomLongId(); + Long sourceLineId = randomLongId(); MesProFeedbackDO feedback = randomPojo(MesProFeedbackDO.class, o -> { o.setStatus(MesProFeedbackStatusEnum.UNCHECK.getStatus()); o.setTaskId(taskId); @@ -87,13 +88,12 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest { BigDecimal laborScrapQty = BigDecimal.valueOf(5); BigDecimal materialScrapQty = BigDecimal.valueOf(10); BigDecimal otherScrapQty = BigDecimal.valueOf(5); - - feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), sourceLineId, qualifiedQty, unqualifiedQty, laborScrapQty, materialScrapQty, otherScrapQty); // 断言 1:调用了 splitPendingAndFinishProduce verify(productProduceService).splitPendingAndFinishProduce( - eq(feedback.getId()), eq(qualifiedQty), eq(unqualifiedQty)); + eq(feedback.getId()), eq(sourceLineId), eq(qualifiedQty), eq(unqualifiedQty)); // 断言 2:报工单状态更新为已完成 MesProFeedbackDO updatedFeedback = feedbackMapper.selectById(feedback.getId()); @@ -137,7 +137,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest { .thenReturn(ListUtil.of(qualifiedLine)); // 调用 - feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), randomLongId(), BigDecimal.valueOf(50), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO); @@ -156,7 +156,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest { // 调用不存在的 feedbackId,应该抛异常 Long feedbackId = randomLongId(); assertThrows(Exception.class, () -> - feedbackService.updateProFeedbackWhenIpqcFinish(feedbackId, + feedbackService.updateProFeedbackWhenIpqcFinish(feedbackId, randomLongId(), BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO)); } @@ -171,12 +171,12 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest { // 调用,应该抛异常 assertThrows(Exception.class, () -> - feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), randomLongId(), BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO)); // 断言:不应该调用任何产出单方法 - verify(productProduceService, never()).splitPendingAndFinishProduce(anyLong(), any(), any()); + verify(productProduceService, never()).splitPendingAndFinishProduce(anyLong(), anyLong(), any(), any()); } @Test @@ -189,7 +189,7 @@ public class MesProFeedbackServiceImplTest extends BaseDbUnitTest { // 调用,应该抛异常 assertThrows(Exception.class, () -> - feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), + feedbackService.updateProFeedbackWhenIpqcFinish(feedback.getId(), randomLongId(), BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO)); } diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImplTest.java index 459cf50..84f69af 100644 --- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImplTest.java +++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImplTest.java @@ -1,16 +1,21 @@ package cn.iocoder.yudao.module.mes.service.qc.ipqc; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.mes.controller.admin.qc.ipqc.vo.MesQcIpqcSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO; import cn.iocoder.yudao.module.mes.dal.mysql.qc.ipqc.MesQcIpqcMapper; import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum; +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; import cn.iocoder.yudao.module.mes.service.pro.feedback.MesProFeedbackService; @@ -19,7 +24,9 @@ import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService; import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; +import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService; import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService; +import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import jakarta.annotation.Resource; import org.junit.jupiter.api.Test; @@ -30,6 +37,7 @@ import java.math.BigDecimal; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -69,11 +77,16 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { private MesProRouteProcessService routeProcessService; @MockitoBean private MesProTaskService taskService; + @MockitoBean + private MesQcIndicatorResultService indicatorResultService; + @MockitoBean + private MesWmProductProduceLineService productProduceLineService; @Test public void testFinishIpqc_writeBack_feedback() { // 准备数据:插入一条草稿状态的 IPQC 单,来源为报工单(PRO_FEEDBACK=304) Long sourceDocId = randomLongId(); + Long sourceLineId = randomLongId(); BigDecimal qualifiedQty = BigDecimal.valueOf(80); BigDecimal unqualifiedQty = BigDecimal.valueOf(20); BigDecimal laborScrapQty = BigDecimal.valueOf(5); @@ -85,7 +98,7 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { o.setCheckResult(1); // 非空,满足 finishIpqc 的校验 o.setSourceDocType(MesBizTypeConstants.PRO_FEEDBACK); o.setSourceDocId(sourceDocId); - o.setSourceLineId(null); // 报工场景下预留不使用 + o.setSourceLineId(sourceLineId); o.setQualifiedQuantity(qualifiedQty); o.setUnqualifiedQuantity(unqualifiedQty); o.setLaborScrapQuantity(laborScrapQty); @@ -101,10 +114,11 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { MesQcIpqcDO updatedIpqc = ipqcMapper.selectById(ipqc.getId()); assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedIpqc.getStatus()); - // 断言 2:调用了 feedbackService.completeFeedbackFromIpqc,传递正确参数 + // 断言 2:调用了 feedbackService,传递 sourceLineId // 注意:数量经过 DB 存取后 scale 可能变化(例如 80 → 80.00),所以用 any() 匹配 verify(feedbackService).updateProFeedbackWhenIpqcFinish( eq(sourceDocId), + eq(sourceLineId), any(BigDecimal.class), any(BigDecimal.class), any(BigDecimal.class), @@ -116,12 +130,13 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { public void testFinishIpqc_writeBack_feedback_withNullQuantities() { // 准备数据:合格品/不合格品/废品数量为 null 的场景,应该 defaultIfNull 为 0 Long sourceDocId = randomLongId(); + Long sourceLineId = randomLongId(); MesQcIpqcDO ipqc = randomPojo(MesQcIpqcDO.class, o -> { o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); o.setCheckResult(1); o.setSourceDocType(MesBizTypeConstants.PRO_FEEDBACK); o.setSourceDocId(sourceDocId); - o.setSourceLineId(null); + o.setSourceLineId(sourceLineId); o.setQualifiedQuantity(null); o.setUnqualifiedQuantity(null); o.setLaborScrapQuantity(null); @@ -136,6 +151,7 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { // 断言:所有数量参数都是 BigDecimal.ZERO(defaultIfNull 处理) verify(feedbackService).updateProFeedbackWhenIpqcFinish( eq(sourceDocId), + eq(sourceLineId), eq(BigDecimal.ZERO), eq(BigDecimal.ZERO), eq(BigDecimal.ZERO), @@ -164,7 +180,7 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { // 断言 2:不应该调用 feedbackService verify(feedbackService, never()).updateProFeedbackWhenIpqcFinish( - anyLong(), any(), any(), any(), any(), any()); + anyLong(), anyLong(), any(), any(), any(), any(), any()); } @Test @@ -308,6 +324,13 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { workOrder.setProductId(productId); when(workOrderService.validateWorkOrderExists(workOrderId)).thenReturn(workOrder); when(workOrderService.validateWorkOrderConfirmed(workOrderId)).thenReturn(workOrder); + // mock 任务 + MesProTaskDO task = new MesProTaskDO(); + task.setId(taskId); + task.setWorkOrderId(workOrderId); + task.setWorkstationId(workstationId); + task.setItemId(productId); + when(taskService.validateTaskNotFinished(taskId)).thenReturn(task); // mock 模板匹配 MesQcTemplateItemDO templateItem = new MesQcTemplateItemDO(); templateItem.setTemplateId(templateId); @@ -374,5 +397,200 @@ public class MesQcIpqcServiceImplTest extends BaseDbUnitTest { assertNull(ipqc.getProcessId()); } -} + // ==================== sourceLineId 校验测试 ==================== + + /** + * sourceDocType=PRO_FEEDBACK 时 sourceLineId 为空 → 创建失败 + */ + @Test + public void testCreateIpqc_sourceLineId_required() { + // 准备参数 + Long workstationId = randomLongId(); + Long workOrderId = randomLongId(); + Long productId = randomLongId(); + Long feedbackId = randomLongId(); + Long templateId = randomLongId(); + + MesQcIpqcSaveReqVO reqVO = new MesQcIpqcSaveReqVO(); + reqVO.setCode("IPQC-SL-001"); + reqVO.setWorkstationId(workstationId); + reqVO.setWorkOrderId(workOrderId); + reqVO.setInspectorUserId(randomLongId()); + reqVO.setSourceDocType(MesBizTypeConstants.PRO_FEEDBACK); + reqVO.setSourceDocId(feedbackId); + reqVO.setSourceLineId(null); // 不传 sourceLineId + + // mock + MesMdWorkstationDO workstation = new MesMdWorkstationDO(); + workstation.setId(workstationId); + workstation.setProcessId(null); + when(workstationService.validateWorkstationExists(workstationId)).thenReturn(workstation); + MesProWorkOrderDO workOrder = new MesProWorkOrderDO(); + workOrder.setId(workOrderId); + workOrder.setProductId(productId); + when(workOrderService.validateWorkOrderExists(workOrderId)).thenReturn(workOrder); + when(workOrderService.validateWorkOrderConfirmed(workOrderId)).thenReturn(workOrder); + MesQcTemplateItemDO templateItem = new MesQcTemplateItemDO(); + templateItem.setTemplateId(templateId); + when(templateItemService.getRequiredTemplateByItemIdAndType(eq(productId), anyInt())).thenReturn(templateItem); + when(feedbackService.validateFeedbackExists(feedbackId)).thenReturn(new MesProFeedbackDO()); + // 调用,断言异常 + ServiceException ex = assertThrows(ServiceException.class, () -> ipqcService.createIpqc(reqVO)); + assertEquals(QC_IPQC_SOURCE_LINE_REQUIRED.getCode(), ex.getCode()); + } + + /** + * sourceLineId 不属于该报工的产出行 → 创建失败 + */ + @Test + public void testCreateIpqc_sourceLineId_notBelong() { + // 准备参数 + Long workstationId = randomLongId(); + Long workOrderId = randomLongId(); + Long productId = randomLongId(); + Long feedbackId = randomLongId(); + Long sourceLineId = randomLongId(); + Long templateId = randomLongId(); + + MesQcIpqcSaveReqVO reqVO = new MesQcIpqcSaveReqVO(); + reqVO.setCode("IPQC-SL-002"); + reqVO.setWorkstationId(workstationId); + reqVO.setWorkOrderId(workOrderId); + reqVO.setInspectorUserId(randomLongId()); + reqVO.setSourceDocType(MesBizTypeConstants.PRO_FEEDBACK); + reqVO.setSourceDocId(feedbackId); + reqVO.setSourceLineId(sourceLineId); + + // mock + MesMdWorkstationDO workstation = new MesMdWorkstationDO(); + workstation.setId(workstationId); + workstation.setProcessId(null); + when(workstationService.validateWorkstationExists(workstationId)).thenReturn(workstation); + MesProWorkOrderDO workOrder = new MesProWorkOrderDO(); + workOrder.setId(workOrderId); + workOrder.setProductId(productId); + when(workOrderService.validateWorkOrderExists(workOrderId)).thenReturn(workOrder); + when(workOrderService.validateWorkOrderConfirmed(workOrderId)).thenReturn(workOrder); + MesQcTemplateItemDO templateItem = new MesQcTemplateItemDO(); + templateItem.setTemplateId(templateId); + when(templateItemService.getRequiredTemplateByItemIdAndType(eq(productId), anyInt())).thenReturn(templateItem); + when(feedbackService.validateFeedbackExists(feedbackId)).thenReturn(new MesProFeedbackDO()); + // mock:产出行存在但 feedbackId 不匹配 + MesWmProductProduceLineDO line = new MesWmProductProduceLineDO(); + line.setId(sourceLineId); + line.setFeedbackId(randomLongId()); // 不同的 feedbackId + line.setQualityStatus(MesWmQualityStatusEnum.PENDING.getStatus()); + when(productProduceLineService.validateProductProduceLineExists(sourceLineId)).thenReturn(line); + + // 调用,断言异常 + ServiceException ex = assertThrows(ServiceException.class, () -> ipqcService.createIpqc(reqVO)); + assertEquals(QC_IPQC_SOURCE_LINE_NOT_BELONG.getCode(), ex.getCode()); + } + + /** + * sourceLineId 对应的产出行不是待检验状态 → 创建失败 + */ + @Test + public void testCreateIpqc_sourceLineId_notPending() { + // 准备参数 + Long workstationId = randomLongId(); + Long workOrderId = randomLongId(); + Long productId = randomLongId(); + Long feedbackId = randomLongId(); + Long sourceLineId = randomLongId(); + Long templateId = randomLongId(); + + MesQcIpqcSaveReqVO reqVO = new MesQcIpqcSaveReqVO(); + reqVO.setCode("IPQC-SL-003"); + reqVO.setWorkstationId(workstationId); + reqVO.setWorkOrderId(workOrderId); + reqVO.setInspectorUserId(randomLongId()); + reqVO.setSourceDocType(MesBizTypeConstants.PRO_FEEDBACK); + reqVO.setSourceDocId(feedbackId); + reqVO.setSourceLineId(sourceLineId); + + // mock + MesMdWorkstationDO workstation = new MesMdWorkstationDO(); + workstation.setId(workstationId); + workstation.setProcessId(null); + when(workstationService.validateWorkstationExists(workstationId)).thenReturn(workstation); + MesProWorkOrderDO workOrder = new MesProWorkOrderDO(); + workOrder.setId(workOrderId); + workOrder.setProductId(productId); + when(workOrderService.validateWorkOrderExists(workOrderId)).thenReturn(workOrder); + when(workOrderService.validateWorkOrderConfirmed(workOrderId)).thenReturn(workOrder); + MesQcTemplateItemDO templateItem = new MesQcTemplateItemDO(); + templateItem.setTemplateId(templateId); + when(templateItemService.getRequiredTemplateByItemIdAndType(eq(productId), anyInt())).thenReturn(templateItem); + when(feedbackService.validateFeedbackExists(feedbackId)).thenReturn(new MesProFeedbackDO()); + // mock:产出行存在且归属正确,但不是 PENDING 状态 + MesWmProductProduceLineDO line = new MesWmProductProduceLineDO(); + line.setId(sourceLineId); + line.setFeedbackId(feedbackId); + line.setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus()); // 已合格,非待检 + when(productProduceLineService.validateProductProduceLineExists(sourceLineId)).thenReturn(line); + + // 调用,断言异常 + ServiceException ex = assertThrows(ServiceException.class, () -> ipqcService.createIpqc(reqVO)); + assertEquals(QC_IPQC_SOURCE_LINE_NOT_PENDING.getCode(), ex.getCode()); + } + + /** + * sourceLineId 校验全部通过 → 创建成功 + */ + @Test + public void testCreateIpqc_sourceLineId_success() { + // 准备参数 + Long workstationId = randomLongId(); + Long workOrderId = randomLongId(); + Long productId = randomLongId(); + Long feedbackId = randomLongId(); + Long sourceLineId = randomLongId(); + Long templateId = randomLongId(); + + MesQcIpqcSaveReqVO reqVO = new MesQcIpqcSaveReqVO(); + reqVO.setCode("IPQC-SL-004"); + reqVO.setWorkstationId(workstationId); + reqVO.setWorkOrderId(workOrderId); + reqVO.setInspectorUserId(randomLongId()); + reqVO.setSourceDocType(MesBizTypeConstants.PRO_FEEDBACK); + reqVO.setSourceDocId(feedbackId); + reqVO.setSourceLineId(sourceLineId); + + // mock + MesMdWorkstationDO workstation = new MesMdWorkstationDO(); + workstation.setId(workstationId); + workstation.setProcessId(null); + when(workstationService.validateWorkstationExists(workstationId)).thenReturn(workstation); + MesProWorkOrderDO workOrder = new MesProWorkOrderDO(); + workOrder.setId(workOrderId); + workOrder.setProductId(productId); + when(workOrderService.validateWorkOrderExists(workOrderId)).thenReturn(workOrder); + when(workOrderService.validateWorkOrderConfirmed(workOrderId)).thenReturn(workOrder); + MesQcTemplateItemDO templateItem = new MesQcTemplateItemDO(); + templateItem.setTemplateId(templateId); + when(templateItemService.getRequiredTemplateByItemIdAndType(eq(productId), anyInt())).thenReturn(templateItem); + MesProFeedbackDO feedback = new MesProFeedbackDO(); + feedback.setId(feedbackId); + feedback.setCode("FB-001"); + when(feedbackService.validateFeedbackExists(feedbackId)).thenReturn(feedback); + // mock:产出行存在、归属正确、PENDING 状态 + MesWmProductProduceLineDO line = new MesWmProductProduceLineDO(); + line.setId(sourceLineId); + line.setFeedbackId(feedbackId); + line.setQualityStatus(MesWmQualityStatusEnum.PENDING.getStatus()); + when(productProduceLineService.validateProductProduceLineExists(sourceLineId)).thenReturn(line); + + // 调用 + Long ipqcId = ipqcService.createIpqc(reqVO); + + // 断言:创建成功,sourceDocCode 回写 + MesQcIpqcDO ipqc = ipqcMapper.selectById(ipqcId); + assertNotNull(ipqc); + assertEquals(feedbackId, ipqc.getSourceDocId()); + assertEquals(sourceLineId, ipqc.getSourceLineId()); + assertEquals("FB-001", ipqc.getSourceDocCode()); + } + +} diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImplTest.java index 43b7472..e7bf99a 100644 --- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImplTest.java +++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImplTest.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.mes.service.wm.productproduce; import cn.hutool.core.collection.ListUtil; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDetailDO; @@ -27,8 +28,8 @@ import java.math.BigDecimal; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; /** @@ -66,6 +67,7 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { public void testSplitPendingAndFinishProduce_withUnqualified() { // 准备数据:插入一个 PREPARE 状态的产出单 Long feedbackId = randomLongId(); + Long sourceLineId = 100L; Long itemId = randomLongId(); Long batchId = randomLongId(); String batchCode = "BATCH-001"; @@ -85,19 +87,17 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { when(locationService.getWarehouseLocationByCode(MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION)).thenReturn(loc); when(areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA)).thenReturn(area); - // mock: 返回一条 PENDING 的产出行 + // mock: 通过 sourceLineId 直接定位 PENDING 产出行 MesWmProductProduceLineDO pendingLine = MesWmProductProduceLineDO.builder() - .id(100L).produceId(produce.getId()).feedbackId(feedbackId) + .id(sourceLineId).produceId(produce.getId()).feedbackId(feedbackId) .itemId(itemId).quantity(BigDecimal.valueOf(100)) .batchId(batchId).batchCode(batchCode) .qualityStatus(MesWmQualityStatusEnum.PENDING.getStatus()) .build(); - when(productProduceLineService.getProductProduceLineListByProduceId(produce.getId())) - .thenReturn(ListUtil.of(pendingLine)); + when(productProduceLineService.validateProductProduceLineExists(sourceLineId)) + .thenReturn(pendingLine); - // mock: finishProductProduce 内部会再查一次行和明细(用于创建库存事务) - // 由于 finishProductProduce 在拆分行后调用,此时行已经变了,但由于 line/detail 是 mock 的, - // 我们需要 mock 已拆分后的行给 finishProductProduce + // mock: finishProductProduce 内部查行和明细(用于创建库存事务) MesWmProductProduceLineDO qualifiedLine = MesWmProductProduceLineDO.builder() .id(100L).produceId(produce.getId()).itemId(itemId) .quantity(BigDecimal.valueOf(80)) @@ -108,10 +108,8 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { .quantity(BigDecimal.valueOf(20)) .qualityStatus(MesWmQualityStatusEnum.FAIL.getStatus()) .build(); - // finishProductProduce 内部第二次调用 getProductProduceLineListByProduceId when(productProduceLineService.getProductProduceLineListByProduceId(produce.getId())) - .thenReturn(ListUtil.of(pendingLine)) // 第 1 次:splitPendingAndFinishProduce 查待检行 - .thenReturn(ListUtil.of(qualifiedLine, unqualifiedLine)); // 第 2 次:finishProductProduce 查所有行 + .thenReturn(ListUtil.of(qualifiedLine, unqualifiedLine)); // mock: finishProductProduce 中按行查明细 MesWmProductProduceDetailDO qualifiedDetail = MesWmProductProduceDetailDO.builder() @@ -124,7 +122,8 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { .thenReturn(ListUtil.of(unqualifiedDetail)); // 调用 - productProduceService.splitPendingAndFinishProduce(feedbackId, BigDecimal.valueOf(80), BigDecimal.valueOf(20)); + productProduceService.splitPendingAndFinishProduce(feedbackId, sourceLineId, + BigDecimal.valueOf(80), BigDecimal.valueOf(20)); // 断言 1:不合格品行 - 新建了一行 ArgumentCaptor lineCaptor = ArgumentCaptor.forClass(MesWmProductProduceLineDO.class); @@ -156,6 +155,7 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { public void testSplitPendingAndFinishProduce_allQualified() { // 准备数据:全部合格品场景 Long feedbackId = randomLongId(); + Long sourceLineId = 200L; Long itemId = randomLongId(); MesWmProductProduceDO produce = randomPojo(MesWmProductProduceDO.class, o -> { @@ -173,30 +173,31 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { when(locationService.getWarehouseLocationByCode(any())).thenReturn(loc); when(areaService.getWarehouseAreaByCode(any())).thenReturn(area); + // mock: 通过 sourceLineId 直接定位 PENDING 产出行 MesWmProductProduceLineDO pendingLine = MesWmProductProduceLineDO.builder() - .id(200L).produceId(produce.getId()).feedbackId(feedbackId) + .id(sourceLineId).produceId(produce.getId()).feedbackId(feedbackId) .itemId(itemId).quantity(BigDecimal.valueOf(50)) .qualityStatus(MesWmQualityStatusEnum.PENDING.getStatus()) .build(); + when(productProduceLineService.validateProductProduceLineExists(sourceLineId)) + .thenReturn(pendingLine); - // 第 1 次查行(拆分阶段)返回 PENDING 行;第 2 次查行(finishProductProduce)返回已更新的合格行 + // mock: finishProductProduce 查行和明细 MesWmProductProduceLineDO qualifiedLine = MesWmProductProduceLineDO.builder() .id(200L).produceId(produce.getId()).itemId(itemId) .quantity(BigDecimal.valueOf(50)) .qualityStatus(MesWmQualityStatusEnum.PASS.getStatus()) .build(); when(productProduceLineService.getProductProduceLineListByProduceId(produce.getId())) - .thenReturn(ListUtil.of(pendingLine)) .thenReturn(ListUtil.of(qualifiedLine)); - - // mock: finishProductProduce 中按行查明细 MesWmProductProduceDetailDO detail = MesWmProductProduceDetailDO.builder() .lineId(200L).quantity(BigDecimal.valueOf(50)).build(); when(productProduceDetailService.getProductProduceDetailListByLineId(200L)) .thenReturn(ListUtil.of(detail)); // 调用:不合格品数量 = 0 - productProduceService.splitPendingAndFinishProduce(feedbackId, BigDecimal.valueOf(50), BigDecimal.ZERO); + productProduceService.splitPendingAndFinishProduce(feedbackId, sourceLineId, + BigDecimal.valueOf(50), BigDecimal.ZERO); // 断言 1:没有新建行(不合格品数量为 0) verify(productProduceLineService, never()).createProductProduceLine(any()); @@ -218,14 +219,18 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { public void testSplitPendingAndFinishProduce_produceNotExists() { // 调用不存在的 feedbackId,应该抛异常 Long feedbackId = randomLongId(); - assertThrows(Exception.class, () -> - productProduceService.splitPendingAndFinishProduce(feedbackId, BigDecimal.TEN, BigDecimal.ZERO)); + Long sourceLineId = randomLongId(); + ServiceException ex = assertThrows(ServiceException.class, () -> + productProduceService.splitPendingAndFinishProduce(feedbackId, sourceLineId, + BigDecimal.TEN, BigDecimal.ZERO)); + assertEquals(WM_PRODUCT_PRODUCE_NOT_EXISTS.getCode(), ex.getCode()); } @Test - public void testSplitPendingAndFinishProduce_noPendingLine() { - // 准备数据:产出单存在,但没有 PENDING 行 + public void testSplitPendingAndFinishProduce_lineNotExists() { + // 准备数据:产出单存在,但 sourceLineId 对应的行不存在 Long feedbackId = randomLongId(); + Long sourceLineId = randomLongId(); MesWmProductProduceDO produce = randomPojo(MesWmProductProduceDO.class, o -> { o.setFeedbackId(feedbackId); o.setStatus(MesWmProductProduceStatusEnum.PREPARE.getStatus()); @@ -240,17 +245,15 @@ public class MesWmProductProduceServiceImplTest extends BaseDbUnitTest { when(locationService.getWarehouseLocationByCode(any())).thenReturn(loc); when(areaService.getWarehouseAreaByCode(any())).thenReturn(area); - // mock: 返回一条 PASS 状态的行(不是 PENDING) - MesWmProductProduceLineDO passLine = MesWmProductProduceLineDO.builder() - .id(300L).produceId(produce.getId()) - .qualityStatus(MesWmQualityStatusEnum.PASS.getStatus()) - .build(); - when(productProduceLineService.getProductProduceLineListByProduceId(produce.getId())) - .thenReturn(ListUtil.of(passLine)); + // mock: validateProductProduceLineExists 抛异常 + when(productProduceLineService.validateProductProduceLineExists(sourceLineId)) + .thenThrow(new ServiceException(WM_PRODUCT_PRODUCE_LINE_NOT_EXISTS)); - // 调用,应该抛异常(找不到 PENDING 行) - assertThrows(Exception.class, () -> - productProduceService.splitPendingAndFinishProduce(feedbackId, BigDecimal.TEN, BigDecimal.ZERO)); + // 调用,应该抛异常 + ServiceException ex = assertThrows(ServiceException.class, () -> + productProduceService.splitPendingAndFinishProduce(feedbackId, sourceLineId, + BigDecimal.TEN, BigDecimal.ZERO)); + assertEquals(WM_PRODUCT_PRODUCE_LINE_NOT_EXISTS.getCode(), ex.getCode()); } } -- libgit2 0.21.4