diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java
index ca965d1..2139ba5 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java
@@ -9,11 +9,9 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo.line.MesQcRqcLineR
import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
-import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO;
import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcLineService;
import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService;
-import cn.iocoder.yudao.module.mes.service.tm.tool.MesTmToolService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -46,8 +44,6 @@ public class MesQcRqcLineController {
private MesQcIndicatorService indicatorService;
@Resource
private MesMdUnitMeasureService unitMeasureService;
- @Resource
- private MesTmToolService toolService;
@GetMapping("/get")
@Operation(summary = "获得退货检验单行")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java
index c8368e2..5966a24 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java
@@ -20,8 +20,8 @@ public class MesQcRqcPageReqVO extends PageParam {
@Schema(description = "检验单编号", example = "RQC2025")
private String code;
- @Schema(description = "来源单据类型", example = "RTISSUE")
- private String sourceDocType;
+ @Schema(description = "来源单据类型", example = "1")
+ private Integer sourceDocType;
@Schema(description = "产品物料 ID", example = "20")
private Long itemId;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java
index 49aa520..7dd1047 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java
@@ -17,7 +17,8 @@ public enum MesMdAutoCodeRuleCodeEnum {
BATCH_CODE("WM_BATCH_CODE", "批次编码"),
TASK_CODE("PRO_TASK_CODE", "生产任务编码"),
QC_IQC_CODE("QC_IQC_CODE", "来料检验单编码"),
- QC_IPQC_CODE("QC_IPQC_CODE", "过程检验单编码");
+ QC_IPQC_CODE("QC_IPQC_CODE", "过程检验单编码"),
+ QC_RQC_CODE("QC_RQC_CODE", "退货检验单编码");
/**
* 规则代码
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java
index cfed9b2..cd6e513 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java
@@ -134,8 +134,8 @@ public class MesQcRqcServiceImpl implements MesQcRqcService {
*
*
根据 sourceDocType 分发:
*
- * - WM_RETURN_ISSUE(生产退料单)→ 回写行的 qualityStatus
- * - WM_RETURN_SALES(销售退货单)→ 回写行的 qualityStatus
+ * - WM_RETURN_ISSUE(生产退料单)→ 根据合格/不合格数量拆分行 + 更新 qualityStatus + 联动主单状态
+ * - WM_RETURN_SALES(销售退货单)→ 同上
*
*
* @param rqc 退货检验单
@@ -150,11 +150,15 @@ public class MesQcRqcServiceImpl implements MesQcRqcService {
}
if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_ISSUE)) {
- // 回写生产退料单行的 qualityStatus
- returnIssueLineService.updateReturnIssueLineWhenRqcFinish(rqc.getSourceLineId(), rqc.getCheckResult());
+ // 回写生产退料单行:拆分行 + 更新质量状态 + 联动主单状态
+ returnIssueLineService.updateReturnIssueLineWhenRqcFinish(
+ rqc.getSourceLineId(), rqc.getSourceDocId(), rqc.getCheckResult(),
+ rqc.getQualifiedQuantity(), rqc.getUnqualifiedQuantity());
} else if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_SALES)) {
- // 回写销售退货单行的 qualityStatus
- returnSalesLineService.updateReturnSalesLineWhenRqcFinish(rqc.getSourceLineId(), rqc.getCheckResult());
+ // 回写销售退货单行:拆分行 + 更新质量状态 + 联动主单状态
+ returnSalesLineService.updateReturnSalesLineWhenRqcFinish(
+ rqc.getSourceLineId(), rqc.getSourceDocId(), rqc.getCheckResult(),
+ rqc.getQualifiedQuantity(), rqc.getUnqualifiedQuantity());
} else {
throw new IllegalArgumentException(
"RQC 单[" + rqc.getId() + "] sourceDocType=" + rqc.getSourceDocType() + " 无法识别,无法回写来源单据");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineService.java
index fb70546..6a8786f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineService.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.line.MesWm
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO;
import jakarta.validation.Valid;
+import java.math.BigDecimal;
import java.util.List;
/**
@@ -83,11 +84,23 @@ public interface MesWmReturnIssueLineService {
void updateReturnIssueQualityStatusByIssueId(Long issueId, Integer issueType);
/**
- * RQC 检验完成后,更新生产退料单行的质量状态
+ * RQC 检验完成后,根据合格品/不合格品数量更新生产退料单行
*
- * @param id 行 ID
- * @param checkResult 检验结果
+ * 拆分逻辑:
+ *
+ * - 全部合格:直接更新行的 qualityStatus 为合格
+ * - 全部不合格:直接更新行的 qualityStatus 为不合格
+ * - 部分合格部分不合格:拆分原行(原行改为合格+数量=合格数,新增一行不合格+数量=不合格数)
+ *
+ * 同时检查退料单下所有行是否都已检验完毕,若全检完则将退料单状态设为待上架。
+ *
+ * @param sourceLineId 来源行 ID
+ * @param sourceDocId 来源退料单 ID
+ * @param checkResult 检验结果
+ * @param qualifiedQuantity 合格品数量
+ * @param unqualifiedQuantity 不合格品数量
*/
- void updateReturnIssueLineWhenRqcFinish(Long id, Integer checkResult);
+ void updateReturnIssueLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult,
+ BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImpl.java
index 335c93b..f4dff35 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImpl.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.service.wm.returnissue;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -8,8 +9,8 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.line.MesWm
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnissue.MesWmReturnIssueLineMapper;
-import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueStatusEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueTypeEnum;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import jakarta.annotation.Resource;
@@ -17,6 +18,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
@@ -137,10 +139,51 @@ public class MesWmReturnIssueLineServiceImpl implements MesWmReturnIssueLineServ
}
@Override
- public void updateReturnIssueLineWhenRqcFinish(Long id, Integer checkResult) {
- Integer qualityStatus = Objects.equals(checkResult, MesQcCheckResultEnum.PASS.getType())
- ? MesWmQualityStatusEnum.PASS.getStatus() : MesWmQualityStatusEnum.FAIL.getStatus();
- issueLineMapper.updateById(new MesWmReturnIssueLineDO().setId(id).setQualityStatus(qualityStatus));
+ public void updateReturnIssueLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult,
+ BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity) {
+ MesWmReturnIssueLineDO sourceLine = validateReturnIssueLineExists(sourceLineId);
+ boolean hasUnqualified = unqualifiedQuantity != null && unqualifiedQuantity.compareTo(BigDecimal.ZERO) > 0;
+ boolean hasQualified = qualifiedQuantity != null && qualifiedQuantity.compareTo(BigDecimal.ZERO) > 0;
+
+ // 1. 根据合格/不合格品数量,更新退料单行的质量状态
+ if (!hasUnqualified) {
+ // 1.A 情况一:全部合格
+ issueLineMapper.updateById(new MesWmReturnIssueLineDO()
+ .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus()));
+ } else if (!hasQualified) {
+ // 1.B 情况二:全部不合格
+ issueLineMapper.updateById(new MesWmReturnIssueLineDO()
+ .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus()));
+ } else {
+ // 1.C 情况三:部分合格部分不合格 → 拆分行
+ // 1.C.1 新增一行不合格品
+ MesWmReturnIssueLineDO unqualifiedLine = new MesWmReturnIssueLineDO()
+ .setIssueId(sourceLine.getIssueId())
+ .setMaterialStockId(sourceLine.getMaterialStockId())
+ .setItemId(sourceLine.getItemId())
+ .setQuantity(unqualifiedQuantity)
+ .setBatchId(sourceLine.getBatchId())
+ .setIpqcId(sourceLine.getIpqcId())
+ .setQcFlag(sourceLine.getQcFlag())
+ .setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus())
+ .setRemark(sourceLine.getRemark());
+ issueLineMapper.insert(unqualifiedLine);
+ // 1.C.2 更新原行为合格品(数量调整为合格数量)
+ issueLineMapper.updateById(new MesWmReturnIssueLineDO()
+ .setId(sourceLineId)
+ .setQuantity(qualifiedQuantity)
+ .setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus()));
+ }
+
+ // 2. 检查退料单下是否还有待检验的行,若全检完则将退料单状态设为"待上架"
+ if (sourceDocId != null) {
+ List allLines = issueLineMapper.selectListByIssueId(sourceDocId);
+ boolean allInspected = !CollUtil.contains(allLines,
+ line -> Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus()));
+ if (allInspected) {
+ issueService.updateReturnIssueStatus(sourceDocId, MesWmReturnIssueStatusEnum.APPROVING.getStatus());
+ }
+ }
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueService.java
index 68118a2..5f16cb5 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueService.java
@@ -85,4 +85,12 @@ public interface MesWmReturnIssueService {
*/
void cancelReturnIssue(Long id);
+ /**
+ * 更新生产退料单状态(供外部模块联动调用,如 RQC 检验完成后)
+ *
+ * @param id 编号
+ * @param status 目标状态
+ */
+ void updateReturnIssueStatus(Long id, Integer status);
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueServiceImpl.java
index 92e634c..cf47a6f 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueServiceImpl.java
@@ -271,4 +271,10 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService {
return issue;
}
+ @Override
+ public void updateReturnIssueStatus(Long id, Integer status) {
+ validateReturnIssueExists(id);
+ issueMapper.updateById(new MesWmReturnIssueDO().setId(id).setStatus(status));
+ }
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineService.java
index 376e454..496d4a1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineService.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWm
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO;
import jakarta.validation.Valid;
+import java.math.BigDecimal;
import java.util.List;
/**
@@ -85,11 +86,23 @@ public interface MesWmReturnSalesLineService {
void updateQualityStatusByReturnId(Long returnId, Integer qualityStatus);
/**
- * RQC 检验完成后,更新销售退货单行的质量状态
+ * RQC 检验完成后,根据合格品/不合格品数量更新销售退货单行
*
- * @param id 行 ID
- * @param checkResult 检验结果
+ * 拆分逻辑:
+ *
+ * - 全部合格:直接更新行的 qualityStatus 为合格
+ * - 全部不合格:直接更新行的 qualityStatus 为不合格
+ * - 部分合格部分不合格:拆分原行(原行改为合格+数量=合格数,新增一行不合格+数量=不合格数)
+ *
+ * 同时检查退货单下所有行是否都已检验完毕,若全检完则将退货单状态设为待上架。
+ *
+ * @param sourceLineId 来源行 ID
+ * @param sourceDocId 来源退货单 ID
+ * @param checkResult 检验结果
+ * @param qualifiedQuantity 合格品数量
+ * @param unqualifiedQuantity 不合格品数量
*/
- void updateReturnSalesLineWhenRqcFinish(Long id, Integer checkResult);
+ void updateReturnSalesLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult,
+ BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity);
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java
index a6478b5..a3fb263 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.service.wm.returnsales;
+import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWmReturnSalesLinePageReqVO;
@@ -7,14 +8,15 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWm
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnsales.MesWmReturnSalesLineMapper;
-import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnSalesStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
@@ -129,11 +131,48 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ
}
@Override
- public void updateReturnSalesLineWhenRqcFinish(Long id, Integer checkResult) {
- Integer qualityStatus = Objects.equals(checkResult, MesQcCheckResultEnum.PASS.getType())
- ? MesWmQualityStatusEnum.PASS.getStatus()
- : MesWmQualityStatusEnum.FAIL.getStatus();
- returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO().setId(id).setQualityStatus(qualityStatus));
+ public void updateReturnSalesLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult,
+ BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity) {
+ MesWmReturnSalesLineDO sourceLine = validateReturnSalesLineExists(sourceLineId);
+ boolean hasUnqualified = unqualifiedQuantity != null && unqualifiedQuantity.compareTo(BigDecimal.ZERO) > 0;
+ boolean hasQualified = qualifiedQuantity != null && qualifiedQuantity.compareTo(BigDecimal.ZERO) > 0;
+
+ // 1. 根据合格/不合格品数量,更新退货单行的质量状态
+ if (!hasUnqualified) {
+ // 1.A 情况一:全部合格
+ returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO()
+ .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus()));
+ } else if (!hasQualified) {
+ // 1.B 情况二:全部不合格
+ returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO()
+ .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus()));
+ } else {
+ // 1.C 情况三:部分合格部分不合格 → 拆分行
+ // 1.C.1 新增一行不合格品
+ MesWmReturnSalesLineDO unqualifiedLine = new MesWmReturnSalesLineDO()
+ .setReturnId(sourceLine.getReturnId())
+ .setItemId(sourceLine.getItemId())
+ .setQuantity(unqualifiedQuantity)
+ .setBatchId(sourceLine.getBatchId())
+ .setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus())
+ .setRemark(sourceLine.getRemark());
+ returnSalesLineMapper.insert(unqualifiedLine);
+ // 1.C.2 更新原行为合格品
+ returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO()
+ .setId(sourceLineId)
+ .setQuantity(qualifiedQuantity)
+ .setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus()));
+ }
+
+ // 2. 检查退货单下是否还有待检验的行,若全检完则将退货单状态设为"待上架"
+ if (sourceDocId != null) {
+ List allLines = returnSalesLineMapper.selectListByReturnId(sourceDocId);
+ boolean allInspected = !CollUtil.contains(allLines,
+ line -> Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus()));
+ if (allInspected) {
+ returnSalesService.updateReturnSalesStatus(sourceDocId, MesWmReturnSalesStatusEnum.APPROVED.getStatus());
+ }
+ }
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesService.java
index 7a9f15c..ccba7c3 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesService.java
@@ -88,6 +88,14 @@ public interface MesWmReturnSalesService {
void cancelReturnSales(Long id);
/**
+ * 更新销售退货单状态(供外部模块联动调用,如 RQC 检验完成后)
+ *
+ * @param id 编号
+ * @param status 目标状态
+ */
+ void updateReturnSalesStatus(Long id, Integer status);
+
+ /**
* 校验销售退货单的数量:每行明细数量之和是否等于行退货数量
*
* @param id 编号
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesServiceImpl.java
index 8b941c9..675ed98 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesServiceImpl.java
@@ -239,4 +239,10 @@ public class MesWmReturnSalesServiceImpl implements MesWmReturnSalesService {
return returnSales;
}
+ @Override
+ public void updateReturnSalesStatus(Long id, Integer status) {
+ validateReturnSalesExists(id);
+ returnSalesMapper.updateById(new MesWmReturnSalesDO().setId(id).setStatus(status));
+ }
+
}
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImplTest.java
index ac174e0..4fc1da9 100644
--- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImplTest.java
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImplTest.java
@@ -16,15 +16,15 @@ import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
+import java.math.BigDecimal;
+
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
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.QC_RQC_NOT_EXISTS;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.QC_RQC_NOT_PREPARE;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -61,18 +61,22 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest {
public void testFinishRqc_successWithReturnIssue() {
// 准备参数
Long sourceLineId = randomLongId();
+ Long sourceDocId = randomLongId();
Integer checkResult = 1;
+ BigDecimal qualifiedQty = new BigDecimal("80");
+ BigDecimal unqualifiedQty = new BigDecimal("20");
// mock 数据
MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> {
o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
o.setSourceDocType(MesBizTypeConstants.WM_RETURN_ISSUE);
+ o.setSourceDocId(sourceDocId);
o.setSourceLineId(sourceLineId);
o.setCheckResult(checkResult);
// 设置数量通过 finishRqc 的数量校验:合格 + 不合格 = 检测数量
- o.setCheckQuantity(new java.math.BigDecimal("100"));
- o.setQualifiedQuantity(new java.math.BigDecimal("80"));
- o.setUnqualifiedQuantity(new java.math.BigDecimal("20"));
+ o.setCheckQuantity(new BigDecimal("100"));
+ o.setQualifiedQuantity(qualifiedQty);
+ o.setUnqualifiedQuantity(unqualifiedQty);
});
rqcMapper.insert(rqc);
@@ -83,28 +87,36 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest {
MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId());
assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus());
- // 断言:验证回写调用生产退料
- verify(returnIssueLineService).updateReturnIssueLineWhenRqcFinish(eq(sourceLineId), eq(checkResult));
+ // 断言:验证回写调用生产退料(含拆分参数)
+ verify(returnIssueLineService).updateReturnIssueLineWhenRqcFinish(
+ eq(sourceLineId), eq(sourceDocId), eq(checkResult),
+ argThat(v -> v.compareTo(qualifiedQty) == 0),
+ argThat(v -> v.compareTo(unqualifiedQty) == 0));
// 断言:未调用销售退货
- verify(returnSalesLineService, never()).updateReturnSalesLineWhenRqcFinish(anyLong(), anyInt());
+ verify(returnSalesLineService, never()).updateReturnSalesLineWhenRqcFinish(
+ anyLong(), anyLong(), anyInt(), any(BigDecimal.class), any(BigDecimal.class));
}
@Test
public void testFinishRqc_successWithReturnSales() {
// 准备参数
Long sourceLineId = randomLongId();
+ Long sourceDocId = randomLongId();
Integer checkResult = 1;
+ BigDecimal qualifiedQty = new BigDecimal("90");
+ BigDecimal unqualifiedQty = new BigDecimal("10");
// mock 数据
MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> {
o.setStatus(MesQcStatusEnum.DRAFT.getStatus());
o.setSourceDocType(MesBizTypeConstants.WM_RETURN_SALES);
+ o.setSourceDocId(sourceDocId);
o.setSourceLineId(sourceLineId);
o.setCheckResult(checkResult);
// 设置数量通过 finishRqc 的数量校验:合格 + 不合格 = 检测数量
- o.setCheckQuantity(new java.math.BigDecimal("100"));
- o.setQualifiedQuantity(new java.math.BigDecimal("90"));
- o.setUnqualifiedQuantity(new java.math.BigDecimal("10"));
+ o.setCheckQuantity(new BigDecimal("100"));
+ o.setQualifiedQuantity(qualifiedQty);
+ o.setUnqualifiedQuantity(unqualifiedQty);
});
rqcMapper.insert(rqc);
@@ -115,10 +127,14 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest {
MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId());
assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus());
- // 断言:验证回写调用销售退货
- verify(returnSalesLineService).updateReturnSalesLineWhenRqcFinish(eq(sourceLineId), eq(checkResult));
+ // 断言:验证回写调用销售退货(含拆分参数)
+ verify(returnSalesLineService).updateReturnSalesLineWhenRqcFinish(
+ eq(sourceLineId), eq(sourceDocId), eq(checkResult),
+ argThat(v -> v.compareTo(qualifiedQty) == 0),
+ argThat(v -> v.compareTo(unqualifiedQty) == 0));
// 断言:未调用生产退料
- verify(returnIssueLineService, never()).updateReturnIssueLineWhenRqcFinish(anyLong(), anyInt());
+ verify(returnIssueLineService, never()).updateReturnIssueLineWhenRqcFinish(
+ anyLong(), anyLong(), anyInt(), any(BigDecimal.class), any(BigDecimal.class));
}
@Test
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImplTest.java
index 8243184..4934dca 100644
--- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImplTest.java
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImplTest.java
@@ -12,8 +12,11 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import java.math.BigDecimal;
+
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.assertNotNull;
/**
* {@link MesWmReturnIssueLineServiceImpl} 的单元测试类
@@ -36,37 +39,75 @@ public class MesWmReturnIssueLineServiceImplTest extends BaseDbUnitTest {
private MesMdItemService itemService;
@Test
- public void testUpdateReturnIssueLineWhenRqcFinish_pass() {
- // 准备参数
+ public void testUpdateReturnIssueLineWhenRqcFinish_allPass() {
+ // 准备参数:全部合格
Integer checkResult = MesQcCheckResultEnum.PASS.getType();
+ BigDecimal qualifiedQty = new BigDecimal("100");
+ BigDecimal unqualifiedQty = BigDecimal.ZERO;
// mock 数据
- MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class);
+ MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class, o -> o.setQuantity(qualifiedQty));
returnIssueLineMapper.insert(lineDO);
- // 调用
- returnIssueLineService.updateReturnIssueLineWhenRqcFinish(lineDO.getId(), checkResult);
+ // 调用(sourceDocId 传 null 不联动主表状态)
+ returnIssueLineService.updateReturnIssueLineWhenRqcFinish(
+ lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty);
- // 断言:验证 mapper 更新参数正确
+ // 断言:验证质量状态更新为合格
MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId());
assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus());
}
@Test
- public void testUpdateReturnIssueLineWhenRqcFinish_fail() {
- // 准备参数
+ public void testUpdateReturnIssueLineWhenRqcFinish_allFail() {
+ // 准备参数:全部不合格
Integer checkResult = MesQcCheckResultEnum.FAIL.getType();
+ BigDecimal qualifiedQty = BigDecimal.ZERO;
+ BigDecimal unqualifiedQty = new BigDecimal("100");
// mock 数据
- MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class);
+ MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class, o -> o.setQuantity(unqualifiedQty));
returnIssueLineMapper.insert(lineDO);
// 调用
- returnIssueLineService.updateReturnIssueLineWhenRqcFinish(lineDO.getId(), checkResult);
+ returnIssueLineService.updateReturnIssueLineWhenRqcFinish(
+ lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty);
- // 断言:验证 mapper 更新参数正确
+ // 断言:验证质量状态更新为不合格
MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId());
assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus());
}
+ @Test
+ public void testUpdateReturnIssueLineWhenRqcFinish_partialSplit() {
+ // 准备参数:部分合格部分不合格,触发行拆分
+ Integer checkResult = MesQcCheckResultEnum.PASS.getType();
+ BigDecimal qualifiedQty = new BigDecimal("80");
+ BigDecimal unqualifiedQty = new BigDecimal("20");
+
+ // mock 数据
+ MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class, o ->
+ o.setQuantity(new BigDecimal("100")));
+ returnIssueLineMapper.insert(lineDO);
+
+ // 调用
+ returnIssueLineService.updateReturnIssueLineWhenRqcFinish(
+ lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty);
+
+ // 断言:原行变为合格,数量调整为合格数量
+ MesWmReturnIssueLineDO originalLine = returnIssueLineMapper.selectById(lineDO.getId());
+ assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), originalLine.getQualityStatus());
+ assertEquals(0, qualifiedQty.compareTo(originalLine.getQuantity()));
+
+ // 断言:新增了一行不合格品
+ var allLines = returnIssueLineMapper.selectListByIssueId(lineDO.getIssueId());
+ assertEquals(2, allLines.size());
+ MesWmReturnIssueLineDO newLine = allLines.stream()
+ .filter(l -> !l.getId().equals(lineDO.getId()))
+ .findFirst().orElse(null);
+ assertNotNull(newLine);
+ assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), newLine.getQualityStatus());
+ assertEquals(0, unqualifiedQty.compareTo(newLine.getQuantity()));
+ }
+
}
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImplTest.java
index b8f9ff3..3ef35fe 100644
--- a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImplTest.java
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImplTest.java
@@ -12,8 +12,11 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import java.math.BigDecimal;
+
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.assertNotNull;
/**
* {@link MesWmReturnSalesLineServiceImpl} 的单元测试类
@@ -36,37 +39,75 @@ public class MesWmReturnSalesLineServiceImplTest extends BaseDbUnitTest {
private MesMdItemService itemService;
@Test
- public void testUpdateReturnSalesLineWhenRqcFinish_pass() {
- // 准备参数
+ public void testUpdateReturnSalesLineWhenRqcFinish_allPass() {
+ // 准备参数:全部合格
Integer checkResult = MesQcCheckResultEnum.PASS.getType();
+ BigDecimal qualifiedQty = new BigDecimal("100");
+ BigDecimal unqualifiedQty = BigDecimal.ZERO;
// mock 数据
- MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class);
+ MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class, o -> o.setQuantity(qualifiedQty));
returnSalesLineMapper.insert(lineDO);
- // 调用
- returnSalesLineService.updateReturnSalesLineWhenRqcFinish(lineDO.getId(), checkResult);
+ // 调用(sourceDocId 传 null 不联动主表状态)
+ returnSalesLineService.updateReturnSalesLineWhenRqcFinish(
+ lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty);
- // 断言:验证 mapper 更新参数正确
+ // 断言:验证质量状态更新为合格
MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId());
assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus());
}
@Test
- public void testUpdateReturnSalesLineWhenRqcFinish_fail() {
- // 准备参数
+ public void testUpdateReturnSalesLineWhenRqcFinish_allFail() {
+ // 准备参数:全部不合格
Integer checkResult = MesQcCheckResultEnum.FAIL.getType();
+ BigDecimal qualifiedQty = BigDecimal.ZERO;
+ BigDecimal unqualifiedQty = new BigDecimal("100");
// mock 数据
- MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class);
+ MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class, o -> o.setQuantity(unqualifiedQty));
returnSalesLineMapper.insert(lineDO);
// 调用
- returnSalesLineService.updateReturnSalesLineWhenRqcFinish(lineDO.getId(), checkResult);
+ returnSalesLineService.updateReturnSalesLineWhenRqcFinish(
+ lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty);
- // 断言:验证 mapper 更新参数正确
+ // 断言:验证质量状态更新为不合格
MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId());
assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus());
}
+ @Test
+ public void testUpdateReturnSalesLineWhenRqcFinish_partialSplit() {
+ // 准备参数:部分合格部分不合格,触发行拆分
+ Integer checkResult = MesQcCheckResultEnum.PASS.getType();
+ BigDecimal qualifiedQty = new BigDecimal("70");
+ BigDecimal unqualifiedQty = new BigDecimal("30");
+
+ // mock 数据
+ MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class, o ->
+ o.setQuantity(new BigDecimal("100")));
+ returnSalesLineMapper.insert(lineDO);
+
+ // 调用
+ returnSalesLineService.updateReturnSalesLineWhenRqcFinish(
+ lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty);
+
+ // 断言:原行变为合格,数量调整为合格数量
+ MesWmReturnSalesLineDO originalLine = returnSalesLineMapper.selectById(lineDO.getId());
+ assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), originalLine.getQualityStatus());
+ assertEquals(0, qualifiedQty.compareTo(originalLine.getQuantity()));
+
+ // 断言:新增了一行不合格品
+ var allLines = returnSalesLineMapper.selectListByReturnId(lineDO.getReturnId());
+ assertEquals(2, allLines.size());
+ MesWmReturnSalesLineDO newLine = allLines.stream()
+ .filter(l -> !l.getId().equals(lineDO.getId()))
+ .findFirst().orElse(null);
+ assertNotNull(newLine);
+ assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), newLine.getQualityStatus());
+ assertEquals(0, unqualifiedQty.compareTo(newLine.getQuantity()));
+ }
+
}