掌握Salesforce审批流程自动化:Apex代码实战详解

42 阅读4分钟

在Salesforce平台中,审批流程是企业运营的核心功能之一。无论是请假申请、费用报销,还是合同审批,审批流程确保了业务的规范性和可控性。今天,我们将深入探讨如何通过Apex代码实现审批流程的自动化,并解析一个完整的实战示例。

一、为什么需要自动化审批流程?

在现实业务场景中,审批流程往往需要:

  1. 批量处理:同时提交多个记录的审批
  2. 系统集成:与外部系统联动触发审批
  3. 定时任务:在特定时间自动提交审批
  4. 测试环境:自动化测试审批流程逻辑

手动操作无法满足这些需求,这时Apex自动化就变得至关重要。

二、审批流程的核心组件

在深入代码之前,我们先了解几个关键概念:

组件说明类比
Approval.ProcessSubmitRequest提交审批请求的对象相当于填写申请表
Approval.ProcessWorkitemRequest处理待审批项的对象相当于审批人做决策
ProcessResult操作结果对象返回操作成功与否
Workitem待办审批任务审批人收件箱中的任务

三、完整代码示例解析

让我们逐段分析这个经典的审批流程自动化示例:

1. 创建记录并提交审批

// 1. 创建测试账户
Account a = new Account(Name='Test', annualRevenue=100.0);
insert a;

// 2. 构建提交请求
Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
req1.setComments('提交审批申请');  // 添加说明
req1.setObjectId(a.id);           // 设置要审批的记录
req1.setSubmitterId(user1.Id);    // 指定提交人
req1.setProcessDefinitionNameOrId('PTO_Request_Process'); // 指定流程
req1.setSkipEntryCriteria(true);  // 跳过进入条件

// 3. 执行提交
Approval.ProcessResult result = Approval.process(req1);

关键点说明:

  • setSkipEntryCriteria(true):在测试时特别有用,可以绕过审批流程的进入条件,确保记录能被提交
  • ProcessDefinitionNameOrId:必须与配置的审批流程名称完全匹配

2. 获取并处理待审批项

// 4. 获取新创建的待办项ID
List<Id> newWorkItemIds = result.getNewWorkitemIds();

// 5. 构建处理请求
Approval.ProcessWorkitemRequest req2 = new Approval.ProcessWorkitemRequest();
req2.setComments('批准通过');      // 审批意见
req2.setAction('Approve');         // 操作类型
req2.setNextApproverIds(new Id[] {UserInfo.getUserId()}); // 下一审批人 不填默认走Approval Process配置的审批人
req2.setWorkitemId(newWorkItemIds.get(0)); // 指定待办项

// 6. 执行批准
Approval.ProcessResult result2 = Approval.process(req2);

操作类型选项:

  • Approve:批准
  • Reject:拒绝
  • Removed:移除
  • Reassign:重新分配

四、实际业务场景应用

场景一:自动化的费用报销流程

public class ExpenseApprovalAutomation {
    
    public static void submitExpenseForApproval(Id expenseReportId, Id submitterId) {
        // 验证记录状态
        Expense_Report__c report = [
            SELECT Id, Status__c, Total_Amount__c 
            FROM Expense_Report__c 
            WHERE Id = :expenseReportId
        ];
        
        // 只有草稿状态且金额大于1000才需要审批
        if (report.Status__c == 'Draft' && report.Total_Amount__c > 1000) {
            Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
            req.setObjectId(expenseReportId);
            req.setSubmitterId(submitterId);
            req.setProcessDefinitionNameOrId('Expense_Approval_Process');
            
            try {
                Approval.ProcessResult result = Approval.process(req);
                if (result.isSuccess()) {
                    System.debug('费用报销单已成功提交审批');
                }
            } catch(Exception e) {
                System.debug('提交审批失败: ' + e.getMessage());
            }
        }
    }
}

场景二:批量审批处理

public class BatchApprovalProcessor {
    
    public static void approveMultipleRequests(List<Id> workItemIds) {
        List<Approval.ProcessWorkitemRequest> requests = new List<Approval.ProcessWorkitemRequest>();
        
        for (Id workItemId : workItemIds) {
            Approval.ProcessWorkitemRequest req = new Approval.ProcessWorkitemRequest();
            req.setWorkitemId(workItemId);
            req.setAction('Approve');
            req.setComments('系统自动批准 - 符合快速审批条件');
            requests.add(req);
        }
        
        // 批量处理所有审批请求
        List<Approval.ProcessResult> results = Approval.process(requests);
        
        // 记录处理结果
        for (Integer i = 0; i < results.size(); i++) {
            if (!results[i].isSuccess()) {
                System.debug('审批失败,工作项ID: ' + workItemIds[i]);
            }
        }
    }
}

五、高级技巧与最佳实践

1. 动态选择审批流程

// 根据金额选择不同的审批流程
public static String determineApprovalProcess(Decimal amount) {
    if (amount <= 1000) return 'Quick_Approval_Process';
    if (amount <= 5000) return 'Standard_Approval_Process';
    return 'Executive_Approval_Process';
}

2. 错误处理与重试机制

public static ProcessResult submitWithRetry(Approval.ProcessSubmitRequest req, Integer maxRetries) {
    Integer retryCount = 0;
    while (retryCount < maxRetries) {
        try {
            return Approval.process(req);
        } catch(Exception e) {
            retryCount++;
            if (retryCount == maxRetries) {
                throw e; // 达到重试上限
            }
            // 等待后重试
            Integer delay = 1000 * retryCount; // 递增延迟
            Long now = DateTime.now().getTime();
            while (DateTime.now().getTime() < now + delay) {
                // 等待
            }
        }
    }
    return null;
}

3. 审批状态监控

public static void monitorApprovalStatus(Id recordId) {
    // 查询审批过程实例
    ProcessInstance instance = [
        SELECT Id, Status, (SELECT Id, ActorId, Comments 
                           FROM ProcessInstanceSteps 
                           ORDER BY CreatedDate DESC)
        FROM ProcessInstance 
        WHERE TargetObjectId = :recordId 
        ORDER BY CreatedDate DESC 
        LIMIT 1
    ];
    
    // 记录审批历史
    for (ProcessInstanceStep history : instance.ProcessInstanceSteps) {
        System.debug('审批步骤: ' + history.StepStatus + 
                    ', 处理人: ' + history.ActorId + 
                    ', 意见: ' + history.Comments);
    }
}

六、常见问题与解决方案

Q1: setSkipEntryCriteria(true) 在生产环境使用安全吗?

A:  不建议在生产环境使用。这个参数主要用于测试。在生产环境,应该确保记录自然满足审批流程的进入条件。

Q2: 如何获取用户的待审批项?

// 查询当前用户的待审批项
List<ProcessInstanceWorkitem> workItems = [
    SELECT Id, ProcessInstance.TargetObjectId, ProcessInstance.Status
    FROM ProcessInstanceWorkitem 
    WHERE ActorId = :UserInfo.getUserId()
];

Q3: 审批被拒绝后如何重新提交?

public static void recallAndResubmit(Id recordId) {
    // 1. 先召回
    ProcessInstanceWorkitem workItem = [
        SELECT Id FROM ProcessInstanceWorkitem 
        WHERE ProcessInstance.TargetObjectId = :recordId 
        LIMIT 1
    ];
    
    Approval.ProcessWorkitemRequest recallReq = new Approval.ProcessWorkitemRequest();
    recallReq.setWorkitemId(workItem.Id);
    recallReq.setAction('Removed');
    Approval.process(recallReq);
    
    // 2. 修改记录后重新提交
    // ... 修改记录逻辑
    // ... 重新提交审批
}

总结

Salesforce的审批流程自动化是一个强大而灵活的功能,通过Apex代码,我们可以实现高度定制化的审批逻辑。无论是简单的单步审批,还是复杂的多级动态审批,Apex都提供了完整的API支持。

关键要点:

  • 理解审批流程的生命周期
  • 合理使用提交和处理API
  • 在生产环境避免跳过进入条件
  • 实现完善的错误处理和日志记录

掌握这些技能后,你将能够构建出既符合业务需求,又具备良好用户体验的审批系统。