Commit 9c94c1f58940f0e3aeb90aa4c449ff88dc584e20
1 parent
0d27932d
feat(mes): 修复 IQC 模块 TODO @AI(第二轮)
1. MesQcIqcSaveReqVO: 新增 @AssertTrue 校验 qualifiedQuantity + unqualifiedQuantity == receivedQuantity 2. MesQcIqcLineDO/ServiceImpl/RespVO/Controller: toolId(Long) 改为 tool(String),从 MesQcIndicatorDO 冗余读取,移除 MesTmToolService 依赖 3. MesWmArrivalNoticeService/Impl: 新增 validateArrivalNoticeAndLineExists 方法,校验通知单+行存在且匹配 4. MesQcIqcServiceImpl: 抽取 validateSourceDoc 私有方法校验来源单据;completeIqc 增加 checkResult 必填校验并移除重复数量校验;writeBackSourceDoc 使用 ObjectUtil.hasNull 简化判断 5. ErrorCodeConstants: 新增 QC_IQC_SOURCE_DOC_PARAMS_MISSING、QC_IQC_CHECK_RESULT_EMPTY
Showing
11 changed files
with
129 additions
and
66 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/MesQcIqcLineController.java
| @@ -9,11 +9,9 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLineR | @@ -9,11 +9,9 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLineR | ||
| 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.iqc.MesQcIqcLineDO; | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO; |
| 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.iqc.MesQcIqcLineService; | 13 | import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcLineService; |
| 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 MesQcIqcLineController { | @@ -46,8 +44,6 @@ public class MesQcIqcLineController { | ||
| 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 = "获得来料检验单行") |
| @@ -85,13 +81,6 @@ public class MesQcIqcLineController { | @@ -85,13 +81,6 @@ public class MesQcIqcLineController { | ||
| 85 | .setIndicatorType(indicator.getType())); | 81 | .setIndicatorType(indicator.getType())); |
| 86 | findAndThen(unitMeasureMap, vo.getUnitMeasureId(), | 82 | findAndThen(unitMeasureMap, vo.getUnitMeasureId(), |
| 87 | unit -> vo.setUnitMeasureName(unit.getName())); | 83 | unit -> vo.setUnitMeasureName(unit.getName())); |
| 88 | - // 逐个查询工具名称(工具数量通常较少) | ||
| 89 | - if (vo.getToolId() != null) { | ||
| 90 | - MesTmToolDO tool = toolService.getTool(vo.getToolId()); | ||
| 91 | - if (tool != null) { | ||
| 92 | - vo.setToolName(tool.getName()); | ||
| 93 | - } | ||
| 94 | - } | ||
| 95 | }); | 84 | }); |
| 96 | } | 85 | } |
| 97 | 86 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcSaveReqVO.java
| 1 | package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo; | 1 | package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.ObjUtil; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | +import jakarta.validation.constraints.AssertTrue; | ||
| 4 | import jakarta.validation.constraints.DecimalMin; | 6 | import jakarta.validation.constraints.DecimalMin; |
| 5 | import jakarta.validation.constraints.NotEmpty; | 7 | import jakarta.validation.constraints.NotEmpty; |
| 6 | import jakarta.validation.constraints.NotNull; | 8 | import jakarta.validation.constraints.NotNull; |
| @@ -82,4 +84,13 @@ public class MesQcIqcSaveReqVO { | @@ -82,4 +84,13 @@ public class MesQcIqcSaveReqVO { | ||
| 82 | @Schema(description = "备注", example = "备注") | 84 | @Schema(description = "备注", example = "备注") |
| 83 | private String remark; | 85 | private String remark; |
| 84 | 86 | ||
| 87 | + @AssertTrue(message = "合格品数量与不合格品数量之和必须等于本次接收数量") | ||
| 88 | + @Schema(hidden = true) | ||
| 89 | + public boolean isQuantityValid() { | ||
| 90 | + if (ObjUtil.hasNull(qualifiedQuantity, unqualifiedQuantity, receivedQuantity)) { | ||
| 91 | + return true; // @NotNull 会处理 null | ||
| 92 | + } | ||
| 93 | + return qualifiedQuantity.add(unqualifiedQuantity).compareTo(receivedQuantity) == 0; | ||
| 94 | + } | ||
| 95 | + | ||
| 85 | } | 96 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/line/MesQcIqcLineRespVO.java
| @@ -30,11 +30,8 @@ public class MesQcIqcLineRespVO { | @@ -30,11 +30,8 @@ public class MesQcIqcLineRespVO { | ||
| 30 | @Schema(description = "检测指标类型", example = "QUANTITATIVE") | 30 | @Schema(description = "检测指标类型", example = "QUANTITATIVE") |
| 31 | private String indicatorType; | 31 | private String indicatorType; |
| 32 | 32 | ||
| 33 | - @Schema(description = "检测工具 ID", example = "5") | ||
| 34 | - private Long toolId; | ||
| 35 | - | ||
| 36 | - @Schema(description = "检测工具名称", example = "卡尺") | ||
| 37 | - private String toolName; | 33 | + @Schema(description = "检测工具", example = "卡尺") |
| 34 | + private String tool; | ||
| 38 | 35 | ||
| 39 | @Schema(description = "检测方法", example = "目测") | 36 | @Schema(description = "检测方法", example = "目测") |
| 40 | private String checkMethod; | 37 | private String checkMethod; |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/iqc/MesQcIqcLineDO.java
| @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc; | @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc; | ||
| 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; | 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| 5 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; | 5 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; |
| 6 | -import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO; | ||
| 7 | import com.baomidou.mybatisplus.annotation.KeySequence; | 6 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 8 | import com.baomidou.mybatisplus.annotation.TableId; | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 9 | import com.baomidou.mybatisplus.annotation.TableName; | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| @@ -44,11 +43,11 @@ public class MesQcIqcLineDO extends BaseDO { | @@ -44,11 +43,11 @@ public class MesQcIqcLineDO extends BaseDO { | ||
| 44 | */ | 43 | */ |
| 45 | private Long indicatorId; | 44 | private Long indicatorId; |
| 46 | /** | 45 | /** |
| 47 | - * 检测工具 ID | 46 | + * 检测工具 |
| 48 | * | 47 | * |
| 49 | - * 关联 {@link MesTmToolDO#getId()} | 48 | + * 冗余 {@link MesQcIndicatorDO#getTool()} |
| 50 | */ | 49 | */ |
| 51 | - private Long toolId; | 50 | + private String tool; |
| 52 | /** | 51 | /** |
| 53 | * 检测方法 | 52 | * 检测方法 |
| 54 | */ | 53 | */ |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/template/MesQcTemplateIndicatorMapper.java
| @@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; | @@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; | ||
| 9 | 9 | ||
| 10 | import java.util.List; | 10 | import java.util.List; |
| 11 | 11 | ||
| 12 | +// TODO @AI:MesQcTemplateIndicatorService 独立一个;然后非 MesQcTemplateIndicatorService 调用 mapper 的地方,都替换下; | ||
| 12 | /** | 13 | /** |
| 13 | * MES 质检方案-检测指标项 Mapper | 14 | * MES 质检方案-检测指标项 Mapper |
| 14 | * | 15 | * |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
| @@ -250,6 +250,8 @@ public interface ErrorCodeConstants { | @@ -250,6 +250,8 @@ public interface ErrorCodeConstants { | ||
| 250 | ErrorCode QC_IQC_NOT_PREPARE = new ErrorCode(1_040_603_002, "只有草稿状态的检验单才可操作"); | 250 | ErrorCode QC_IQC_NOT_PREPARE = new ErrorCode(1_040_603_002, "只有草稿状态的检验单才可操作"); |
| 251 | ErrorCode QC_IQC_QUANTITY_MISMATCH = new ErrorCode(1_040_603_004, "合格品与不合格品数量之和须等于检测数量"); | 251 | ErrorCode QC_IQC_QUANTITY_MISMATCH = new ErrorCode(1_040_603_004, "合格品与不合格品数量之和须等于检测数量"); |
| 252 | ErrorCode QC_IQC_NO_TEMPLATE = new ErrorCode(1_040_603_005, "当前产品未配置 IQC 检测模板"); | 252 | ErrorCode QC_IQC_NO_TEMPLATE = new ErrorCode(1_040_603_005, "当前产品未配置 IQC 检测模板"); |
| 253 | + ErrorCode QC_IQC_SOURCE_DOC_PARAMS_MISSING = new ErrorCode(1_040_603_006, "来源单据类型非空时,来源单据 ID 和来源单据行 ID 不能为空"); | ||
| 254 | + ErrorCode QC_IQC_CHECK_RESULT_EMPTY = new ErrorCode(1_040_603_007, "完成检验单前,检测结果必须填写"); | ||
| 253 | // ========== MES 质量管理-来料检验行(1-040-603-100) ========== | 255 | // ========== MES 质量管理-来料检验行(1-040-603-100) ========== |
| 254 | ErrorCode QC_IQC_LINE_NOT_EXISTS = new ErrorCode(1_040_603_100, "来料检验行不存在"); | 256 | ErrorCode QC_IQC_LINE_NOT_EXISTS = new ErrorCode(1_040_603_100, "来料检验行不存在"); |
| 255 | 257 | ||
| @@ -344,4 +346,10 @@ public interface ErrorCodeConstants { | @@ -344,4 +346,10 @@ public interface ErrorCodeConstants { | ||
| 344 | ErrorCode WM_MATERIAL_REQUEST_STATUS_INVALID = new ErrorCode(1_040_706_001, "领料申请单状态不正确,无法执行该操作"); | 346 | ErrorCode WM_MATERIAL_REQUEST_STATUS_INVALID = new ErrorCode(1_040_706_001, "领料申请单状态不正确,无法执行该操作"); |
| 345 | ErrorCode WM_MATERIAL_REQUEST_LINE_NOT_EXISTS = new ErrorCode(1_040_706_100, "领料申请单行不存在"); | 347 | ErrorCode WM_MATERIAL_REQUEST_LINE_NOT_EXISTS = new ErrorCode(1_040_706_100, "领料申请单行不存在"); |
| 346 | 348 | ||
| 349 | + // ========== MES 仓库管理-外协出库单(1-040-707-000) ========== | ||
| 350 | + ErrorCode WM_OUTSOURCE_ISSUE_NOT_EXISTS = new ErrorCode(1_040_707_000, "外协出库单不存在"); | ||
| 351 | + ErrorCode WM_OUTSOURCE_ISSUE_STATUS_INVALID = new ErrorCode(1_040_707_001, "外协出库单状态不正确,无法执行该操作"); | ||
| 352 | + ErrorCode WM_OUTSOURCE_ISSUE_QUANTITY_MISMATCH = new ErrorCode(1_040_707_002, "出库单行数量与明细数量不一致"); | ||
| 353 | + ErrorCode WM_OUTSOURCE_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_707_100, "外协出库单行不存在"); | ||
| 354 | + | ||
| 347 | } | 355 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcLineServiceImpl.java
| @@ -6,20 +6,24 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | @@ -6,20 +6,24 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 6 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLinePageReqVO; | 6 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLinePageReqVO; |
| 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; | 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; |
| 8 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO; | 8 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO; |
| 9 | +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; | ||
| 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO; | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO; |
| 10 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcLineMapper; | 11 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcLineMapper; |
| 11 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateIndicatorMapper; | 12 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateIndicatorMapper; |
| 12 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; | 13 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; |
| 14 | +import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService; | ||
| 13 | import jakarta.annotation.Resource; | 15 | import jakarta.annotation.Resource; |
| 14 | import org.springframework.stereotype.Service; | 16 | import org.springframework.stereotype.Service; |
| 15 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 16 | 18 | ||
| 17 | import java.util.ArrayList; | 19 | import java.util.ArrayList; |
| 18 | import java.util.List; | 20 | import java.util.List; |
| 21 | +import java.util.Map; | ||
| 19 | import java.util.Objects; | 22 | import java.util.Objects; |
| 20 | 23 | ||
| 21 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 24 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 22 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 25 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| 26 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 23 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; | 27 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| 24 | 28 | ||
| 25 | /** | 29 | /** |
| @@ -36,6 +40,9 @@ public class MesQcIqcLineServiceImpl implements MesQcIqcLineService { | @@ -36,6 +40,9 @@ public class MesQcIqcLineServiceImpl implements MesQcIqcLineService { | ||
| 36 | @Resource | 40 | @Resource |
| 37 | private MesQcTemplateIndicatorMapper templateIndicatorMapper; | 41 | private MesQcTemplateIndicatorMapper templateIndicatorMapper; |
| 38 | 42 | ||
| 43 | + @Resource | ||
| 44 | + private MesQcIndicatorService indicatorService; | ||
| 45 | + | ||
| 39 | @Override | 46 | @Override |
| 40 | public MesQcIqcLineDO validateIqcLineExists(Long id) { | 47 | public MesQcIqcLineDO validateIqcLineExists(Long id) { |
| 41 | MesQcIqcLineDO line = iqcLineMapper.selectById(id); | 48 | MesQcIqcLineDO line = iqcLineMapper.selectById(id); |
| @@ -57,14 +64,22 @@ public class MesQcIqcLineServiceImpl implements MesQcIqcLineService { | @@ -57,14 +64,22 @@ public class MesQcIqcLineServiceImpl implements MesQcIqcLineService { | ||
| 57 | 64 | ||
| 58 | @Override | 65 | @Override |
| 59 | public void createLinesFromTemplate(Long iqcId, Long templateId) { | 66 | public void createLinesFromTemplate(Long iqcId, Long templateId) { |
| 60 | - List<MesQcTemplateIndicatorDO> indicators = templateIndicatorMapper.selectListByTemplateId(templateId); | ||
| 61 | - List<MesQcIqcLineDO> lines = convertList(indicators, indicator -> new MesQcIqcLineDO() | ||
| 62 | - .setIqcId(iqcId).setIndicatorId(indicator.getIndicatorId()) | ||
| 63 | - .setToolId(null) // TODO @芋艿:模板指标暂无 toolId,后续可扩展 | ||
| 64 | - .setCheckMethod(indicator.getCheckMethod()) | ||
| 65 | - .setStandardValue(indicator.getStandardValue()).setUnitMeasureId(indicator.getUnitMeasureId()) | ||
| 66 | - .setMaxThreshold(indicator.getThresholdMax()).setMinThreshold(indicator.getThresholdMin()) | ||
| 67 | - .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0)); | 67 | + List<MesQcTemplateIndicatorDO> templateIndicators = templateIndicatorMapper.selectListByTemplateId(templateId); |
| 68 | + if (CollUtil.isEmpty(templateIndicators)) { | ||
| 69 | + return; | ||
| 70 | + } | ||
| 71 | + Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap( | ||
| 72 | + convertSet(templateIndicators, MesQcTemplateIndicatorDO::getIndicatorId)); | ||
| 73 | + List<MesQcIqcLineDO> lines = convertList(templateIndicators, templateIndicator -> { | ||
| 74 | + MesQcIndicatorDO indicator = indicatorMap.get(templateIndicator.getIndicatorId()); | ||
| 75 | + return new MesQcIqcLineDO() | ||
| 76 | + .setIqcId(iqcId).setIndicatorId(templateIndicator.getIndicatorId()) | ||
| 77 | + .setTool(indicator != null ? indicator.getTool() : null) | ||
| 78 | + .setCheckMethod(templateIndicator.getCheckMethod()) | ||
| 79 | + .setStandardValue(templateIndicator.getStandardValue()).setUnitMeasureId(templateIndicator.getUnitMeasureId()) | ||
| 80 | + .setMaxThreshold(templateIndicator.getThresholdMax()).setMinThreshold(templateIndicator.getThresholdMin()) | ||
| 81 | + .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0); | ||
| 82 | + }); | ||
| 68 | iqcLineMapper.insertBatch(lines); | 83 | iqcLineMapper.insertBatch(lines); |
| 69 | } | 84 | } |
| 70 | 85 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcService.java
| @@ -22,16 +22,18 @@ public interface MesQcIqcService { | @@ -22,16 +22,18 @@ public interface MesQcIqcService { | ||
| 22 | * 创建来料检验单 | 22 | * 创建来料检验单 |
| 23 | * | 23 | * |
| 24 | * @param createReqVO 创建信息 | 24 | * @param createReqVO 创建信息 |
| 25 | + * @param inspectorUserId 检测人员用户 ID | ||
| 25 | * @return 编号 | 26 | * @return 编号 |
| 26 | */ | 27 | */ |
| 27 | - Long createIqc(@Valid MesQcIqcSaveReqVO createReqVO); | 28 | + Long createIqc(@Valid MesQcIqcSaveReqVO createReqVO, Long inspectorUserId); |
| 28 | 29 | ||
| 29 | /** | 30 | /** |
| 30 | * 更新来料检验单 | 31 | * 更新来料检验单 |
| 31 | * | 32 | * |
| 32 | * @param updateReqVO 更新信息 | 33 | * @param updateReqVO 更新信息 |
| 34 | + * @param inspectorUserId 检测人员用户 ID | ||
| 33 | */ | 35 | */ |
| 34 | - void updateIqc(@Valid MesQcIqcSaveReqVO updateReqVO); | 36 | + void updateIqc(@Valid MesQcIqcSaveReqVO updateReqVO, Long inspectorUserId); |
| 35 | 37 | ||
| 36 | /** | 38 | /** |
| 37 | * 完成来料检验单 | 39 | * 完成来料检验单 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcServiceImpl.java
| @@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil; | @@ -4,11 +4,11 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.util.ObjUtil; | 4 | import cn.hutool.core.util.ObjUtil; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 7 | +import cn.hutool.core.util.ObjectUtil; | ||
| 7 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcPageReqVO; | 8 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcPageReqVO; |
| 8 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcSaveReqVO; | 9 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcSaveReqVO; |
| 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; |
| 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO; | 11 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO; |
| 11 | -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO; | ||
| 12 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; | 12 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; |
| 13 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcMapper; | 13 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcMapper; |
| 14 | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; | 14 | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| @@ -16,7 +16,7 @@ import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; | @@ -16,7 +16,7 @@ import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; | ||
| 16 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcIqcStatusEnum; | 16 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcIqcStatusEnum; |
| 17 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; | 17 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; |
| 18 | import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; | 18 | import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; |
| 19 | -import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateService; | 19 | +import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService; |
| 20 | import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; | 20 | import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; |
| 21 | import jakarta.annotation.Resource; | 21 | import jakarta.annotation.Resource; |
| 22 | import org.springframework.stereotype.Service; | 22 | import org.springframework.stereotype.Service; |
| @@ -44,7 +44,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | @@ -44,7 +44,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | ||
| 44 | @Resource | 44 | @Resource |
| 45 | private MesQcIqcMapper iqcMapper; | 45 | private MesQcIqcMapper iqcMapper; |
| 46 | @Resource | 46 | @Resource |
| 47 | - private MesQcTemplateService templateService; | 47 | + private MesQcTemplateDetailService templateDetailService; |
| 48 | 48 | ||
| 49 | @Resource | 49 | @Resource |
| 50 | private MesQcIqcLineService iqcLineService; | 50 | private MesQcIqcLineService iqcLineService; |
| @@ -55,46 +55,42 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | @@ -55,46 +55,42 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | ||
| 55 | 55 | ||
| 56 | @Override | 56 | @Override |
| 57 | @Transactional(rollbackFor = Exception.class) | 57 | @Transactional(rollbackFor = Exception.class) |
| 58 | - public Long createIqc(MesQcIqcSaveReqVO createReqVO) { | 58 | + public Long createIqc(MesQcIqcSaveReqVO createReqVO, Long inspectorUserId) { |
| 59 | // 1.1 校验编号唯一 | 59 | // 1.1 校验编号唯一 |
| 60 | validateIqcCodeUnique(null, createReqVO.getCode()); | 60 | validateIqcCodeUnique(null, createReqVO.getCode()); |
| 61 | - // 1.2 查找物料关联的 IQC 检测模板 | ||
| 62 | - Long templateId = createReqVO.getTemplateId(); | ||
| 63 | - MesQcTemplateDO template = templateService.validateTemplateExists(templateId); | ||
| 64 | - if (!CollUtil.contains(template.getTypes(), MesQcTypeEnum.IQC.getType())) { | ||
| 65 | - throw exception(QC_IQC_NO_TEMPLATE); | ||
| 66 | - } | 61 | + // 1.2 校验来源单据参数,并验证数据存在 |
| 62 | + validateSourceDoc(createReqVO.getSourceDocType(), createReqVO.getSourceDocId(), createReqVO.getSourceLineId()); | ||
| 63 | + // 1.3 通过 itemId + IQC 类型自动查找模板 | ||
| 64 | + MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType( | ||
| 65 | + createReqVO.getItemId(), MesQcTypeEnum.IQC.getType()); | ||
| 66 | + Long templateId = templateItem.getTemplateId(); | ||
| 67 | 67 | ||
| 68 | - // 3.1 从模板的产品关联中获取检测参数(min_check_quantity、max_unqualified_quantity) | ||
| 69 | - MesQcTemplateItemDO templateItem = templateService.getTemplateItemByTemplateIdAndItemId( | ||
| 70 | - templateId, createReqVO.getItemId()); | ||
| 71 | - if (templateItem != null) { | ||
| 72 | - if (createReqVO.getMinCheckQuantity() == null) { | ||
| 73 | - createReqVO.setMinCheckQuantity(templateItem.getQuantityCheck()); | ||
| 74 | - } | ||
| 75 | - if (createReqVO.getMaxUnqualifiedQuantity() == null) { | ||
| 76 | - createReqVO.setMaxUnqualifiedQuantity(templateItem.getQuantityUnqualified()); | ||
| 77 | - } | ||
| 78 | - } | ||
| 79 | - // 3.2 插入主表 | 68 | + // 2. 插入主表 |
| 80 | MesQcIqcDO iqc = BeanUtils.toBean(createReqVO, MesQcIqcDO.class); | 69 | MesQcIqcDO iqc = BeanUtils.toBean(createReqVO, MesQcIqcDO.class); |
| 70 | + iqc.setTemplateId(templateId); | ||
| 71 | + iqc.setCheckQuantity(createReqVO.getQualifiedQuantity().add(createReqVO.getUnqualifiedQuantity())); | ||
| 72 | + iqc.setInspectorUserId(inspectorUserId); | ||
| 81 | iqc.setStatus(MesQcIqcStatusEnum.PREPARE.getType()); | 73 | iqc.setStatus(MesQcIqcStatusEnum.PREPARE.getType()); |
| 82 | iqcMapper.insert(iqc); | 74 | iqcMapper.insert(iqc); |
| 83 | 75 | ||
| 84 | - // 4. 从模板指标自动生成检验行 | 76 | + // 3. 从模板指标自动生成检验行 |
| 85 | iqcLineService.createLinesFromTemplate(iqc.getId(), templateId); | 77 | iqcLineService.createLinesFromTemplate(iqc.getId(), templateId); |
| 86 | return iqc.getId(); | 78 | return iqc.getId(); |
| 87 | } | 79 | } |
| 88 | 80 | ||
| 89 | @Override | 81 | @Override |
| 90 | - public void updateIqc(MesQcIqcSaveReqVO updateReqVO) { | 82 | + public void updateIqc(MesQcIqcSaveReqVO updateReqVO, Long inspectorUserId) { |
| 91 | // 1.1 校验存在 + 草稿状态 | 83 | // 1.1 校验存在 + 草稿状态 |
| 92 | validateIqcStatusPrepare(updateReqVO.getId()); | 84 | validateIqcStatusPrepare(updateReqVO.getId()); |
| 93 | // 1.2 校验编号唯一 | 85 | // 1.2 校验编号唯一 |
| 94 | validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); | 86 | validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); |
| 95 | 87 | ||
| 96 | - // 2. 更新 | 88 | + // 2. 更新主表 |
| 97 | MesQcIqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIqcDO.class); | 89 | MesQcIqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIqcDO.class); |
| 90 | + updateObj.setSourceDocType(null).setSourceDocId(null).setSourceLineId(null); // 不允许修改来源单据 | ||
| 91 | + updateObj.setTemplateId(null); // 不允许修改模板 | ||
| 92 | + updateObj.setCheckQuantity(updateReqVO.getQualifiedQuantity().add(updateReqVO.getUnqualifiedQuantity())); | ||
| 93 | + updateObj.setInspectorUserId(inspectorUserId); | ||
| 98 | iqcMapper.updateById(updateObj); | 94 | iqcMapper.updateById(updateObj); |
| 99 | } | 95 | } |
| 100 | 96 | ||
| @@ -102,14 +98,11 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | @@ -102,14 +98,11 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | ||
| 102 | public void completeIqc(Long id) { | 98 | public void completeIqc(Long id) { |
| 103 | // 1.1 校验存在 + 草稿状态 | 99 | // 1.1 校验存在 + 草稿状态 |
| 104 | MesQcIqcDO iqc = validateIqcStatusPrepare(id); | 100 | MesQcIqcDO iqc = validateIqcStatusPrepare(id); |
| 105 | - // 1.2 校验合格品 + 不合格品 = 检测数量 | ||
| 106 | - if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) { | ||
| 107 | - BigDecimal total = ObjUtil.defaultIfNull(iqc.getQualifiedQuantity(), BigDecimal.ZERO) | ||
| 108 | - .add(ObjUtil.defaultIfNull(iqc.getUnqualifiedQuantity(), BigDecimal.ZERO)); | ||
| 109 | - if (total.compareTo(iqc.getCheckQuantity()) != 0) { | ||
| 110 | - throw exception(QC_IQC_QUANTITY_MISMATCH); | ||
| 111 | - } | 101 | + // DONE @AI:已修复,增加 checkResult 必填校验 |
| 102 | + if (iqc.getCheckResult() == null) { | ||
| 103 | + throw exception(QC_IQC_CHECK_RESULT_EMPTY); | ||
| 112 | } | 104 | } |
| 105 | + // DONE @AI:已修复,数量校验已在 MesQcIqcSaveReqVO 的 @AssertTrue 中保证,此处移除 | ||
| 113 | 106 | ||
| 114 | // 2. 更新状态为已完成 | 107 | // 2. 更新状态为已完成 |
| 115 | MesQcIqcDO updateObj = new MesQcIqcDO() | 108 | MesQcIqcDO updateObj = new MesQcIqcDO() |
| @@ -130,7 +123,8 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | @@ -130,7 +123,8 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | ||
| 130 | if (iqc.getSourceDocType() == null) { | 123 | if (iqc.getSourceDocType() == null) { |
| 131 | return; | 124 | return; |
| 132 | } | 125 | } |
| 133 | - if (iqc.getSourceLineId() == null || iqc.getSourceDocId() == null) { | 126 | + // DONE @AI:已修复,使用 ObjectUtil.hasNull() 简化判断 |
| 127 | + if (ObjectUtil.hasNull(iqc.getSourceLineId(), iqc.getSourceDocId())) { | ||
| 134 | throw new IllegalArgumentException( | 128 | throw new IllegalArgumentException( |
| 135 | "IQC 单[" + iqc.getId() + "] sourceDocType 非空但 sourceLineId 或 sourceDocId 为空"); | 129 | "IQC 单[" + iqc.getId() + "] sourceDocType 非空但 sourceLineId 或 sourceDocId 为空"); |
| 136 | } | 130 | } |
| @@ -152,9 +146,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | @@ -152,9 +146,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | ||
| 152 | // 2.1 删除主表 | 146 | // 2.1 删除主表 |
| 153 | iqcMapper.deleteById(id); | 147 | iqcMapper.deleteById(id); |
| 154 | // 2.2 级联删除行 | 148 | // 2.2 级联删除行 |
| 155 | - iqcLineService.deleteByIqcId(id); | 149 | + iqcLineService.deleteListByIqcId(id); |
| 156 | // 2.3 级联删除缺陷记录 | 150 | // 2.3 级联删除缺陷记录 |
| 157 | - defectRecordService.deleteByQcTypeAndQcId(MesQcTypeEnum.IQC.getType(), id); | 151 | + defectRecordService.deleteListByQcTypeAndQcId(MesQcTypeEnum.IQC.getType(), id); |
| 158 | } | 152 | } |
| 159 | 153 | ||
| 160 | @Override | 154 | @Override |
| @@ -190,6 +184,26 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | @@ -190,6 +184,26 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | ||
| 190 | } | 184 | } |
| 191 | } | 185 | } |
| 192 | 186 | ||
| 187 | + /** | ||
| 188 | + * 校验来源单据参数,并验证数据存在 | ||
| 189 | + * | ||
| 190 | + * @param sourceDocType 来源单据类型 | ||
| 191 | + * @param sourceDocId 来源单据 ID | ||
| 192 | + * @param sourceLineId 来源单据行 ID | ||
| 193 | + */ | ||
| 194 | + private void validateSourceDoc(Integer sourceDocType, Long sourceDocId, Long sourceLineId) { | ||
| 195 | + if (sourceDocType == null) { | ||
| 196 | + return; | ||
| 197 | + } | ||
| 198 | + if (ObjUtil.hasNull(sourceDocId, sourceLineId)) { | ||
| 199 | + throw exception(QC_IQC_SOURCE_DOC_PARAMS_MISSING); | ||
| 200 | + } | ||
| 201 | + // 根据来源单据类型,校验数据存在且匹配 | ||
| 202 | + if (Objects.equals(sourceDocType, MesBizTypeConstants.WM_ARRIVAL_NOTICE)) { | ||
| 203 | + arrivalNoticeService.validateArrivalNoticeAndLineExists(sourceDocId, sourceLineId); | ||
| 204 | + } | ||
| 205 | + } | ||
| 206 | + | ||
| 193 | @Override | 207 | @Override |
| 194 | public MesQcIqcDO getIqc(Long id) { | 208 | public MesQcIqcDO getIqc(Long id) { |
| 195 | return iqcMapper.selectById(id); | 209 | return iqcMapper.selectById(id); |
| @@ -246,7 +260,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | @@ -246,7 +260,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { | ||
| 246 | if (CollUtil.isEmpty(ids)) { | 260 | if (CollUtil.isEmpty(ids)) { |
| 247 | return Collections.emptyMap(); | 261 | return Collections.emptyMap(); |
| 248 | } | 262 | } |
| 249 | - List<MesQcIqcDO> list = iqcMapper.selectBatchIds(ids); | 263 | + List<MesQcIqcDO> list = iqcMapper.selectByIds(ids); |
| 250 | return convertMap(list, MesQcIqcDO::getId); | 264 | return convertMap(list, MesQcIqcDO::getId); |
| 251 | } | 265 | } |
| 252 | 266 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java
| @@ -93,6 +93,14 @@ public interface MesWmArrivalNoticeService { | @@ -93,6 +93,14 @@ public interface MesWmArrivalNoticeService { | ||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | /** | 95 | /** |
| 96 | + * 校验到货通知单和行存在,且行属于该通知单 | ||
| 97 | + * | ||
| 98 | + * @param noticeId 到货通知单 ID | ||
| 99 | + * @param lineId 到货通知单行 ID | ||
| 100 | + */ | ||
| 101 | + void validateArrivalNoticeAndLineExists(Long noticeId, Long lineId); | ||
| 102 | + | ||
| 103 | + /** | ||
| 96 | * 按状态获得到货通知单列表 | 104 | * 按状态获得到货通知单列表 |
| 97 | * | 105 | * |
| 98 | * @param status 状态 | 106 | * @param status 状态 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java
| @@ -21,6 +21,7 @@ import java.math.BigDecimal; | @@ -21,6 +21,7 @@ import java.math.BigDecimal; | ||
| 21 | import java.util.Collection; | 21 | import java.util.Collection; |
| 22 | import java.util.Collections; | 22 | import java.util.Collections; |
| 23 | import java.util.List; | 23 | import java.util.List; |
| 24 | +import java.util.Objects; | ||
| 24 | 25 | ||
| 25 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 26 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; | 27 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| @@ -166,6 +167,24 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService | @@ -166,6 +167,24 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService | ||
| 166 | return arrivalNoticeMapper.selectListByStatus(status); | 167 | return arrivalNoticeMapper.selectListByStatus(status); |
| 167 | } | 168 | } |
| 168 | 169 | ||
| 170 | + @Override | ||
| 171 | + public void validateArrivalNoticeAndLineExists(Long noticeId, Long lineId) { | ||
| 172 | + // 1. 校验通知单存在 | ||
| 173 | + MesWmArrivalNoticeDO notice = arrivalNoticeMapper.selectById(noticeId); | ||
| 174 | + if (notice == null) { | ||
| 175 | + throw exception(WM_ARRIVAL_NOTICE_NOT_EXISTS); | ||
| 176 | + } | ||
| 177 | + // 2.1 校验行存在 | ||
| 178 | + MesWmArrivalNoticeLineDO line = arrivalNoticeLineService.getArrivalNoticeLine(lineId); | ||
| 179 | + if (line == null) { | ||
| 180 | + throw exception(WM_ARRIVAL_NOTICE_LINE_NOT_EXISTS); | ||
| 181 | + } | ||
| 182 | + // 2.2 校验行属于该通知单 | ||
| 183 | + if (ObjUtil.notEqual(line.getNoticeId(), noticeId)) { | ||
| 184 | + throw exception(WM_ARRIVAL_NOTICE_LINE_NOT_EXISTS); | ||
| 185 | + } | ||
| 186 | + } | ||
| 187 | + | ||
| 169 | private MesWmArrivalNoticeDO validateArrivalNoticeExists(Long id) { | 188 | private MesWmArrivalNoticeDO validateArrivalNoticeExists(Long id) { |
| 170 | MesWmArrivalNoticeDO notice = arrivalNoticeMapper.selectById(id); | 189 | MesWmArrivalNoticeDO notice = arrivalNoticeMapper.selectById(id); |
| 171 | if (notice == null) { | 190 | if (notice == null) { |