大道至简,新一代企业应用无栈开发

平台之上,一种语言,可视化、脚本化、全端一体化开发

工作流

表单附加的工作流程

.. 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:以谁的身份执行

工作转交的时候,会导致:

  1. 当前工作项直接废弃,同时会触发步骤的 on_exit 脚本, 传入action参数为 deliver
  2. 会就当前步骤,重复克隆一个新的工作项,保留其他人的操作历史

工作协助 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)

此时:

  1. 执行步骤的 on_exit 脚本,传入action为 assist
  2. 之前工作的再次激活

废弃工作项 abort

表单库的管理员,可以直接废弃一个工作项::

item.workitems.abort(workitem_name, **options)

这时候:

  1. 当前工作项直接废弃,并执行所在步骤的 on_exit 脚本,传入action参数为 abort
  2. 如果没有其他的工作项步骤,表单库进入废弃状态

搜索工作项 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个工作日之内必须完成。
  • 如果是参加会议,表示会议的举办时间
  1. 可通过脚本设置 deadline ::

    workitem.md['deadline'] = datatime.datetime.now() + datetime.timedelta(hours=24)

  2. 如果希望显示一段时间,可以设置 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)