深入理解OpenERP的工作流(Workflow)

来源:互联网 发布:java file 文件大小 编辑:程序博客网 时间:2024/05/18 03:04
一、工作流定义:
<?xml version="1.0"?>
  <terp><data>
    <record model="workflow" id=workflow_id>
    <field name="name">workflow.name</field>
    <field name="osv">resource.model</field>
    <field name="on_create">True | False</field>
  </record>
</data></terp>

model:固定取值"workflow"
id:任意值,唯一标识本工作流
name: 工作流的名称,任意定义
osv: 本工作流关联的对象类型,是OpenERP模块中定义的某对象名,如采购单对象(purchase.order)。是本工作流处理的数据对象。
on_create:每当系统新产生一个osv 中定义的对象的实例时候,是否对应的产生一个和该对象实例关联的工作流实例。默认是True.

工作流和工作流实例:工作流定义了对某一类型的对象,如采购订单(PO)的处理流程。例如,PO单的一般处理流程也许是:1)新建PO,State = draft;2)审批PO,审批的同时,a)系统自动产生收货单,工仓库收货;b)系统自动产生凭据(Invoice),供财务确认付款;c)系统自动产生PDF的采购订单,并自动EMail给该PO单对应的供应商。但对于特定的某个PO对象,需要一个工作流实例,以记录本PO对象处在流程的哪个阶段,如PO1尚在draft状态,PO2已经审批通过。
PO单的审批,以及对应的a)、b)、c)的动作,都可以在OE的工作流中定义解决,而不需要全编码在PO对象上。即工作流实现了流程处理相关的代码和被处理对象的代码相分离,降低了不同处理代码的耦合性,增加了系统功能的柔软性。

二、活动(Activity)定义
<record model="workflow.activity" id="activity_id">
  <field name="wkf_id" ref="workflow_id"/>
  <field name="name">activity.name</field>
  <field name="kind">dummy | function | subflow | stopall</field>
  <field name="subflow_id">subflow_id</field>
  <field name="action">(...)</field>
  <field name="action_id">(...)</field>
  <field name="split_mode">XOR | OR | AND</field>
  <field name="join_mode">XOR | AND</field>
  <field name="signal_send">(...)</field>
  <field name="flow_start">True | False</field>
  <field name="flow_stop">True | False</field>
</record>

model:固定取值workflow.activity
wkf_id:本Activity所属的工作流id
name: 本Activity名称,任意值
kind:本Activity类型,有Dummy, Function, Subflow, Stop All 四种。kind说明,如果流程到达本节点,系统应执行的动作类别。
  Dummy 表示不执行任何动作,即action中定义的代码不会被执行。
  Function 表示执行action中定义的python代码,且,执行action_id中定义的server action。常见情况是,action中定义一个write方法,修改流程关联的对象的状态。对于Function类型的节点,action中定义的代码或者返回False,或者返回一个客户端动作id(A client action should be returned)。
  Subflow类型表示触发“subflow_id”中指定的工作流。仔细的读者或许要问,工作流的执行总是和某个被处理的对象关联,是的,如果定义了action,subflow 关联的对象id 由action中定义的代码返回。如果没有定义action,系统默认subflow关联的对象和本节点所属的工作流处理的对象id一致。stopall类型表示,流程到此节点则结束,但结束前,系统仍会执行action中的代码。

signal_send:执行完本节点的动作(action及action_id定义的动作)后,应向别的工作流发往的signal,格式是:subflow.signal。subflow_id和signal_send必须配合使用,subflow_id表示,触发子工作流subflow_id,在该子工作流中,通常必须定义signal_send,signal_send定义父流程中的某个signal,表示,子流程处理结束后触发父流程中的信号subflow.signal。注意,用于父子流程通信的工作流signal必须是形如subflow.* 。例如,在HR模块的workflow "wkf_expenses"中,需要开发票时候,它触发流程account模块中的工作流“account.wkf”(<field name="subflow_id" ref="account.wkf"/>)。account.wkf处理完成后,发出信号subflow.paid 通知wkf_expenses流程(<field name="signal_send">subflow.paid</field>)。wkf_expenses中定义了信号subflow.paid(<field name="signal">subflow.paid</field>)。

split_mode:有三个选项,XOR,OR,AND,默认是XOR。XOR 表示,由本节点始发的出迁移中,沿着第一个满足迁移条件的迁移跳转。OR 表示由本节点始发的出迁移中,只要满足迁移条件即沿该迁移跳转。AND 表示由本节点始发的出迁移中,只有所有迁移皆满足迁移条件才跳转,而且是同时沿所有迁移跳转。XOR 只有一个跳转,OR 有零或多个跳转,AND 有零或全部跳转。
join_mode:有两个选项,XOR,AND,默认是XOR。XOR 表示,以本节点为终点的入迁移中,只要有一个跳至本节点,即执行本节点的action。AND 表示,以本节点为终点的入迁移中,只有所有迁移都已经跳至本节点,才执行本节点的action。
flow_start:表示流程的开始节点。
flow_stop:表示流程的结束节点。

三、迁移(Transition)的定义
迁移的完整 XML 定义格式如下。
<record model="workflow.transition" id="transition_id">
  <field name="act_from" ref="activity_id_1"/>
  <field name="act_to" ref="activity_id_2"/>
  <field name="signal">(...)</field>
  <field name="condition">(...)</field>
  <field name="trigger_model">(...)</field>
  <field name="trigger_expr_id">(...)</field>
</record>

act_from:本迁移的起始节点,引用之前定义的Activity。
act_to:本迁移的结束节点,引用之前定义的Activity。
signal:触发本迁移的信号,表示,如果系统收到signal定义的信号,则触发本迁移。触发信号有三种方式,1)最常见的是用户点击视图中的“name = 本处定义的signal”的button,此时相当于向系统发送迁移信号量。系统会根据视图中的对象id,找到对象关联的workflow,再找到与button name相同的signal,触发之。2)调用workflow_service的方法:trg_validate(self, uid, res_type, res_id, signal, cr),此方法表示,触发对象类型res_type关联的workflow的signal信号,工作流实例关联的对象实例是 res_id。3)子流程的signal_send 发出的信号,此种情况前文已说过。

condition:迁移的条件,是一段Python代码,通常是一个函数调用。当系统收到signal中定义的信号时候,检查此处的条件,条件为真则实际触发迁移。
trigger_model和trigger_expr_id:此二字段表示启动一个新工作流实例。trigger_model定义对象类型,trigger_expr_id 定义一段Python代码,返回trigger_model类型的对象id。此二字段表示,如果act_from 中的action 执行完毕,且condition 条件OK,则系统中插入一个trigger_model类型,trigger_expr_id返回的对象id关联的工作流实例。然后,可以调用workflow_service的方法trg_trigger(self, uid, res_type, res_id, cr)实际执行该工作流。实际使用例子请参考Sale模块的工作流定义 wkf_sale:
            <field name="trigger_model">procurement.order</field>

            <field name="trigger_expr_id">procurement_lines_get()</field>



迁移(Transition)的定义漏了权限组group_id,修正如下。表示只有该权限组可以触发本迁移。
迁移的完整 XML 定义格式如下。
<record model="workflow.transition" id="transition_id">
  <field name="act_from" ref="activity_id_1"/>
  <field name="act_to" ref="activity_id_2"/>
  <field name="group_id" ref="groupid"/>
  <field name="signal">(...)</field>
  <field name="condition">(...)</field>
  <field name="trigger_model">(...)</field>
  <field name="trigger_expr_id">(...)</field>
</record>


上文关于Trigger model和Trigger expr_id的解释不够清楚,更清楚的解释参看链接:http://www.openerp.com/forum/post82154.html#p82154
原文部分摘抄如下:

I'll explain here what these two fields do: trigger_model and trigger_expr_id, for people looking for help :
- These fields let you ask for an "evaluation" of the condition when a specific object changed.

For example, suppose you want to set a Sale Order into the state "Done" once it has been shipped. The first the time the condition will be evaluated, it will be False. But later (some days after), we will confirm the shipping order. But our workflow condition is not checked again. Unless you define trigger_model and trigger_expr_id.

- Trigger model: The object type which will trigger an evaluation of your condition.
- Trigger expr_id: A list of model ids which will trigger the condition.

For example, to take the example of our Sale Order, we don't want to check the condition each time a shipping order is confirmed, but only when the shipping order associated to our sale order is confirmed !

Note: You can put a call to a function into trigger_expr_id, like <field name="trigger_expr_id">get_shipping_ids()</field>, or you can directly put a python value (like in my example in the previous post).

WARNING: Currently (OpenERP 6.0) you can only use trigger_model and trigger_expr_id a few objects: account.move.line, procurement.order and stock.move !