Commit d2feaae7d48c3526ba74cab619f95d9c77a3ce5b
1 parent
40a6786a
✨ feat(mes): 更新退货检验单逻辑,支持合格/不合格数量拆分
优化退货检验单的处理逻辑,新增对合格品和不合格品数量的支持。实现了根据检验结果更新退货单行的质量状态,并在部分合格的情况下进行行拆分。同时,更新了相关的接口和数据结构,确保数据一致性和完整性。
Showing
15 changed files
with
304 additions
and
69 deletions
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 | @@ -9,11 +9,9 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo.line.MesQcRqcLineR | ||
| 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; | 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO; | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO; |
| 11 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; | 11 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; |
| 12 | -import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO; | ||
| 13 | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; | 12 | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| 14 | import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcLineService; | 13 | import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcLineService; |
| 15 | import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService; | 14 | import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService; |
| 16 | -import cn.iocoder.yudao.module.mes.service.tm.tool.MesTmToolService; | ||
| 17 | import io.swagger.v3.oas.annotations.Operation; | 15 | import io.swagger.v3.oas.annotations.Operation; |
| 18 | import io.swagger.v3.oas.annotations.Parameter; | 16 | import io.swagger.v3.oas.annotations.Parameter; |
| 19 | import io.swagger.v3.oas.annotations.tags.Tag; | 17 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -46,8 +44,6 @@ public class MesQcRqcLineController { | @@ -46,8 +44,6 @@ public class MesQcRqcLineController { | ||
| 46 | private MesQcIndicatorService indicatorService; | 44 | private MesQcIndicatorService indicatorService; |
| 47 | @Resource | 45 | @Resource |
| 48 | private MesMdUnitMeasureService unitMeasureService; | 46 | private MesMdUnitMeasureService unitMeasureService; |
| 49 | - @Resource | ||
| 50 | - private MesTmToolService toolService; | ||
| 51 | 47 | ||
| 52 | @GetMapping("/get") | 48 | @GetMapping("/get") |
| 53 | @Operation(summary = "获得退货检验单行") | 49 | @Operation(summary = "获得退货检验单行") |
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 { | @@ -20,8 +20,8 @@ public class MesQcRqcPageReqVO extends PageParam { | ||
| 20 | @Schema(description = "检验单编号", example = "RQC2025") | 20 | @Schema(description = "检验单编号", example = "RQC2025") |
| 21 | private String code; | 21 | private String code; |
| 22 | 22 | ||
| 23 | - @Schema(description = "来源单据类型", example = "RTISSUE") | ||
| 24 | - private String sourceDocType; | 23 | + @Schema(description = "来源单据类型", example = "1") |
| 24 | + private Integer sourceDocType; | ||
| 25 | 25 | ||
| 26 | @Schema(description = "产品物料 ID", example = "20") | 26 | @Schema(description = "产品物料 ID", example = "20") |
| 27 | private Long itemId; | 27 | private Long itemId; |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java
| @@ -17,7 +17,8 @@ public enum MesMdAutoCodeRuleCodeEnum { | @@ -17,7 +17,8 @@ public enum MesMdAutoCodeRuleCodeEnum { | ||
| 17 | BATCH_CODE("WM_BATCH_CODE", "批次编码"), | 17 | BATCH_CODE("WM_BATCH_CODE", "批次编码"), |
| 18 | TASK_CODE("PRO_TASK_CODE", "生产任务编码"), | 18 | TASK_CODE("PRO_TASK_CODE", "生产任务编码"), |
| 19 | QC_IQC_CODE("QC_IQC_CODE", "来料检验单编码"), | 19 | QC_IQC_CODE("QC_IQC_CODE", "来料检验单编码"), |
| 20 | - QC_IPQC_CODE("QC_IPQC_CODE", "过程检验单编码"); | 20 | + QC_IPQC_CODE("QC_IPQC_CODE", "过程检验单编码"), |
| 21 | + QC_RQC_CODE("QC_RQC_CODE", "退货检验单编码"); | ||
| 21 | 22 | ||
| 22 | /** | 23 | /** |
| 23 | * 规则代码 | 24 | * 规则代码 |
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 { | @@ -134,8 +134,8 @@ public class MesQcRqcServiceImpl implements MesQcRqcService { | ||
| 134 | * | 134 | * |
| 135 | * <p>根据 sourceDocType 分发: | 135 | * <p>根据 sourceDocType 分发: |
| 136 | * <ul> | 136 | * <ul> |
| 137 | - * <li>WM_RETURN_ISSUE(生产退料单)→ 回写行的 qualityStatus</li> | ||
| 138 | - * <li>WM_RETURN_SALES(销售退货单)→ 回写行的 qualityStatus</li> | 137 | + * <li>WM_RETURN_ISSUE(生产退料单)→ 根据合格/不合格数量拆分行 + 更新 qualityStatus + 联动主单状态</li> |
| 138 | + * <li>WM_RETURN_SALES(销售退货单)→ 同上</li> | ||
| 139 | * </ul> | 139 | * </ul> |
| 140 | * | 140 | * |
| 141 | * @param rqc 退货检验单 | 141 | * @param rqc 退货检验单 |
| @@ -150,11 +150,15 @@ public class MesQcRqcServiceImpl implements MesQcRqcService { | @@ -150,11 +150,15 @@ public class MesQcRqcServiceImpl implements MesQcRqcService { | ||
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_ISSUE)) { | 152 | if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_ISSUE)) { |
| 153 | - // 回写生产退料单行的 qualityStatus | ||
| 154 | - returnIssueLineService.updateReturnIssueLineWhenRqcFinish(rqc.getSourceLineId(), rqc.getCheckResult()); | 153 | + // 回写生产退料单行:拆分行 + 更新质量状态 + 联动主单状态 |
| 154 | + returnIssueLineService.updateReturnIssueLineWhenRqcFinish( | ||
| 155 | + rqc.getSourceLineId(), rqc.getSourceDocId(), rqc.getCheckResult(), | ||
| 156 | + rqc.getQualifiedQuantity(), rqc.getUnqualifiedQuantity()); | ||
| 155 | } else if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_SALES)) { | 157 | } else if (Objects.equals(rqc.getSourceDocType(), MesBizTypeConstants.WM_RETURN_SALES)) { |
| 156 | - // 回写销售退货单行的 qualityStatus | ||
| 157 | - returnSalesLineService.updateReturnSalesLineWhenRqcFinish(rqc.getSourceLineId(), rqc.getCheckResult()); | 158 | + // 回写销售退货单行:拆分行 + 更新质量状态 + 联动主单状态 |
| 159 | + returnSalesLineService.updateReturnSalesLineWhenRqcFinish( | ||
| 160 | + rqc.getSourceLineId(), rqc.getSourceDocId(), rqc.getCheckResult(), | ||
| 161 | + rqc.getQualifiedQuantity(), rqc.getUnqualifiedQuantity()); | ||
| 158 | } else { | 162 | } else { |
| 159 | throw new IllegalArgumentException( | 163 | throw new IllegalArgumentException( |
| 160 | "RQC 单[" + rqc.getId() + "] sourceDocType=" + rqc.getSourceDocType() + " 无法识别,无法回写来源单据"); | 164 | "RQC 单[" + rqc.getId() + "] sourceDocType=" + rqc.getSourceDocType() + " 无法识别,无法回写来源单据"); |
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 | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.line.MesWm | ||
| 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO; | 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO; |
| 7 | import jakarta.validation.Valid; | 7 | import jakarta.validation.Valid; |
| 8 | 8 | ||
| 9 | +import java.math.BigDecimal; | ||
| 9 | import java.util.List; | 10 | import java.util.List; |
| 10 | 11 | ||
| 11 | /** | 12 | /** |
| @@ -83,11 +84,23 @@ public interface MesWmReturnIssueLineService { | @@ -83,11 +84,23 @@ public interface MesWmReturnIssueLineService { | ||
| 83 | void updateReturnIssueQualityStatusByIssueId(Long issueId, Integer issueType); | 84 | void updateReturnIssueQualityStatusByIssueId(Long issueId, Integer issueType); |
| 84 | 85 | ||
| 85 | /** | 86 | /** |
| 86 | - * RQC 检验完成后,更新生产退料单行的质量状态 | 87 | + * RQC 检验完成后,根据合格品/不合格品数量更新生产退料单行 |
| 87 | * | 88 | * |
| 88 | - * @param id 行 ID | ||
| 89 | - * @param checkResult 检验结果 | 89 | + * <p>拆分逻辑: |
| 90 | + * <ul> | ||
| 91 | + * <li>全部合格:直接更新行的 qualityStatus 为合格</li> | ||
| 92 | + * <li>全部不合格:直接更新行的 qualityStatus 为不合格</li> | ||
| 93 | + * <li>部分合格部分不合格:拆分原行(原行改为合格+数量=合格数,新增一行不合格+数量=不合格数)</li> | ||
| 94 | + * </ul> | ||
| 95 | + * 同时检查退料单下所有行是否都已检验完毕,若全检完则将退料单状态设为待上架。 | ||
| 96 | + * | ||
| 97 | + * @param sourceLineId 来源行 ID | ||
| 98 | + * @param sourceDocId 来源退料单 ID | ||
| 99 | + * @param checkResult 检验结果 | ||
| 100 | + * @param qualifiedQuantity 合格品数量 | ||
| 101 | + * @param unqualifiedQuantity 不合格品数量 | ||
| 90 | */ | 102 | */ |
| 91 | - void updateReturnIssueLineWhenRqcFinish(Long id, Integer checkResult); | 103 | + void updateReturnIssueLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult, |
| 104 | + BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity); | ||
| 92 | 105 | ||
| 93 | } | 106 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueLineServiceImpl.java
| 1 | package cn.iocoder.yudao.module.mes.service.wm.returnissue; | 1 | package cn.iocoder.yudao.module.mes.service.wm.returnissue; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.hutool.core.util.ObjUtil; | 4 | import cn.hutool.core.util.ObjUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 6 | 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 | @@ -8,8 +9,8 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnissue.vo.line.MesWm | ||
| 8 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueDO; | 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueDO; |
| 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO; | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnissue.MesWmReturnIssueLineDO; |
| 10 | import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnissue.MesWmReturnIssueLineMapper; | 11 | import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnissue.MesWmReturnIssueLineMapper; |
| 11 | -import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum; | ||
| 12 | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; | 12 | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| 13 | +import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueStatusEnum; | ||
| 13 | import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueTypeEnum; | 14 | import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnIssueTypeEnum; |
| 14 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; | 15 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| 15 | import jakarta.annotation.Resource; | 16 | import jakarta.annotation.Resource; |
| @@ -17,6 +18,7 @@ import org.springframework.context.annotation.Lazy; | @@ -17,6 +18,7 @@ import org.springframework.context.annotation.Lazy; | ||
| 17 | import org.springframework.stereotype.Service; | 18 | import org.springframework.stereotype.Service; |
| 18 | import org.springframework.validation.annotation.Validated; | 19 | import org.springframework.validation.annotation.Validated; |
| 19 | 20 | ||
| 21 | +import java.math.BigDecimal; | ||
| 20 | import java.util.List; | 22 | import java.util.List; |
| 21 | import java.util.Objects; | 23 | import java.util.Objects; |
| 22 | 24 | ||
| @@ -137,10 +139,51 @@ public class MesWmReturnIssueLineServiceImpl implements MesWmReturnIssueLineServ | @@ -137,10 +139,51 @@ public class MesWmReturnIssueLineServiceImpl implements MesWmReturnIssueLineServ | ||
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | @Override | 141 | @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)); | 142 | + public void updateReturnIssueLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult, |
| 143 | + BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity) { | ||
| 144 | + MesWmReturnIssueLineDO sourceLine = validateReturnIssueLineExists(sourceLineId); | ||
| 145 | + boolean hasUnqualified = unqualifiedQuantity != null && unqualifiedQuantity.compareTo(BigDecimal.ZERO) > 0; | ||
| 146 | + boolean hasQualified = qualifiedQuantity != null && qualifiedQuantity.compareTo(BigDecimal.ZERO) > 0; | ||
| 147 | + | ||
| 148 | + // 1. 根据合格/不合格品数量,更新退料单行的质量状态 | ||
| 149 | + if (!hasUnqualified) { | ||
| 150 | + // 1.A 情况一:全部合格 | ||
| 151 | + issueLineMapper.updateById(new MesWmReturnIssueLineDO() | ||
| 152 | + .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus())); | ||
| 153 | + } else if (!hasQualified) { | ||
| 154 | + // 1.B 情况二:全部不合格 | ||
| 155 | + issueLineMapper.updateById(new MesWmReturnIssueLineDO() | ||
| 156 | + .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus())); | ||
| 157 | + } else { | ||
| 158 | + // 1.C 情况三:部分合格部分不合格 → 拆分行 | ||
| 159 | + // 1.C.1 新增一行不合格品 | ||
| 160 | + MesWmReturnIssueLineDO unqualifiedLine = new MesWmReturnIssueLineDO() | ||
| 161 | + .setIssueId(sourceLine.getIssueId()) | ||
| 162 | + .setMaterialStockId(sourceLine.getMaterialStockId()) | ||
| 163 | + .setItemId(sourceLine.getItemId()) | ||
| 164 | + .setQuantity(unqualifiedQuantity) | ||
| 165 | + .setBatchId(sourceLine.getBatchId()) | ||
| 166 | + .setIpqcId(sourceLine.getIpqcId()) | ||
| 167 | + .setQcFlag(sourceLine.getQcFlag()) | ||
| 168 | + .setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus()) | ||
| 169 | + .setRemark(sourceLine.getRemark()); | ||
| 170 | + issueLineMapper.insert(unqualifiedLine); | ||
| 171 | + // 1.C.2 更新原行为合格品(数量调整为合格数量) | ||
| 172 | + issueLineMapper.updateById(new MesWmReturnIssueLineDO() | ||
| 173 | + .setId(sourceLineId) | ||
| 174 | + .setQuantity(qualifiedQuantity) | ||
| 175 | + .setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus())); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + // 2. 检查退料单下是否还有待检验的行,若全检完则将退料单状态设为"待上架" | ||
| 179 | + if (sourceDocId != null) { | ||
| 180 | + List<MesWmReturnIssueLineDO> allLines = issueLineMapper.selectListByIssueId(sourceDocId); | ||
| 181 | + boolean allInspected = !CollUtil.contains(allLines, | ||
| 182 | + line -> Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())); | ||
| 183 | + if (allInspected) { | ||
| 184 | + issueService.updateReturnIssueStatus(sourceDocId, MesWmReturnIssueStatusEnum.APPROVING.getStatus()); | ||
| 185 | + } | ||
| 186 | + } | ||
| 144 | } | 187 | } |
| 145 | 188 | ||
| 146 | } | 189 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnissue/MesWmReturnIssueService.java
| @@ -85,4 +85,12 @@ public interface MesWmReturnIssueService { | @@ -85,4 +85,12 @@ public interface MesWmReturnIssueService { | ||
| 85 | */ | 85 | */ |
| 86 | void cancelReturnIssue(Long id); | 86 | void cancelReturnIssue(Long id); |
| 87 | 87 | ||
| 88 | + /** | ||
| 89 | + * 更新生产退料单状态(供外部模块联动调用,如 RQC 检验完成后) | ||
| 90 | + * | ||
| 91 | + * @param id 编号 | ||
| 92 | + * @param status 目标状态 | ||
| 93 | + */ | ||
| 94 | + void updateReturnIssueStatus(Long id, Integer status); | ||
| 95 | + | ||
| 88 | } | 96 | } |
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 { | @@ -271,4 +271,10 @@ public class MesWmReturnIssueServiceImpl implements MesWmReturnIssueService { | ||
| 271 | return issue; | 271 | return issue; |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | + @Override | ||
| 275 | + public void updateReturnIssueStatus(Long id, Integer status) { | ||
| 276 | + validateReturnIssueExists(id); | ||
| 277 | + issueMapper.updateById(new MesWmReturnIssueDO().setId(id).setStatus(status)); | ||
| 278 | + } | ||
| 279 | + | ||
| 274 | } | 280 | } |
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 | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWm | ||
| 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO; | 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO; |
| 7 | import jakarta.validation.Valid; | 7 | import jakarta.validation.Valid; |
| 8 | 8 | ||
| 9 | +import java.math.BigDecimal; | ||
| 9 | import java.util.List; | 10 | import java.util.List; |
| 10 | 11 | ||
| 11 | /** | 12 | /** |
| @@ -85,11 +86,23 @@ public interface MesWmReturnSalesLineService { | @@ -85,11 +86,23 @@ public interface MesWmReturnSalesLineService { | ||
| 85 | void updateQualityStatusByReturnId(Long returnId, Integer qualityStatus); | 86 | void updateQualityStatusByReturnId(Long returnId, Integer qualityStatus); |
| 86 | 87 | ||
| 87 | /** | 88 | /** |
| 88 | - * RQC 检验完成后,更新销售退货单行的质量状态 | 89 | + * RQC 检验完成后,根据合格品/不合格品数量更新销售退货单行 |
| 89 | * | 90 | * |
| 90 | - * @param id 行 ID | ||
| 91 | - * @param checkResult 检验结果 | 91 | + * <p>拆分逻辑: |
| 92 | + * <ul> | ||
| 93 | + * <li>全部合格:直接更新行的 qualityStatus 为合格</li> | ||
| 94 | + * <li>全部不合格:直接更新行的 qualityStatus 为不合格</li> | ||
| 95 | + * <li>部分合格部分不合格:拆分原行(原行改为合格+数量=合格数,新增一行不合格+数量=不合格数)</li> | ||
| 96 | + * </ul> | ||
| 97 | + * 同时检查退货单下所有行是否都已检验完毕,若全检完则将退货单状态设为待上架。 | ||
| 98 | + * | ||
| 99 | + * @param sourceLineId 来源行 ID | ||
| 100 | + * @param sourceDocId 来源退货单 ID | ||
| 101 | + * @param checkResult 检验结果 | ||
| 102 | + * @param qualifiedQuantity 合格品数量 | ||
| 103 | + * @param unqualifiedQuantity 不合格品数量 | ||
| 92 | */ | 104 | */ |
| 93 | - void updateReturnSalesLineWhenRqcFinish(Long id, Integer checkResult); | 105 | + void updateReturnSalesLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult, |
| 106 | + BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity); | ||
| 94 | 107 | ||
| 95 | } | 108 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesLineServiceImpl.java
| 1 | package cn.iocoder.yudao.module.mes.service.wm.returnsales; | 1 | package cn.iocoder.yudao.module.mes.service.wm.returnsales; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWmReturnSalesLinePageReqVO; | 6 | 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 | @@ -7,14 +8,15 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWm | ||
| 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; | 8 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 8 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO; | 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO; |
| 9 | import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnsales.MesWmReturnSalesLineMapper; | 10 | 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; | 11 | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| 12 | +import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnSalesStatusEnum; | ||
| 12 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; | 13 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| 13 | import jakarta.annotation.Resource; | 14 | import jakarta.annotation.Resource; |
| 14 | import org.springframework.context.annotation.Lazy; | 15 | import org.springframework.context.annotation.Lazy; |
| 15 | import org.springframework.stereotype.Service; | 16 | import org.springframework.stereotype.Service; |
| 16 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 17 | 18 | ||
| 19 | +import java.math.BigDecimal; | ||
| 18 | import java.util.List; | 20 | import java.util.List; |
| 19 | import java.util.Objects; | 21 | import java.util.Objects; |
| 20 | 22 | ||
| @@ -129,11 +131,48 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ | @@ -129,11 +131,48 @@ public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineServ | ||
| 129 | } | 131 | } |
| 130 | 132 | ||
| 131 | @Override | 133 | @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)); | 134 | + public void updateReturnSalesLineWhenRqcFinish(Long sourceLineId, Long sourceDocId, Integer checkResult, |
| 135 | + BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity) { | ||
| 136 | + MesWmReturnSalesLineDO sourceLine = validateReturnSalesLineExists(sourceLineId); | ||
| 137 | + boolean hasUnqualified = unqualifiedQuantity != null && unqualifiedQuantity.compareTo(BigDecimal.ZERO) > 0; | ||
| 138 | + boolean hasQualified = qualifiedQuantity != null && qualifiedQuantity.compareTo(BigDecimal.ZERO) > 0; | ||
| 139 | + | ||
| 140 | + // 1. 根据合格/不合格品数量,更新退货单行的质量状态 | ||
| 141 | + if (!hasUnqualified) { | ||
| 142 | + // 1.A 情况一:全部合格 | ||
| 143 | + returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO() | ||
| 144 | + .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus())); | ||
| 145 | + } else if (!hasQualified) { | ||
| 146 | + // 1.B 情况二:全部不合格 | ||
| 147 | + returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO() | ||
| 148 | + .setId(sourceLineId).setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus())); | ||
| 149 | + } else { | ||
| 150 | + // 1.C 情况三:部分合格部分不合格 → 拆分行 | ||
| 151 | + // 1.C.1 新增一行不合格品 | ||
| 152 | + MesWmReturnSalesLineDO unqualifiedLine = new MesWmReturnSalesLineDO() | ||
| 153 | + .setReturnId(sourceLine.getReturnId()) | ||
| 154 | + .setItemId(sourceLine.getItemId()) | ||
| 155 | + .setQuantity(unqualifiedQuantity) | ||
| 156 | + .setBatchId(sourceLine.getBatchId()) | ||
| 157 | + .setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus()) | ||
| 158 | + .setRemark(sourceLine.getRemark()); | ||
| 159 | + returnSalesLineMapper.insert(unqualifiedLine); | ||
| 160 | + // 1.C.2 更新原行为合格品 | ||
| 161 | + returnSalesLineMapper.updateById(new MesWmReturnSalesLineDO() | ||
| 162 | + .setId(sourceLineId) | ||
| 163 | + .setQuantity(qualifiedQuantity) | ||
| 164 | + .setQualityStatus(MesWmQualityStatusEnum.PASS.getStatus())); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + // 2. 检查退货单下是否还有待检验的行,若全检完则将退货单状态设为"待上架" | ||
| 168 | + if (sourceDocId != null) { | ||
| 169 | + List<MesWmReturnSalesLineDO> allLines = returnSalesLineMapper.selectListByReturnId(sourceDocId); | ||
| 170 | + boolean allInspected = !CollUtil.contains(allLines, | ||
| 171 | + line -> Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus())); | ||
| 172 | + if (allInspected) { | ||
| 173 | + returnSalesService.updateReturnSalesStatus(sourceDocId, MesWmReturnSalesStatusEnum.APPROVED.getStatus()); | ||
| 174 | + } | ||
| 175 | + } | ||
| 137 | } | 176 | } |
| 138 | 177 | ||
| 139 | } | 178 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnsales/MesWmReturnSalesService.java
| @@ -88,6 +88,14 @@ public interface MesWmReturnSalesService { | @@ -88,6 +88,14 @@ public interface MesWmReturnSalesService { | ||
| 88 | void cancelReturnSales(Long id); | 88 | void cancelReturnSales(Long id); |
| 89 | 89 | ||
| 90 | /** | 90 | /** |
| 91 | + * 更新销售退货单状态(供外部模块联动调用,如 RQC 检验完成后) | ||
| 92 | + * | ||
| 93 | + * @param id 编号 | ||
| 94 | + * @param status 目标状态 | ||
| 95 | + */ | ||
| 96 | + void updateReturnSalesStatus(Long id, Integer status); | ||
| 97 | + | ||
| 98 | + /** | ||
| 91 | * 校验销售退货单的数量:每行明细数量之和是否等于行退货数量 | 99 | * 校验销售退货单的数量:每行明细数量之和是否等于行退货数量 |
| 92 | * | 100 | * |
| 93 | * @param id 编号 | 101 | * @param id 编号 |
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 { | @@ -239,4 +239,10 @@ public class MesWmReturnSalesServiceImpl implements MesWmReturnSalesService { | ||
| 239 | return returnSales; | 239 | return returnSales; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | + @Override | ||
| 243 | + public void updateReturnSalesStatus(Long id, Integer status) { | ||
| 244 | + validateReturnSalesExists(id); | ||
| 245 | + returnSalesMapper.updateById(new MesWmReturnSalesDO().setId(id).setStatus(status)); | ||
| 246 | + } | ||
| 247 | + | ||
| 242 | } | 248 | } |
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; | @@ -16,15 +16,15 @@ import org.junit.jupiter.api.Test; | ||
| 16 | import org.springframework.context.annotation.Import; | 16 | import org.springframework.context.annotation.Import; |
| 17 | import org.springframework.test.context.bean.override.mockito.MockitoBean; | 17 | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| 18 | 18 | ||
| 19 | +import java.math.BigDecimal; | ||
| 20 | + | ||
| 19 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | 21 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; |
| 20 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | 22 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; |
| 21 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 23 | 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; | 24 | 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; | 25 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.QC_RQC_NOT_PREPARE; |
| 24 | import static org.junit.jupiter.api.Assertions.assertEquals; | 26 | 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; | 27 | +import static org.mockito.ArgumentMatchers.*; |
| 28 | import static org.mockito.Mockito.never; | 28 | import static org.mockito.Mockito.never; |
| 29 | import static org.mockito.Mockito.verify; | 29 | import static org.mockito.Mockito.verify; |
| 30 | 30 | ||
| @@ -61,18 +61,22 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest { | @@ -61,18 +61,22 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest { | ||
| 61 | public void testFinishRqc_successWithReturnIssue() { | 61 | public void testFinishRqc_successWithReturnIssue() { |
| 62 | // 准备参数 | 62 | // 准备参数 |
| 63 | Long sourceLineId = randomLongId(); | 63 | Long sourceLineId = randomLongId(); |
| 64 | + Long sourceDocId = randomLongId(); | ||
| 64 | Integer checkResult = 1; | 65 | Integer checkResult = 1; |
| 66 | + BigDecimal qualifiedQty = new BigDecimal("80"); | ||
| 67 | + BigDecimal unqualifiedQty = new BigDecimal("20"); | ||
| 65 | 68 | ||
| 66 | // mock 数据 | 69 | // mock 数据 |
| 67 | MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> { | 70 | MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> { |
| 68 | o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); | 71 | o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| 69 | o.setSourceDocType(MesBizTypeConstants.WM_RETURN_ISSUE); | 72 | o.setSourceDocType(MesBizTypeConstants.WM_RETURN_ISSUE); |
| 73 | + o.setSourceDocId(sourceDocId); | ||
| 70 | o.setSourceLineId(sourceLineId); | 74 | o.setSourceLineId(sourceLineId); |
| 71 | o.setCheckResult(checkResult); | 75 | o.setCheckResult(checkResult); |
| 72 | // 设置数量通过 finishRqc 的数量校验:合格 + 不合格 = 检测数量 | 76 | // 设置数量通过 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")); | 77 | + o.setCheckQuantity(new BigDecimal("100")); |
| 78 | + o.setQualifiedQuantity(qualifiedQty); | ||
| 79 | + o.setUnqualifiedQuantity(unqualifiedQty); | ||
| 76 | }); | 80 | }); |
| 77 | rqcMapper.insert(rqc); | 81 | rqcMapper.insert(rqc); |
| 78 | 82 | ||
| @@ -83,28 +87,36 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest { | @@ -83,28 +87,36 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest { | ||
| 83 | MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId()); | 87 | MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId()); |
| 84 | assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus()); | 88 | assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus()); |
| 85 | 89 | ||
| 86 | - // 断言:验证回写调用生产退料 | ||
| 87 | - verify(returnIssueLineService).updateReturnIssueLineWhenRqcFinish(eq(sourceLineId), eq(checkResult)); | 90 | + // 断言:验证回写调用生产退料(含拆分参数) |
| 91 | + verify(returnIssueLineService).updateReturnIssueLineWhenRqcFinish( | ||
| 92 | + eq(sourceLineId), eq(sourceDocId), eq(checkResult), | ||
| 93 | + argThat(v -> v.compareTo(qualifiedQty) == 0), | ||
| 94 | + argThat(v -> v.compareTo(unqualifiedQty) == 0)); | ||
| 88 | // 断言:未调用销售退货 | 95 | // 断言:未调用销售退货 |
| 89 | - verify(returnSalesLineService, never()).updateReturnSalesLineWhenRqcFinish(anyLong(), anyInt()); | 96 | + verify(returnSalesLineService, never()).updateReturnSalesLineWhenRqcFinish( |
| 97 | + anyLong(), anyLong(), anyInt(), any(BigDecimal.class), any(BigDecimal.class)); | ||
| 90 | } | 98 | } |
| 91 | 99 | ||
| 92 | @Test | 100 | @Test |
| 93 | public void testFinishRqc_successWithReturnSales() { | 101 | public void testFinishRqc_successWithReturnSales() { |
| 94 | // 准备参数 | 102 | // 准备参数 |
| 95 | Long sourceLineId = randomLongId(); | 103 | Long sourceLineId = randomLongId(); |
| 104 | + Long sourceDocId = randomLongId(); | ||
| 96 | Integer checkResult = 1; | 105 | Integer checkResult = 1; |
| 106 | + BigDecimal qualifiedQty = new BigDecimal("90"); | ||
| 107 | + BigDecimal unqualifiedQty = new BigDecimal("10"); | ||
| 97 | 108 | ||
| 98 | // mock 数据 | 109 | // mock 数据 |
| 99 | MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> { | 110 | MesQcRqcDO rqc = randomPojo(MesQcRqcDO.class, o -> { |
| 100 | o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); | 111 | o.setStatus(MesQcStatusEnum.DRAFT.getStatus()); |
| 101 | o.setSourceDocType(MesBizTypeConstants.WM_RETURN_SALES); | 112 | o.setSourceDocType(MesBizTypeConstants.WM_RETURN_SALES); |
| 113 | + o.setSourceDocId(sourceDocId); | ||
| 102 | o.setSourceLineId(sourceLineId); | 114 | o.setSourceLineId(sourceLineId); |
| 103 | o.setCheckResult(checkResult); | 115 | o.setCheckResult(checkResult); |
| 104 | // 设置数量通过 finishRqc 的数量校验:合格 + 不合格 = 检测数量 | 116 | // 设置数量通过 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")); | 117 | + o.setCheckQuantity(new BigDecimal("100")); |
| 118 | + o.setQualifiedQuantity(qualifiedQty); | ||
| 119 | + o.setUnqualifiedQuantity(unqualifiedQty); | ||
| 108 | }); | 120 | }); |
| 109 | rqcMapper.insert(rqc); | 121 | rqcMapper.insert(rqc); |
| 110 | 122 | ||
| @@ -115,10 +127,14 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest { | @@ -115,10 +127,14 @@ public class MesQcRqcServiceImplTest extends BaseDbUnitTest { | ||
| 115 | MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId()); | 127 | MesQcRqcDO updatedRqc = rqcMapper.selectById(rqc.getId()); |
| 116 | assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus()); | 128 | assertEquals(MesQcStatusEnum.FINISHED.getStatus(), updatedRqc.getStatus()); |
| 117 | 129 | ||
| 118 | - // 断言:验证回写调用销售退货 | ||
| 119 | - verify(returnSalesLineService).updateReturnSalesLineWhenRqcFinish(eq(sourceLineId), eq(checkResult)); | 130 | + // 断言:验证回写调用销售退货(含拆分参数) |
| 131 | + verify(returnSalesLineService).updateReturnSalesLineWhenRqcFinish( | ||
| 132 | + eq(sourceLineId), eq(sourceDocId), eq(checkResult), | ||
| 133 | + argThat(v -> v.compareTo(qualifiedQty) == 0), | ||
| 134 | + argThat(v -> v.compareTo(unqualifiedQty) == 0)); | ||
| 120 | // 断言:未调用生产退料 | 135 | // 断言:未调用生产退料 |
| 121 | - verify(returnIssueLineService, never()).updateReturnIssueLineWhenRqcFinish(anyLong(), anyInt()); | 136 | + verify(returnIssueLineService, never()).updateReturnIssueLineWhenRqcFinish( |
| 137 | + anyLong(), anyLong(), anyInt(), any(BigDecimal.class), any(BigDecimal.class)); | ||
| 122 | } | 138 | } |
| 123 | 139 | ||
| 124 | @Test | 140 | @Test |
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; | @@ -12,8 +12,11 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean; | ||
| 12 | 12 | ||
| 13 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; | 13 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| 14 | 14 | ||
| 15 | +import java.math.BigDecimal; | ||
| 16 | + | ||
| 15 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 17 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 16 | import static org.junit.jupiter.api.Assertions.assertEquals; | 18 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 19 | +import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| 17 | 20 | ||
| 18 | /** | 21 | /** |
| 19 | * {@link MesWmReturnIssueLineServiceImpl} 的单元测试类 | 22 | * {@link MesWmReturnIssueLineServiceImpl} 的单元测试类 |
| @@ -36,37 +39,75 @@ public class MesWmReturnIssueLineServiceImplTest extends BaseDbUnitTest { | @@ -36,37 +39,75 @@ public class MesWmReturnIssueLineServiceImplTest extends BaseDbUnitTest { | ||
| 36 | private MesMdItemService itemService; | 39 | private MesMdItemService itemService; |
| 37 | 40 | ||
| 38 | @Test | 41 | @Test |
| 39 | - public void testUpdateReturnIssueLineWhenRqcFinish_pass() { | ||
| 40 | - // 准备参数 | 42 | + public void testUpdateReturnIssueLineWhenRqcFinish_allPass() { |
| 43 | + // 准备参数:全部合格 | ||
| 41 | Integer checkResult = MesQcCheckResultEnum.PASS.getType(); | 44 | Integer checkResult = MesQcCheckResultEnum.PASS.getType(); |
| 45 | + BigDecimal qualifiedQty = new BigDecimal("100"); | ||
| 46 | + BigDecimal unqualifiedQty = BigDecimal.ZERO; | ||
| 42 | 47 | ||
| 43 | // mock 数据 | 48 | // mock 数据 |
| 44 | - MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class); | 49 | + MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class, o -> o.setQuantity(qualifiedQty)); |
| 45 | returnIssueLineMapper.insert(lineDO); | 50 | returnIssueLineMapper.insert(lineDO); |
| 46 | 51 | ||
| 47 | - // 调用 | ||
| 48 | - returnIssueLineService.updateReturnIssueLineWhenRqcFinish(lineDO.getId(), checkResult); | 52 | + // 调用(sourceDocId 传 null 不联动主表状态) |
| 53 | + returnIssueLineService.updateReturnIssueLineWhenRqcFinish( | ||
| 54 | + lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty); | ||
| 49 | 55 | ||
| 50 | - // 断言:验证 mapper 更新参数正确 | 56 | + // 断言:验证质量状态更新为合格 |
| 51 | MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId()); | 57 | MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId()); |
| 52 | assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus()); | 58 | assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus()); |
| 53 | } | 59 | } |
| 54 | 60 | ||
| 55 | @Test | 61 | @Test |
| 56 | - public void testUpdateReturnIssueLineWhenRqcFinish_fail() { | ||
| 57 | - // 准备参数 | 62 | + public void testUpdateReturnIssueLineWhenRqcFinish_allFail() { |
| 63 | + // 准备参数:全部不合格 | ||
| 58 | Integer checkResult = MesQcCheckResultEnum.FAIL.getType(); | 64 | Integer checkResult = MesQcCheckResultEnum.FAIL.getType(); |
| 65 | + BigDecimal qualifiedQty = BigDecimal.ZERO; | ||
| 66 | + BigDecimal unqualifiedQty = new BigDecimal("100"); | ||
| 59 | 67 | ||
| 60 | // mock 数据 | 68 | // mock 数据 |
| 61 | - MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class); | 69 | + MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class, o -> o.setQuantity(unqualifiedQty)); |
| 62 | returnIssueLineMapper.insert(lineDO); | 70 | returnIssueLineMapper.insert(lineDO); |
| 63 | 71 | ||
| 64 | // 调用 | 72 | // 调用 |
| 65 | - returnIssueLineService.updateReturnIssueLineWhenRqcFinish(lineDO.getId(), checkResult); | 73 | + returnIssueLineService.updateReturnIssueLineWhenRqcFinish( |
| 74 | + lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty); | ||
| 66 | 75 | ||
| 67 | - // 断言:验证 mapper 更新参数正确 | 76 | + // 断言:验证质量状态更新为不合格 |
| 68 | MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId()); | 77 | MesWmReturnIssueLineDO updateLine = returnIssueLineMapper.selectById(lineDO.getId()); |
| 69 | assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus()); | 78 | assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus()); |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 81 | + @Test | ||
| 82 | + public void testUpdateReturnIssueLineWhenRqcFinish_partialSplit() { | ||
| 83 | + // 准备参数:部分合格部分不合格,触发行拆分 | ||
| 84 | + Integer checkResult = MesQcCheckResultEnum.PASS.getType(); | ||
| 85 | + BigDecimal qualifiedQty = new BigDecimal("80"); | ||
| 86 | + BigDecimal unqualifiedQty = new BigDecimal("20"); | ||
| 87 | + | ||
| 88 | + // mock 数据 | ||
| 89 | + MesWmReturnIssueLineDO lineDO = randomPojo(MesWmReturnIssueLineDO.class, o -> | ||
| 90 | + o.setQuantity(new BigDecimal("100"))); | ||
| 91 | + returnIssueLineMapper.insert(lineDO); | ||
| 92 | + | ||
| 93 | + // 调用 | ||
| 94 | + returnIssueLineService.updateReturnIssueLineWhenRqcFinish( | ||
| 95 | + lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty); | ||
| 96 | + | ||
| 97 | + // 断言:原行变为合格,数量调整为合格数量 | ||
| 98 | + MesWmReturnIssueLineDO originalLine = returnIssueLineMapper.selectById(lineDO.getId()); | ||
| 99 | + assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), originalLine.getQualityStatus()); | ||
| 100 | + assertEquals(0, qualifiedQty.compareTo(originalLine.getQuantity())); | ||
| 101 | + | ||
| 102 | + // 断言:新增了一行不合格品 | ||
| 103 | + var allLines = returnIssueLineMapper.selectListByIssueId(lineDO.getIssueId()); | ||
| 104 | + assertEquals(2, allLines.size()); | ||
| 105 | + MesWmReturnIssueLineDO newLine = allLines.stream() | ||
| 106 | + .filter(l -> !l.getId().equals(lineDO.getId())) | ||
| 107 | + .findFirst().orElse(null); | ||
| 108 | + assertNotNull(newLine); | ||
| 109 | + assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), newLine.getQualityStatus()); | ||
| 110 | + assertEquals(0, unqualifiedQty.compareTo(newLine.getQuantity())); | ||
| 111 | + } | ||
| 112 | + | ||
| 72 | } | 113 | } |
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; | @@ -12,8 +12,11 @@ import org.springframework.test.context.bean.override.mockito.MockitoBean; | ||
| 12 | 12 | ||
| 13 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; | 13 | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| 14 | 14 | ||
| 15 | +import java.math.BigDecimal; | ||
| 16 | + | ||
| 15 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 17 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 16 | import static org.junit.jupiter.api.Assertions.assertEquals; | 18 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 19 | +import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| 17 | 20 | ||
| 18 | /** | 21 | /** |
| 19 | * {@link MesWmReturnSalesLineServiceImpl} 的单元测试类 | 22 | * {@link MesWmReturnSalesLineServiceImpl} 的单元测试类 |
| @@ -36,37 +39,75 @@ public class MesWmReturnSalesLineServiceImplTest extends BaseDbUnitTest { | @@ -36,37 +39,75 @@ public class MesWmReturnSalesLineServiceImplTest extends BaseDbUnitTest { | ||
| 36 | private MesMdItemService itemService; | 39 | private MesMdItemService itemService; |
| 37 | 40 | ||
| 38 | @Test | 41 | @Test |
| 39 | - public void testUpdateReturnSalesLineWhenRqcFinish_pass() { | ||
| 40 | - // 准备参数 | 42 | + public void testUpdateReturnSalesLineWhenRqcFinish_allPass() { |
| 43 | + // 准备参数:全部合格 | ||
| 41 | Integer checkResult = MesQcCheckResultEnum.PASS.getType(); | 44 | Integer checkResult = MesQcCheckResultEnum.PASS.getType(); |
| 45 | + BigDecimal qualifiedQty = new BigDecimal("100"); | ||
| 46 | + BigDecimal unqualifiedQty = BigDecimal.ZERO; | ||
| 42 | 47 | ||
| 43 | // mock 数据 | 48 | // mock 数据 |
| 44 | - MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class); | 49 | + MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class, o -> o.setQuantity(qualifiedQty)); |
| 45 | returnSalesLineMapper.insert(lineDO); | 50 | returnSalesLineMapper.insert(lineDO); |
| 46 | 51 | ||
| 47 | - // 调用 | ||
| 48 | - returnSalesLineService.updateReturnSalesLineWhenRqcFinish(lineDO.getId(), checkResult); | 52 | + // 调用(sourceDocId 传 null 不联动主表状态) |
| 53 | + returnSalesLineService.updateReturnSalesLineWhenRqcFinish( | ||
| 54 | + lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty); | ||
| 49 | 55 | ||
| 50 | - // 断言:验证 mapper 更新参数正确 | 56 | + // 断言:验证质量状态更新为合格 |
| 51 | MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId()); | 57 | MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId()); |
| 52 | assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus()); | 58 | assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), updateLine.getQualityStatus()); |
| 53 | } | 59 | } |
| 54 | 60 | ||
| 55 | @Test | 61 | @Test |
| 56 | - public void testUpdateReturnSalesLineWhenRqcFinish_fail() { | ||
| 57 | - // 准备参数 | 62 | + public void testUpdateReturnSalesLineWhenRqcFinish_allFail() { |
| 63 | + // 准备参数:全部不合格 | ||
| 58 | Integer checkResult = MesQcCheckResultEnum.FAIL.getType(); | 64 | Integer checkResult = MesQcCheckResultEnum.FAIL.getType(); |
| 65 | + BigDecimal qualifiedQty = BigDecimal.ZERO; | ||
| 66 | + BigDecimal unqualifiedQty = new BigDecimal("100"); | ||
| 59 | 67 | ||
| 60 | // mock 数据 | 68 | // mock 数据 |
| 61 | - MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class); | 69 | + MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class, o -> o.setQuantity(unqualifiedQty)); |
| 62 | returnSalesLineMapper.insert(lineDO); | 70 | returnSalesLineMapper.insert(lineDO); |
| 63 | 71 | ||
| 64 | // 调用 | 72 | // 调用 |
| 65 | - returnSalesLineService.updateReturnSalesLineWhenRqcFinish(lineDO.getId(), checkResult); | 73 | + returnSalesLineService.updateReturnSalesLineWhenRqcFinish( |
| 74 | + lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty); | ||
| 66 | 75 | ||
| 67 | - // 断言:验证 mapper 更新参数正确 | 76 | + // 断言:验证质量状态更新为不合格 |
| 68 | MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId()); | 77 | MesWmReturnSalesLineDO updateLine = returnSalesLineMapper.selectById(lineDO.getId()); |
| 69 | assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus()); | 78 | assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), updateLine.getQualityStatus()); |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 81 | + @Test | ||
| 82 | + public void testUpdateReturnSalesLineWhenRqcFinish_partialSplit() { | ||
| 83 | + // 准备参数:部分合格部分不合格,触发行拆分 | ||
| 84 | + Integer checkResult = MesQcCheckResultEnum.PASS.getType(); | ||
| 85 | + BigDecimal qualifiedQty = new BigDecimal("70"); | ||
| 86 | + BigDecimal unqualifiedQty = new BigDecimal("30"); | ||
| 87 | + | ||
| 88 | + // mock 数据 | ||
| 89 | + MesWmReturnSalesLineDO lineDO = randomPojo(MesWmReturnSalesLineDO.class, o -> | ||
| 90 | + o.setQuantity(new BigDecimal("100"))); | ||
| 91 | + returnSalesLineMapper.insert(lineDO); | ||
| 92 | + | ||
| 93 | + // 调用 | ||
| 94 | + returnSalesLineService.updateReturnSalesLineWhenRqcFinish( | ||
| 95 | + lineDO.getId(), null, checkResult, qualifiedQty, unqualifiedQty); | ||
| 96 | + | ||
| 97 | + // 断言:原行变为合格,数量调整为合格数量 | ||
| 98 | + MesWmReturnSalesLineDO originalLine = returnSalesLineMapper.selectById(lineDO.getId()); | ||
| 99 | + assertEquals(MesWmQualityStatusEnum.PASS.getStatus(), originalLine.getQualityStatus()); | ||
| 100 | + assertEquals(0, qualifiedQty.compareTo(originalLine.getQuantity())); | ||
| 101 | + | ||
| 102 | + // 断言:新增了一行不合格品 | ||
| 103 | + var allLines = returnSalesLineMapper.selectListByReturnId(lineDO.getReturnId()); | ||
| 104 | + assertEquals(2, allLines.size()); | ||
| 105 | + MesWmReturnSalesLineDO newLine = allLines.stream() | ||
| 106 | + .filter(l -> !l.getId().equals(lineDO.getId())) | ||
| 107 | + .findFirst().orElse(null); | ||
| 108 | + assertNotNull(newLine); | ||
| 109 | + assertEquals(MesWmQualityStatusEnum.FAIL.getStatus(), newLine.getQualityStatus()); | ||
| 110 | + assertEquals(0, unqualifiedQty.compareTo(newLine.getQuantity())); | ||
| 111 | + } | ||
| 112 | + | ||
| 72 | } | 113 | } |