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 | 9 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| 10 | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO; |
| 11 | 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 | 12 | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| 14 | 13 | import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcLineService; |
| 15 | 14 | import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService; |
| 16 | -import cn.iocoder.yudao.module.mes.service.tm.tool.MesTmToolService; | |
| 17 | 15 | import io.swagger.v3.oas.annotations.Operation; |
| 18 | 16 | import io.swagger.v3.oas.annotations.Parameter; |
| 19 | 17 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | ... | @@ -46,8 +44,6 @@ public class MesQcIqcLineController { |
| 46 | 44 | private MesQcIndicatorService indicatorService; |
| 47 | 45 | @Resource |
| 48 | 46 | private MesMdUnitMeasureService unitMeasureService; |
| 49 | - @Resource | |
| 50 | - private MesTmToolService toolService; | |
| 51 | 47 | |
| 52 | 48 | @GetMapping("/get") |
| 53 | 49 | @Operation(summary = "获得来料检验单行") |
| ... | ... | @@ -85,13 +81,6 @@ public class MesQcIqcLineController { |
| 85 | 81 | .setIndicatorType(indicator.getType())); |
| 86 | 82 | findAndThen(unitMeasureMap, vo.getUnitMeasureId(), |
| 87 | 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 | 1 | package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.ObjUtil; | |
| 3 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | +import jakarta.validation.constraints.AssertTrue; | |
| 4 | 6 | import jakarta.validation.constraints.DecimalMin; |
| 5 | 7 | import jakarta.validation.constraints.NotEmpty; |
| 6 | 8 | import jakarta.validation.constraints.NotNull; |
| ... | ... | @@ -82,4 +84,13 @@ public class MesQcIqcSaveReqVO { |
| 82 | 84 | @Schema(description = "备注", example = "备注") |
| 83 | 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 | 30 | @Schema(description = "检测指标类型", example = "QUANTITATIVE") |
| 31 | 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 | 36 | @Schema(description = "检测方法", example = "目测") |
| 40 | 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 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| 5 | 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 | 6 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 8 | 7 | import com.baomidou.mybatisplus.annotation.TableId; |
| 9 | 8 | import com.baomidou.mybatisplus.annotation.TableName; |
| ... | ... | @@ -44,11 +43,11 @@ public class MesQcIqcLineDO extends BaseDO { |
| 44 | 43 | */ |
| 45 | 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
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
| ... | ... | @@ -250,6 +250,8 @@ public interface ErrorCodeConstants { |
| 250 | 250 | ErrorCode QC_IQC_NOT_PREPARE = new ErrorCode(1_040_603_002, "只有草稿状态的检验单才可操作"); |
| 251 | 251 | ErrorCode QC_IQC_QUANTITY_MISMATCH = new ErrorCode(1_040_603_004, "合格品与不合格品数量之和须等于检测数量"); |
| 252 | 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 | 255 | // ========== MES 质量管理-来料检验行(1-040-603-100) ========== |
| 254 | 256 | ErrorCode QC_IQC_LINE_NOT_EXISTS = new ErrorCode(1_040_603_100, "来料检验行不存在"); |
| 255 | 257 | |
| ... | ... | @@ -344,4 +346,10 @@ public interface ErrorCodeConstants { |
| 344 | 346 | ErrorCode WM_MATERIAL_REQUEST_STATUS_INVALID = new ErrorCode(1_040_706_001, "领料申请单状态不正确,无法执行该操作"); |
| 345 | 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 | 6 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLinePageReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; |
| 8 | 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 | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO; |
| 10 | 11 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcLineMapper; |
| 11 | 12 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateIndicatorMapper; |
| 12 | 13 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; |
| 14 | +import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService; | |
| 13 | 15 | import jakarta.annotation.Resource; |
| 14 | 16 | import org.springframework.stereotype.Service; |
| 15 | 17 | import org.springframework.validation.annotation.Validated; |
| 16 | 18 | |
| 17 | 19 | import java.util.ArrayList; |
| 18 | 20 | import java.util.List; |
| 21 | +import java.util.Map; | |
| 19 | 22 | import java.util.Objects; |
| 20 | 23 | |
| 21 | 24 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 22 | 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 | 27 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| 24 | 28 | |
| 25 | 29 | /** |
| ... | ... | @@ -36,6 +40,9 @@ public class MesQcIqcLineServiceImpl implements MesQcIqcLineService { |
| 36 | 40 | @Resource |
| 37 | 41 | private MesQcTemplateIndicatorMapper templateIndicatorMapper; |
| 38 | 42 | |
| 43 | + @Resource | |
| 44 | + private MesQcIndicatorService indicatorService; | |
| 45 | + | |
| 39 | 46 | @Override |
| 40 | 47 | public MesQcIqcLineDO validateIqcLineExists(Long id) { |
| 41 | 48 | MesQcIqcLineDO line = iqcLineMapper.selectById(id); |
| ... | ... | @@ -57,14 +64,22 @@ public class MesQcIqcLineServiceImpl implements MesQcIqcLineService { |
| 57 | 64 | |
| 58 | 65 | @Override |
| 59 | 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 | 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 | 22 | * 创建来料检验单 |
| 23 | 23 | * |
| 24 | 24 | * @param createReqVO 创建信息 |
| 25 | + * @param inspectorUserId 检测人员用户 ID | |
| 25 | 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 | 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 | 4 | import cn.hutool.core.util.ObjUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 7 | +import cn.hutool.core.util.ObjectUtil; | |
| 7 | 8 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcPageReqVO; |
| 8 | 9 | import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcSaveReqVO; |
| 9 | 10 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; |
| 10 | 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 | 12 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; |
| 13 | 13 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcMapper; |
| 14 | 14 | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| ... | ... | @@ -16,7 +16,7 @@ import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; |
| 16 | 16 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcIqcStatusEnum; |
| 17 | 17 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; |
| 18 | 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 | 20 | import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; |
| 21 | 21 | import jakarta.annotation.Resource; |
| 22 | 22 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -44,7 +44,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 44 | 44 | @Resource |
| 45 | 45 | private MesQcIqcMapper iqcMapper; |
| 46 | 46 | @Resource |
| 47 | - private MesQcTemplateService templateService; | |
| 47 | + private MesQcTemplateDetailService templateDetailService; | |
| 48 | 48 | |
| 49 | 49 | @Resource |
| 50 | 50 | private MesQcIqcLineService iqcLineService; |
| ... | ... | @@ -55,46 +55,42 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 55 | 55 | |
| 56 | 56 | @Override |
| 57 | 57 | @Transactional(rollbackFor = Exception.class) |
| 58 | - public Long createIqc(MesQcIqcSaveReqVO createReqVO) { | |
| 58 | + public Long createIqc(MesQcIqcSaveReqVO createReqVO, Long inspectorUserId) { | |
| 59 | 59 | // 1.1 校验编号唯一 |
| 60 | 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 | 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 | 73 | iqc.setStatus(MesQcIqcStatusEnum.PREPARE.getType()); |
| 82 | 74 | iqcMapper.insert(iqc); |
| 83 | 75 | |
| 84 | - // 4. 从模板指标自动生成检验行 | |
| 76 | + // 3. 从模板指标自动生成检验行 | |
| 85 | 77 | iqcLineService.createLinesFromTemplate(iqc.getId(), templateId); |
| 86 | 78 | return iqc.getId(); |
| 87 | 79 | } |
| 88 | 80 | |
| 89 | 81 | @Override |
| 90 | - public void updateIqc(MesQcIqcSaveReqVO updateReqVO) { | |
| 82 | + public void updateIqc(MesQcIqcSaveReqVO updateReqVO, Long inspectorUserId) { | |
| 91 | 83 | // 1.1 校验存在 + 草稿状态 |
| 92 | 84 | validateIqcStatusPrepare(updateReqVO.getId()); |
| 93 | 85 | // 1.2 校验编号唯一 |
| 94 | 86 | validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); |
| 95 | 87 | |
| 96 | - // 2. 更新 | |
| 88 | + // 2. 更新主表 | |
| 97 | 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 | 94 | iqcMapper.updateById(updateObj); |
| 99 | 95 | } |
| 100 | 96 | |
| ... | ... | @@ -102,14 +98,11 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 102 | 98 | public void completeIqc(Long id) { |
| 103 | 99 | // 1.1 校验存在 + 草稿状态 |
| 104 | 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 | 107 | // 2. 更新状态为已完成 |
| 115 | 108 | MesQcIqcDO updateObj = new MesQcIqcDO() |
| ... | ... | @@ -130,7 +123,8 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 130 | 123 | if (iqc.getSourceDocType() == null) { |
| 131 | 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 | 128 | throw new IllegalArgumentException( |
| 135 | 129 | "IQC 单[" + iqc.getId() + "] sourceDocType 非空但 sourceLineId 或 sourceDocId 为空"); |
| 136 | 130 | } |
| ... | ... | @@ -152,9 +146,9 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 152 | 146 | // 2.1 删除主表 |
| 153 | 147 | iqcMapper.deleteById(id); |
| 154 | 148 | // 2.2 级联删除行 |
| 155 | - iqcLineService.deleteByIqcId(id); | |
| 149 | + iqcLineService.deleteListByIqcId(id); | |
| 156 | 150 | // 2.3 级联删除缺陷记录 |
| 157 | - defectRecordService.deleteByQcTypeAndQcId(MesQcTypeEnum.IQC.getType(), id); | |
| 151 | + defectRecordService.deleteListByQcTypeAndQcId(MesQcTypeEnum.IQC.getType(), id); | |
| 158 | 152 | } |
| 159 | 153 | |
| 160 | 154 | @Override |
| ... | ... | @@ -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 | 207 | @Override |
| 194 | 208 | public MesQcIqcDO getIqc(Long id) { |
| 195 | 209 | return iqcMapper.selectById(id); |
| ... | ... | @@ -246,7 +260,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 246 | 260 | if (CollUtil.isEmpty(ids)) { |
| 247 | 261 | return Collections.emptyMap(); |
| 248 | 262 | } |
| 249 | - List<MesQcIqcDO> list = iqcMapper.selectBatchIds(ids); | |
| 263 | + List<MesQcIqcDO> list = iqcMapper.selectByIds(ids); | |
| 250 | 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 | 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 | 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 | 21 | import java.util.Collection; |
| 22 | 22 | import java.util.Collections; |
| 23 | 23 | import java.util.List; |
| 24 | +import java.util.Objects; | |
| 24 | 25 | |
| 25 | 26 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | 27 | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| ... | ... | @@ -166,6 +167,24 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService |
| 166 | 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 | 188 | private MesWmArrivalNoticeDO validateArrivalNoticeExists(Long id) { |
| 170 | 189 | MesWmArrivalNoticeDO notice = arrivalNoticeMapper.selectById(id); |
| 171 | 190 | if (notice == null) { | ... | ... |