工作流程-商业处理流程

简介

工作流程系统在OpenERP里是非常有用的机制,可以用于及时描述文件(模型)的演进过程。

Workflows are entirely customizable, they can be adapted to the flows and trade logic of almost any company. The workflow system makes OpenERP very flexible and allows it to easily support changing needs without having to program new functionalities.

目标

  • 及时描述文件的演进

  • 符合某些条件时自动触发动作

  • 管理公司里人员的角色和验证步骤

  • 管理不同物件/模块间的互动

  • 为文件流程可视化提供图形化的工具

To understand its utility, see these three examples:

WkfExample1: Discount On Orders

第一个流程图代表了一种非常基本的订单流程:

/doc_static/5.0/_images/Workflow_bc1.png

The order starts in the ‘draft’ state, when it is in redaction and not approved. When the user press on the ‘Confirm’ button, the invoice is created and the order comes into the ‘CONFIRMED’ state.

然后, 可能有2个动作:

  1. 订单完成(已出货)

  2. 订单被取消

Let’s suppose a company has a need not implemented in OpenERP. For example, suppose their sales staff can only offer discounts of 15% or less. Every order having a discount above 15% must be approved by the sales manager.

This modification in the sale logic doesn’t need any line of python code! A simple modification of the workflow allows us to take this new need into account and add the extra validation step.

/doc_static/5.0/_images/Workflow_bc2.png

The workflow is thus modified as above and the orders will react as we want to. We then only need to modify the order form view and add a validation button at the desired location.

We could then further improve this workflow by sending a request to the sales manager when an order enters the ‘Validation’ state. Workflow nodes can execute object methods; only two lines of Python are needed to send a request asking the sales manager to validate or not the order.

WkfExample2: A sale order that generates an invoice and a shipping order.

/doc_static/5.0/_images/Workflow_sale.png

WkfExample3: Acount invoice basic workflow

/doc_static/5.0/_images/Acount_inv_wkf.jpg

定义工作流程

Workflows are defined in the file server/bin/addons/base/ir/workflow/workflow.py. The first three classes defined in this file are workflow, wkf_activity and wkf_transition. They correspond to the three types of resources that are necessary to describe a workflow :

工作流程 XML 档案的一般结构

The general structure of a workflow XML file is as follows :

  1. <?xml version="1.0"?>
  2. <openerp>
  3. <data>
  4. <record model="workflow" id=workflow_id>
  5. <field name="name">workflow.name</field>
  6. <field name="osv">resource.model</field>
  7. <field name="on_create">True | False</field>
  8. </record>
  9. </data>
  10. </openerp>

这里的

  • id (就是 “workflow_id”) 是工作流程的识别码。每个工作流程必须有一个唯一的识别码。

  • name (就是 “workflow.name”) 是工作流程的名称。工作流程的名称必须符合 OpenERP 文法的 “带点名称” 要求。

  • osv (就是 “resource.model”) 是我们当做模型使用的物件名称 [-(请记得 OpenERP 物件是从 osv.osv 继承属性,所以 ‘<字段名称=”osv”>’)-]。

  • on_create 如果为 True,在创建 resource.model 时会自动将 workflow.name 实体化,如果是 False 则相反。

范例

The workflow “sale.order.basic” defined in addons/sale/sale_workflow.xml follows exactly this model, the code of its workflow tag is :

  1. <record model="workflow" id="wkf_sale">
  2. <field name="name">sale.order.basic</field>
  3. <field name="osv">sale.order</field>
  4. <field name="on_create">True</field>
  5. </record>

Activity(活动)

简介

The wkf_activity class represents the nodes of workflows. These nodes are the actions to be executed.

字段

split_mode

/doc_static/5.0/_images/Wkf_split.png

  • XOR: 一个必须的转变, 取找到的第一个转变(预设值)。

  • OR : Take only valid transitions (0 or more) in sequential order.

  • AND: 所有有效的转变都会同时出现(分叉)。

在 OR 和 AND 分离模式,可能会产生一些工作时间。

在 AND 模式,活动会等到所有转变都生效才会开始进行;即使是有小部分转变还没有生效,活动也不会开始进行。所有活动是同时被触发的。

join_mode

/doc_static/5.0/_images/Wkf_join.png

  • XOR: 进行目标的活动前,还必须继续一个转变(预设值)。

  • AND: 等待所有转变都生效,才能执行活动。

kind:

The type of the activity can take several values:
 
  • DUMMY: Do nothing (default).

  • FUNCTION: Execute the function selected by an action.

  • SUBFLOW: Execute a sub-workflow SUBFLOW_ID. The action method must return the ID of the concerned resource by the subflow ! If the action returns False, the workitem disappears !

  • STOPALL:

当某一个活动是 SUBFLOW 形态时,就会执行子工作流程。当子工作流程结束时活动也会结束。当子工作流程在作用中,这个活动的工作项目会被冻结。

action:

行动是指当某一个工作项目来到这个活动时,所要执行的程序方法。这些程序方法必须在这个工作流程里的物件里有定义,而且具有以下特征:

def object_method(self, cr, uid, ids):

在实际行动里,这些程序方法会被以下的叙述方式呼叫:

object_method()

signal_send

flow_start

Indicates if the node is a start node. When a new instance of a workflow is created, a workitem is activated for each activity marked as a flow_start.

警告

Be warned to not use this flag unless your activity really is a “flow start”. There are tiny versions that do not care about the tags contents like “true” or “false”. Using such tag and tiny version, you will always end up with an activity which is tagged as “flow start = true”, leaving u with a nasty hunt to find out where your workflow design could be wrong.

This is because tags content are always evaluated as string. Read the section about the eval attribute for an explanation.

flow_stop

标记这个节点是否为结束的节点。当一个实例(instance)里所有作用中的工作项目来到标记为``flow_stop``(流程停止)的节点,工作流程将会结束。

警告

Be warned to not use this flag unless your activity really is a “flow stop”. There are tiny versions that do not care about the tags contents like “true” or “false”. Using such tag and tiny version, you will always end up with an activity which is tagged as “flow stop = true”, leaving u with a nasty hunt to find out where your workflow design could be wrong.

This is because tags content are always evaluated as string. Read the section about the eval attribute for an explanation.

wkf_id(工作流程识别码)

The workflow which this activity belongs to.

使用XML档案定义活动

活动记录的一般结构如下

  1. <record model="workflow.activity" id="''activity_id''">
  2. <field name="wkf_id" ref="''workflow_id''"/>
  3. <field name="name">''activity.name''</field>::
  4. <field name="split_mode">XOR | OR | AND</field>
  5. <field name="join_mode">XOR | AND</field>
  6. <field name="kind">dummy | function | subflow | stopall</field>
  7. <field name="action">''(...)''</field>
  8. <field name="signal_send">''(...)''</field>
  9. <field name="flow_start">True | False</field>
  10. <field name="flow_stop">True | False</field>
  11. </record>

开始的**wkf_id**和**name**是强制要求要有的两个参数。

警告

Be warned to not use flow_start and flow_stop unless your activity really is a flow start or flow_stop. There are tiny versions that do not care about the tags contents like “True” or “False”.

This is because tags content are always evaluated as string. Read the section about the eval attribute for an explanation.

范例

There are too many possibilities of activity definition to choose from using this definition. We recommend you to have a look at the file server/bin/addons/sale/sale_workflow.xml for several examples of activity definitions.

Transition(转变)

简介

Workflow transitions are the conditions to be satisfied to go from one activity to the next one. They are represented by one-way arrows joining two activities.

条件有以下几种:

  • role to satisfy by the user

  • 在使用界面里按下某个按钮

  • 经由某个指定的活动达到这个子流程的结束点

系统是在表达式之前先判断任务或信号是否成立,所以如果任务或信号为伪(false),系统不会进行表达式的判断。

转变的判断可能不会在物件里写入任何值。

字段

  1. act_from

转变的来源活动。当这个(来源)活动结束后,系统会检查这个字段的状态,来确认是不是可以开始进行 ACT_TO 活动。

  1. act_to

转变要进行到的目标活动

  1. condition

要满足**表达式(Expression)** 才能完成转变。

  1. signal

当转变的运作是来自于在使用者界面里按下一个按钮,信号会检查被按下的按钮的名称。

如果信号为空值(NULL),表示不需要任何按钮来启动这个转变。

  1. role_id

使用者必须符合某个**角色**才能启动这个转变

用 XML 档案定义转变

转变记录的一般结构如下

  1. <record model="workflow.transition" id="transition_id">
  2. <field name="act_from" ref="activity_id'_1_'"/>
  3. <field name="act_to" ref="activity_id'_2_'"/>
  4. <field name="signal">(...)</field>
  5. <field name="role_id" ref="role_id'_1_'"/>
  6. <field name="condition">(...)</field>
  7. <field name="trigger_model">(...)</field>
  8. <field name="trigger_expr_id">(...)</field>
  9. </record>

只有**act_from**和**act_to**这两个字段是强制要求要有的。

Expressions(表达式)

Expressions are written as in python:

  • True

  • 1==1

  • ‘hello’ in [‘hello’,’bye’]

工作流程指向的资源里,任何字段都可以用在表达式里。例如,如果想要为伙伴地址建立一个工作流程,可以用类似以下的表达式:

  • zip==1400

  • phone==mobile

使用者角色

Roles can be attached to transitions. If a role is given for a transition, that transition can only be executed if the user who triggered it possess the necessary role.

每个使用者可以有一个或多个角色。角色会被定义在一个角色树状图里,上层(父层)的角色拥有所有下层(子层)的权力。

范例:

执行长

  • 技术经理

    • 研发组长

      • 研发员

      • 测试员

  • 销售经理

    • 广告人员

假设我们要查找数据库里的错误,需要测试员的角色才能在找到的错误上做标示,在上述范例的角色树里,有以下角色的人都可以在找到的错误上做标示:测试员,研发组长,技术经理,执行长。

错误处理

在以下的叙述中,工作流程里没有包含错误处理。

如果工作流程是批量执行的动作组成的,就不会触发例外状况。为了提升执行效率和尽量不被锁住,工作流程在每一个活动结束时才提交一个结果。这个策略是合理的,因为在每一个动作要求的条件被满足后,活动才会被执行。

唯一可能出现例外状况的问题是编程上的错误;这种状况下,只有属于整个已经执行完成的活动的动作才会被执行,其他的活动会被回退到上个检查点。

创建一个工作流程

以下步骤是用于创建一个名为**mymod**的定制模块,是一个简单的改变状态的工作流程

定义你的物件的状态

第一步是定义你的物件可以有那些状态。我们在物件的栏目(_columns)集合里加上一个 ‘state’ 字段,用于定义物件的状态。

  1. _columns = {
  2. ...
  3. 'state': fields.selection([
  4. ('new','New'),
  5. ('assigned','Assigned'),
  6. ('negotiation','Negotiation'),
  7. ('won','Won'),
  8. ('lost','Lost')], 'Stage', readonly=True),
  9. }

定义状态改变的处理方式

Add the following additional methods to your object. These will be called by our workflow buttons

  1. def mymod_new(self, cr, uid, ids):
  2. self.write(cr, uid, ids, { 'state' : 'new' })
  3. return True
  4. def mymod_assigned(self, cr, uid, ids):
  5. self.write(cr, uid, ids, { 'state' : 'assigned' })
  6. return True
  7. def mymod_negotiation(self, cr, uid, ids):
  8. self.write(cr, uid, ids, { 'state' : 'negotiation' })
  9. return True
  10. def mymod_won(self, cr, uid, ids):
  11. self.write(cr, uid, ids, { 'state' : 'won' })
  12. return True
  13. def mymod_lost(self, cr, uid, ids):
  14. self.write(cr, uid, ids, { 'state' : 'lost' })
  15. return True

显然你以后会想把这些方法扩充改成执行更有用的事项!

创建你的工作流程XML档案

There are three types of records we need to define in a file called mymod_workflow.xml

  1. 工作流程标题记录

    1. <record model="workflow" id="wkf_mymod">
    2. <field name="name">mymod.wkf</field>
    3. <field name="osv">mymod.mymod</field>
    4. <field name="on_create">True</field>
    5. </record>
  2. 工作流程活动记录

    These define the actions that should be executed when the workflow reaches a particular state

    1. <record model="workflow.activity" id="act_new">
    2. <field name="wkf_id" ref="wkf_mymod" />
    3. <field name="flow_start">True</field>
    4. <field name="name">new</field>
    5. <field name="kind">function</field>
    6. <field name="action">mymod_new()</field>
    7. </record>
    8. <record model="workflow.activity" id="act_assigned">
    9. <field name="wkf_id" ref="wkf_mymod" />
    10. <field name="name">assigned</field>
    11. <field name="kind">function</field>
    12. <field name="action">mymod_assigned()</field>
    13. </record>
    14. <record model="workflow.activity" id="act_negotiation">
    15. <field name="wkf_id" ref="wkf_mymod" />
    16. <field name="name">negotiation</field>
    17. <field name="kind">function</field>
    18. <field name="action">mymod_negotiation()</field>
    19. </record>
    20. <record model="workflow.activity" id="act_won">
    21. <field name="wkf_id" ref="wkf_mymod" />
    22. <field name="name">won</field>
    23. <field name="kind">function</field>
    24. <field name="action">mymod_won()</field>
    25. <field name="flow_stop">True</field>
    26. </record>
    27. <record model="workflow.activity" id="act_lost">
    28. <field name="wkf_id" ref="wkf_mymod" />
    29. <field name="name">lost</field>
    30. <field name="kind">function</field>
    31. <field name="action">mymod_lost()</field>
    32. <field name="flow_stop">True</field>
    33. </record>
  3. 工作流程转变记录

    这种记录是在定义工作流程的状态间,可能的转变

    1. <record model="workflow.transition" id="t1">
    2. <field name="act_from" ref="act_new" />
    3. <field name="act_to" ref="act_assigned" />
    4. <field name="signal">mymod_assigned</field>
    5. </record>
    6. <record model="workflow.transition" id="t2">
    7. <field name="act_from" ref="act_assigned" />
    8. <field name="act_to" ref="act_negotiation" />
    9. <field name="signal">mymod_negotiation</field>
    10. </record>
    11. <record model="workflow.transition" id="t3">
    12. <field name="act_from" ref="act_negotiation" />
    13. <field name="act_to" ref="act_won" />
    14. <field name="signal">mymod_won</field>
    15. </record>
    16. <record model="workflow.transition" id="t4">
    17. <field name="act_from" ref="act_negotiation" />
    18. <field name="act_to" ref="act_lost" />
    19. <field name="signal">mymod_lost</field>
    20. </record>

Add mymod_workflow.xml to __terp__.py

Edit your module’s __terp__.py and add mymod_workflow.xml to the “update_xml” array, so that OpenERP picks it up next time your module is loaded.

在你的视图里加上工作流程按钮

The final step is to add the required buttons to mymod_views.xml file.

Add the following at the end of the

section of your object’s view definition:

  1. <separator string="Workflow Actions" colspan="4"/>
  2. <group colspan="4" col="3">
  3. <button name="mymod_assigned" string="Assigned" states="new" />
  4. <button name="mymod_negotiation" string="In Negotiation" states="assigned" />
  5. <button name="mymod_won" string="Won" states="negotiating" />
  6. <button name="mymod_lost" string="Lost" states="negotiating" />
  7. </group>

测试

现在可以用模块管理员(Module Manager)来安装或更新你的模块。如果你有正确地完成所有事项,应该不会出现任何错误。你可以检查你的工作流程是不是有被安装在菜单里:选择菜单(menuselection):管理(Administration) —> 定制(Customization) —> 工作流程定义(Workflow Definitions).

当你进行测试时,记得新加入的工作流程只会被应用在新创建的记录上。

故障排除

如果你的按钮看起来没有任何作用,或许是因为以下两个问题的其中一个:

  1. 你正在处理的记录没有连接到工作流程实例(Instance)记录(也许是这笔记录是在你定义你的工作流程以前创建的)

  2. You have not set the “osv” field correctly in your workflow XML file