2026-09-03 f4a412cebe9532833320bad81cc92e7930d7715a
feat(mes): 优化MES模块功能与配置

- 更新本地环境Redis数据库索引从0到5
- 修改YZFX环境数据库连接地址从172.17.0.1到42.63.70.231
- 新增MES退货检验类型字典常量MES_RQC_TYPE
- 修正MDM计量单位权限标识从unit-measure统一为unit
- 优化MES生产反馈倒冲工序物料消耗逻辑,改为按报工工序的投料BOM自动扣料
- 调整MES工艺路线工序保存请求对象,将工序编号和序号设为可选字段
- 实现工艺路线工序更新时对未传必填字段的回填逻辑
- 修复MES工单BOM控制器中的空指针异常风险,使用Objects.equals比较
- 新增按工单编号和工序编号查询BOM列表的服务接口
- 为MES质检相关响应对象添加Excel导出的字典格式转换注解
- 优化MES物料消耗服务中倒冲扣料的BOM查询逻辑,精确到工序级别
已添加1个文件
已修改15个文件
158 ■■■■■ 文件已修改
workbench-current-state.png 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/MdmUnitMeasureController.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/ipqc/vo/MesQcIpqcRespVO.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcRespVO.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/application-local.yaml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/application-yzfx.yaml 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
workbench-current-state.png
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/MdmUnitMeasureController.java
@@ -46,14 +46,14 @@
    @PostMapping("/create")
    @Operation(summary = "创建计量单位")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:create')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:create')")
    public CommonResult<Long> createUnitMeasure(@Valid @RequestBody MdmUnitMeasureSaveReqVO createReqVO) {
        return success(unitMeasureService.createUnitMeasure(createReqVO));
    }
    @PutMapping("/update")
    @Operation(summary = "更新计量单位")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:update')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:update')")
    public CommonResult<Boolean> updateUnitMeasure(@Valid @RequestBody MdmUnitMeasureSaveReqVO updateReqVO) {
        unitMeasureService.updateUnitMeasure(updateReqVO);
        return success(true);
@@ -63,7 +63,7 @@
    @Operation(summary = "更新计量单位状态")
    @Parameter(name = "id", description = "编号", required = true, example = "1")
    @Parameter(name = "status", description = "状态", required = true, example = "0")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:update')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:update')")
    public CommonResult<Boolean> updateUnitMeasureStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) {
        unitMeasureService.updateUnitMeasureStatus(id, status);
        return success(true);
@@ -72,7 +72,7 @@
    @DeleteMapping("/delete")
    @Operation(summary = "删除计量单位")
    @Parameter(name = "id", description = "编号", required = true, example = "1")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:delete')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:delete')")
    public CommonResult<Boolean> deleteUnitMeasure(@RequestParam("id") Long id) {
        unitMeasureService.deleteUnitMeasure(id);
        return success(true);
@@ -81,21 +81,21 @@
    @GetMapping("/get")
    @Operation(summary = "获得计量单位")
    @Parameter(name = "id", description = "编号", required = true, example = "1")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:query')")
    public CommonResult<MdmUnitMeasureDO> getUnitMeasure(@RequestParam("id") Long id) {
        return success(unitMeasureService.getUnitMeasure(id));
    }
    @GetMapping("/page")
    @Operation(summary = "获得计量单位分页")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:query')")
    public CommonResult<PageResult<MdmUnitMeasureDO>> getUnitMeasurePage(@Valid MdmUnitMeasurePageReqVO pageReqVO) {
        return success(unitMeasureService.getUnitMeasurePage(pageReqVO));
    }
    @GetMapping("/list")
    @Operation(summary = "获得计量单位列表")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:query')")
    public CommonResult<List<MdmUnitMeasureDO>> getUnitMeasureList() {
        return success(unitMeasureService.getUnitMeasureList(null));
    }
@@ -103,14 +103,14 @@
    @GetMapping("/list-by-ids")
    @Operation(summary = "获得计量单位列表")
    @Parameter(name = "ids", description = "编号列表", required = true, example = "1,2,3")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:query')")
    public CommonResult<List<MdmUnitMeasureDO>> getUnitMeasureListByIds(@RequestParam("ids") List<Long> ids) {
        return success(unitMeasureService.getUnitMeasureList(ids));
    }
    @GetMapping("/export-excel")
    @Operation(summary = "导出计量单位 Excel")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:export')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportUnitMeasureExcel(@Valid MdmUnitMeasurePageReqVO pageReqVO,
                                       HttpServletResponse response) throws IOException {
@@ -138,7 +138,7 @@
    @GetMapping("/get-import-template")
    @Operation(summary = "获得导入计量单位模板")
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:import')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:import')")
    public void importTemplate(HttpServletResponse response) throws IOException {
        List<MdmUnitMeasureImportExcelVO> list = Arrays.asList(
                MdmUnitMeasureImportExcelVO.builder().code("PC").name("片").primaryFlag(true).changeRate(new java.math.BigDecimal("1")).status(0).remark("示例:主单位").build(),
@@ -153,7 +153,7 @@
            @Parameter(name = "file", description = "Excel 文件", required = true),
            @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
    })
    @PreAuthorize("@ss.hasPermission('mdm:unit-measure:import')")
    @PreAuthorize("@ss.hasPermission('mdm:unit:import')")
    public CommonResult<MdmUnitMeasureImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
                                                                @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
        List<MdmUnitMeasureImportExcelVO> list = ExcelUtils.read(file, MdmUnitMeasureImportExcelVO.class);
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java
@@ -17,15 +17,13 @@
    @NotNull(message = "工艺路线编号不能为空")
    private Long routeId;
    @Schema(description = "工序编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @NotNull(message = "工序编号不能为空")
    @Schema(description = "工序编号", example = "1")
    private Long processId;
    @Schema(description = "工艺参数模板编号", example = "1")
    private Long paramTemplateId;
    @Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @NotNull(message = "序号不能为空")
    @Schema(description = "序号", example = "1")
    private Integer sort;
    @Schema(description = "与下一道工序关系", example = "0")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java
@@ -245,7 +245,9 @@
            }
            List<MesProWorkOrderBomDO> items = new ArrayList<>();
            for (MesProWorkOrderBomDO bom : bomList) {
                if (bom.getProcessId().equals(process.getProcessId())) {
                // 跳过无工序编号的投料行(工单 BOM 中仅按工序维护投料明细,无工序的行不参与展开,
                // 且 getProcessId 可能为 null,直接 equals 会 NPE)
                if (Objects.equals(bom.getProcessId(), process.getProcessId())) {
                    items.add(bom);
                }
            }
@@ -263,7 +265,7 @@
        // 3. 以最后一道工序的投料为起点
        Map<Long, BigDecimal> currentLayer = new LinkedHashMap<>();
        for (MesProWorkOrderBomDO bom : bomList) {
            if (bom.getProcessId().equals(lastProcess.getProcessId())) {
            if (Objects.equals(bom.getProcessId(), lastProcess.getProcessId())) {
                currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add);
            }
        }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/ipqc/vo/MesQcIpqcRespVO.java
@@ -2,6 +2,9 @@
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -26,7 +29,8 @@
    private String name;
    @Schema(description = "IPQC 检验类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @ExcelProperty("检验类型")
    @ExcelProperty(value = "检验类型", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_IPQC_TYPE)
    private Integer type;
    @Schema(description = "检验模板 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
@@ -89,9 +93,11 @@
    private String itemName;
    @Schema(description = "规格型号", example = "100mm*50mm")
    @ExcelProperty("规格型号")
    private String itemSpecification;
    @Schema(description = "单位名称", example = "个")
    @ExcelProperty("单位")
    private String unitName;
    // ========== 数量 ==========
@@ -143,7 +149,8 @@
    // ========== 检验 ==========
    @Schema(description = "检测结果", example = "1")
    @ExcelProperty("检测结果")
    @ExcelProperty(value = "检测结果", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT)
    private Integer checkResult;
    @Schema(description = "检测日期")
@@ -158,7 +165,8 @@
    private String inspectorNickname;
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
    @ExcelProperty("状态")
    @ExcelProperty(value = "状态", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_ORDER_STATUS)
    private Integer status;
    @Schema(description = "备注", example = "备注")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcRespVO.java
@@ -2,6 +2,9 @@
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -48,6 +51,7 @@
    private Long vendorId;
    @Schema(description = "供应商简称", example = "供应商A")
    @ExcelProperty("供应商简称")
    private String vendorNickname;
    @Schema(description = "供应商批次号", example = "VB20250101")
@@ -114,7 +118,8 @@
    // ========== 检验 ==========
    @Schema(description = "检测结果", example = "1")
    @ExcelProperty("检测结果")
    @ExcelProperty(value = "检测结果", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT)
    private Integer checkResult;
    @Schema(description = "来料日期")
@@ -133,7 +138,8 @@
    private String inspectorNickname;
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
    @ExcelProperty("状态")
    @ExcelProperty(value = "状态", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_ORDER_STATUS)
    private Integer status;
    @Schema(description = "备注", example = "备注")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java
@@ -2,6 +2,9 @@
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -69,9 +72,11 @@
    private String itemName;
    @Schema(description = "规格型号", example = "100mm*50mm")
    @ExcelProperty("规格型号")
    private String itemSpecification;
    @Schema(description = "单位名称", example = "个")
    @ExcelProperty("单位")
    private String unitName;
    // ========== 数量 ==========
@@ -121,7 +126,8 @@
    // ========== 检验 ==========
    @Schema(description = "检测结果", example = "1")
    @ExcelProperty("检测结果")
    @ExcelProperty(value = "检测结果", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT)
    private Integer checkResult;
    @Schema(description = "出货日期")
@@ -140,7 +146,8 @@
    private String inspectorNickname;
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
    @ExcelProperty("状态")
    @ExcelProperty(value = "状态", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_ORDER_STATUS)
    private Integer status;
    @Schema(description = "备注", example = "备注")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java
@@ -2,6 +2,9 @@
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -31,6 +34,8 @@
    // ========== 来源单据 ==========
    @Schema(description = "来源单据类型", example = "116")
    @ExcelProperty(value = "来源单据类型", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_QC_SOURCE_DOC_TYPE)
    private Integer sourceDocType;
    @Schema(description = "来源单据 ID", example = "200")
@@ -40,12 +45,14 @@
    private Long sourceLineId;
    @Schema(description = "来源单据编码", example = "RT20250101001")
    @ExcelProperty("来源单据编码")
    private String sourceDocCode;
    // ========== 检验类型 ==========
    @Schema(description = "检验类型", example = "1")
    @ExcelProperty("检验类型")
    @ExcelProperty(value = "检验类型", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_RQC_TYPE)
    private Integer type;
    // ========== 物料 ==========
@@ -62,9 +69,11 @@
    private String itemName;
    @Schema(description = "规格型号", example = "100mm*50mm")
    @ExcelProperty("规格型号")
    private String itemSpecification;
    @Schema(description = "单位名称", example = "个")
    @ExcelProperty("单位")
    private String unitName;
    @Schema(description = "批次号", example = "BATCH001")
@@ -108,7 +117,8 @@
    // ========== 检验 ==========
    @Schema(description = "检测结果", example = "1")
    @ExcelProperty("检测结果")
    @ExcelProperty(value = "检测结果", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT)
    private Integer checkResult;
    @Schema(description = "检测日期")
@@ -123,7 +133,8 @@
    private String inspectorNickname;
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
    @ExcelProperty("状态")
    @ExcelProperty(value = "状态", converter = DictConvert.class)
    @DictFormat(DictTypeConstants.MES_ORDER_STATUS)
    private Integer status;
    @Schema(description = "备注", example = "备注")
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java
@@ -76,6 +76,7 @@
    String MES_DEFECT_LEVEL = "mes_defect_level"; // MES 缺陷等级
    String MES_QC_TYPE = "mes_qc_type"; // MES 检测种类(IQC/IPQC/OQC/RQC)
    String MES_IPQC_TYPE = "mes_ipqc_type"; // MES IPQC 检验类型
    String MES_RQC_TYPE = "mes_rqc_type"; // MES 退货检验类型
    String MES_ORDER_STATUS = "mes_order_status"; // MES 单据状态(IQC/IPQC/OQC/RQC 通用)
    String MES_QC_CHECK_RESULT = "mes_qc_check_result"; // MES 检测结果
    String MES_QC_SOURCE_DOC_TYPE = "mes_qc_source_doc_type"; // MES 来源单据类型
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
@@ -296,16 +296,17 @@
            throw exception(PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS, feedback.getUncheckQuantity());
        }
        // 3. 物料消耗:倒冲工序按 BOM 自动扣料;非倒冲工序跳过(物料走手工领料/投料)
        // 3. 物料消耗:倒冲工序按本工序投料 BOM 自动扣料;非倒冲工序跳过(物料走手工领料/投料)
        boolean backflushFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getBackflushFlag());
        if (backflushFlag) {
            // 3.1 校验倒冲工序必须配置 BOM 消耗,避免静默不扣料
            List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderId(
                    feedback.getWorkOrderId());
            // 3.1 校验倒冲工序必须配置本工序的投料 BOM,避免静默不扣料
            //     (只校验当前报工工序的投料,其他工序投料由各自工序报工时扣除)
            List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderIdAndProcessId(
                    feedback.getWorkOrderId(), feedback.getProcessId());
            if (CollUtil.isEmpty(boms)) {
                throw exception(PRO_FEEDBACK_BACKFLUSH_BOM_REQUIRED);
            }
            // 3.2 生成消耗记录并执行扣减(BOM × 报工数量,FIFO 扣线边库)
            // 3.2 生成消耗记录并执行扣减(本工序投料用量比例 × 报工数量,FIFO 扣线边库)
            MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback);
            if (itemConsume != null) {
                itemConsumeService.finishItemConsume(itemConsume.getId());
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java
@@ -81,8 +81,14 @@
    public void updateRouteProcess(MesProRouteProcessSaveReqVO updateReqVO) {
        // 1.0 已启用的工艺路线,不允许操作
        routeService.validateRouteNotEnable(updateReqVO.getRouteId());
        // 1.1 校验存在
        validateRouteProcessExists(updateReqVO.getId());
        // 1.1 校验存在;部分更新(如仅调整产出产品)时未传的必填字段用现有值回填
        MesProRouteProcessDO existing = validateRouteProcessExists(updateReqVO.getId());
        if (updateReqVO.getProcessId() == null) {
            updateReqVO.setProcessId(existing.getProcessId());
        }
        if (updateReqVO.getSort() == null) {
            updateReqVO.setSort(existing.getSort());
        }
        // 1.2 校验工艺路线、工序存在
        validateRouteAndProcessExists(updateReqVO.getRouteId(), updateReqVO.getProcessId());
        // 1.3 校验唯一性
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java
@@ -63,6 +63,15 @@
    List<MesProWorkOrderBomDO> getWorkOrderBomListByWorkOrderId(Long workOrderId);
    /**
     * 根据工单编号与工序编号获得 BOM 列表(倒冲扣料按报工工序的投料明细过滤)
     *
     * @param workOrderId 工单编号
     * @param processId   工序编号
     * @return BOM 列表
     */
    List<MesProWorkOrderBomDO> getWorkOrderBomListByWorkOrderIdAndProcessId(Long workOrderId, Long processId);
    /**
     * 根据工单编号删除 BOM
     *
     * @param workOrderId 工单编号
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java
@@ -116,6 +116,11 @@
    }
    @Override
    public List<MesProWorkOrderBomDO> getWorkOrderBomListByWorkOrderIdAndProcessId(Long workOrderId, Long processId) {
        return workOrderBomMapper.selectListByWorkOrderIdAndProcessId(workOrderId, processId);
    }
    @Override
    public void deleteWorkOrderBomByWorkOrderId(Long workOrderId) {
        workOrderBomMapper.deleteByWorkOrderId(workOrderId);
    }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java
@@ -78,9 +78,10 @@
        if (feedback.getWorkOrderId() == null) {
            throw exception(PRO_FEEDBACK_ROUTE_PROCESS_INVALID);
        }
        // 1.2 查询工单 BOM 物料列表(倒冲按工单投料,非工艺路线)
        List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderId(
                feedback.getWorkOrderId());
        // 1.2 查询该倒冲工序的投料 BOM 列表(按报工工序过滤,只扣当前工序的投料明细,
        //     避免把其他工序的投料一并扣除导致多扣物料)
        List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderIdAndProcessId(
                feedback.getWorkOrderId(), feedback.getProcessId());
        if (CollUtil.isEmpty(boms)) {
            return null;
        }
yudao-server/src/main/resources/application-local.yaml
@@ -74,7 +74,7 @@
    redis:
      host: localhost # 地址
      port: 6379 # 端口
      database: 0 # 数据库索引
      database: 5 # 数据库索引
#      password: # 密码,建议生产环境开启
--- #################### 定时任务相关配置 ####################
yudao-server/src/main/resources/application-yzfx.yaml
@@ -65,33 +65,10 @@
      primary: master
      datasource:
        master:
          url: jdbc:mysql://172.17.0.1:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
          #          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例
          #          url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
          #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
          #          url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例
          #          url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
          #          url: jdbc:kingbase8://127.0.0.1:54321/test  # 人大金仓 KingbaseES 连接的示例
          #          url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
          #          url: jdbc:postgresql://127.0.0.1:5866/ruoyi-vue-pro # 瀚高 HighGo 连接的示例
#          url: jdbc:mysql://172.17.0.1:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
          url: jdbc:mysql://42.63.70.231:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
          username: root
          password: yzfx@123456..
          #          username: sa # SQL Server 连接的示例
          #          password: Yudao@2024 # SQL Server 连接的示例
          #          username: SYSDBA # DM 连接的示例
          #          password: SYSDBA001 # DM 连接的示例
          #          username: root # OpenGauss 连接的示例
          #          password: Yudao@2024 # OpenGauss 连接的示例
          #          username: root # 瀚高 HighGo 连接的示例
          #          password: 123456 # 瀚高 HighGo 连接的示例
#        tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!)
#          lazy: true # 开启懒加载,保证启动速度
#          url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro?varcharAsString=true&enableAutoReconnect=true # 参见:https://t.zsxq.com/qaX9c,开启 TDengine WebSocket 自动重连
#          driver-class-name: com.taosdata.jdbc.ws.WebSocketDriver
#          username: root
#          password: taosdata
#          druid:
#            validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL
  # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
  data: