由于Salesforce只支持根据条件动态选择审批分支,如果我们想进一步支持动态根据页面的某种条件选择审批人,Salesforce是不支持的。因此我们只能通过override salesforce审批类来实现,具体步骤如下:

0,以管理员身份新建立一个审批流为Opportunity(审批流名称和每个节点的名称我们从写时候时候需要用到)

1,添加一个名称为Submit for Approval By Neo 自定义按钮给Opportunity(由于我们要重写的是Opportunity的审批流)在Opportunity Object 中的 ‘Buttons, Links, and Actions’ 如下:

填完后填写js代码,由于我们想通过点击直接启动工作流,所以我们需要在这里通过js 调用webservice 类启动。代码如下:

 <!--参数名区分大小写,对于跨层object直接在Object名后直接加参字段名即可-->
{!REQUIRESCRIPT("/soap/ajax/30.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/30.0/apex.js")} var OppID='{!Opportunity.Id}'
var Comments = 'submited'
var OppSubmitter = '{!$User.Id}'
var result = sforce.apex.execute("OppApprovalProcess", "SubmitforApproval", {oppID:OppID,Comments:Comments,userID:OppSubmitter });
window.location.reload()

2,在这里我们看到我们需要调用OppApprovalProcess类下SubmitforApproval方法实现审批的提交,下面就是调用提交的代码:(里面还还涉及动态选择审批人的问题,我们后边会讲到)

 global class OppApprovalProcess {

     //submit
webservice static boolean SubmitforApproval(string oppID, string Comments, string userID)
{
try
{
system.debug('oppID:'+oppID);
User nextapprover = getApprover(oppID);;
Approval.ProcessSubmitRequest subReq = new Approval.ProcessSubmitRequest();
subReq.setComments(Comments);
subReq.setObjectId(oppID);
subReq.setSubmitterId(userID);
subReq.setNextApproverIds(new Id[]{nextapprover.Id});
subReq.setProcessDefinitionNameOrId('Opportunity_Discount');
Approval.ProcessResult submitResult = Approval.process(subReq); return submitResult.isSuccess();
}
catch(Exception ex)
{
system.debug('ex:'+ex.getMessage());
return false;
}
}

3,创建完按钮后,我们需要把这个自定义按钮添加到page layout中,我们的最终目的是在添加完成后替换原有默认的提交按钮,所以我们要重写原有的Opportunity的Detail页面通过Jquery进行代码注入,所以我们要新建一个vistualforce 页面代码如下:

 <apex:page sidebar="true" standardController="Opportunity">
<!-- <apex:relatedList list="ProcessSteps" ></apex:relatedList>-->
<apex:includescript value="{!$Resource.JQuery}"/>
<script type="text/javascript">
$(function(){ //添加新按钮隐藏老按钮
// alert($('input[name="piSubmit"]').val());
if($('input[name="piSubmit"]').val()=='Submit for Approval')
{
($('input[name="piSubmit"]').hide()).parent().append($('input[name="submit_for_approval"]'));
$('input[name="piSubmit"]').next().hide();
}
else
{
//alert($('input[name="piSubmit"]').val());
$('input[name="submit_for_approval"]').hide();
//替换HistoryList中的审批链接
var OppId = ('{!Opportunity.Id}').substring(0,15);
var ApprovalListID = OppId + '_RelatedProcessHistoryList_body';
//alert(ApprovalListID);
var Approvalprocessdiv=document.getElementById(ApprovalListID);
//alert(Approvalprocessdiv.getAttribute('class'));
if(Approvalprocessdiv!=null)
{
var originalHTML=Approvalprocessdiv.innerHTML;
var newHtml=originalHTML.replace('/p/process/ProcessInstanceWorkitemWizardStageManager?','/apex/ProcessInstance?OppId='+OppId+'&');
Approvalprocessdiv.innerHTML=newHtml;
}
}
});
</script>
<apex:detail relatedList="true" title="true"/>
</apex:page>

添加完成后效果如下:submit for approval by Neo 就是我们的自定义按钮

4,添加提交按钮后,我们同时要替换审批页面的同意和拒绝按钮,但是由于salesforce不支持重写这个页面,所以我们自己创建一个审批页面来替换salesforce默认的审批页面,前端代码如下:

 <apex:page controller="ProcessInstanceController" tabStyle="Opportunity">
<apex:form >
<apex:sectionHeader title="Opportunity" subtitle="{!objOpp.Name}"/>
<apex:pageBlock title="Approve/Reject Approval Request">
<apex:pageBlockButtons location="bottom">
<apex:commandButton value="Approve" action="{!Approval}" reRender="block">
<apex:param name="approve" value="Approve" assignTo="{!ApprovalAction}"/>
</apex:commandButton>
<apex:commandButton value="Reject" action="{!Approval}" reRender="block">
<apex:param name="reject" value="Reject" assignTo="{!ApprovalAction}"/>
</apex:commandButton>
<apex:commandButton value="Cancel" action="{!Approval}" reRender="block">
<apex:param name="cancel" value="Cancel" assignTo="{!ApprovalAction}"/>
</apex:commandButton>
</apex:pageBlockButtons>
<apex:pageBlockSection columns="1">
<apex:pageBlockSectionItem >
Name <apex:outputField value="{!objOpp.Name}"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
Lead Owner <apex:outputField value="{!objOpp.Owner.Name}"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
Rejection Reason <font color="red">(Mandatory while Rejection)</font><apex:inputField value="{!objOpp.Rejection_Reason__c}"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
Comments <font color="red">(Mandatory while Rejection)</font> <apex:inputTextArea value="{!objOpp.Comments__c}" rows="5" cols="100"/>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>

5,同时在后台类中重写Apprve 和 Reject 类,代码如下:

 public class ProcessInstanceController {
public String processId;
public String OppId;
public ProcessInstance objProcessInstance;
public Opportunity objOpp {get; set;}
public string ApprovalAction {get;set;}
public PageReference redirectPage;
//初始化
public ProcessInstanceController()
{
processId = ApexPages.currentPage().getParameters().get('id'); //获取当前的工作流ID
OppId = ApexPages.currentPage().getParameters().get('OppId'); //获取当前case ID
objOpp = [select Name,Owner.Name,Rejection_Reason__c,Comments__c from Opportunity where id =:OppId]; //获取当前Opp对象为了后面更新comments和Reson
redirectPage = new PageReference('/'+OppId);
}
//审批
public PageReference Approval(){
try
{
if(ApprovalAction == 'Approve' || ApprovalAction == 'Reject')
{
//system.debug('ApprovalAction:'+this.ApprovalAction);
User nextapprover =[select Id from User where username = 'yinghai_guo_neo@sina.com'];//新建立一个object 并mapping关系
Approval.ProcessWorkitemRequest approvalNode = new Approval.ProcessWorkitemRequest();
// system.debug('comments:'+objOpp.Comments__c);
approvalNode.setComments(objOpp.Comments__c);
approvalNode.setAction(ApprovalAction);
approvalNode.setNextApproverIds(new Id[]{nextapprover.Id});
approvalNode.setWorkitemId(processId);
//system.debug('processID'+processId);
Approval.ProcessResult result = Approval.process(approvalNode);
//system.debug('result:'+result.isSuccess());
update objOpp;
//system.debug('update objOpp');
}
else
{
//system.debug('ApprovalAction:'+this.ApprovalAction);
}
}
catch(Exception ex)
{
system.debug('Ex:'+ex.getMessage());
}
return redirectPage;
}
}

最后生成的审批页面效果如下:

6, 最后我们要做的事情就是在动态查找审批人的方法,我们通过判断审批的每个节点等条件赛选出最终审批人

  //get approver
private static User getApprover(string OppID)
{
string ProcessNodeName = 'Sumbit';
//获取当前需要审批节点名称
for (ProcessInstance piw:[select Id,(SELECT ProcessNode.Name FROM StepsAndWorkitems)
FROM ProcessInstance where TargetObjectId = :OppID order by CreatedDate])
{
for(ProcessInstanceHistory PIH : piw.StepsAndWorkitems)
{
ProcessNodeName=PIH.ProcessNode.Name;
break;
}
}
User nextApprover = null;
if(ProcessNodeName == 'Submit')
{
//do sth
}
else if(ProcessNodeName == 'Director Approval')
{
//do sth
}
else if(ProcessNodeName == 'CEO Approval')
{
//do sth
} return nextApprover;
}

7,由于我们的opportunity 的页面是我们自定义的,所以我们要在系统中替换Opportunity list View按钮中的链接子页面,我们直接在Buttons, Links, and Actions修改,截图如下:

至此,我们实现审批人的动态审批,有任何问题,留言讨论,谢谢!!!

Salesforce 动态审批的更多相关文章

  1. salesforce 零基础学习(四十六)动态美观显示列表中记录的审批状态

    项目中,申请者申请某些事项以后,常常需要在申请列表中查看当前申请的记录所在的审批状态,动态美观的显示状态可以使UI更符合客户要求,比如下面这样. 以Goods__c表为例,申请者申请的一些采购以前需要 ...

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

    项目中,审批操作无处不在.配置审批流时,我们有时候会用到queue,related user设置当前步骤的审批人,审批人可以一个或者多个.当审批人有多个时,邮件中获取当前记录的审批人和审批意见就不能随 ...

  3. Salesforce 开发整理(七)配置审批流

    salesforce提供了比较强大的可配置审批流功能,在系统中翻译为“批准过程”.所以需要配置审批时,选择创建 ——>  工作流和批准 ——> 批准过程,然后选择管理批准过程,选择需要配置 ...

  4. salesforce 零基础学习(三十四)动态的Custom Label

    custom label在项目中经常用到,常用在apex class或者VF里面用来显示help text或者error message.有的时候我们需要用到的信息是动态变化的,那样就需要动态来显示信 ...

  5. salesforce 零基础开发入门学习(九)Approval Process 介绍

    在阅读此篇文章前,可以先参考阅读一个前辈总结的关于Approval Process的操作.以下为参考的链接: http://www.cnblogs.com/mingmingruyuedlut/p/37 ...

  6. salesforce 零基础学习(六十七)SingleEmailMessage 那点事

    在salesforce开发中,发送邮件是一个很常见的功能.比如在进入审批流以后的通过和拒绝的操作需要发送邮件给记录的owner,和其他系统交互以后更改了某些状态通知相关的User或者Contact等等 ...

  7. salesforce

    salesforce&apex salesforce开发的小心得 salesforce零基础学习(七十七)队列的实现以及应用 摘要: 队列和栈简单的区别为栈是后进先出,队列是先进先出.队列也是 ...

  8. Salesforce开发者学习笔记之一:基本知识

    本文介绍了Salesforce开发平台的基本知识, 包括如下内容: Salesforce平台介绍 Salesforce基本术语 定制和扩展Salesforce平台 创建一个简单的应用程序 Salesf ...

  9. salesforce 零基础学习(五十四)常见异常友好消息提示

    异常或者error code汇总:https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_con ...

随机推荐

  1. Quartus II 增量编译

    在开发阶段,经常需要改代码,而且往往只改局部代码,但是编译的时候,通常会全部重新编译,这会很浪费时间,使得开发效率大大降低.那么有没有一种方法能够降低不必要的编译时间呢?通过查询Quartus II ...

  2. WaitForMultipleObjects返回失败原因之一

    上网搜了下 关于 WaitForMultipleObjects等待多个线程退出的状态失败的情况,也有人遇到类似的情况. 一次项目中我也遇到这么个情况.项目中创建线程都是用的  _beginthread ...

  3. [java]wordcount程序

    词数统计系统. 作业解析:这次作业的内容是从本地读取一个程序代码,计算出这个程序中的行数,单词数,也可进行拓展. 实现语言:java 编程思路: 程序是由各种单词和符号组成的,单词包括关键字,标识符这 ...

  4. Pyside开篇杂记

    最近学习刚开始学习pyside,基本了解了一些类的用法,个人感觉就接触而言与pyqt并无本质区别. 双方资料基本可以相互借鉴,个人更倾向与pyside,查阅资料时也经常会在pyqt内得到解决方案. 之 ...

  5. soanar,jenkins

    http://www.sonarqube.org/ https://blogs.msdn.microsoft.com/visualstudioalm/2016/02/18/sonarqube-scan ...

  6. php://input

    从官网信息来看,php://input是一个只读信息流,当请求方式是post的,并且enctype不等于"multipart/form-data"时,可以使用php://input ...

  7. 如何比较两个SQL数据库的字段差别。

    程序好几个版本了,数据也弄出好好几版本,这下好了,原程序要升级,当然数据库也要升,可是里面已经有了大量的数据了,这时候怎么办.写了个存储过程来解决,一目了然. 因为2005及以上的数据库已经没有表sy ...

  8. linux shell:nginx日志切割脚本

    需求原因:nginx不具备日志切割功能,日志量较大,方便分析. 实现目的:完成nginx日志切割,并根据时间命名   简要命令: mv /usr/local/tengine/logs/access.l ...

  9. MariaDB Galera Cluster部署手册

    MariaDB Galera Cluster部署手册 galara保证双主数据库的同步及一致性 1.环境准备 基于新部署.最小化安装centos6.5 1>  yum install opens ...

  10. NVMe over Fabrics又让RDMA技术火了一把

    RDMA是个什么鬼?相信大部分不关心高性能网络的童鞋都不太了解.但是NVMe over Fabrics的出现让搞存储的不得不抽出时间来看看这个东西,这篇文章就来介绍下我所了解的RDMA. RDMA(R ...