Просмотр исходного кода

流程状态为审批中,但是节点状态为已同意

huanglc 1 месяц назад
Родитель
Сommit
45ec575fb8

+ 259 - 7
bpm-core/src/main/java/com/srm/bpm/logic/service/impl/BillBpmnLogicImpl.java

@@ -38,16 +38,13 @@ import com.srm.bpm.logic.dto.UserInfoDTO;
38 38
 import com.srm.bpm.logic.dto.UserOrgDTO;
39 39
 import com.srm.bpm.logic.dto.UserPositionDTO;
40 40
 import com.srm.bpm.logic.error.BillCode;
41
-import com.srm.bpm.logic.service.BillBpmnLogic;
42
-import com.srm.bpm.logic.service.BillItemLogic;
43
-import com.srm.bpm.logic.service.CallBackLogic;
44
-import com.srm.bpm.logic.service.FlowMsgLogic;
45
-import com.srm.bpm.logic.service.UserCenterlogic;
41
+import com.srm.bpm.logic.service.*;
46 42
 import com.srm.bpm.logic.vo.FormPermissionVO;
47 43
 import com.srm.bpm.logic.constant.FormConst;
48 44
 import com.srm.common.data.exception.RbException;
49 45
 import com.srm.common.util.datetime.DateTimeUtil;
50 46
 
47
+import com.srm.config.SpringContextHolder;
51 48
 import org.activiti.bpmn.model.BpmnModel;
52 49
 import org.activiti.bpmn.model.FlowElement;
53 50
 import org.activiti.bpmn.model.FlowNode;
@@ -484,7 +481,7 @@ public class BillBpmnLogicImpl implements BillBpmnLogic {
484 481
 //        if (task == null) {
485 482
 //            throw new RbException(BillCode.TASK_NOT_FOUND);
486 483
 //        }
487
-        Map<String, Object> variables = Maps.newHashMap();
484
+        /*Map<String, Object> variables = Maps.newHashMap();
488 485
         variables.put(BpmnConst.VAR_OPINION, opinion);
489 486
         variables.put(BpmnConst.VAR_APPROVER_EMPLOYEE, userCode);
490 487
         variables.put(BpmnConst.VAR_ACTION, BillAction.agree.name());
@@ -493,10 +490,265 @@ public class BillBpmnLogicImpl implements BillBpmnLogic {
493 490
         variables.put(BpmnConst.VAR_LAST_TASK_ID, lastTaskId);
494 491
         variables.put(BpmnConst.VAR_AGREE_DATA, JSON.parseObject(formData, Map.class));
495 492
         taskService.complete(taskId, variables);
496
-        return true;
493
+        return true;*/
494
+
495
+        // 先检查运行时任务是否存在
496
+        final Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
497
+        if (task == null) {
498
+            // 检查历史任务,看是否已经完成
499
+            final org.activiti.engine.history.HistoricTaskInstance historicTask = historyService
500
+                    .createHistoricTaskInstanceQuery()
501
+                    .taskId(taskId)
502
+                    .singleResult();
503
+            if (historicTask != null) {
504
+                log.warn("任务已经完成,跳过完成操作。taskId: {}, billId: {}, 完成时间: {}",
505
+                        taskId, bill != null ? bill.getId() : null, historicTask.getEndTime());
506
+                // 检查归档条件并触发回调
507
+                checkAndTriggerArchiveCallback(bill, taskId);
508
+                // 检查流程是否应该结束
509
+                checkAndCompleteBillIfNeeded(bill);
510
+                return true;
511
+            } else {
512
+                log.warn("Activiti任务不存在,可能已经被删除。taskId: {}, billId: {},跳过完成操作。业务数据已更新。",
513
+                        taskId, bill != null ? bill.getId() : null);
514
+                // 检查归档条件并触发回调
515
+                checkAndTriggerArchiveCallback(bill, taskId);
516
+                // 检查流程是否应该结束
517
+                checkAndCompleteBillIfNeeded(bill);
518
+                return true; // 业务数据已更新,返回成功
519
+            }
520
+        }
521
+
522
+        Map<String, Object> variables = Maps.newHashMap();
523
+        variables.put(BpmnConst.VAR_OPINION, opinion);
524
+        variables.put(BpmnConst.VAR_APPROVER_EMPLOYEE, userCode);
525
+        variables.put(BpmnConst.VAR_ACTION, BillAction.agree.name());
526
+        variables.put(BpmnConst.VAR_NEXT_APPROVER, nextApprover);
527
+        variables.put(BpmnConst.VAR_LAST_NODE_KEY, lastTaskNodeId);
528
+        variables.put(BpmnConst.VAR_LAST_TASK_ID, lastTaskId);
529
+        // 安全处理 formData,避免空值或 null 导致解析失败
530
+        if (!Strings.isNullOrEmpty(formData) && !"null".equals(formData) && !"{}".equals(formData)) {
531
+            try {
532
+                variables.put(BpmnConst.VAR_AGREE_DATA, JSON.parseObject(formData, Map.class));
533
+            } catch (Exception e) {
534
+                log.warn("解析 formData 失败,使用空 Map。billId: {}, taskId: {}, formData: {}", 
535
+                        bill != null ? bill.getId() : null, taskId, formData);
536
+                variables.put(BpmnConst.VAR_AGREE_DATA, Maps.newHashMap());
537
+            }
538
+        } else {
539
+            variables.put(BpmnConst.VAR_AGREE_DATA, Maps.newHashMap());
540
+        }
541
+
542
+        try {
543
+            taskService.complete(taskId, variables);
544
+
545
+            // 任务完成后,先检查归档条件并触发回调
546
+            checkAndTriggerArchiveCallback(bill, taskId);
547
+
548
+            // 任务完成后,立即检查流程是否结束,如果结束则触发回调
549
+            if (bill != null && bill.getId() != null) {
550
+                final String processInstanceId = bill.getProcessInstanceId();
551
+                if (!Strings.isNullOrEmpty(processInstanceId)) {
552
+                    // 先检查运行时流程实例是否还有待办任务
553
+                    final List<Task> activeTasks = taskService.createTaskQuery()
554
+                            .processInstanceId(processInstanceId)
555
+                            .active()
556
+                            .list();
557
+
558
+                    // 如果没有待办任务,检查流程是否已结束
559
+                    if (CollectionUtil.isEmpty(activeTasks)) {
560
+                        // 检查历史流程实例是否已结束
561
+                        final org.activiti.engine.history.HistoricProcessInstance historicProcessInstance = historyService
562
+                                .createHistoricProcessInstanceQuery()
563
+                                .processInstanceId(processInstanceId)
564
+                                .singleResult();
565
+
566
+                        if (historicProcessInstance != null && historicProcessInstance.getEndTime() != null) {
567
+                            // 流程已结束,立即触发完成逻辑和回调
568
+                            log.info("任务完成后,检测到流程已结束(没有待办任务且历史流程实例已结束)。立即触发审批单完成逻辑和回调。billId: {}, taskId: {}",
569
+                                    bill.getId(), taskId);
570
+                            triggerBillCompleteCallback(bill);
571
+                            return true;
572
+                        }
573
+                    }
574
+                }
575
+            }
576
+
577
+            // 如果流程未结束,检查是否应该结束(用于处理没有Activiti任务但业务任务已完成的情况)
578
+            checkAndCompleteBillIfNeeded(bill);
579
+            return true;
580
+        } catch (org.activiti.engine.ActivitiObjectNotFoundException e) {
581
+            log.warn("完成Activiti任务时发生异常,任务可能已被删除。taskId: {}, billId: {}, 错误: {}",
582
+                    taskId, bill != null ? bill.getId() : null, e.getMessage());
583
+            // 检查归档条件并触发回调
584
+            checkAndTriggerArchiveCallback(bill, taskId);
585
+            // 业务数据已更新,检查流程是否应该结束
586
+            checkAndCompleteBillIfNeeded(bill);
587
+            return true;
588
+        }
589
+
497 590
     }
498 591
 
499 592
     /**
593
+     * 检查归档条件并触发回调
594
+     * 如果 toa_bill 的 status 为 1(审批中)且 bill_task 的最后一个节点审批状态为 2(已同意),则触发回调
595
+     *
596
+     * @param bill 审批单实体
597
+     * @param taskId 任务ID
598
+     */
599
+    private void checkAndTriggerArchiveCallback(ToaBillEntity bill, String taskId) {
600
+        if (bill == null || bill.getId() == null) {
601
+            return;
602
+        }
603
+
604
+        try {
605
+            // 重新查询最新的bill数据,确保使用最新状态
606
+            final ToaBillEntity latestBill = billService.getById(bill.getId());
607
+            if (latestBill == null) {
608
+                return;
609
+            }
610
+
611
+            // 检查 toa_bill 的 status 是否为 1(审批中)
612
+            if (latestBill.getStatus() != BillStatus.APPROVAL.getStatus()) {
613
+                return;
614
+            }
615
+
616
+            // 查找最后一个节点的 bill_task,按 sort 降序排列取第一个
617
+            final List<BillTaskEntity> billTasks = billTaskService.list(
618
+                    com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery(BillTaskEntity.class)
619
+                            .eq(BillTaskEntity::getBillId, latestBill.getId())
620
+                            .eq(BillTaskEntity::getIsDeleted, 0)
621
+                            .orderByDesc(BillTaskEntity::getSort)
622
+                            .last("LIMIT 1")
623
+            );
624
+
625
+            if (CollectionUtil.isEmpty(billTasks)) {
626
+                return;
627
+            }
628
+
629
+            final BillTaskEntity lastTask = billTasks.get(0);
630
+
631
+            // 检查最后一个节点的审批状态是否为 2(已同意)
632
+            if (lastTask.getNodeStatus() == BillTaskStatus.AGREE.getStatus()) {
633
+                // 检查最后一个任务是否是归档节点
634
+                final Long processId = latestBill.getProcessId();
635
+                if (processId != null && !Strings.isNullOrEmpty(lastTask.getTaskNodeKey())) {
636
+                    final Optional<ProcessNodeExtendEntity> nodeExtendOpt = nodeExtendService
637
+                            .findByNodeIdAndProcessId(processId, lastTask.getTaskNodeKey());
638
+
639
+                    if (nodeExtendOpt.isPresent()) {
640
+                        final ProcessNodeExtendEntity nodeExtend = nodeExtendOpt.get();
641
+                        final String linkType = nodeExtend.getLinkType();
642
+
643
+                        // 如果是归档节点,触发回调
644
+                        if (NodeLinkType.archive.name().equals(linkType)) {
645
+                            log.info("检测到归档节点且满足条件:toa_bill status=1(审批中),最后一个节点 status=2(已同意)。触发回调。billId: {}, taskId: {}, lastTaskNodeKey: {}",
646
+                                    latestBill.getId(), taskId, lastTask.getTaskNodeKey());
647
+                            triggerBillCompleteCallback(latestBill);
648
+                        }
649
+                    }
650
+                }
651
+            }
652
+        } catch (Exception e) {
653
+            log.error("检查归档条件并触发回调时发生异常。billId: {}, taskId: {}, 错误: {}",
654
+                    bill != null ? bill.getId() : null, taskId, e.getMessage(), e);
655
+        }
656
+    }
657
+
658
+    /**
659
+     * 触发审批单完成逻辑和回调
660
+     *
661
+     * @param bill 审批单实体
662
+     */
663
+    private void triggerBillCompleteCallback(ToaBillEntity bill) {
664
+        if (bill == null || bill.getId() == null) {
665
+            return;
666
+        }
667
+
668
+        try {
669
+            log.info("触发审批单完成逻辑和回调。billId: {}", bill.getId());
670
+            final BillLogic billLogic = SpringContextHolder.getBean(BillLogic.class);
671
+            // 重新查询最新的bill数据,确保使用最新状态
672
+            final ToaBillEntity latestBill = billService.getById(bill.getId());
673
+            if (latestBill != null && latestBill.getStatus() != BillStatus.COMPLETE.getStatus()) {
674
+                billLogic.complete(latestBill, BillAction.agree.name());
675
+                log.info("已成功触发审批单完成逻辑和回调。billId: {}", bill.getId());
676
+            } else if (latestBill != null && latestBill.getStatus() == BillStatus.COMPLETE.getStatus()) {
677
+                log.debug("审批单已完成,无需再次触发。billId: {}", bill.getId());
678
+            }
679
+        } catch (Exception e) {
680
+            log.error("触发审批单完成逻辑和回调时发生异常。billId: {}, 错误: {}", bill.getId(), e.getMessage(), e);
681
+        }
682
+    }
683
+
684
+    /**
685
+     * 检查审批单是否应该完成,如果是最后一个节点且没有待审批任务,则完成审批单
686
+     * 
687
+     * @param bill 审批单实体
688
+     */
689
+    public void checkAndCompleteBillIfNeeded(ToaBillEntity bill) {
690
+        if (bill == null || bill.getId() == null) {
691
+            return;
692
+        }
693
+        
694
+        try {
695
+            // 先检查是否有待审批的bill_task
696
+            final List<BillTaskEntity> approvalTasks = billTaskService.list(
697
+                    com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery(BillTaskEntity.class)
698
+                            .eq(BillTaskEntity::getBillId, bill.getId())
699
+                            .eq(BillTaskEntity::getNodeStatus, BillTaskStatus.APPROVAL.getStatus())
700
+                            .eq(BillTaskEntity::getIsDeleted, 0)
701
+            );
702
+            
703
+            // 如果没有待审批任务,说明所有任务都已完成
704
+            if (CollectionUtil.isEmpty(approvalTasks)) {
705
+                // 检查流程实例状态
706
+                final String processInstanceId = bill.getProcessInstanceId();
707
+                boolean shouldComplete = false;
708
+                
709
+                if (!Strings.isNullOrEmpty(processInstanceId)) {
710
+                    // 检查运行时流程实例是否还有待办任务
711
+                    final List<Task> activeTasks = taskService.createTaskQuery()
712
+                            .processInstanceId(processInstanceId)
713
+                            .active()
714
+                            .list();
715
+                    
716
+                    if (CollectionUtil.isEmpty(activeTasks)) {
717
+                        // 没有运行时待办任务,检查历史流程实例是否已结束
718
+                        final org.activiti.engine.history.HistoricProcessInstance historicProcessInstance = historyService
719
+                                .createHistoricProcessInstanceQuery()
720
+                                .processInstanceId(processInstanceId)
721
+                                .singleResult();
722
+                        
723
+                        if (historicProcessInstance != null && historicProcessInstance.getEndTime() != null) {
724
+                            // 流程已结束
725
+                            log.info("流程实例已结束,但审批单状态未更新。billId: {}, processInstanceId: {}", bill.getId(), processInstanceId);
726
+                            shouldComplete = true;
727
+                        } else {
728
+                            // 流程实例不存在或未结束,但也没有待办任务和待审批任务,应该完成
729
+                            log.info("没有待办任务和待审批任务,流程应该结束。billId: {}, processInstanceId: {}", bill.getId(), processInstanceId);
730
+                            shouldComplete = true;
731
+                        }
732
+                    }
733
+                } else {
734
+                    // 流程实例ID为空,但所有bill_task都已完成,应该完成审批单
735
+                    log.info("流程实例ID为空,但所有任务都已完成,应该完成审批单。billId: {}", bill.getId());
736
+                    shouldComplete = true;
737
+                }
738
+                
739
+                if (shouldComplete && bill.getStatus() != BillStatus.COMPLETE.getStatus()) {
740
+                    // 审批单状态不是完成,需要触发完成逻辑和回调
741
+                    log.info("检测到流程应该结束,但审批单状态未更新。手动触发审批单完成逻辑和回调。billId: {}, 当前状态: {}", 
742
+                            bill.getId(), bill.getStatus());
743
+                    triggerBillCompleteCallback(bill);
744
+                }
745
+            }
746
+        } catch (Exception e) {
747
+            log.error("检查审批单完成状态时发生异常。billId: {}, 错误: {}", bill.getId(), e.getMessage(), e);
748
+        }
749
+    }
750
+    
751
+    /**
500 752
      * 审批拒绝接口
501 753
      *
502 754
      * @param taskId   审批任务

+ 55 - 1
bpm-core/src/main/java/com/srm/bpm/logic/service/impl/BillNextNodeLogicImpl.java

@@ -179,11 +179,65 @@ public class BillNextNodeLogicImpl implements BillNextNodeLogic {
179 179
         // 构建流程变量
180 180
         final BpmnBillContext bpmnBillContext = billBpmnLogic.createBpmnContext(employeeId, billDataValue);
181 181
         final String nodeKey = billTask.getTaskNodeKey();
182
-        final Task task = taskService.createTaskQuery().taskDefinitionKey(nodeKey).processInstanceId(processInstanceId).singleResult();
182
+/*        final Task task = taskService.createTaskQuery().taskDefinitionKey(nodeKey).processInstanceId(processInstanceId).singleResult();
183 183
         final BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
184 184
         final List<Process> processes = bpmnModel.getProcesses();
185 185
         final Process process = processes.get(0);
186
+        final FlowElement flowElement = process.getFlowElement(nodeKey);*/
187
+        if (Strings.isNullOrEmpty(nodeKey)) {
188
+            log.error("任务节点标识为空,billTaskId: {}", billTask.getId());
189
+            return Pair.of(0, StrUtil.EMPTY);
190
+        }
191
+
192
+        // 先尝试从运行时任务获取流程定义ID
193
+        String processDefinitionId = null;
194
+        final Task task = taskService.createTaskQuery().taskDefinitionKey(nodeKey).processInstanceId(processInstanceId).singleResult();
195
+        if (task != null) {
196
+            processDefinitionId = task.getProcessDefinitionId();
197
+            log.debug("从运行时任务获取流程定义ID: {}", processDefinitionId);
198
+        } else {
199
+            log.warn("未找到对应的Activiti运行时任务,taskId: {}, nodeKey: {}, processInstanceId: {},尝试从流程定义获取", taskId, nodeKey, processInstanceId);
200
+            // 如果任务不存在,从流程定义获取
201
+            if (!Strings.isNullOrEmpty(processDetailDTO.getFlowId())) {
202
+                final ProcessDefinition processDefinition = findLastVersionByFlowId(processDetailDTO.getFlowId());
203
+                if (processDefinition != null) {
204
+                    processDefinitionId = processDefinition.getId();
205
+                    log.debug("从流程定义获取流程定义ID: {}", processDefinitionId);
206
+                } else {
207
+                    log.error("未找到流程定义,flowId: {}", processDetailDTO.getFlowId());
208
+                    return Pair.of(0, StrUtil.EMPTY);
209
+                }
210
+            } else {
211
+                log.error("流程FlowId为空,无法获取流程定义");
212
+                return Pair.of(0, StrUtil.EMPTY);
213
+            }
214
+        }
215
+
216
+        if (Strings.isNullOrEmpty(processDefinitionId)) {
217
+            log.error("流程定义ID为空,无法获取BPMN模型");
218
+            return Pair.of(0, StrUtil.EMPTY);
219
+        }
220
+
221
+        final BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
222
+        if (bpmnModel == null) {
223
+            log.error("未找到对应的BPMN模型,processDefinitionId: {}", processDefinitionId);
224
+            return Pair.of(0, StrUtil.EMPTY);
225
+        }
226
+        final List<Process> processes = bpmnModel.getProcesses();
227
+        if (CollectionUtil.isEmpty(processes)) {
228
+            log.error("BPMN模型中未找到流程定义,processDefinitionId: {}", processDefinitionId);
229
+            return Pair.of(0, StrUtil.EMPTY);
230
+        }
231
+        final Process process = processes.get(0);
232
+        if (process == null) {
233
+            log.error("流程定义对象为空,processDefinitionId: {}", processDefinitionId);
234
+            return Pair.of(0, StrUtil.EMPTY);
235
+        }
186 236
         final FlowElement flowElement = process.getFlowElement(nodeKey);
237
+        if (flowElement == null) {
238
+            log.error("未找到对应的流程节点,nodeKey: {}, processDefinitionId: {}", nodeKey, processDefinitionId);
239
+            return Pair.of(0, StrUtil.EMPTY);
240
+        }
187 241
         return getCorrespondConnection(flowElement, formDataMap, bpmnBillContext);
188 242
     }
189 243