项目中,审批操作无处不在。配置审批流时,我们有时候会用到queue,related user设置当前步骤的审批人,审批人可以一个或者多个。当审批人有多个时,邮件中获取当前记录的审批人和审批意见就不能随便的取一个审批人了,有以下方式针对不同的场景可以获取到当前记录的最终审批人以及审批意见。

邮件内容使用以下几种方式实现:

  1.代码里面实现邮件发送

  2.email template(text/html/custom)

  3.visualforce emailTemplate

对发送邮件方式不清楚的,可以参看:salesforce 零基础学习(六十七)SingleEmailMessage 那点事

为方便查看效果,设置一下场景:针对Account更新操作,如果Account中Type进行了改变,提交一个更新申请的审批流程,如果审批流程在审批过程中,再次更改Type则提示有审批中的记录,不允许再次修改。审批通过或者失败则发送给创建人。邮件内容包括最终审批人以及审批意见。

准备工作

1.在Account上新增两个字段 Type New用来记录新更改的Type值,Type更改以后是不直接回写的,只有审批通过以后才能回写,Update Status用来记录审批状态

2.增加Account上的validation rule,避免已经有修改申请单情况下重复更改Type

3.增加申请单表以及相关的字段

4.增加审批流以及审批人对应的Queue,当Status是Pending Approval时,进入审批流,审批通过或者拒绝更新状态

5.配置Account以及Main_Info_Update__c的trigger,实现相关的赋值以及自动进入审批流操作

AccountTrigger:实现更新前对关键字段赋值以及更新后的创建更新申请数据以及自动提交审批流

 trigger AccountTrigger on Account(before update,after update) {

     if(Trigger.isBefore) {
if(Trigger.isUpdate) {
for(Account acc : trigger.new) {
String oldType = trigger.oldMap.get(acc.Id).Type;
System.debug(LoggingLevel.INFO, '*** acc.Update_Status__c: ' + acc.Update_Status__c);
if(acc.Update_Status__c <> 'Pending Approval') {
if(acc.Type <> oldType) {
//将Account的Type_New__c赋值,Account的值回滚到以前的值
acc.Type_New__c = acc.Type;
acc.Type = oldType;
acc.Update_Status__c = 'Pending Approval';
}
} else {
//TODO
//add error or do something
}
}
}
} if(Trigger.isAfter) {
if(Trigger.isUpdate) {
List<Main_Information_Update__c> updateList = new List<Main_Information_Update__c>();
for(Account acc : trigger.new) {
if(acc.Type_New__c <> null) {
Main_Information_Update__c updateItem = new Main_Information_Update__c();
updateItem.Type__c = acc.Type_New__c;
updateItem.Type_Old__c = acc.Type;
updateItem.Update_Status__c = 'Pending Approval';
updateItem.Account__c = acc.Id;
updateList.add(updateItem);
}
} //插入数据并提交到审批流
if(updateList.size() > 0) {
insert updateList;
List< Approval.ProcessSubmitRequest> requestList = new List< Approval.ProcessSubmitRequest>();
for(Main_Information_Update__c item : updateList) {
Approval.ProcessSubmitRequest request = new Approval.ProcessSubmitRequest();
request.setObjectId(item.Id);
requestList.add(request);
//List<Approval.ProcessResult> requestResultList = Approval.process(requestList,false); //TODO
//对于提交审批流失败的数据处理,
}
Approval.process(requestList);
}
}
} }

MainInformationUpdateTrigger:实现审批通过回写Account以及发送邮件操作

 trigger MainInformationUpdateTrigger on Main_Information_Update__c (after update) {
if(Trigger.isAfter) {
if(Trigger.isUpdate) {
List<Account> updateAccountList = new List<Account>();
//记录哪些需要发送邮件
Map<Id,Main_Information_Update__c> mainId2ObjMap = new Map<Id,Main_Information_Update__c>();
for(Main_Information_Update__c updateItem : Trigger.new) {
if(updateItem.Update_Status__c == 'Approved' || updateItem.Update_Status__c == 'Rejected') {
Account acc = new Account();
acc.Id = updateItem.Account__c;
acc.Type_New__c = null;
//acc.Update_Status__c = updateItem.Update_Status__c;
acc.Update_Status__c = null;
updateAccountList.add(acc);
mainId2ObjMap.put(updateItem.Id, updateItem);
}
} if(updateAccountList.size() > 0) {
//TODO
//try catch处理
update updateAccountList; //发送邮件
for(Id mainId : mainId2ObjMap.keySet()) {
if(mainId2ObjMap.get(mainId).Update_Status__c == 'Approved') {
EmailUtil.sendEmail('Approved', mainId2ObjMap.get(mainId));
} else {
EmailUtil.sendEmail('Rejected', mainId2ObjMap.get(mainId));
} }
}
}
}
}

至此准备工作结束,下面是几种方式寻找审批人

一.在代码里面处理邮件功能(不使用email template)

email template可以配置,更加利于维护,但是有时需要在email template进行相关的特殊操作,比如某些计算,汇总以及日期格式转换等操作是email template(text/html/custom)无法搞定的功能,所以有时候需要在代码里面写邮件的body部分。通过代码获取。通过代码获取审批人以及审批意见主要需要ProcessInstance以及ProcessInstanceStep两个表。具体实现如下:

 public without sharing class EmailUtil {

     //获取审批意见,审批人,以及其他简单信息
public static String getAccountUpdateAprovedEmailBody(Main_Information_Update__c updateItem) {
String returnBody = ''; ProcessInstance processResult = [SELECT Id,
(SELECT StepStatus, Comments,ActorId FROM Steps order by createddate desc)
FROM ProcessInstance
WHERE targetObjectId = :updateItem.Id limit 1];
String actorId = processResult.Steps[0].ActorId;
String comments = processResult.Steps[0].comments;
User actor = [select Id,Name from User where Id = :actorId limit 1];
returnBody += '申请单编号为 : ' + updateItem.Id + '<br/>';
returnBody += '审批人:' + actor.Name + '<br/>';
returnBody += '审批意见:' + comments;
return returnBody;
} public static void sendEmail(String type,Main_Information_Update__c updateItem) {
String htmlBody;
htmlBody = getAccountUpdateAprovedEmailBody(updateItem);
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
email.setSenderDisplayName('System Admin');
email.setHtmlBody(htmlBody);
if(type == 'Approved') {
email.setSubject('审批通过提示');
} else {
email.setSubject('审批失败提示');
} email.setTargetObjectId(updateItem.Account__r.OwnerId);//使用此种方式给org内部User/Contact/Lead发邮件,email limit的count不加1
email.setSaveAsActivity(false);//如果设置targetObjectId,则必须设置setSaveAsActivity为false
Messaging.sendEmail(new List<Messaging.SingleEmailMessage>{email});
}
}

二.使用text/html/custom类型的email template:email template这三种类型可以使用merge field,提供了获取审批流的相关属性信息,比如审批人,审批意见,审批状态等,可以直接获取到。

在审批流中的final approve配置email alert即可。

三.使用visualforce EmailTemplate方式获取审批人和审批意见:上面也说到了,有一些情况下,html,text,custom实现不了,这个时候visualforce emailTemplate就可以上了,但是email template中无法使用到Approval相关的merge field,而且没有controller,这种情况下,可以使用两种方式进行解决。

1)在email template中使用apex component,通过component的controller方法获取需要的相关信息。

1.在email template中使用component,component传递当前记录的ID,用来处理获取审批人和审批意见的逻辑。

 <messaging:emailTemplate subject="审批通过提示" recipientType="User" relatedToType="Main_Information_Update__c">
<messaging:htmlEmailBody>
<p>申请单编号:{!relatedTo.Id}</p>
<p><c:approvalResult showComponent="ActorName" objId="{!relatedTo.Id}"/></p>
<p><c:approvalResult showComponent="Comments" objId="{!relatedTo.Id}"/></p>
</messaging:htmlEmailBody>
</messaging:emailTemplate>

2.approvalResult.Component用来显示UI

 <apex:component controller="ApprovalResultClr" access="global" allowDML="true">
<apex:attribute name="showComponent" description="approval comments" type="String"/>
<apex:attribute name="objId" description="approval comments" type="String" assignTo="{!targetObjId}"/> <apex:outputPanel rendered="{!showComponent == 'Comments'}">
审批意见:{!comments}
</apex:outputPanel>
<apex:outputPanel rendered="{!showComponent == 'ActorName'}">
审批人:{!actorName}
</apex:outputPanel>
</apex:component>

3.ApprovalResultClr用来获取审批人和审批意见。使用apex class时应该注意,component中绑定的attribute在后台的变量是没法使用在controller中的,所以不能再构造函数中使用targetObjId.

 global without sharing class ApprovalResultClr {

     public String targetObjId{get;set;}

     public String comments{get{
ProcessInstance pi = [SELECT Id,
(SELECT StepStatus, Comments,ActorId FROM Steps order by createddate desc)
FROM ProcessInstance
WHERE targetObjectId = :targetObjId limit 1];
if(pi <> null) {
comments = pi.Steps[0].Comments;
}
return comments;
}set;} public String actorName{get{
ProcessInstance pi = [SELECT Id,
(SELECT StepStatus, Comments,ActorId FROM Steps order by createddate desc)
FROM ProcessInstance
WHERE targetObjectId = :targetObjId limit 1];
if(pi <> null) {
String actorId = pi.Steps[0].ActorId;
User actor = [select Id,Name from User where Id = :actorId limit 1];
actorName = actor.Name;
}
return actorName;
}set;} }

4.配置在审批流中,使用email template

2)在Main_Information_Update__c增加Approver__c字段以及comments,在after update的trigger中获取审批人的信息放到相关字段上,然后配置workflow,当approver__c存在值情况下,发送邮件,邮件模板中的审批人使用Approver__c即可,此种方式不在下面体现了,有兴趣的可以自行尝试。

效果展示

1.对客户类型进行更改

2.保存后生成申请单

3.使用审批队列中名称为test1的审批人进行审批

4.发送邮件内容展示

总结:此篇通过一个简单的审批流的例子来展示出几种不同的方式获取审批人审批意见信息的方法,使用email template的text/html/custom最为简单,如果需求的邮件可以使用这些方式实现,建议使用此种方式,便于维护;如果实现不了情况下,也可以使用visual force template方式,不能获取到的内容可以内嵌apex:component搞定,如果最终这些都不太好操作情况下,退而求其次在代码里面写邮件发送的body。

salesforce零基础学习(八十二)审批邮件获取最终审批人和审批意见的更多相关文章

  1. salesforce 零基础学习(十八)WorkFlow介绍及用法

    说起workflow大家肯定都不陌生,这里简单介绍一下salesforce中什么情况下使用workflow. 当你分配许多任务,定期发送电子邮件,记录修改时,可以通过自动配置workflow来完成以上 ...

  2. salesforce零基础学习(一百二十)快去迁移你的代码中的 Alert / Confirm 以及 Prompt吧

    本篇参考: https://developer.salesforce.com/blogs/2022/01/preparing-your-components-for-the-removal-of-al ...

  3. salesforce零基础学习(九十二)使用Ant Migration Tool 实现Metadata迁移

    我们在做项目时经常会使用changeset作为部署工具,但是某些场景使用changeset会比较难操作,比如当我们在sandbox将apex class更改名字想要部署到生产的org或者其他环境的or ...

  4. salesforce 零基础学习(十九)Permission sets 讲解及设置

    Permission sets以及Profile是常见的设置访问权限的方式. Profile规则为'who see what'.通过Profile可以将一类的用户设置相同的访问权限.对于有着相同Pro ...

  5. salesforce 零基础学习(十六)Validation Rules & Date/time

    上一篇介绍的内容为Formula,其中的Date/time部分未指出,此篇主要介绍Date/time部分以及Validation rules. 本篇参考PDF: Date/time:https://r ...

  6. salesforce零基础学习(八十)使用autoComplete 输入内容自动联想结果以及去重实现

    项目中,我们有时候会需要实现自动联想功能,比如我们想输入用户或者联系人名称,去联想出系统中有的相关的用户和联系人,当点击以后获取相关的邮箱或者其他信息等等.这种情况下可以使用jquery ui中的au ...

  7. salesforce零基础学习(八十九)使用 input type=file 以及RemoteAction方式上传附件

    在classic环境中,salesforce提供了<apex:inputFile>标签用来实现附件的上传以及内容获取.salesforce 零基础学习(二十四)解析csv格式内容中有类似的 ...

  8. salesforce 零基础学习(五十二)Trigger使用篇(二)

    第十七篇的Trigger用法为通过Handler方式实现Trigger的封装,此种好处是一个Handler对应一个sObject,使本该在Trigger中写的代码分到Handler中,代码更加清晰. ...

  9. salesforce 零基础学习(六十八)http callout test class写法

    此篇可以参考: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restfu ...

随机推荐

  1. JavaWeb(一)之细说Servlet

    前言 其实javaWeb的知识早就学过了,可是因为现在在搞大数据开发,所以web的知识都忘记了.准备开始慢慢的把Web的知识一点一点的回忆起来,多学一点没有关系,就怕到时候要用的话,什么都不会了. 一 ...

  2. http://codeforces.com/contest/834

    A. The Useless Toy time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  3. .Neter玩转Linux系列之六:Linux下MySQL的安装、配置、使用

    一.Linux安装MySQL (1)下载安装包:https://dev.mysql.com/downloads/mysql/ (2)解压并安装 命令:tar zxvf 文件名 解压完成之后,重名一下文 ...

  4. 【JAVA零基础入门系列】Day4 变量与常量

    这一篇主要讲解Java中的变量,什么是变量,变量的作用以及如何声明,使用变量. 那么什么是变量?对于初学者而言,可以将变量理解为盒子,这些盒子可以用来存放数据,不同类型的数据需要放在对应类型的盒子里. ...

  5. .net通用防SQL注入漏洞程序(Global.asax方式)

    原理很简单:使用Global.asax中的Application_BeginRequest(object sender, EventArgs e)事件,实现表单或URL提交数据的获取,然后通过SQLI ...

  6. 【解决方案】Django管理页面无法显示静态文件

    [问题描述]:Django管理界面无法获取页面的css样式文件.图片等静态文件.调试模式下看到静态url显示404. [问题原因]:跟踪源码可以发现,静态文件的url是由Django自带的app(dj ...

  7. 阿里巴巴Java规约插件试用

    阿里Java开发规约Eclipse插件介绍 阿里巴巴集团配合<阿里巴巴Java开发手册>PDF终极版开发的IDE插件,目前包括IDEA插件.Eclipse插件. 安装 检查环境 插件要求: ...

  8. python中sys.exit()和os._exit(0)退出程序

    python中退出程序的两种方法,0为默认状态,可以为空,两者均会退出当前运行的程序,os._exit(0)中的0不能省略 sys.exit(0):可以捕获SystemExit异常,然后做相应的清理工 ...

  9. MVC(一)-MVC的基础认知

    MVC是一种编程模式和设计思想,MVC大致切割为三个主要单元:Model(实体模型),View(视图),Contrller(控制器),MVC主要目在于简化软件开发的复杂度,让程序代码形成一个松耦合. ...

  10. Kinect v2(Microsoft Kinect for Windows v2 )配置移动电源解决方案

    Kinect v2配置移动电源解决方案 Kinect v2如果用于移动机器人上(也可以是其他应用场景),为方便有效地展开后续工作,为其配置移动电源是十分必要的. 一.选择移动电源 Kinect v2原 ...