5 天以前 1d56cb54d8e606547ba5e763cade1c3e26c46be9
feat(mes): 为MES仓储模块添加BPM审批流程支持

- 为杂项出库单、杂项入库单、供应商退货单添加审批流程支持
- 新增APPROVING状态用于标识审批中状态
- 在DO和VO中添加processInstanceId字段存储BPM流程实例编号
- 实现submitApproval方法用于提交审批并创建BPM流程实例
- 添加getApprovalProcessList接口获取可用审批流程定义
- 集成BpmProcessInstanceApi和BpmProcessDefinitionService进行流程管理
- 实现审批状态更新逻辑,根据BPM结果更新单据状态
- 为三个单据类型添加对应的审批分类常量配置
- 更新控制器接口参数,增加processDefinitionKey传入
- 优化流程定义列表获取逻辑,过滤激活状态并保留最新版本
已添加3个文件
已修改18个文件
636 ■■■■■ 文件已修改
docs/wm_bpm_progress.md 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscissue/MesWmMiscIssueController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscissue/vo/MesWmMiscIssueRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/vo/MesWmMiscReceiptRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnvendor/MesWmReturnVendorController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnvendor/vo/MesWmReturnVendorRespVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/miscissue/MesWmMiscIssueDO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/miscreceipt/MesWmMiscReceiptDO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnvendor/MesWmReturnVendorDO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMiscIssueStatusEnum.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMiscReceiptStatusEnum.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueServiceImpl.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/listener/MesWmMiscIssueStatusListener.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/MesWmMiscReceiptService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/MesWmMiscReceiptServiceImpl.java 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/listener/MesWmMiscReceiptStatusListener.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorServiceImpl.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/listener/MesWmReturnVendorStatusListener.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/wm_bpm_progress.md
@@ -1,7 +1,7 @@
# WM ä»“储单据 BPM å®¡æ‰¹ + è®¾å¤‡è”动 - å®žæ–½è¿›åº¦
> è®°å½•日期:2026-09-07
> çŠ¶æ€ï¼šé˜¶æ®µ1 åˆ†æžå®Œæˆï¼Œå°šæœªæ”¹ç ï¼›é˜¶æ®µ2/3 å°šæœªå¼€å§‹
> çŠ¶æ€ï¼šé˜¶æ®µ1 æ”¹ç å®Œæˆä¸” MES æ¨¡å—编译通过、数据库字段已补;阶段2 å·²å®Œæˆä»£ç åˆ†æžï¼Œå°šæœªæ”¹ç ï¼›é˜¶æ®µ3 å°šæœªå¼€å§‹
## éœ€æ±‚
@@ -9,7 +9,7 @@
2. è®¾å¤‡ç®¡ç†ï¼ˆè®¾å¤‡å°è´¦ï¼‰åˆ›å»ºæ—¶è‡ªåŠ¨å…¥åº“è®¾å¤‡ä»“ï¼Œä¸Žåº“å­˜è”åŠ¨ã€‚
3. è®¾å¤‡**复用物料主数据模型**(已确认)。
## é˜¶æ®µ1:三大单据补齐 BPM å®¡æ‰¹é—­çޝ â€”— åˆ†æžå®Œæˆï¼Œæœªæ”¹ç 
## é˜¶æ®µ1:三大单据补齐 BPM å®¡æ‰¹é—­çޝ â€”— æ”¹ç å®Œæˆï¼Œç¼–译通过
### å·²ç¡®è®¤çŽ°çŠ¶ï¼ˆå¯ç›´æŽ¥é‡‡ä¿¡ï¼‰
@@ -37,11 +37,42 @@
6. æ–°å¢ž 3 ä¸ªç›‘听器:`MesWmMiscReceiptStatusListener`/`MesWmMiscIssueStatusListener`/`MesWmReturnVendorStatusListener`,分类 `misc_receipt_approve`/`misc_issue_approve`/`return_vendor_approve`。
7. æ•°æ®åº“:三个表各加 `process_instance_id VARCHAR(64)`(遵守 sql-syntax/sql-script è§„范)。
## é˜¶æ®µ2:设备台账联动设备仓(未开始改码)
### å·²å®Œæˆï¼ˆæ”¹ç ï¼‰
- æžšä¸¾ï¼šmiscreceipt/miscissue å·²åŠ  `APPROVING(MesOrderStatusConstants.APPROVING, "审批中")`。
- DO:三个 DO å‡å·²åŠ  `processInstanceId` å­—段。
- RespVO:三个单据 RespVO å‡å·²åŠ  `processInstanceId`。
- Service æŽ¥å£ + Impl:三个单据已加 `submit<Biz>Approval(id, processDefinitionKey)`、`update<Biz>AuditStatus(id, bpmResult)`(APPROVE→APPROVED, REJECT→PREPARE, CANCEL→CANCELED)、`get<Biz>ApprovalProcessDefinitionList()`(复用 `MesWmItemReceipt` æ¨¡å¼ï¼Œè¿‡æ»¤æŒ‚起、取最新版本)。三个新增常量分类:`APPROVE_CATEGORY_CODE = misc_receipt_approve / misc_issue_approve / return_vendor_approve`。
- Controller:三个单据已加 `GET /approval-process-list`;`/submit` æ”¹ä¸ºå¸¦ `processDefinitionKey`,调用审批提交方法。
- ç›‘听器:已新增 `MesWmMiscReceiptStatusListener`、`MesWmMiscIssueStatusListener`、`MesWmReturnVendorStatusListener`,同 `MesWmItemReceiptStatusListener` é£Žæ ¼ã€‚
- ç¼–译:`mvn compile -pl yudao-module-mes -am -q` é€šè¿‡ã€‚
- æ•°æ®åº“(实际运行库 mom-xgdl):
  - `mes_wm_misc_receipt`、`mes_wm_misc_issue` åŽŸå·²æœ‰ `process_instance_id`。
  - `mes_wm_return_vendor` å·²è¡¥ `process_instance_id VARCHAR(64)`(已验证生效)。
### æœªå®Œæˆï¼ˆé˜¶æ®µ1 æ”¶å°¾ï¼‰
- è¾“出前端联调方案文档到 `docs/`。
## é˜¶æ®µ2:设备台账联动设备仓(分析完成,未改码)
- å…³é”®äº‹å®žï¼š`MdmItemApi.createItem(MdmItemCreateReqDTO)` å¯å»ºç‰©æ–™ï¼ˆå¿…å¡« code/name/categoryId/unitMeasureId/itemType);`MesDvMachineryDO` æ—  item_id;内置设备仓 id=5 / åº“区 SYS-EQUIP-LOC-01(id=11) / åº“位 SYS-EQUIP-BIN-01(id=10)。
- æ–¹æ¡ˆï¼š`createMachinery` åŠ äº‹åŠ¡ â†’ å»º MDM ç‰©æ–™ â†’ æ’设备台账(item_id) â†’ è‡ªåŠ¨ç”Ÿæˆæ¡ç  â†’ `MesWmTransactionService` å…¥è®¾å¤‡ä»“(IN, qty=1)。更新/删除/导入路径同步。
### é˜¶æ®µ2 çŽ°çŠ¶ä¸Žåˆ†æžç»“è®ºï¼ˆ2026-09-07 è¡¥å……)
- è®¾å¤‡å°è´¦å·²å®šä½ï¼š`MesDvMachineryServiceImpl.java`(需改入口文件),`createMachinery`/`updateMachinery`/`deleteMachinery` å½“前均**无** `@Transactional`;仅有 `importMachineryList` æœ‰ `@Transactional`。
- çŽ°æœ‰ä¾èµ–ï¼š`machineryMapper`、`barcodeService`(自动生成条码 â†’ `BarcodeBizTypeEnum.MACHINERY`=DV_MACHINERY=400)。
- éœ€è¿½åŠ æ³¨å…¥ï¼š`MdmItemApi`(mes æ¨¡å—已依赖 yudao-module-mdm,且有现成注入先例)、`MesWmTransactionService`。
-`MdmItemCreateReqDTO` å¿…填:code/name/categoryId/unitMeasureId/itemType;可选 warehouseId/warehouseCode/barCode/specification/remark。**无设备专用字段**,设备-物料关联依赖新增 `mes_dv_machinery.item_id` ä¿å­˜è¿”回的 itemId。
- `MdmItemCreateReqDTO` ç¼ºå°‘ categoryId/unitMeasureId/itemType çš„æ¥æºï¼šè®¾å¤‡ SaveReqVO æ²¡æœ‰è¿™äº›å­—段,**需明确默认物料分类、默认计量单位、物料类型(设备)**再实现(横线留待确定)。
- åº“存事务 DTO `MesWmTransactionSaveReqDTO` å¿…填:type(IN=正数)/bizType/bizId/bizCode/bizLineId/itemId/quantity/warehouseId/locationId/areaId。设备台账无独立行 ID,bizLineId ä¸šåŠ¡çº¦å®šç”¨**设备主键 id**。
- è®¾å¤‡ StatusEnum éœ€ç¡®è®¤ï¼ˆè®¾å¤‡çŠ¶æ€å­—æ®µ `status` å·²æœ‰ï¼Œä½†å…¶æžšä¸¾å‘½åä¸Žå–值尚未核对;物料状态由 MDM æŽ§åˆ¶ï¼‰ã€‚
- è®¾å¤‡ç‰©æ–™ç±»åž‹ï¼šå½“前 MDM ç‰©æ–™ç±»åž‹ä¸šåŠ¡æ˜¯å¦å…è®¸è®¾å¤‡ç±»åž‹éœ€ç¡®è®¤ï¼Œè‹¥åªå…è®¸ 1/2/3,则新增正式设备类型值并同步字典(不在 MES å†…部硬编码未知类型)。
- è®¾å¤‡ã€ŒdeleteMachinery」已有点检/保养/维修关联校验,删除库存校验可在库存事务存在性校验处补充。
(阶段2 å°šæœªå¼€å§‹æ”¹ç ï¼‰
## é˜¶æ®µ3:独立设备入库单(未开始)
- æ–°å¢ž `mes_wm_equipment_receipt` ä¸»è¡¨+明细表、DO/Mapper/Service/VO/Controller/枚举/业务常量,BPM é—­çŽ¯ï¼Œå®Œæˆå…¥åº“å†™è®¾å¤‡ä»“ã€‚
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscissue/MesWmMiscIssueController.java
@@ -96,14 +96,23 @@
    }
    @PutMapping("/submit")
    @Operation(summary = "提交杂项出库单")
    @Operation(summary = "提交杂项出库单审批")
    @Parameter(name = "id", description = "编号", required = true)
    @Parameter(name = "processDefinitionKey", description = "流程定义 Key", required = true)
    @PreAuthorize("@ss.hasPermission('mes:wm-misc-issue:update')")
    public CommonResult<Boolean> submitMiscIssue(@RequestParam("id") Long id) {
        miscIssueService.submitMiscIssue(id);
    public CommonResult<Boolean> submitMiscIssue(@RequestParam("id") Long id,
                                                  @RequestParam("processDefinitionKey") String processDefinitionKey) {
        miscIssueService.submitMiscIssueApproval(id, processDefinitionKey);
        return success(true);
    }
    @GetMapping("/approval-process-list")
    @Operation(summary = "获得杂项出库审批流程定义列表")
    @PreAuthorize("@ss.hasPermission('mes:wm-misc-issue:query')")
    public CommonResult<List<java.util.Map<String, Object>>> getApprovalProcessList() {
        return success(miscIssueService.getMiscIssueApprovalProcessDefinitionList());
    }
    @PutMapping("/finish")
    @Operation(summary = "执行出库")
    @Parameter(name = "id", description = "编号", required = true)
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscissue/vo/MesWmMiscIssueRespVO.java
@@ -35,6 +35,9 @@
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
    private Integer status;
    @Schema(description = "BPM æµç¨‹å®žä¾‹ç¼–号", example = "xxx")
    private String processInstanceId;
    @Schema(description = "备注", example = "备注")
    private String remark;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/MesWmMiscReceiptController.java
@@ -77,14 +77,23 @@
    }
    @PutMapping("/submit")
    @Operation(summary = "提交审批")
    @Operation(summary = "提交杂项入库单审批")
    @Parameter(name = "id", description = "编号", required = true)
    @Parameter(name = "processDefinitionKey", description = "流程定义 Key", required = true)
    @PreAuthorize("@ss.hasPermission('mes:wm:misc-receipt:submit')")
    public CommonResult<Boolean> submitMiscReceipt(@RequestParam("id") Long id) {
        miscReceiptService.submitMiscReceipt(id);
    public CommonResult<Boolean> submitMiscReceipt(@RequestParam("id") Long id,
                                                    @RequestParam("processDefinitionKey") String processDefinitionKey) {
        miscReceiptService.submitMiscReceiptApproval(id, processDefinitionKey);
        return success(true);
    }
    @GetMapping("/approval-process-list")
    @Operation(summary = "获得杂项入库审批流程定义列表")
    @PreAuthorize("@ss.hasPermission('mes:wm:misc-receipt:query')")
    public CommonResult<List<java.util.Map<String, Object>>> getApprovalProcessList() {
        return success(miscReceiptService.getMiscReceiptApprovalProcessDefinitionList());
    }
    @PutMapping("/finish")
    @Operation(summary = "执行入库")
    @Parameter(name = "id", description = "编号", required = true)
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/miscreceipt/vo/MesWmMiscReceiptRespVO.java
@@ -35,6 +35,9 @@
    @Schema(description = "状态", example = "0")
    private Integer status;
    @Schema(description = "BPM æµç¨‹å®žä¾‹ç¼–号", example = "xxx")
    private String processInstanceId;
    @Schema(description = "备注", example = "备注")
    private String remark;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnvendor/MesWmReturnVendorController.java
@@ -103,14 +103,23 @@
    }
    @PutMapping("/submit")
    @Operation(summary = "提交供应商退货单")
    @Operation(summary = "提交供应商退货单审批")
    @Parameter(name = "id", description = "编号", required = true)
    @Parameter(name = "processDefinitionKey", description = "流程定义 Key", required = true)
    @PreAuthorize("@ss.hasPermission('mes:wm-return-vendor:update')")
    public CommonResult<Boolean> submitReturnVendor(@RequestParam("id") Long id) {
        returnVendorService.submitReturnVendor(id);
    public CommonResult<Boolean> submitReturnVendor(@RequestParam("id") Long id,
                                                     @RequestParam("processDefinitionKey") String processDefinitionKey) {
        returnVendorService.submitReturnVendorApproval(id, processDefinitionKey);
        return success(true);
    }
    @GetMapping("/approval-process-list")
    @Operation(summary = "获得供应商退货审批流程定义列表")
    @PreAuthorize("@ss.hasPermission('mes:wm-return-vendor:query')")
    public CommonResult<List<java.util.Map<String, Object>>> getApprovalProcessList() {
        return success(returnVendorService.getReturnVendorApprovalProcessDefinitionList());
    }
    @PutMapping("/stock")
    @Operation(summary = "执行拣货")
    @Parameter(name = "id", description = "编号", required = true)
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/returnvendor/vo/MesWmReturnVendorRespVO.java
@@ -48,6 +48,9 @@
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
    private Integer status;
    @Schema(description = "BPM æµç¨‹å®žä¾‹ç¼–号", example = "xxx")
    private String processInstanceId;
    @Schema(description = "备注", example = "备注")
    private String remark;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/miscissue/MesWmMiscIssueDO.java
@@ -68,6 +68,10 @@
     */
    private Integer status;
    /**
     * BPM æµç¨‹å®žä¾‹ç¼–号
     */
    private String processInstanceId;
    /**
     * å¤‡æ³¨
     */
    private String remark;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/miscreceipt/MesWmMiscReceiptDO.java
@@ -68,6 +68,10 @@
     */
    private Integer status;
    /**
     * BPM æµç¨‹å®žä¾‹ç¼–号
     */
    private String processInstanceId;
    /**
     * å¤‡æ³¨
     */
    private String remark;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/returnvendor/MesWmReturnVendorDO.java
@@ -70,6 +70,10 @@
     */
    private Integer status;
    /**
     * BPM æµç¨‹å®žä¾‹ç¼–号
     */
    private String processInstanceId;
    /**
     * å¤‡æ³¨
     */
    private String remark;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMiscIssueStatusEnum.java
@@ -25,9 +25,15 @@
     */
    PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
    /**
     * å®¡æ‰¹ä¸­
     *
     * å¯¹åº” MesWmMiscIssueService#submitMiscIssueApproval æ–¹æ³•
     */
    APPROVING(MesOrderStatusConstants.APPROVING, "审批中"),
    /**
     * å¾…执行出库
     *
     * å¯¹åº” MesWmMiscIssueService#submitMiscIssue æ–¹æ³•
     * å¯¹åº” MesWmMiscIssueService#updateMiscIssueAuditStatus æ–¹æ³•
     */
    APPROVED(MesOrderStatusConstants.APPROVED, "待执行出库"),
    /**
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmMiscReceiptStatusEnum.java
@@ -23,9 +23,15 @@
     */
    PREPARE(MesOrderStatusConstants.PREPARE, "草稿"),
    /**
     * å®¡æ‰¹ä¸­
     *
     * å¯¹åº” MesWmMiscReceiptService#submitMiscReceiptApproval æ–¹æ³•
     */
    APPROVING(MesOrderStatusConstants.APPROVING, "审批中"),
    /**
     * å·²å®¡æ‰¹
     *
     * å¯¹åº” MesWmMiscReceiptService#submitMiscReceipt æ–¹æ³•
     * å¯¹åº” MesWmMiscReceiptService#updateMiscReceiptAuditStatus æ–¹æ³•
     */
    APPROVED(MesOrderStatusConstants.APPROVED, "已审批"),
    /**
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueService.java
@@ -6,10 +6,18 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue.MesWmMiscIssueDO;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
/**
 * MES æ‚项出库单 Service æŽ¥å£
 */
public interface MesWmMiscIssueService {
    /**
     * æ‚项出库 BPM å®¡æ‰¹åˆ†ç±»ç¼–码
     */
    String APPROVE_CATEGORY_CODE = "misc_issue_approve";
    /**
     * åˆ›å»ºæ‚项出库单
@@ -50,11 +58,27 @@
    PageResult<MesWmMiscIssueDO> getMiscIssuePage(MesWmMiscIssuePageReqVO pageReqVO);
    /**
     * æäº¤æ‚项出库单(草稿 â†’ å¾…执行出库)
     * æäº¤æ‚项出库单审批(草稿 â†’ å®¡æ‰¹ä¸­ï¼‰ï¼Œåˆ›å»º BPM æµç¨‹å®žä¾‹
     *
     * @param id ç¼–号
     * @param processDefinitionKey æµç¨‹å®šä¹‰ Key
     */
    void submitMiscIssue(Long id);
    void submitMiscIssueApproval(Long id, String processDefinitionKey);
    /**
     * æ›´æ–°æ‚项出库单审批状态(审批中 â†’ å¾…执行出库/草稿/已取消)
     *
     * @param id ç¼–号
     * @param bpmResult BPM å®¡æ‰¹ç»“æžœ
     */
    void updateMiscIssueAuditStatus(Long id, Integer bpmResult);
    /**
     * èŽ·å–æ‚é¡¹å‡ºåº“å®¡æ‰¹å¯ç”¨çš„ BPM æµç¨‹å®šä¹‰åˆ—表
     *
     * @return æµç¨‹å®šä¹‰åˆ—表(id/key/name)
     */
    List<Map<String, Object>> getMiscIssueApprovalProcessDefinitionList();
    /**
     * æ‰§è¡Œå‡ºåº“(待执行出库 â†’ å·²å®Œæˆï¼‰ï¼Œæ‰£å‡åº“å­˜
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueServiceImpl.java
@@ -15,13 +15,21 @@
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@@ -42,6 +50,10 @@
    private MesWmMiscIssueLineService miscIssueLineService;
    @Resource
    private MesWmTransactionService wmTransactionService;
    @Resource
    private BpmProcessInstanceApi processInstanceApi;
    @Resource
    private BpmProcessDefinitionService bpmProcessDefinitionService;
    @Override
    public Long createMiscIssue(MesWmMiscIssueSaveReqVO createReqVO) {
@@ -91,7 +103,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitMiscIssue(Long id) {
    public void submitMiscIssueApproval(Long id, String processDefinitionKey) {
        // æ ¡éªŒå­˜åœ¨ + è‰ç¨¿çŠ¶æ€
        validateMiscIssueExistsAndDraft(id);
        // æ ¡éªŒè‡³å°‘有一条行
@@ -99,10 +111,87 @@
        if (CollUtil.isEmpty(lines)) {
            throw exception(WM_MISC_ISSUE_NO_LINE);
        }
        // æäº¤ï¼ˆè‰ç¨¿ â†’ å¾…执行出库)
        // åˆ›å»º BPM æµç¨‹å®žä¾‹
        String processInstanceId = processInstanceApi.createProcessInstance(getCurrentUserId(),
                new BpmProcessInstanceCreateReqDTO()
                        .setProcessDefinitionKey(processDefinitionKey)
                        .setBusinessKey(String.valueOf(id)));
        // æäº¤å®¡æ‰¹ï¼ˆè‰ç¨¿ â†’ å®¡æ‰¹ä¸­ï¼‰
        miscIssueMapper.updateById(new MesWmMiscIssueDO()
                .setId(id).setStatus(MesWmMiscIssueStatusEnum.APPROVED.getStatus()));
                .setId(id)
                .setStatus(MesWmMiscIssueStatusEnum.APPROVING.getStatus())
                .setProcessInstanceId(processInstanceId));
    }
    @Override
    public List<Map<String, Object>> getMiscIssueApprovalProcessDefinitionList() {
        return getProcessDefinitionListByCategory(APPROVE_CATEGORY_CODE);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMiscIssueAuditStatus(Long id, Integer bpmResult) {
        // 1. æ ¡éªŒå­˜åœ¨
        MesWmMiscIssueDO issue = validateMiscIssueExists(id);
        if (!MesWmMiscIssueStatusEnum.APPROVING.getStatus().equals(issue.getStatus())) {
            log.warn("[updateMiscIssueAuditStatus] æ‚项出库单({}) ä¸å¤„于审批中状态", id);
            return;
        }
        // 2. æ ¹æ®å®¡æ‰¹ç»“果更新状态
        Integer newStatus = convertBpmResultToStatus(bpmResult);
        if (newStatus != null) {
            miscIssueMapper.updateById(new MesWmMiscIssueDO().setId(id).setStatus(newStatus));
        }
    }
    private Integer convertBpmResultToStatus(Integer bpmResult) {
        if (BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) {
            return MesWmMiscIssueStatusEnum.APPROVED.getStatus();
        }
        if (BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) {
            return MesWmMiscIssueStatusEnum.PREPARE.getStatus();
        }
        if (BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) {
            return MesWmMiscIssueStatusEnum.CANCELED.getStatus();
        }
        return null;
    }
    private List<Map<String, Object>> getProcessDefinitionListByCategory(String categoryCode) {
        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
                .getProcessDefinitionInfoListByCategory(categoryCode);
        if (CollUtil.isEmpty(definitionInfoList)) {
            return Collections.emptyList();
        }
        // è¿‡æ»¤æ¿€æ´»çŠ¶æ€ï¼Œä¿ç•™æœ€æ–°ç‰ˆæœ¬
        Map<String, ProcessDefinition> latestVersionMap = new HashMap<>();
        for (BpmProcessDefinitionInfoDO info : definitionInfoList) {
            ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId());
            if (pd == null || pd.isSuspended()) {
                continue;
            }
            ProcessDefinition existing = latestVersionMap.get(pd.getKey());
            if (existing == null || pd.getVersion() > existing.getVersion()) {
                latestVersionMap.put(pd.getKey(), pd);
            }
        }
        List<Map<String, Object>> result = new ArrayList<>();
        for (ProcessDefinition pd : latestVersionMap.values()) {
            Map<String, Object> item = new HashMap<>();
            item.put("id", pd.getId());
            item.put("key", pd.getKey());
            item.put("name", pd.getName());
            result.add(item);
        }
        return result;
    }
    private Long getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof Long) {
            return (Long) authentication.getPrincipal();
        }
        return 1L; // é»˜è®¤ç”¨æˆ·
    }
    @Override
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/listener/MesWmMiscIssueStatusListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.mes.service.wm.miscissue.listener;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.mes.service.wm.miscissue.MesWmMiscIssueService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
 * æ‚项出库单 BPM å®¡æ‰¹çŠ¶æ€ç›‘å¬å™¨
 *
 * ç›‘听 BPM æµç¨‹å®žä¾‹çŠ¶æ€å˜æ›´äº‹ä»¶ï¼Œæ›´æ–°æ‚é¡¹å‡ºåº“å•çš„å®¡æ‰¹çŠ¶æ€
 */
@Component
@Slf4j
public class MesWmMiscIssueStatusListener
        extends cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener {
    @Resource
    private MesWmMiscIssueService miscIssueService;
    @Override
    protected String getProcessDefinitionKey() {
        return MesWmMiscIssueService.APPROVE_CATEGORY_CODE;
    }
    @Override
    protected void onEvent(BpmProcessInstanceStatusEvent event) {
        Long id;
        try {
            id = Long.parseLong(event.getBusinessKey());
        } catch (NumberFormatException e) {
            log.warn("[onEvent] businessKey({}) ä¸æ˜¯æœ‰æ•ˆçš„æ‚项出库单编号", event.getBusinessKey());
            return;
        }
        log.info("[onEvent] æ”¶åˆ°BPM审批事件,miscIssueId={}, status={}", id, event.getStatus());
        try {
            miscIssueService.updateMiscIssueAuditStatus(id, event.getStatus());
            log.info("[onEvent] æ‚项出库单({}) å®¡æ‰¹çŠ¶æ€æ›´æ–°å®Œæˆ", id);
        } catch (Exception e) {
            log.error("[onEvent] æ›´æ–°æ‚项出库单审批状态失败,miscIssueId={}", id, e);
        }
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/MesWmMiscReceiptService.java
@@ -6,12 +6,20 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscreceipt.MesWmMiscReceiptDO;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
/**
 * MES æ‚项入库单 Service æŽ¥å£
 *
 * @author è¶…级管理员
 */
public interface MesWmMiscReceiptService {
    /**
     * æ‚项入库 BPM å®¡æ‰¹åˆ†ç±»ç¼–码
     */
    String APPROVE_CATEGORY_CODE = "misc_receipt_approve";
    /**
     * åˆ›å»ºæ‚项入库单
@@ -52,11 +60,27 @@
    PageResult<MesWmMiscReceiptDO> getMiscReceiptPage(MesWmMiscReceiptPageReqVO pageReqVO);
    /**
     * æäº¤å®¡æ‰¹ï¼ˆè‰ç¨¿ â†’ å·²å®¡æ‰¹ï¼‰
     * æäº¤æ‚项入库单审批(草稿 â†’ å®¡æ‰¹ä¸­ï¼‰ï¼Œåˆ›å»º BPM æµç¨‹å®žä¾‹
     *
     * @param id ç¼–号
     * @param processDefinitionKey æµç¨‹å®šä¹‰ Key
     */
    void submitMiscReceipt(Long id);
    void submitMiscReceiptApproval(Long id, String processDefinitionKey);
    /**
     * æ›´æ–°æ‚项入库单审批状态(审批中 â†’ å·²å®¡æ‰¹/草稿/已取消)
     *
     * @param id ç¼–号
     * @param bpmResult BPM å®¡æ‰¹ç»“æžœ
     */
    void updateMiscReceiptAuditStatus(Long id, Integer bpmResult);
    /**
     * èŽ·å–æ‚é¡¹å…¥åº“å®¡æ‰¹å¯ç”¨çš„ BPM æµç¨‹å®šä¹‰åˆ—表
     *
     * @return æµç¨‹å®šä¹‰åˆ—表(id/key/name)
     */
    List<Map<String, Object>> getMiscReceiptApprovalProcessDefinitionList();
    /**
     * æ‰§è¡Œå…¥åº“(已审批 â†’ å·²å®Œæˆï¼‰ï¼Œæ›´æ–°åº“存台账
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/MesWmMiscReceiptServiceImpl.java
@@ -14,13 +14,22 @@
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -43,6 +52,10 @@
    private MesWmMiscReceiptLineService miscReceiptLineService;
    @Resource
    private MesWmTransactionService wmTransactionService;
    @Resource
    private BpmProcessInstanceApi processInstanceApi;
    @Resource
    private BpmProcessDefinitionService bpmProcessDefinitionService;
    @Override
    public Long createMiscReceipt(MesWmMiscReceiptSaveReqVO createReqVO) {
@@ -92,7 +105,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitMiscReceipt(Long id) {
    public void submitMiscReceiptApproval(Long id, String processDefinitionKey) {
        // æ ¡éªŒå­˜åœ¨ + è‰ç¨¿çŠ¶æ€
        validateMiscReceiptExistsAndPrepare(id);
        // æ ¡éªŒè‡³å°‘有一条行
@@ -100,10 +113,87 @@
        if (CollUtil.isEmpty(lines)) {
            throw exception(WM_MISC_RECEIPT_NO_LINE);
        }
        // æäº¤å®¡æ‰¹ï¼ˆè‰ç¨¿ â†’ å·²å®¡æ‰¹ï¼‰
        // åˆ›å»º BPM æµç¨‹å®žä¾‹
        String processInstanceId = processInstanceApi.createProcessInstance(getCurrentUserId(),
                new BpmProcessInstanceCreateReqDTO()
                        .setProcessDefinitionKey(processDefinitionKey)
                        .setBusinessKey(String.valueOf(id)));
        // æäº¤å®¡æ‰¹ï¼ˆè‰ç¨¿ â†’ å®¡æ‰¹ä¸­ï¼‰
        miscReceiptMapper.updateById(new MesWmMiscReceiptDO()
                .setId(id).setStatus(MesWmMiscReceiptStatusEnum.APPROVED.getStatus()));
                .setId(id)
                .setStatus(MesWmMiscReceiptStatusEnum.APPROVING.getStatus())
                .setProcessInstanceId(processInstanceId));
    }
    @Override
    public List<Map<String, Object>> getMiscReceiptApprovalProcessDefinitionList() {
        return getProcessDefinitionListByCategory(APPROVE_CATEGORY_CODE);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMiscReceiptAuditStatus(Long id, Integer bpmResult) {
        // 1. æ ¡éªŒå­˜åœ¨
        MesWmMiscReceiptDO receipt = validateMiscReceiptExists(id);
        if (!MesWmMiscReceiptStatusEnum.APPROVING.getStatus().equals(receipt.getStatus())) {
            log.warn("[updateMiscReceiptAuditStatus] æ‚项入库单({}) ä¸å¤„于审批中状态", id);
            return;
        }
        // 2. æ ¹æ®å®¡æ‰¹ç»“果更新状态
        Integer newStatus = convertBpmResultToStatus(bpmResult);
        if (newStatus != null) {
            miscReceiptMapper.updateById(new MesWmMiscReceiptDO().setId(id).setStatus(newStatus));
        }
    }
    private Integer convertBpmResultToStatus(Integer bpmResult) {
        if (BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) {
            return MesWmMiscReceiptStatusEnum.APPROVED.getStatus();
        }
        if (BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) {
            return MesWmMiscReceiptStatusEnum.PREPARE.getStatus();
        }
        if (BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) {
            return MesWmMiscReceiptStatusEnum.CANCELED.getStatus();
        }
        return null;
    }
    private List<Map<String, Object>> getProcessDefinitionListByCategory(String categoryCode) {
        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
                .getProcessDefinitionInfoListByCategory(categoryCode);
        if (CollUtil.isEmpty(definitionInfoList)) {
            return Collections.emptyList();
        }
        // è¿‡æ»¤æ¿€æ´»çŠ¶æ€ï¼Œä¿ç•™æœ€æ–°ç‰ˆæœ¬
        Map<String, ProcessDefinition> latestVersionMap = new HashMap<>();
        for (BpmProcessDefinitionInfoDO info : definitionInfoList) {
            ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId());
            if (pd == null || pd.isSuspended()) {
                continue;
            }
            ProcessDefinition existing = latestVersionMap.get(pd.getKey());
            if (existing == null || pd.getVersion() > existing.getVersion()) {
                latestVersionMap.put(pd.getKey(), pd);
            }
        }
        List<Map<String, Object>> result = new ArrayList<>();
        for (ProcessDefinition pd : latestVersionMap.values()) {
            Map<String, Object> item = new HashMap<>();
            item.put("id", pd.getId());
            item.put("key", pd.getKey());
            item.put("name", pd.getName());
            result.add(item);
        }
        return result;
    }
    private Long getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof Long) {
            return (Long) authentication.getPrincipal();
        }
        return 1L; // é»˜è®¤ç”¨æˆ·
    }
    @Override
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/listener/MesWmMiscReceiptStatusListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.mes.service.wm.miscreceipt.listener;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.mes.service.wm.miscreceipt.MesWmMiscReceiptService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
 * æ‚项入库单 BPM å®¡æ‰¹çŠ¶æ€ç›‘å¬å™¨
 *
 * ç›‘听 BPM æµç¨‹å®žä¾‹çŠ¶æ€å˜æ›´äº‹ä»¶ï¼Œæ›´æ–°æ‚é¡¹å…¥åº“å•çš„å®¡æ‰¹çŠ¶æ€
 */
@Component
@Slf4j
public class MesWmMiscReceiptStatusListener
        extends cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener {
    @Resource
    private MesWmMiscReceiptService miscReceiptService;
    @Override
    protected String getProcessDefinitionKey() {
        return MesWmMiscReceiptService.APPROVE_CATEGORY_CODE;
    }
    @Override
    protected void onEvent(BpmProcessInstanceStatusEvent event) {
        Long id;
        try {
            id = Long.parseLong(event.getBusinessKey());
        } catch (NumberFormatException e) {
            log.warn("[onEvent] businessKey({}) ä¸æ˜¯æœ‰æ•ˆçš„æ‚项入库单编号", event.getBusinessKey());
            return;
        }
        log.info("[onEvent] æ”¶åˆ°BPM审批事件,miscReceiptId={}, status={}", id, event.getStatus());
        try {
            miscReceiptService.updateMiscReceiptAuditStatus(id, event.getStatus());
            log.info("[onEvent] æ‚项入库单({}) å®¡æ‰¹çŠ¶æ€æ›´æ–°å®Œæˆ", id);
        } catch (Exception e) {
            log.error("[onEvent] æ›´æ–°æ‚项入库单审批状态失败,miscReceiptId={}", id, e);
        }
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorService.java
@@ -6,10 +6,18 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorDO;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
/**
 * MES ä¾›åº”商退货单 Service æŽ¥å£
 */
public interface MesWmReturnVendorService {
    /**
     * ä¾›åº”商退货 BPM å®¡æ‰¹åˆ†ç±»ç¼–码
     */
    String APPROVE_CATEGORY_CODE = "return_vendor_approve";
    /**
     * åˆ›å»ºä¾›åº”商退货单
@@ -58,11 +66,27 @@
    MesWmReturnVendorDO validateReturnVendorExists(Long id);
    /**
     * æäº¤ä¾›åº”商退货单(草稿 -> å¾…拣货)
     * æäº¤ä¾›åº”商退货单审批(草稿 -> å®¡æ‰¹ä¸­ï¼‰ï¼Œåˆ›å»º BPM æµç¨‹å®žä¾‹
     *
     * @param id ç¼–号
     * @param processDefinitionKey æµç¨‹å®šä¹‰ Key
     */
    void submitReturnVendor(Long id);
    void submitReturnVendorApproval(Long id, String processDefinitionKey);
    /**
     * æ›´æ–°ä¾›åº”商退货单审批状态(审批中 -> å¾…执行退货/草稿/已取消)
     *
     * @param id ç¼–号
     * @param bpmResult BPM å®¡æ‰¹ç»“æžœ
     */
    void updateReturnVendorAuditStatus(Long id, Integer bpmResult);
    /**
     * èŽ·å–ä¾›åº”å•†é€€è´§å®¡æ‰¹å¯ç”¨çš„ BPM æµç¨‹å®šä¹‰åˆ—表
     *
     * @return æµç¨‹å®šä¹‰åˆ—表(id/key/name)
     */
    List<Map<String, Object>> getReturnVendorApprovalProcessDefinitionList();
    /**
     * æ‰§è¡Œæ‹£è´§ï¼ˆå¾…拣货 -> å¾…执行退货)
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/MesWmReturnVendorServiceImpl.java
@@ -18,13 +18,22 @@
import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.List;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@@ -35,6 +44,7 @@
 */
@Service
@Validated
@Slf4j
public class MesWmReturnVendorServiceImpl implements MesWmReturnVendorService {
    @Resource
@@ -48,6 +58,10 @@
    private SrmSupplierApi srmSupplierApi;
    @Resource
    private MesWmTransactionService wmTransactionService;
    @Resource
    private BpmProcessInstanceApi processInstanceApi;
    @Resource
    private BpmProcessDefinitionService bpmProcessDefinitionService;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -99,7 +113,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitReturnVendor(Long id) {
    public void submitReturnVendorApproval(Long id, String processDefinitionKey) {
        // æ ¡éªŒå­˜åœ¨ + è‰ç¨¿çŠ¶æ€
        validateReturnVendorExistsAndPrepare(id);
        // æ ¡éªŒè‡³å°‘有一条行
@@ -107,10 +121,87 @@
        if (CollUtil.isEmpty(lines)) {
            throw exception(WM_RETURN_VENDOR_NO_LINE);
        }
        // æäº¤ï¼ˆè‰ç¨¿ -> å¾…拣货)
        // åˆ›å»º BPM æµç¨‹å®žä¾‹
        String processInstanceId = processInstanceApi.createProcessInstance(getCurrentUserId(),
                new BpmProcessInstanceCreateReqDTO()
                        .setProcessDefinitionKey(processDefinitionKey)
                        .setBusinessKey(String.valueOf(id)));
        // æäº¤å®¡æ‰¹ï¼ˆè‰ç¨¿ â†’ å®¡æ‰¹ä¸­ï¼‰
        returnVendorMapper.updateById(new MesWmReturnVendorDO()
                .setId(id).setStatus(MesWmReturnVendorStatusEnum.APPROVING.getStatus()));
                .setId(id)
                .setStatus(MesWmReturnVendorStatusEnum.APPROVING.getStatus())
                .setProcessInstanceId(processInstanceId));
    }
    @Override
    public List<Map<String, Object>> getReturnVendorApprovalProcessDefinitionList() {
        return getProcessDefinitionListByCategory(APPROVE_CATEGORY_CODE);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateReturnVendorAuditStatus(Long id, Integer bpmResult) {
        // 1. æ ¡éªŒå­˜åœ¨
        MesWmReturnVendorDO returnVendor = validateReturnVendorExists(id);
        if (!MesWmReturnVendorStatusEnum.APPROVING.getStatus().equals(returnVendor.getStatus())) {
            log.warn("[updateReturnVendorAuditStatus] ä¾›åº”商退货单({}) ä¸å¤„于审批中状态", id);
            return;
        }
        // 2. æ ¹æ®å®¡æ‰¹ç»“果更新状态
        Integer newStatus = convertBpmResultToStatus(bpmResult);
        if (newStatus != null) {
            returnVendorMapper.updateById(new MesWmReturnVendorDO().setId(id).setStatus(newStatus));
        }
    }
    private Integer convertBpmResultToStatus(Integer bpmResult) {
        if (BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) {
            return MesWmReturnVendorStatusEnum.APPROVED.getStatus();
        }
        if (BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) {
            return MesWmReturnVendorStatusEnum.PREPARE.getStatus();
        }
        if (BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) {
            return MesWmReturnVendorStatusEnum.CANCELED.getStatus();
        }
        return null;
    }
    private List<Map<String, Object>> getProcessDefinitionListByCategory(String categoryCode) {
        List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService
                .getProcessDefinitionInfoListByCategory(categoryCode);
        if (CollUtil.isEmpty(definitionInfoList)) {
            return Collections.emptyList();
        }
        // è¿‡æ»¤æ¿€æ´»çŠ¶æ€ï¼Œä¿ç•™æœ€æ–°ç‰ˆæœ¬
        Map<String, ProcessDefinition> latestVersionMap = new HashMap<>();
        for (BpmProcessDefinitionInfoDO info : definitionInfoList) {
            ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId());
            if (pd == null || pd.isSuspended()) {
                continue;
            }
            ProcessDefinition existing = latestVersionMap.get(pd.getKey());
            if (existing == null || pd.getVersion() > existing.getVersion()) {
                latestVersionMap.put(pd.getKey(), pd);
            }
        }
        List<Map<String, Object>> result = new ArrayList<>();
        for (ProcessDefinition pd : latestVersionMap.values()) {
            Map<String, Object> item = new HashMap<>();
            item.put("id", pd.getId());
            item.put("key", pd.getKey());
            item.put("name", pd.getName());
            result.add(item);
        }
        return result;
    }
    private Long getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof Long) {
            return (Long) authentication.getPrincipal();
        }
        return 1L; // é»˜è®¤ç”¨æˆ·
    }
    @Override
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/returnvendor/listener/MesWmReturnVendorStatusListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.mes.service.wm.returnvendor.listener;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.mes.service.wm.returnvendor.MesWmReturnVendorService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
 * ä¾›åº”商退货单 BPM å®¡æ‰¹çŠ¶æ€ç›‘å¬å™¨
 *
 * ç›‘听 BPM æµç¨‹å®žä¾‹çŠ¶æ€å˜æ›´äº‹ä»¶ï¼Œæ›´æ–°ä¾›åº”å•†é€€è´§å•çš„å®¡æ‰¹çŠ¶æ€
 */
@Component
@Slf4j
public class MesWmReturnVendorStatusListener
        extends cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener {
    @Resource
    private MesWmReturnVendorService returnVendorService;
    @Override
    protected String getProcessDefinitionKey() {
        return MesWmReturnVendorService.APPROVE_CATEGORY_CODE;
    }
    @Override
    protected void onEvent(BpmProcessInstanceStatusEvent event) {
        Long id;
        try {
            id = Long.parseLong(event.getBusinessKey());
        } catch (NumberFormatException e) {
            log.warn("[onEvent] businessKey({}) ä¸æ˜¯æœ‰æ•ˆçš„供应商退货单编号", event.getBusinessKey());
            return;
        }
        log.info("[onEvent] æ”¶åˆ°BPM审批事件,returnVendorId={}, status={}", id, event.getStatus());
        try {
            returnVendorService.updateReturnVendorAuditStatus(id, event.getStatus());
            log.info("[onEvent] ä¾›åº”商退货单({}) å®¡æ‰¹çŠ¶æ€æ›´æ–°å®Œæˆ", id);
        } catch (Exception e) {
            log.error("[onEvent] æ›´æ–°ä¾›åº”商退货单审批状态失败,returnVendorId={}", id, e);
        }
    }
}