salesforce零基础学习(八十二)审批邮件获取最终审批人和审批意见

项目中,审批操作无处不在。配置审批流时,我们有时候会用到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:实现更新前对关键字段赋值以及更新后的创建更新申请数据以及自动提交审批流

 1 trigger AccountTrigger on Account(before update,after update) {
 2 
 3     if(Trigger.isBefore) {
 4         if(Trigger.isUpdate) {
 5             for(Account acc : trigger.new) {
 6                 String oldType = trigger.oldMap.get(acc.Id).Type;
 7                 System.debug(LoggingLevel.INFO, '*** acc.Update_Status__c: ' + acc.Update_Status__c);
 8                 if(acc.Update_Status__c <> 'Pending Approval') {
 9                     if(acc.Type <> oldType) {
10                         //将Account的Type_New__c赋值,Account的值回滚到以前的值
11                         acc.Type_New__c = acc.Type;
12                         acc.Type = oldType;
13                         acc.Update_Status__c = 'Pending Approval';
14                     }
15                 } else {
16                     //TODO
17                     //add error or do something
18                 }
19             }
20         }
21     }
22 
23     if(Trigger.isAfter) {
24         if(Trigger.isUpdate) {
25             List<Main_Information_Update__c> updateList = new List<Main_Information_Update__c>();
26             for(Account acc : trigger.new) {
27                 if(acc.Type_New__c <> null) {
28                     Main_Information_Update__c updateItem = new Main_Information_Update__c();
29                     updateItem.Type__c = acc.Type_New__c;
30                     updateItem.Type_Old__c = acc.Type;
31                     updateItem.Update_Status__c = 'Pending Approval';
32                     updateItem.Account__c = acc.Id;
33                     updateList.add(updateItem);
34                 }
35             }
36 
37             //插入数据并提交到审批流
38             if(updateList.size() > 0) {
39                 insert updateList;
40                 List< Approval.ProcessSubmitRequest> requestList = new List< Approval.ProcessSubmitRequest>();
41                 for(Main_Information_Update__c item : updateList) {
42                     Approval.ProcessSubmitRequest request = new Approval.ProcessSubmitRequest();
43                     request.setObjectId(item.Id);
44                     requestList.add(request);
45                     //List<Approval.ProcessResult> requestResultList =  Approval.process(requestList,false);
46                     
47                     //TODO
48                     //对于提交审批流失败的数据处理,
49                 }
50                 Approval.process(requestList);
51             }
52         }
53     }
54 
55 }

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

 1 trigger MainInformationUpdateTrigger on Main_Information_Update__c (after update) {
 2     if(Trigger.isAfter) {
 3         if(Trigger.isUpdate) {
 4             List<Account> updateAccountList = new List<Account>();
 5             //记录哪些需要发送邮件
 6             Map<Id,Main_Information_Update__c> mainId2ObjMap = new Map<Id,Main_Information_Update__c>();
 7             for(Main_Information_Update__c updateItem : Trigger.new) {
 8                 if(updateItem.Update_Status__c == 'Approved' || updateItem.Update_Status__c == 'Rejected') {
 9                     Account acc = new Account();
10                     acc.Id = updateItem.Account__c;
11                     acc.Type_New__c = null;
12                     //acc.Update_Status__c = updateItem.Update_Status__c;
13                     acc.Update_Status__c = null;
14                     updateAccountList.add(acc);
15                     mainId2ObjMap.put(updateItem.Id, updateItem);
16                 }
17             }
18 
19             if(updateAccountList.size() > 0) {
20                 //TODO
21                 //try catch处理
22                 update updateAccountList;
23 
24                 //发送邮件
25                 for(Id mainId : mainId2ObjMap.keySet()) {
26                     if(mainId2ObjMap.get(mainId).Update_Status__c == 'Approved') {
27                         EmailUtil.sendEmail('Approved', mainId2ObjMap.get(mainId));
28                     } else {
29                         EmailUtil.sendEmail('Rejected', mainId2ObjMap.get(mainId));
30                     }
31                     
32                 }
33             }
34         }
35     }
36 }

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

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

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

 1 public without sharing class EmailUtil {
 2     
 3     //获取审批意见,审批人,以及其他简单信息
 4     public static String getAccountUpdateAprovedEmailBody(Main_Information_Update__c updateItem) {
 5         String returnBody = '';
 6 
 7         ProcessInstance processResult = [SELECT Id,
 8                                             (SELECT StepStatus, Comments,ActorId FROM Steps order by createddate desc)
 9                                          FROM ProcessInstance
10                                          WHERE targetObjectId = :updateItem.Id limit 1];
11         String actorId = processResult.Steps[0].ActorId;
12         String comments = processResult.Steps[0].comments;
13         User actor = [select Id,Name from User where Id = :actorId limit 1];
14         returnBody += '申请单编号为 : ' + updateItem.Id + '<br/>';
15         returnBody += '审批人:' + actor.Name + '<br/>';
16         returnBody += '审批意见:' + comments;
17         return returnBody;
18     }
19 
20 
21     public static void sendEmail(String type,Main_Information_Update__c updateItem) {
22         String htmlBody;
23         htmlBody = getAccountUpdateAprovedEmailBody(updateItem);
24         Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
25         email.setSenderDisplayName('System Admin');
26         email.setHtmlBody(htmlBody);
27         if(type == 'Approved') {
28             email.setSubject('审批通过提示');
29         } else {
30             email.setSubject('审批失败提示');
31         }
32 
33         email.setTargetObjectId(updateItem.Account__r.OwnerId);//使用此种方式给org内部User/Contact/Lead发邮件,email limit的count不加1
34         email.setSaveAsActivity(false);//如果设置targetObjectId,则必须设置setSaveAsActivity为false
35         Messaging.sendEmail(new List<Messaging.SingleEmailMessage>{email});
36     }
37 }

二.使用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,用来处理获取审批人和审批意见的逻辑。

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

2.approvalResult.Component用来显示UI

 1 <apex:component controller="ApprovalResultClr" access="global" allowDML="true">
 2     <apex:attribute name="showComponent" description="approval comments" type="String"/>
 3     <apex:attribute name="objId" description="approval comments" type="String" assignTo="{!targetObjId}"/>
 4 
 5     <apex:outputPanel rendered="{!showComponent == 'Comments'}">
 6         审批意见:{!comments}
 7     </apex:outputPanel>
 8     <apex:outputPanel rendered="{!showComponent == 'ActorName'}">
 9         审批人:{!actorName}
10     </apex:outputPanel>
11 </apex:component>

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

 1 global without sharing class ApprovalResultClr {
 2     
 3     public String targetObjId{get;set;}
 4 
 5     public String comments{get{
 6         ProcessInstance pi = [SELECT Id,
 7                                         (SELECT StepStatus, Comments,ActorId FROM Steps order by createddate desc)
 8                                      FROM ProcessInstance
 9                                      WHERE targetObjectId = :targetObjId limit 1];
10         if(pi <> null) {
11             comments = pi.Steps[0].Comments;
12         }
13         return comments;
14     }set;}
15 
16     public String actorName{get{
17         ProcessInstance pi = [SELECT Id,
18                                             (SELECT StepStatus, Comments,ActorId FROM Steps order by createddate desc)
19                                          FROM ProcessInstance
20                                          WHERE targetObjectId = :targetObjId limit 1];
21         if(pi <> null) {
22             String actorId = pi.Steps[0].ActorId;
23             User actor = [select Id,Name from User where Id = :actorId limit 1];
24             actorName = actor.Name;
25         }
26         return actorName;
27     }set;}
28 
29 }

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。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户画像

第31章 配置链路聚合

190. 在S3610 交换机上创建包含有端口Ethernet1/0/1,ID 为2 的聚合端口,其正确命令是_____。B

661
来自专栏数据和云

关于 Oracle 存储双活配置和实战

作者简介 ? 任小闯 云和恩墨交付技术顾问,6年以上数据库开发维护工作经历,Oracle 10g OCM,Oracle 11g OCP,曾就职于某互联网行业任数...

3138
来自专栏张善友的专栏

Sqlite介绍

1、SQLite简介 SQLite第一个Alpha版本诞生于2000年5月. 至今已经有4个年头了. 而在今年的5月SQLite也迎来了一个新的里程: SQL...

1949
来自专栏CodingToDie

业余作者

Your good friend, an amateur writer, is full of energy and ready to write again.

504
来自专栏恰同学骚年

《大型网站技术架构》读书笔记之六:永无止境之网站的伸缩性架构

此篇已收录至《大型网站技术架构》读书笔记系列目录贴,点击访问该目录可获取更多内容。

612
来自专栏SDNLAB

SDN中的Segment Routing

作者简介:晏志文,原就职于中兴通讯,目前供职于安徽皖通邮电股份有限公司。数通测试专家,本领域从业深耕多年,熟悉传统网络技术及行业解决方案,密切关注新兴网络,IC...

994
来自专栏Albert陈凯

2018-05-17 架构师技能图谱,搞懂这些找工作无敌数据结构常用算法并发操作系统设计模式运维 & 统计 & 技术支持中间件网络数据库搜索引擎性能大数据安全常用开源框架分布式设计设计思想 & 开发模

1682
来自专栏IT笔记

SpringBoot开发案例之配置Druid数据库连接池

前言 好久没有更新Spring Boot系列文章,你说忙么?也可能是,前段时间的关注点也许在其他方面了,最近项目中需要开发小程序,正好采用Spring Boot...

2614
来自专栏大魏分享(微信公众号:david-share)

Ansible如何管理你的云:AWS、Openstack?你的运维也可以很帅!

一、云时代的运维 本文是我和李尧老师一起实验。李尧是红帽高级培训讲师,目前负责红帽中国区员工内部技术培训与认证。 物理机时代的运维,由于设备数量较少,运维人员的...

4486
来自专栏Java Edge

网站的伸缩性架构一、网站架构的伸缩性设计二、应用服务器集群的伸缩性设计三、分布式缓存集群的伸缩性设计四、数据存储服务器集群的伸缩性设计

3549

扫码关注云+社区