Odoo Workflow

##概述

在Odoo中工作流用于管理与某个模型的记录相关的一系列”需要做的事情”. 工作流为组织各种记录相关的任务提供了一种高层次的方法.

一个工作流是一个有向图, 其中节点称为”activities(活动)”, 边叫做”transitions(转移)”:

  • 活动定义了在Odoo服务器内部完成的某工作, 例如改变某些记录的状态或者发送Email;
  • 转移控制工作流程如何从一个活动到另一个活动.

在工作流的定义中, 还可以附加条件, 信号, 触发转移的触发器, 所以工作流的行为依赖于用户的动作(例如点击按钮), 或记录值的变化, 或任意的Python代码.

Odoo的工作流系统提供了以下功能:

  • 描述记录或文档随时间的演化过程;
  • 基于多种灵活条件的自动动作(automatic actions);
  • 公司规则及验证步骤的管理;
  • 对象间交互的管理;
  • 文档流转整个生命周期的可视化表示.

例如, 一个简单的订单可能的流程如下图:

订单开始于草稿状态, 经过用户确认, 最终发货(Closed)或取消

再看一个复杂些的例子, 有时销售员可以对订单给出折扣, 但是如果要求折扣超过15%则需要上级领导进行确认才能继续, 那么可以在Odoo中直接修改工作流而不需要对Python或XML文件进行编辑:

根据订单草稿中的折扣不同, 确认(Validation)这个活动会在条件满足时自动触发, 给相关的管理人员发送一个确认请求

注意: 相应地, 上级管理人员的订单视图上需要增加一个"接受折扣"的按钮.

##基础

可以使用数据文件直接定义工作流, 例如下面的XML代码片段定义了一个两个活动的工作流.

<record id="test_workflow" model="workflow">
    <field name="name">test.workflow</field>
    <field name="osv">test.workflow.model</field>
    <field name="on_create">True</field>
</record>

<record id="activity_a" model="workflow.activity">
    <field name="wkf_id" ref="test_workflow"/>
    <field name="flow_start">True</field>
    <field name="name">a</field>
    <field name="kind">function</field>
    <field name="action">print_a()</field>
</record>
<record id="activity_b" model="workflow.activity">
    <field name="wkf_id" ref="test_workflow"/>
    <field name="flow_stop">True</field>
    <field name="name">b</field>
    <field name="kind">function</field>
    <field name="action">print_b()</field>
</record>

<record id="trans_a_b" model="workflow.transition">
    <field name="act_from" ref="activity_a"/>
    <field name="act_to" ref="activity_b"/>
</record>

工作流定义总是关于一个特定模型的, 该模型在XML配置中用osv属性指定, 活动和转移中指定的方法应该在该模型中定义, 调用时将会到这个模型中查看.

例如上面的XML中, 创建了一个名为”test_workflow”的工作流, 它由两个活动中组成, 一个名为”a”, 一个名为”b”, 还有一个转移, 从”a”到”b”.

第一个活动的”flow_start”属性为True, Odoo在实例化工作流后据此知道工作流从哪开始. 因为第一个record段中的”on_create”属性设置为True, 所以该工作流在每次创建新的记录后都会被实例化; 如果该属性为False, 工作流就不会在创建记录时被实例化, 必须用其他方式实例化, 例如从模块的Python代码中实例化.

当工作流实例化后, 它处于活动”a”, 这个活动的类型属性是”function”, 动作(action)属性为”print_a()”, 表示需要调用模型test.workflow中的”print_a()”方法.

“a”和”b”之间的转移没有任何条件, 意味着当”a”处理完成后立刻转移到活动”b”.

##活动(Activities)

转移可以看做是工作流的控制结构, 活动是从改变记录状态到发送Email等任何事情发生的地方.

有多种不同类型的活动: Dummy, Function, Subflow和Stop all, 不同类型的活动在执行过程中有不同的作用.

###Flow start and flow stop

flow_start是一个布尔型属性, 用于指定工作流实例化时该活动是否被执行. 一个工作流中可以有多个活动的flow_start属性被标记为True, 这种情况下, 实例化工作流时Odoo将处理所有这些活动, 并评估它们的outgoing转移.

flow_stop属性也是一个布尔型属性, 用于确定某个活动是否停止工作流实例. 当一个工作流的所有活动的flow_stop属性均为True时, 该工作流就完成了.

###Subflow

一个活动可以嵌入一个完整的工作流, 称为子工作流, 被嵌入的工作流称为父工作流. 某个活动用subflow_id属性来指明其对应的子工作流.

如果一个活动是子工作流类型的, 那么只有当这个子工作流完成后, 才能被认为该活动完成了(并准备评估其outgoing转移).

###从子工作流发送信号

当一个工作流中存在嵌入的子工作流时, 子工作流可以从它的活动中(例如某个函数调用)发送信号给它的父工作流, 通过在signal_send属性中给定一个信号名称即可. Odoo processes those activities by sending the value of signal_send prefixed by “subflow.” to the parent workflow instance.

也就是说, 可以在子工作流执行时与扶工作流进行反应和转移.

###Server actions

一个活动可以通过在action_id属性中指定”Server Action”的ID来运行它.

###Python action

活动可以执行一些Python代码, action属性中指定即可.

###Split mode

当一个活动处理完成后, Odoo评估其转移以到达工作流中的下一个活动. 但是如果一个活动有多个转移, Odoo必须决定下一/几个活动是什么.

Split mode

split_mode属性控制:

XOR(default)

默认情况下, Odoo将使用第一个满足条件的转移(in sequence order), 并忽略其他所有的转移.

OR

OR模式下, 所有满足某个条件的转移将会同时发生, 无效的转移将忽略, 即使它随后变得有效也忽略.

AND

AND模式下, Odoo将会等待所有转移都满足后进行所有的转移.

###Join mode

类似于outgoing转移条件可以组合使用, incoming转移也可以组合在一起使用.

Join mode

join_mode属性控制:

XOR(default)

任何incoming转移enables该活动并开始其处理过程.

AND

只有所有incoming转移都到达才能enable该活动并开始其处理过程.

###Kinds

活动的类型定义这个活动可以执行任务的类型, 有以下几种:

Dummy(dummy, default)

不作任何事情, 或调用一个server action. 经常用作转移的分发或收集hubs.

Function(function)

执行一些Python代码, 执行一个server action.

Stop all(stopall)

完全停止工作流实例并标记其为完成.

Subflow(subflow)

启动另一个工作流, 一旦子工作流完成该活动即处理完成.
默认情况下子工作流是与父工作流相同的记录上实例化, 但是也可以改变, 通过提供一段Python代码, 返回记录ID(但必须是相同的模型)即可.

##转移

转移提供控制结构来编排工作流. 当一个活动完成后, 工作流引擎尝试利用转移离开已完成的活动, 到达下一个活动. 上一节的转移是最简单的形式, 前序活动完成后直接执行后续的活动.

除了一下完成所有活动外, 还可以在转移中等待, 并且在某些条件满足后结束等待继续流程, 这些待确认的条件可以是条件(conditions), 信号(signals)或触发器(triggers).

###条件
当一个活动完成后, 它的outgoing转移会检查确认该工作流是否可以继续流转到下一个活动. 如果只定义了条件(没有信号或触发器定义), 那么Odoo将会评估这个条件, 并且如果评估的结果是True, 那么工作流通过这个转移; 如果不满足条件, 那么Odoo将会在每次相关数据记录发生变化后再次评估该条件, 或者也可以通过一个明确的方法调用进行条件评估.

###信号
除了条件外, 一个转移也可以指定一个信号名, 这种情况下即使条件评估为True, 这个转移将不会发生, 而会保持阻塞状态直到被唤醒.

为了用某个信号名唤醒一个转移, 信号必须被发送到工作流实例. 一般的做法是按下界面上的某个按钮发送一个信号过去.

注意, 在信号发送到工作流实例后, 还需要评估条件是否为True.