【转】金蝶EAS BOS工作流开发(附带JAVA脚本)
目录(?)[+]
- 流程配置基本知识及示例
- 重要概念
- 流程变量
- 任务输入输出
- 注意事项
- 基本流程的配置示例
- 单流程
- 审批流程
- 带分支的审批流程
- 常见的流程配置需求
- 配置参与人
- 配置多级审批
- 函数节点
- 用流程变量配置条件参予人
- 工作流脚本
- JAVA脚本
- 多UI相同实体需要触发不同的流程条件启动流程
- 重要概念
1. 流程配置基本知识及示例
1.1. 重要概念
1.1.1.流程变量
工作流承载业务,驱动业务流程,但是不会执行业务。工作流中的业务执行,全部都会委托给具体的业务模块执行。那么,这些被工作流分割的业务功能,在工作流中被调用执行的时候,如何保证做操作的数据的一致性?
通过流程变量,在每一步的业务功能执行的过程中,将业务数据保存在流程变量中,那么整个流程的后续活动中,都可以引用该流程变量,来完成业务功能,保证业务数据的一致性。
1.1.2.任务输入输出
1.2. 注意事项
l 绘画工作流图之前一定要先将业务流整理清楚,分析业务流的特性,提取可以抽象出来公用的东西,分析是否可以进行优化等,好的业务流程可以直接映射为工作流流程。
l 利用“流程变量”的威力,建立单据和流程之间数据交换的桥梁。输入输出参数用来在流程和单据之间进行数据的传递。输入输出参数和流程变量搭建了流程和单据之间的数据联系通道。
l 流程变量赋值时需注意:变量是否在另外地方被改变,有子流程时变量关系如何匹配,对应的是否正确,每个节点对应的变量是否正确,不同的节点可能对应不同的单据id,给变量赋值时需特别细心。
l 如存在一些系统预定义功能无法满足的需求,可以采用自己开发功能,根据输入参数和输出参数来与工作流交互,如在单据中增加function,绑定到自动节点执行,或者是利用脚本节点,获取一些有用的信息输出到流程变量中在工作流中使用。还可以利用工作流的一些新增功能,比如利用函数节点,BOTP节点等来执行特殊需求。
l 参与人动态变化或根据条件变化时,可以充分利用“参与人变量”作为动态值,变量的值可以通过各种方式获取,比如脚本式(后置脚本或脚本活动)、或者任务输出属性方式等。(流程变量中可以定义类型为参与人的变量)
l 利用条件参与人设置一些动态的参与人场景。比如当某条件满足时,设置为某些参与人,当条件不满足或为另外情况时,设置为另外的参与人,通过条件参与人和参与人变量可以满足大部分复杂的参与人场景。条件参与人的参与人范围还可以做为运行期指定下一步活动的参与人范围。
l 善于利用路由节点,除了可设置模式外,还可以对流程图进行美化。
l 一些公用的业务逻辑可以单独抽取出来配置为子流程给其他流程共用,减少维护的流程数量,比如一些常用的审批流程等。
1.3. 基本流程的配置示例
1.3.1.单流程
说明:流程只有一个人工型活动,完成凭证提交的任务,流程结束。没有具体的业务含义。
定义步骤:
1、 拖入开始、结束活动
2、 拖入人工型活动,用连接弧连接起来。
3、 定义人工型活动
首先,定义人工型活动的任务,选择任务
选定任务后,定制任务的输入输出。
输入参数是由任务定义带出的
根据任务输入的意义,指的是在凭证提交之前,由工作流告知凭证的数据。新建一个流程变量,绑定该输入。
这里绑定的意思是:在提交之前,工作流会将billID这个流程变量中的数据传递给业务。业务拿到这个值之后,会根据业务需要做出判断。
[说明]所有人工型任务的输入参数,全部是在定义任务的时候就定义好的。每个任务的输出参数可能不同,是由于各个不同的业务系统对于业务开始之前,所需要的数据不同导致。但是在EAS系统中,基本上任务的输入参数只有一个BOID类型的参数。这是因为一般来说,通过这样一个类型的值,就可以完全定位一个业务单据,并且拿到这个业务单据,就可以满足大部分的业务需求了。
这里,将ID属性输出,并且选定输出的流程变量是billID
凭证提交完毕后,将可以唯一标示一张凭证的ID属性保存在流程变量billID中,在后续的活动中,如果还需要操作这张凭证,就可以通过billID来唯一定位这张凭证,保证业务的一致性。
参与人定义中,分为了默认参与人和条件参与人。工作流在获取执行人的时候,首先根据条件来逐个扫描条件参与人,发现没有符合,那么会取默认参与人。
这里简单处理,选择任意人。
提交就可以匹配到该流程
到现在为止,这条简单的流程就已经定义完毕。发布。到EAS中提交凭证,然后到工作流监控中,会发现有一条流程实例,并且状态是已完成。
1.3.2.审批流程
3、 配置提交活动。和场景1.3.1中一样选择任务,参与人也是任意人。但是任务的输出夺一项。由于在后续的消息中想展现出单据的编码,所以多输出一个单据编码到一个流程变量number中
4、 配置审批活动。为了方便测试,参与人设定为流程发起人的本人
这一部分,就是任务输入。对于现在的场景,审批凭证,那么在业务单据内码这一栏选中billID。此时billID已经在提交之后,保存了刚刚提交的凭证的ID。一旦这个审批任务发生执行,那么,在执行前,工作流会将billID这个变量中保存的值传给业务系统。那么审批时就可以唯一定位到一条业务单据。
任务输出,选择将审批结果输出到一个枚举型的流程变量 审批结果 中。
定制审批消息
流程定义完毕。发布,在EAS中执行。
提交凭证,在消息中心收到一条消息,审批,通过。然后回到凭证序时簿,察看该流程,发现,凭证的状态还是“提交”而不是“审核”。
这是因为工作流中的多极审批,只是单纯的驱动流程,做一个选择而已,不会修改业务数据。
为了能够让凭证打上审批标记,按照如下方式修改流程定义
最后的这个自动活动,就完成给凭证打审核标记的功能。
任务选择如下:
保存、发布,再到EAS中执行一下。发现审批状态打上了。
1.3.3.带分支的审批流程
定义步骤
1、 提交、审批、自动节点的设置和场景2中一样。
2、 增加一个人工型活动,修改。选择的任务和“提交”一样。但是由于单据的ID和单据的编码是新增的时候就定好的,无法修改。所以只需要定义任务输入就可以了,不需要定义任务输出。
谁提交的谁修改,参与人设置为流程发起人本人
定制修改消息
3、 编辑连接弧
首先编辑“审批”到“自动”的连接弧。
建模工具会自动根据之前的定义识别枚举,然后将枚举的值也会自动列在选择范围内。
然后编辑“审批”到“修改”的连接弧。按照如下方式设置条件
保存。流程定制完毕。发布。
[说明]业务单据一旦进入工作流,就要受到工作流的约束。例如,刚刚提交完凭证,流程执行到审批节点。这个时候工作流要求的行为是“某个人执行审批操作”。如果这个时候修改凭证,会提示:“已在工作流处理中,任务不匹配”。
1.4. 常见的流程配置需求
1.4.1.配置参与人
1.4.2.配置多级审批
管理员收到申请单后,传给多个领导。由各领导分别进行审批,审批不通过的要能够来回进行审批。直到审批通过,也即是多级审批,每级审批不通过回到相应的审批节点继续进行审批。
流程配置
面对此种问题首先想到的应该是通过流程变量来设置审批节点的标志,在每级审批节点完成后设置一个标志,标志目前走到那个审批级别,如果不通过,根据流程变量上审批标志的值直接回到此审批节点。具体配置请查看下面截图:
完整流程图
综合处审批节点后置脚本
总结:充分利用流程变量作为流程流转的条件
1.4.3.函数节点
需要重复使用某些脚本,希望能减低脚本维护的复杂度,同时提高脚本的复用率和使用效率。
在工具菜单 窗口->显示视图,查找选择工作流视图组->函数定义
点击确定后会出现函数定义的界面,其中已经内置了一些函数,双击选择的某个函数可以打开函数编辑界面
函数编辑界面,在此可以定义函数的输入输出以及一些描述性的说明,并可在编辑框内输入具体的代码(目前支持KScript和java代码),代码其实就是脚本。
然后定义工作流,在流程定义中增加一个函数节点。
在函数任务界面选择函数定义,会弹出函数定义选择界面,选择合适的函数即可。
在函数任务界面配置好函数的输入输出参数即可在流程中使用此函数的输出值。
如需自己定义函数,直接在函数视图中按照右键菜单提示进行操作即可。
1.4.4.用流程变量配置条件参予人
在提交单据节点输出提交人的部门到流程变量“归口部门”,并在后置脚本中根据归口部门的值设置流程变量“是否财务部”的值。
在审批节点设置条件参与人,根据流程变量 “是否财务部”来设置相关的条件参与人,并将审批人输出到流程变量“审批人”中。
在审批节点后设置一脚本节点->负责人判断,用来判断上级审批的人员是否是部门负责人。如果是则流程结束。如果不是则继续在部门内多级审批,直到部门负责人审批完成(循环过程)。负责人判断的脚本内容为:
是否部门负责人=
com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal(
__bosContext,审批人,归口部门);
其中,是否为部门负责人,审批人,归口部门为流程变量。
最终流程如下:
总结:充分利用了条件参与人与流程变量,并通过脚本来获取流程必须的信息。
2. 工作流脚本
2.1.JAVA脚本
在工作流中经常会需要使用到一些脚本来获取单据的信息或者是执行一些特殊的操作,脚本应如何写?需要注意那些地方?有没有更好的定义和使用方法?
如下是一些脚本的示例:
l 根据人获取对应主负责的行政组织脚本:
首先新建一个流程变量 BOID类型 例如 orgId
String userId = "";
//获取User对象的远程控制接口
com.kingdee.eas.base.permission.IUser iUser =com.kingdee.eas.base.permission.UserFactory
.getLocalInstance(__bosContext);
com.kingdee.eas.base.permission.IUser iUser =com.kingdee.eas.base.permission.UserFactory
.getLocalInstance(__bosContext);
com.kingdee.eas.basedata.person.PersonInfo info =iUser.getUserInfo(
new com.kingdee.bos.dao.ormapping.ObjectUuidPK(
com.kingdee.bos.util.BOSUuid.read(userId))).getPerson();
if (info != null) {
String personId = info.getId().toString();
com.kingdee.eas.basedata.org.IPositionMemberiPositionMember =
com.kingdee.eas.basedata.org.PositionMemberFactory
.getLocalInstance(__bosContext);
com.kingdee.eas.basedata.org.PositionMemberInfopositionMemberInfo = iPositionMember
.getPositionMemberInfo("select
position.adminOrgUnit.id where person.id = '"+personId + "' and isPrimary = 1");
orgId =positionMemberInfo.getPosition().getAdminOrgUnit().getId();
}
l 根据组织的id获取公司的名称,然后在条件参与人中根据此进行判断
1、 增加一个流程变量adminId、companyId、companyNum。都是字符串型
2、 在新增节点的任务输出中,输出组织的ID到adminId变量中
3、 增加脚本节点,其中脚本如下:
companyId =
com.kingdee.eas.basedata.person.app.PersonToWFAdapter.getCompanyIdByAdminId(__bosContext,adminId);
com.kingdee.eas.basedata.org.INewOrgUnitFacadeiOrg =
com.kingdee.eas.basedata.org.NewOrgUnitFacadeFactory.getLocalInstance(__bosContext);
com.kingdee.eas.basedata.org.CompanyOrgUnitInfofiInfo =
(com.kingdee.eas.basedata.org.CompanyOrgUnitInfo)
iOrg.getDelegateUnit(companyId,com.kingdee.eas.basedata.org.OrgType.Company);
if (fiInfo != null) {
companyNum =fiInfo.getNumber();
}
l 判断有无直接上下级的脚本
首先定义一流程变量,类型为布尔:有直接上级
com.kingdee.bos.workflow.service.ormrpc.IEnactmentServiceservice = new
com.kingdee.bos.workflow.service.ormrpc.EnactmentService(__bosContext);
com.kingdee.bos.workflow.ProcessInstInfo[]procInstInfos =
service.getProcessInstanceByHoldedObjectId(billID.toString());
com.kingdee.bos.workflow.ProcessInstInfocurProcInst = null;
for (int i = 0, n =procInstInfos.length; i < n; i++) {
if(procInstInfos[i].getState().startsWith("open.run")) {
curProcInst =procInstInfos[i];
}
}
if (curProcInst != null) {
initUserId =curProcInst.getInitiatorId();
com.kingdee.eas.basedata.person.app.PersonToWFAdapteradapter = new
com.kingdee.eas.basedata.person.app.PersonToWFAdapter();
com.kingdee.bos.workflow.participant.Person[]persons =
adapter.getSupervisor(__bosContext, initUserId);
if (persons != null&& persons.length > 0 && persons[0] != null) {
有直接上级 = true;
} else {
有直接上级 = false;
}
}
l 委托时,判断审批人是否是部门负责人
判断审批人是否是部门负责人,如果审批人是委托任务处理人,则判断委托人是否是部门负责人
变量声明:
下述脚本使用了如下变量:
__bosContext: 系统内置变量
单据Id : 单据内码,一般由单据直接输出
归口部门: 类型为字符串,为部门id
审批人: 类型为字符串,为审批任务的处理人,在审批节点中输出
审批节点名称: 类型为字符串,为节点定义名称
是否部门负责人: 类型为布尔,为返回的结果值,用来在流程中判断
com.kingdee.bos.workflow.enactment.WfEngineengine =
com.kingdee.bos.workflow.enactment.WfEngine.getEngine(__bosContext);
com.kingdee.bos.workflow.ProcessInstInfo[]infos =
engine.getProcessInstanceByHoldedObjectId(单据Id);
if(infos!= null && infos.length>0){
ProcessControlDataKScriptAdapteradapter =
newProcessControlDataKScriptAdapter(infos[0],engine.getLocale(),engine);
String constituentUserId=adapter.getTopConstituent(审批节点名称);
if(constituentUserId !=null&& !constituentUserId.trim().equals("")){
//有委托人,判断委托人是否是部门负责人
是否部门负责人
=com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal (
__bosContext ,constituentUserId ," 归口部门) ;
}else{//没有委托人,直接判断审批人是否有直接上级
是否部门负责人
=com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal (
__bosContext ,审批人 ,归口部门) ;
}
} else{
是否部门负责人
=com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal (
__bosContext ,审批人 ,归口部门) ;
}
l 在脚本中执行SQL语句
java.lang.StringBuffersql = java.lang.new StringBuffer();
//将SQL语句保存到sql对象中
//…
java.sql.Connectioncon =
com.kingdee.bos.framework.ejb.EJBFactory.getConnection(__bosContext);
java.sql.StatementbatchStatement = con.createStatement();
batchStatement.execute(sql.toString());
com.kingdee.util.db.SQLUtils.cleanup(batchStatement,con);
com.kingdee.util.db.SQLUtils.cleanup(con);
l 将活动的参与人设为单据对应部门的负责人
场景:在单据上有个“费用的承担部门”的属性,现在要将审批活动的参与人设置为该部门的负责人。
1. 声明变量
var_principal 外部数据类型
var_orgUnitId 内码(BOID)
2. 在做业务单据时(审核节点之前)将单据上的“费用的承担部门”的ID关联到var_orgUnitId变量中 ,并在该节点的后继脚本中填入如下内容:
com.kingdee.eas.basedata.org.AdminOrgUnitInfo adminInfo = com.kingdee.eas.basedata.org.AdminOrgUnitFactory.getRemoteInstance().getAdminOrgUnit(var_orgUnitId);
if(adminInfo != null && adminInfo.getResponPosition != null)
{
com.kingdee.eas.basedata.org.IPosition iPosition = com.kingdee.eas.basedata.org.PositionFactory.getRemoteInstance();
com.kingdee.eas.basedata.person.PersonCollection pColl = iPosition.getAllPersons(adminInfo.getResponPosition.getId());
var_principal = new String[pColl.size()];
for (int i=0; i<pColl.size(); i++) {
com.kingdee.eas.basedata.person.PersonInfo pi = pColl.get(i);
var_principal[i] = pi.getId().toString();
}
}
3. 在审核节点中定义参与人,选择为参与人变量,并把var_princial添加进去。
l 根据分录信息循环发送消息给业务员
收集:脚本一
java.lang.String commonStr = data +"," + billNumber + "," + chauffeur + "," +regnumber + "," + contact + ".";
java.lang.HashMap map = newjava.lang.HashMap();
for (int i=0; i<records.size(); i++) {
//请替换成出车单的分录对象
com.kingdee.eas.fi.gl.VoucherEntryInforecord = records.get(i);
java.lang.String s =record.get("wareName") + "(" + record.get("wareNumber") + ")已发往" + record.get("customer") + ";";
java.langString op =record.("operator").getId().toString();
if (map.get(op) == null) {
map.put(op, s);
} else {
map.put(map.get(op) + s);
}
}
userList = new java.util.ArrayList();
msgList = new java.util.ArrayList();
//此段已废弃 begin
for (java.lang.Iterator i = map.getKeySet.iterator();i.hasNext();) {
Object key = i.next();
Object msg = map.get(key);
userList.add(key);
msgList.add(commonStr + msg);
}
//此段已废弃 end
修改为:
list = new java.util.ArrayList();
list.addAll(map.keySet());
for (int i=0; i<list.size(); i++) {
Object key = list.get(i);
Object msg = map.get(key);
userList.add(key);
msgList.add(commonStr + msg);
}
pos = 0;
count = userList.size();
if (count > 0) {
user = userList.get(0);
msg = msgList.get(0);
}
2.2.多UI相同实体需要触发不同的流程,条件启动流程
图一.设置启动条件
图二.双击链接符,弹出设置条件界面
图三.内置变量支持打点弹出业务对象的所有属性特征
图四.最终设置条件,示例为只有当单据的number为121的时候才启动此流程,此处根据业务需求来设定
可以使用一些比较复杂的条件来做判断,只要最后返回一个boolean值即可,如下述代码:
com.kingdee.bos.dao.ormapping.ObjectUuidPK pk = new com.kingdee.bos.dao.ormapping.ObjectUuidPK(__processTrigger.getProposer().getId()); com.kingdee.bos.metadata.entity.SelectorItemCollection sic = new com.kingdee.bos.metadata.entity.SelectorItemCollection(); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("id")); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("name")); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("employeeClassify.id")); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("employeeClassify.name")); com.kingdee.eas.basedata.person.PersonInfo person = com.kingdee.eas.basedata.person.PersonFactory.getLocalInstance(__bosContext).getPersonInfo(pk,sic); return person.getEmployeeClassify().getName().equals("一般员工"); |
目录(?)[+]
- 流程配置基本知识及示例
- 重要概念
- 流程变量
- 任务输入输出
- 注意事项
- 基本流程的配置示例
- 单流程
- 审批流程
- 带分支的审批流程
- 常见的流程配置需求
- 配置参与人
- 配置多级审批
- 函数节点
- 用流程变量配置条件参予人
- 工作流脚本
- JAVA脚本
- 多UI相同实体需要触发不同的流程条件启动流程
- 重要概念
1. 流程配置基本知识及示例
1.1. 重要概念
1.1.1.流程变量
工作流承载业务,驱动业务流程,但是不会执行业务。工作流中的业务执行,全部都会委托给具体的业务模块执行。那么,这些被工作流分割的业务功能,在工作流中被调用执行的时候,如何保证做操作的数据的一致性?
通过流程变量,在每一步的业务功能执行的过程中,将业务数据保存在流程变量中,那么整个流程的后续活动中,都可以引用该流程变量,来完成业务功能,保证业务数据的一致性。
1.1.2.任务输入输出
1.2. 注意事项
l 绘画工作流图之前一定要先将业务流整理清楚,分析业务流的特性,提取可以抽象出来公用的东西,分析是否可以进行优化等,好的业务流程可以直接映射为工作流流程。
l 利用“流程变量”的威力,建立单据和流程之间数据交换的桥梁。输入输出参数用来在流程和单据之间进行数据的传递。输入输出参数和流程变量搭建了流程和单据之间的数据联系通道。
l 流程变量赋值时需注意:变量是否在另外地方被改变,有子流程时变量关系如何匹配,对应的是否正确,每个节点对应的变量是否正确,不同的节点可能对应不同的单据id,给变量赋值时需特别细心。
l 如存在一些系统预定义功能无法满足的需求,可以采用自己开发功能,根据输入参数和输出参数来与工作流交互,如在单据中增加function,绑定到自动节点执行,或者是利用脚本节点,获取一些有用的信息输出到流程变量中在工作流中使用。还可以利用工作流的一些新增功能,比如利用函数节点,BOTP节点等来执行特殊需求。
l 参与人动态变化或根据条件变化时,可以充分利用“参与人变量”作为动态值,变量的值可以通过各种方式获取,比如脚本式(后置脚本或脚本活动)、或者任务输出属性方式等。(流程变量中可以定义类型为参与人的变量)
l 利用条件参与人设置一些动态的参与人场景。比如当某条件满足时,设置为某些参与人,当条件不满足或为另外情况时,设置为另外的参与人,通过条件参与人和参与人变量可以满足大部分复杂的参与人场景。条件参与人的参与人范围还可以做为运行期指定下一步活动的参与人范围。
l 善于利用路由节点,除了可设置模式外,还可以对流程图进行美化。
l 一些公用的业务逻辑可以单独抽取出来配置为子流程给其他流程共用,减少维护的流程数量,比如一些常用的审批流程等。
1.3. 基本流程的配置示例
1.3.1.单流程
说明:流程只有一个人工型活动,完成凭证提交的任务,流程结束。没有具体的业务含义。
定义步骤:
1、 拖入开始、结束活动
2、 拖入人工型活动,用连接弧连接起来。
3、 定义人工型活动
首先,定义人工型活动的任务,选择任务
选定任务后,定制任务的输入输出。
输入参数是由任务定义带出的
根据任务输入的意义,指的是在凭证提交之前,由工作流告知凭证的数据。新建一个流程变量,绑定该输入。
这里绑定的意思是:在提交之前,工作流会将billID这个流程变量中的数据传递给业务。业务拿到这个值之后,会根据业务需要做出判断。
[说明]所有人工型任务的输入参数,全部是在定义任务的时候就定义好的。每个任务的输出参数可能不同,是由于各个不同的业务系统对于业务开始之前,所需要的数据不同导致。但是在EAS系统中,基本上任务的输入参数只有一个BOID类型的参数。这是因为一般来说,通过这样一个类型的值,就可以完全定位一个业务单据,并且拿到这个业务单据,就可以满足大部分的业务需求了。
这里,将ID属性输出,并且选定输出的流程变量是billID
凭证提交完毕后,将可以唯一标示一张凭证的ID属性保存在流程变量billID中,在后续的活动中,如果还需要操作这张凭证,就可以通过billID来唯一定位这张凭证,保证业务的一致性。
参与人定义中,分为了默认参与人和条件参与人。工作流在获取执行人的时候,首先根据条件来逐个扫描条件参与人,发现没有符合,那么会取默认参与人。
这里简单处理,选择任意人。
提交就可以匹配到该流程
到现在为止,这条简单的流程就已经定义完毕。发布。到EAS中提交凭证,然后到工作流监控中,会发现有一条流程实例,并且状态是已完成。
1.3.2.审批流程
3、 配置提交活动。和场景1.3.1中一样选择任务,参与人也是任意人。但是任务的输出夺一项。由于在后续的消息中想展现出单据的编码,所以多输出一个单据编码到一个流程变量number中
4、 配置审批活动。为了方便测试,参与人设定为流程发起人的本人
这一部分,就是任务输入。对于现在的场景,审批凭证,那么在业务单据内码这一栏选中billID。此时billID已经在提交之后,保存了刚刚提交的凭证的ID。一旦这个审批任务发生执行,那么,在执行前,工作流会将billID这个变量中保存的值传给业务系统。那么审批时就可以唯一定位到一条业务单据。
任务输出,选择将审批结果输出到一个枚举型的流程变量 审批结果 中。
定制审批消息
流程定义完毕。发布,在EAS中执行。
提交凭证,在消息中心收到一条消息,审批,通过。然后回到凭证序时簿,察看该流程,发现,凭证的状态还是“提交”而不是“审核”。
这是因为工作流中的多极审批,只是单纯的驱动流程,做一个选择而已,不会修改业务数据。
为了能够让凭证打上审批标记,按照如下方式修改流程定义
最后的这个自动活动,就完成给凭证打审核标记的功能。
任务选择如下:
保存、发布,再到EAS中执行一下。发现审批状态打上了。
1.3.3.带分支的审批流程
定义步骤
1、 提交、审批、自动节点的设置和场景2中一样。
2、 增加一个人工型活动,修改。选择的任务和“提交”一样。但是由于单据的ID和单据的编码是新增的时候就定好的,无法修改。所以只需要定义任务输入就可以了,不需要定义任务输出。
谁提交的谁修改,参与人设置为流程发起人本人
定制修改消息
3、 编辑连接弧
首先编辑“审批”到“自动”的连接弧。
建模工具会自动根据之前的定义识别枚举,然后将枚举的值也会自动列在选择范围内。
然后编辑“审批”到“修改”的连接弧。按照如下方式设置条件
保存。流程定制完毕。发布。
[说明]业务单据一旦进入工作流,就要受到工作流的约束。例如,刚刚提交完凭证,流程执行到审批节点。这个时候工作流要求的行为是“某个人执行审批操作”。如果这个时候修改凭证,会提示:“已在工作流处理中,任务不匹配”。
1.4. 常见的流程配置需求
1.4.1.配置参与人
1.4.2.配置多级审批
管理员收到申请单后,传给多个领导。由各领导分别进行审批,审批不通过的要能够来回进行审批。直到审批通过,也即是多级审批,每级审批不通过回到相应的审批节点继续进行审批。
流程配置
面对此种问题首先想到的应该是通过流程变量来设置审批节点的标志,在每级审批节点完成后设置一个标志,标志目前走到那个审批级别,如果不通过,根据流程变量上审批标志的值直接回到此审批节点。具体配置请查看下面截图:
完整流程图
综合处审批节点后置脚本
总结:充分利用流程变量作为流程流转的条件
1.4.3.函数节点
需要重复使用某些脚本,希望能减低脚本维护的复杂度,同时提高脚本的复用率和使用效率。
在工具菜单 窗口->显示视图,查找选择工作流视图组->函数定义
点击确定后会出现函数定义的界面,其中已经内置了一些函数,双击选择的某个函数可以打开函数编辑界面
函数编辑界面,在此可以定义函数的输入输出以及一些描述性的说明,并可在编辑框内输入具体的代码(目前支持KScript和java代码),代码其实就是脚本。
然后定义工作流,在流程定义中增加一个函数节点。
在函数任务界面选择函数定义,会弹出函数定义选择界面,选择合适的函数即可。
在函数任务界面配置好函数的输入输出参数即可在流程中使用此函数的输出值。
如需自己定义函数,直接在函数视图中按照右键菜单提示进行操作即可。
1.4.4.用流程变量配置条件参予人
在提交单据节点输出提交人的部门到流程变量“归口部门”,并在后置脚本中根据归口部门的值设置流程变量“是否财务部”的值。
在审批节点设置条件参与人,根据流程变量 “是否财务部”来设置相关的条件参与人,并将审批人输出到流程变量“审批人”中。
在审批节点后设置一脚本节点->负责人判断,用来判断上级审批的人员是否是部门负责人。如果是则流程结束。如果不是则继续在部门内多级审批,直到部门负责人审批完成(循环过程)。负责人判断的脚本内容为:
是否部门负责人=
com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal(
__bosContext,审批人,归口部门);
其中,是否为部门负责人,审批人,归口部门为流程变量。
最终流程如下:
总结:充分利用了条件参与人与流程变量,并通过脚本来获取流程必须的信息。
2. 工作流脚本
2.1.JAVA脚本
在工作流中经常会需要使用到一些脚本来获取单据的信息或者是执行一些特殊的操作,脚本应如何写?需要注意那些地方?有没有更好的定义和使用方法?
如下是一些脚本的示例:
l 根据人获取对应主负责的行政组织脚本:
首先新建一个流程变量 BOID类型 例如 orgId
String userId = "";
//获取User对象的远程控制接口
com.kingdee.eas.base.permission.IUser iUser =com.kingdee.eas.base.permission.UserFactory
.getLocalInstance(__bosContext);
com.kingdee.eas.base.permission.IUser iUser =com.kingdee.eas.base.permission.UserFactory
.getLocalInstance(__bosContext);
com.kingdee.eas.basedata.person.PersonInfo info =iUser.getUserInfo(
new com.kingdee.bos.dao.ormapping.ObjectUuidPK(
com.kingdee.bos.util.BOSUuid.read(userId))).getPerson();
if (info != null) {
String personId = info.getId().toString();
com.kingdee.eas.basedata.org.IPositionMemberiPositionMember =
com.kingdee.eas.basedata.org.PositionMemberFactory
.getLocalInstance(__bosContext);
com.kingdee.eas.basedata.org.PositionMemberInfopositionMemberInfo = iPositionMember
.getPositionMemberInfo("select
position.adminOrgUnit.id where person.id = '"+personId + "' and isPrimary = 1");
orgId =positionMemberInfo.getPosition().getAdminOrgUnit().getId();
}
l 根据组织的id获取公司的名称,然后在条件参与人中根据此进行判断
1、 增加一个流程变量adminId、companyId、companyNum。都是字符串型
2、 在新增节点的任务输出中,输出组织的ID到adminId变量中
3、 增加脚本节点,其中脚本如下:
companyId =
com.kingdee.eas.basedata.person.app.PersonToWFAdapter.getCompanyIdByAdminId(__bosContext,adminId);
com.kingdee.eas.basedata.org.INewOrgUnitFacadeiOrg =
com.kingdee.eas.basedata.org.NewOrgUnitFacadeFactory.getLocalInstance(__bosContext);
com.kingdee.eas.basedata.org.CompanyOrgUnitInfofiInfo =
(com.kingdee.eas.basedata.org.CompanyOrgUnitInfo)
iOrg.getDelegateUnit(companyId,com.kingdee.eas.basedata.org.OrgType.Company);
if (fiInfo != null) {
companyNum =fiInfo.getNumber();
}
l 判断有无直接上下级的脚本
首先定义一流程变量,类型为布尔:有直接上级
com.kingdee.bos.workflow.service.ormrpc.IEnactmentServiceservice = new
com.kingdee.bos.workflow.service.ormrpc.EnactmentService(__bosContext);
com.kingdee.bos.workflow.ProcessInstInfo[]procInstInfos =
service.getProcessInstanceByHoldedObjectId(billID.toString());
com.kingdee.bos.workflow.ProcessInstInfocurProcInst = null;
for (int i = 0, n =procInstInfos.length; i < n; i++) {
if(procInstInfos[i].getState().startsWith("open.run")) {
curProcInst =procInstInfos[i];
}
}
if (curProcInst != null) {
initUserId =curProcInst.getInitiatorId();
com.kingdee.eas.basedata.person.app.PersonToWFAdapteradapter = new
com.kingdee.eas.basedata.person.app.PersonToWFAdapter();
com.kingdee.bos.workflow.participant.Person[]persons =
adapter.getSupervisor(__bosContext, initUserId);
if (persons != null&& persons.length > 0 && persons[0] != null) {
有直接上级 = true;
} else {
有直接上级 = false;
}
}
l 委托时,判断审批人是否是部门负责人
判断审批人是否是部门负责人,如果审批人是委托任务处理人,则判断委托人是否是部门负责人
变量声明:
下述脚本使用了如下变量:
__bosContext: 系统内置变量
单据Id : 单据内码,一般由单据直接输出
归口部门: 类型为字符串,为部门id
审批人: 类型为字符串,为审批任务的处理人,在审批节点中输出
审批节点名称: 类型为字符串,为节点定义名称
是否部门负责人: 类型为布尔,为返回的结果值,用来在流程中判断
com.kingdee.bos.workflow.enactment.WfEngineengine =
com.kingdee.bos.workflow.enactment.WfEngine.getEngine(__bosContext);
com.kingdee.bos.workflow.ProcessInstInfo[]infos =
engine.getProcessInstanceByHoldedObjectId(单据Id);
if(infos!= null && infos.length>0){
ProcessControlDataKScriptAdapteradapter =
newProcessControlDataKScriptAdapter(infos[0],engine.getLocale(),engine);
String constituentUserId=adapter.getTopConstituent(审批节点名称);
if(constituentUserId !=null&& !constituentUserId.trim().equals("")){
//有委托人,判断委托人是否是部门负责人
是否部门负责人
=com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal (
__bosContext ,constituentUserId ," 归口部门) ;
}else{//没有委托人,直接判断审批人是否有直接上级
是否部门负责人
=com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal (
__bosContext ,审批人 ,归口部门) ;
}
} else{
是否部门负责人
=com.kingdee.bos.workflow.participant.ParticipantHelper.isOrgPrincipal (
__bosContext ,审批人 ,归口部门) ;
}
l 在脚本中执行SQL语句
java.lang.StringBuffersql = java.lang.new StringBuffer();
//将SQL语句保存到sql对象中
//…
java.sql.Connectioncon =
com.kingdee.bos.framework.ejb.EJBFactory.getConnection(__bosContext);
java.sql.StatementbatchStatement = con.createStatement();
batchStatement.execute(sql.toString());
com.kingdee.util.db.SQLUtils.cleanup(batchStatement,con);
com.kingdee.util.db.SQLUtils.cleanup(con);
l 将活动的参与人设为单据对应部门的负责人
场景:在单据上有个“费用的承担部门”的属性,现在要将审批活动的参与人设置为该部门的负责人。
1. 声明变量
var_principal 外部数据类型
var_orgUnitId 内码(BOID)
2. 在做业务单据时(审核节点之前)将单据上的“费用的承担部门”的ID关联到var_orgUnitId变量中 ,并在该节点的后继脚本中填入如下内容:
com.kingdee.eas.basedata.org.AdminOrgUnitInfo adminInfo = com.kingdee.eas.basedata.org.AdminOrgUnitFactory.getRemoteInstance().getAdminOrgUnit(var_orgUnitId);
if(adminInfo != null && adminInfo.getResponPosition != null)
{
com.kingdee.eas.basedata.org.IPosition iPosition = com.kingdee.eas.basedata.org.PositionFactory.getRemoteInstance();
com.kingdee.eas.basedata.person.PersonCollection pColl = iPosition.getAllPersons(adminInfo.getResponPosition.getId());
var_principal = new String[pColl.size()];
for (int i=0; i<pColl.size(); i++) {
com.kingdee.eas.basedata.person.PersonInfo pi = pColl.get(i);
var_principal[i] = pi.getId().toString();
}
}
3. 在审核节点中定义参与人,选择为参与人变量,并把var_princial添加进去。
l 根据分录信息循环发送消息给业务员
收集:脚本一
java.lang.String commonStr = data +"," + billNumber + "," + chauffeur + "," +regnumber + "," + contact + ".";
java.lang.HashMap map = newjava.lang.HashMap();
for (int i=0; i<records.size(); i++) {
//请替换成出车单的分录对象
com.kingdee.eas.fi.gl.VoucherEntryInforecord = records.get(i);
java.lang.String s =record.get("wareName") + "(" + record.get("wareNumber") + ")已发往" + record.get("customer") + ";";
java.langString op =record.("operator").getId().toString();
if (map.get(op) == null) {
map.put(op, s);
} else {
map.put(map.get(op) + s);
}
}
userList = new java.util.ArrayList();
msgList = new java.util.ArrayList();
//此段已废弃 begin
for (java.lang.Iterator i = map.getKeySet.iterator();i.hasNext();) {
Object key = i.next();
Object msg = map.get(key);
userList.add(key);
msgList.add(commonStr + msg);
}
//此段已废弃 end
修改为:
list = new java.util.ArrayList();
list.addAll(map.keySet());
for (int i=0; i<list.size(); i++) {
Object key = list.get(i);
Object msg = map.get(key);
userList.add(key);
msgList.add(commonStr + msg);
}
pos = 0;
count = userList.size();
if (count > 0) {
user = userList.get(0);
msg = msgList.get(0);
}
2.2.多UI相同实体需要触发不同的流程,条件启动流程
图一.设置启动条件
图二.双击链接符,弹出设置条件界面
图三.内置变量支持打点弹出业务对象的所有属性特征
图四.最终设置条件,示例为只有当单据的number为121的时候才启动此流程,此处根据业务需求来设定
可以使用一些比较复杂的条件来做判断,只要最后返回一个boolean值即可,如下述代码:
com.kingdee.bos.dao.ormapping.ObjectUuidPK pk = new com.kingdee.bos.dao.ormapping.ObjectUuidPK(__processTrigger.getProposer().getId()); com.kingdee.bos.metadata.entity.SelectorItemCollection sic = new com.kingdee.bos.metadata.entity.SelectorItemCollection(); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("id")); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("name")); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("employeeClassify.id")); sic.add(new com.kingdee.bos.metadata.entity.SelectorItemInfo("employeeClassify.name")); com.kingdee.eas.basedata.person.PersonInfo person = com.kingdee.eas.basedata.person.PersonFactory.getLocalInstance(__bosContext).getPersonInfo(pk,sic); return person.getEmployeeClassify().getName().equals("一般员工"); |
【转】金蝶EAS BOS工作流开发(附带JAVA脚本)相关推荐
- 金蝶EAS BOS开发常用的代码说明及常见问题
2019独角兽企业重金招聘Python工程师标准>>> 概要 此工程是针对金蝶EAS BOS开发者提供代码参考,内容来源有网络,QQ群及个人收集等 主要功能 1.常见问题处理,对开发 ...
- EAS BOS 报表开发
EAS BOS 报表开发 只是做为新手BOS报表开发一个参考: 开发所需要新建的文件 ContractReportFilterUI:报表弹出的条件选择框,在新建时需要继承系统UI类 com.kingd ...
- 金蝶EAS BOS开发之扩展表应用
我们在客户业务系统开发中,经常会遇到一些单据信息量很大(字段很多),由于关系数据库的表中一行最多只能存储8000个字符,这样经常会导致我们通过一个实体(通常是一个实体一张表)无法解决,需要再另外新建一 ...
- 金蝶EAS BOS 元数据介绍
元数据归类总结 解决方案 解决方案是元数据的最大载体,对应于一个元数据集合.任一个元数据都必须归属于某个解决方案,譬如,EAS就是一个解决方案. ♢ ♢ 所有客户端加载的元数据都是加载 deploye ...
- 金蝶EAS BOS 快捷键(待更新)
[快捷键] BOS业务建模工具 左上方菜单栏搜索 可以搜索元数据 JAVA 视图下 快捷键 作用 ctrl+T 查看该接口的所有实现类 ctrl+shift+T 快速找到某个类 alt+/ 自动把方法 ...
- EAS BOS 单据开发 自定义枚举+下拉列表
1.在BOS业务建模工具,打开单据界面,先定义枚举,再新增一个下拉列表字段 2.这是我已定义好的,步骤就是:新增-->填写名称和别名-->再点新增枚举值-->确定. 3.新增字段,数 ...
- 金蝶EAS,扩展报表,Java数据集代码示例
业务场景:业务相对复杂时,无法直接通过SQL直接查询出相应的数据集.可以使用Java数据集实现. Java数据集可以针对查询结果进行相应的加工,向前端扩展报表提供符合要求的结果集. package c ...
- 金蝶EAS/BOS开发小知识二
1:如何通过IObjectPK pk获取实体对象 IObjectPK是一个表示实体对象id的对象,在日常开发工作中,经常需要通过它来获取实体对象.以下是通过IObjectPK获取实体对象代码的模版: ...
- 金蝶EAS/BOS开发小知识三
1:部署时提示版本不一致的解决办法 从服务器的目录:如: D:\Kingdee\eas\server\propertiesCopy文件eascomponents.xml 到部署机的目录: 如:E:\w ...
- 金蝶EAS BOS合并报表取数公式(二次开发取数公式)在调整分录模板和抵消分录模板显示
合并报表取数公式(二次开发取数公式)在不同的情形下想显示 标准产品自定义汇率取数公式是在这里不显示的 通过对标准产品的类进行扩展或者新增一个代码逻辑完全一样的类 //需要扩展的类 com.kingde ...
最新文章
- 中国CIO最关心的八大问题(上)
- leetcode每日刷题计划-简单篇day8
- 实战c++中的vector系列--vectorlt;unique_ptrlt;gt;gt;初始化(全部权转移)
- 计算机无法查找新硬件,电脑弹出新硬件向导怎么办_win7开机显示找到新的硬件向导的解决方法...
- asp.net core在linux进行上传视频ffmpeg截图
- C++ auto和decltype关键字
- 你最近学到的 飞鸽传书 东西的题目
- 修改oracle数据库内存参数,物理内存扩容,oracle 11g R1数据库相关参数修改
- Java生成和操作Excel文件
- 基于×××环境下的远程视频监控传输
- 软件测试工程师,需要达到什么水平才能顺利拿到 20k+ 无压力?
- ASP.NET网站限制访问频率
- Html加水印和禁用复制和右键(jquery.watermark.js)
- App_Offline.htm 功能,app_offline.htm 是怎样产生的?
- python爬虫实例100例-10个python爬虫入门实例
- 奶奶常说,黑白照片看的不清晰,还好我会Python,分分钟给她变成彩色的~
- otc机器人tp_发那科机器人TP 示教器按键使用简介
- layui的layer弹出层内置方法
- 1227. 飞机座位分配概率
- jQuery中siblings无效