用业务过程来实现计划的状态控制
在【使用计划】一文中能看到,我们来查看计划时,我们实现了一个小功能:不同的人在不同的阶段【编辑、执行、结束等】查看计划,其可执行的操作是不一样的。
这样的功能很通用、很常用,所以jxTMS就对此类功能进行了高度的集成,最终的成果就是jxTMS中在显示计划时,上述的功能在代码层面就三行:
#获取本计划的业务过程
pb = bp.get(db,ctx.getCurrentOrg(),parent,planName)
#根据该业务过程确定当前用户的操作列表
al = pb.listActiveByPeople(ctx.getCaller().id())
#将该操作列表发送到前端
self.setWOAttr('activeList','values',al)
这个集成就叫做业务过程,可用于对有多人参与的、过程化的业务进行集中管控。即业务过程是用一个通用模型来跟踪业务状态、管理不同用户在不同状态下的操作权限、并根据用户操作来推进业务状态变更,从而可靠而高效的实现业务管控。
大家应该注意到了,我上面用了一个词:在代码层面。对的,要能正确使用业务过程,我们先要定义相应的业务过程,这也是jxTMS一贯的思想:尽可能的用静态定义来取代编程。我们以计划的业务过程为例:
#对任务的计划过程进行管理
@myModule.bizProcess('计划过程'.decode('utf-8'))
def bp_plan():
'''
initState 修改计划 ;
active 修改计划 is 'task.plan.disp.editPlan' ;
active 启动计划 is 'task.plan.cmd.startPlan' ;
active 结束计划 is 'task.plan.cmd.closePlan' ;
active 自动结束 ;
/* 任务的执行人才能制定、修改、保存、启动计划 */
/* 计划可以反复修改 */
主执行人 can exec 修改计划 when 修改计划 ;
/* 计划启动后就无法修改 */
主执行人 can exec 启动计划 when 修改计划 to 计划已启动 ;
/* 手动结束时执行:task.plan.cmd.closePlan */
主执行人 can exec 结束计划 when 计划已启动 to 计划结束 ;
/* 自动结束不动作 */
nobody can exec 自动结束 when 计划已启动 to 计划结束 ;
'''
pass
可以看到,我们定义了一个名为【计划过程】的业务过程,而在jxTMS看来,一个业务过程,其实就是一个状态机,所以整个定义包括了三个部分:
-
动作:和jxTMS在其它地方所用的状态机【智能控制的编程模型部分、状态机】有所不同,业务过程中没有区分事件和动作,而是将其进行了合一,所以业务过程不是事件-响应模型,而是操作驱动模型
-
业务状态变化:洋泾浜式的语法,非常容易理解:谁在什么状态下执行什么动作就会跃迁到什么状态
-
从哪个初始状态开始
所以计划的业务状态图是:
业务过程中的角色
凡谈业务,必有权限。业务过程自然如此,基于jxTMS一贯的思想,业务过程使用了角色来分配权限。在上面的定义中的,主执行人和nobody,就是业务过程的角色。其中:
-
主执行人在【修改计划】状态下可执行:修改计划、启动计划;在【计划已启动】状态下可执行:结束计划、启动计划
-
nobody在【计划已启动】状态下可执行:自动结束。由nobody这个名字就可以知道,这肯定是保留给系统在结束节点时用于结束计划的,所以也没有相应的用户函数需要执行
角色是在创建计划时,jxTMS主动添加的:
#根据定义,以事的数据对象和计划名为标识,生成一个计划过程的bp
pb = bp.New(ctx.getCurrentOrg(),'计划过程'.decode('utf-8'),planName,parent)
#在该业务过程中,将当前用户指定为主执行人
pb.addParty('主执行人'.decode('utf-8'),ctx.getCaller().id())
#保存业务过程
pb.saveAll(db)
由于没有为其他人指定任何角色,所以其他用户无法得知当前能对该业务过程做什么、也做不了什么,因为业务过程在执行操作时,会先对当前用户的角色进行核准,如果当前用户无权执行该操作,则会予以明确的拒绝。
所以,对于计划,其他用户只能查看而不能执行任何操作。而查看不在计划管控的业务过程的定义中,所以查看计划就不受本业务过程的管控。
业务过程的使用
在定义好一个业务过程后,其使用方法主要是:
1、针对不同的业务对象,生成并保存一个对应的业务过程。就如一件事可以定义多个计划,业务过程是根据业务对象ID+实际名称这两者来识别的,具体使用如上面的展示。
2、获取当前用户当前可用操作列表,就是我们在本文开头所展示的。
3、用户选择了一个操作后,请求执行:
pb = bp.get(db,ctx.getCurrentOrg(),parent,planName)
#bpActive是用户所选的操作名
pb.active(db,ctx,self,bpActive)
大家可以从【计划过程】的定义看到各个操作其实就是对一个个入口的调用,所以根据需要正常实现这些入口函数即可。大家可下拉jxTMS镜像,阅读task.plan的相应web定义与代码就很容易理解了。