工作流
表单附加的工作流程
.. contents:: .. sectnum::
流程定义
表单的处理,通常是多人协作完成,比如:有人提交,有人处理,有人检查, 每个人能填写的表单字段不同,点击不同的操作按钮,表单会跳转到不同的地方。
在软件包内,可以对工作流进行图形化定义,包括“步骤step”和“操作项action”的定义:
- step: 流程分为若干步骤,每个步骤有特定的人员负责执行
- action: 每个步骤分为若干操作项,这些操作项对应不同的按钮
系统工作流定义支持编写表达式或者脚本,更加灵活,具体包括:
- 步骤进入条件
- 步骤进入的触发脚本
- 操作项的条件
- 操作项的完成条件:可能多人并审
- 操作项执行的触发脚本
表单绑定流程运行
表单可以附带工作流程,通过 context.workitems
进行管理
表单库的默认流程
部署表单库的时候,可以指定默认流程的定义 item_workflow
,也可以修改设置调整::
datacontainer.settings['item_workflow'] = ('zopen.sales:query',)
启动流程 start
为表单库中的每个表单页,启动一个默认流程::
dataitem.workitems.start(request=request)
一旦启动流程,会按照流程定义的步骤分配 工作项 到相关负责人。
如果希望启动别的流程,可以::
dataitem.workitems.start(workflow='zopen.plan:plan', request=request)
这样一个表单可以对应多个流程,在通过流程处理脚本动态在多个流程之间切换。
也可以直接启动流程的某个步骤(不从流程起始步骤运行)::
dataitem.workitems.start(workflow='zopen.plan:plan', step_name="submit", request=request)
或者指定人员强制重做某个步骤::
dataitem.workitems.start(workflow='zopen.plan:plan', step_name="submit", responsibles=[request.me.id], request=request)
表单输入项 get_form_elements
位于不同的步骤,表单可以输入的字段不同,有些字段会隐藏,另外可执行的操作也不同。
可以查看表单的字段::
dataitem.workitems.get_form_elements(pid, **options)
其中:
- pid表示以哪个用户身份来展示表单
- options是用来计算表单显示字段,需要额外的参数,比如
context=context, request=reuqest
返回::
( [], # 可编辑的字段:fields,
[], # 隐藏的字段:invisible_fields,
[(workitem_name, action_name, action_title)] # 可操作的按钮
)
执行工作项 execute
用户填写表单,点击可操作的按钮,就可以执行工作项。
也可以通过程序触发某个操作,推动流程前进::
errors = item.workitems.execute(workitem_name, action_name, as_principal=None, comment="")
其中:
- workitem_name: 某个工作项的name(具体见下一节)
- action_name: 操作
- as_principal: 可以指定以某人的身份去执行这个流程(如:users.admin)。
返回值是表单校验的错误信息,可以做错误处理::
if errors: import transaction transaction.abort() view.message(errors.value()[0], 'warning')
管理工作项
表单根据所属流程,在运行过程中,会产生一组“工作项workitem”。
工作项会进入每个人的待办事项或者日程中。这些工作项也自动成为表单自身的工作流程历史。
工作项历史 values
查看所有的工作项::
for workitem in dataitem.workitems.values():
print workitem.name
print workitem.title
print workitem.actions
得到工作项 get
得到具体某个workitem::
workitem = dataitem.workitems.get(workitem_name)
搜索 query
可以搜索工作项::
workitems = item.workitems.query(pid=None, state=set(['flowtask.active']))
工作项属性
object_types
每个工作项的对象类型 workitem.object_types
::
(WorkItem, Item)
内容类型 workitem.content_types
是步骤定义的代号(软件包名:流程名:步骤名)::
('zopen.plan:plan:review',)
状态 stati
状态 workitem.stati
包括:
- flowtask.active: 活动, 任务还没开始处理
- flowtask.working: 工作中, 任务正在处理中(用于多人并审)
- flowtask.pending: 暂停, 暂停处理该任务
- flowtask.abandoned: 取消, 任务已被取消
- flowtask.finished: 完成, 任务已经处理完成
角色授权 acl
每个工作项的相关的角色包括(可通过 workitem.acl
管理授权):
- Responsible: 负责人,可通过workitem.responsibles查看
- Delegator: 委托执行人(见工作项异动),可通过workitem.delegators
属性 md
包含的属性信息 workitem.md
:
-
workflow: ('zopen.plan:plan',) # 具体的流程定义
-
step: ('review',) # 具体的步骤
-
deadline_start: # 工作期限的开始时间
-
deadline: '2012-12-13', # 工作期限
-
finished: '', # 完结时间
-
start: #工作安排时间
-
category: ('handle', ) 分类
- 我发起的 start, 流程的第一个步骤
- 我处理的 handle 独自一人处理
- 我参与的 participate,多人参与
- 我转交的 deliver
- 我协助的 assist
-
delegations: { delegator: [pids] }
操作历史 actions
每个工作项目的执行动作保存在 workitem.actions
中 :
- username: 用户名
- action_name": 操作id
- title: 操作名称
- time: 操作时间
- comment: 说明
从工作项也可以找到关联的表单页::
workitem.related_item
工作项辅助函数: workitem.vote
多人执行的任务,通常要求全部投票完成才通过,可以用如下方法检查操作的完成条件::
workitem.vote(action_title, limit=0)
表示点击操作按钮action_title的流程执行人,至少需要limit张才通过(返回True). 如果limit为0表示需要全票通过。
工作项异动
工作项支持转发、协助、委托的功能,脱离工作流定义,完成一些常见的临时流程异动处理。
工作委托 delegate
当负责人休假、生病,可将工作委托其他人处理,期间他仍然可以选择自己处理::
dataitem.delegate(responsible, delegators)
如果取消某个负责人的代理::
dataitem.undelegate(responsible)
每个人可以根据转交策略进行转交(不同位置,委托给谁处理)::
root.profiles.delegate(pid, policy=[{'location':[], pids:[]}]) root.profiles.undelegate(pid) # 停止转交
读取设置::
root.profiles.get(pid, 'delegation_policy') root.profiles.get(pid, 'delegation')
查出某个委托发起人::
workitem.delegated_by(delegator)
工作转交 deliver
将某个人的工作完全转交工作给其他人负责,自己不再处理::
item.workitems.deliver(workitem_name, pid, new_responsibles, as_principal=None, body='', **options)
其中:
- pid,被转交的人,为空,表示替换全部负责人
- new_responsible: 转交给谁
- as_principal:以谁的身份执行
工作转交的时候,会导致:
- 当前工作项直接废弃,同时会触发步骤的
on_exit
脚本, 传入action参数为 deliver - 会就当前步骤,重复克隆一个新的工作项,保留其他人的操作历史
工作协助 assist
/ assist_end
如果工作需要其他人协助,可以想他人发起一个协助::
item.workitems.assist(workitem_name, pid, new_responsibles, body='', **options)
其中:
- workitem_name:需要协作的工作项名字
- pid:需要协助的人
- new_responsibles: 提供协助的人
这时候,当前工作暂停,对当前步骤重复创建一个新的协助工作项。
这个工作项有如下2个属性:
workitem.next_workitem
: 协助完成之后需要激活的工作项workitem.assist_to
:为谁做协助
协助人员点击确定完成工作项::
item.workitems.assist_end(workitem_name, as_principal=None, **options)
此时:
- 执行步骤的
on_exit
脚本,传入action为 assist - 之前工作的再次激活
废弃工作项 abort
表单库的管理员,可以直接废弃一个工作项::
item.workitems.abort(workitem_name, **options)
这时候:
- 当前工作项直接废弃,并执行所在步骤的
on_exit
脚本,传入action参数为 abort - 如果没有其他的工作项步骤,表单库进入废弃状态
搜索工作项 WorkQuerySet
WorkQuerySet 用于搜索工作项,接口类似 QuerySet.
按负责人和委托负责人搜索组合得到工作项::
query1 = WorkQuerySet()
.anyof(Responsible=('users.admin',), field='acl_grant')
.anyof(stati=('flowtask.finished', 'flowtask.working'))
query2 = WorkQuerySet()
.anyof(Delegator=('users.admin',), field='acl_grant')
.anyof(stati=('flowtask.finished', 'flowtask.working'))
admin_workitems = query1 | query2
搜索我负责、未处理的待办工作方法为::
WorkQuerySet().anyof(path=[project])
.anyof(stati=('flowtask.active', 'flowtask.pending'))
.anyof(Responsible=(pid, ), field='acl_grant')
.exclude_anyof(done=[pid])
支持QuerySet的所有接口。其中索引 done
表示多人任务情况下,已经处理的人员。
其他条件搜索,可参见"内容搜索"一章。
在日程中显示
可以在日历上显示工作项。日历上的时间含义工作要求时间:
- 如果是任务,表示完结期限,比如3个工作日之内必须完成。
- 如果是参加会议,表示会议的举办时间
-
可通过脚本设置
deadline
::workitem.md['deadline'] = datatime.datetime.now() + datetime.timedelta(hours=24)
-
如果希望显示一段时间,可以设置
deadline_start
::workitem.md['deadline_start'] = datatime.datetime.now()
工作安排
每个人都可以进行工作安排,工作安排调整了这个时间::
workitem.md['start']
可以把个人的工作安排,共享给其他人(通常是上级领导)协助安排::
managers = root.profiles.get(pid, 'workitem_managers') root.prfiles.set(pid, 'workitem_managers', maangers)