~openerp-vietnam/openobject-doc/technical-tutorial

« back to all changes in this revision

Viewing changes to build/html/_sources/part_3/wf_changes.txt

  • Committer: Najlaâ EL KHAYAT
  • Date: 2009-04-07 12:47:35 UTC
  • Revision ID: nel@tinyerp.com-20090407124735-fvnl6acj42fhff34
doc

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
=========================
 
2
Workflow-Business Process
 
3
=========================
 
4
 
 
5
Introduction
 
6
============
 
7
 
 
8
The workflow system in Open ERP is a very powerful mechanism that can describe the evolution of documents (model) in time.
 
9
 
 
10
Workflows are entirely customizable, they can be adapted to the flows and trade logic of almost any company. The workflow system makes Tiny ERP very flexible and allows it to easily support changing needs without having to program new functionalities.
 
11
 
 
12
**Goals**
 
13
 
 
14
 
 
15
    * description of document evolution in time
 
16
    * automatic trigger of actions if some conditions are met
 
17
    * management of company roles and validation steps
 
18
    * management of interactions between the different objects/modules
 
19
    * graphical tool for visualization of document flows
 
20
 
 
21
**To understand its utility, see these three examples:**
 
22
 
 
23
 
 
24
WkfExample1: Discount On Orders
 
25
-------------------------------
 
26
 
 
27
The first diagram represent a very basic workflow of an order:
 
28
 
 
29
.. image:: images/Workflow_bc1.png
 
30
 
 
31
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.
 
32
 
 
33
Then, two operations are possible:
 
34
 
 
35
#. the order is done (shipped)
 
36
 
 
37
#. the order is canceled
 
38
 
 
39
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.
 
40
 
 
41
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.
 
42
 
 
43
.. image:: images/Workflow_bc2.png
 
44
 
 
45
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.
 
46
 
 
47
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.
 
48
 
 
49
 
 
50
WkfExample2: A sale order that generates an invoice and a shipping order.
 
51
-------------------------------------------------------------------------
 
52
 
 
53
 
 
54
.. image:: images/Workflow_sale.png
 
55
 
 
56
WkfExample3: Acount invoice basic workflow
 
57
 
 
58
.. image:: images/Acount_inv_wkf.jpg
 
59
 
 
60
Defining Workflow
 
61
=================
 
62
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 :
 
63
 
 
64
    * `workflow <http://openobject.com/wiki/index.php/WkfDefXML>`_ : the workflow,
 
65
    * `wkf_activity <http://openobject.com/wiki/index.php/WorkflowActivity>`_ : the activities (nodes),
 
66
    * `wkf_transition <http://openobject.com/wiki/index.php/WorkflowTransition>`_ : the transitions between the activities.
 
67
 
 
68
 
 
69
General structure of a workflow XML file
 
70
========================================
 
71
 
 
72
The general structure of a workflow XML file is as follows :
 
73
 
 
74
.. code-block:: xml
 
75
 
 
76
    <?xml version="1.0"?>
 
77
    <terp>
 
78
    <data>
 
79
    <record model="workflow" id=workflow_id>
 
80
 
 
81
        <field name="name">workflow.name</field>
 
82
        <field name="osv">resource.model</field>
 
83
        <field name="on_create">True | False</field>
 
84
 
 
85
    </record>
 
86
 
 
87
    </data>
 
88
    </terp>
 
89
 
 
90
**Where**
 
91
 
 
92
    * **id** (here "workflow_id") is a workflow identifier. Each workflow must have an unique identifier.
 
93
    * **name** (here "workflow.name") is the name of the workflow. The name of the workflow must respect the Open ERP syntax of "dotted names".
 
94
    * **osv** (here "resource.model") is the name of the Tiny object we use as a model [-(Remember a Open object inherits from osv.osv, hence the '<field name="osv">')-].
 
95
    * **on_create** is True if workflow.name must be instantiated automatically when resource.model is created, and False otherwise.
 
96
 
 
97
**Example**
 
98
 
 
99
The workflow **"sale.order.basic"** defined in addons/sale/sale_workflow.xml follows exactly this model, the code of its workflow tag is :
 
100
 
 
101
.. code-block:: xml
 
102
 
 
103
    <record model="workflow" id="wkf_sale">
 
104
 
 
105
        <field name="name">sale.order.basic</field>
 
106
        <field name="osv">sale.order</field>
 
107
        <field name="on_create">True</field>
 
108
 
 
109
    </record>
 
110
 
 
111
Activity
 
112
==========
 
113
 
 
114
Introduction
 
115
------------
 
116
 
 
117
The wkf_activity class represents the nodes of workflows. These nodes are the actions to be executed.
 
118
 
 
119
The fields
 
120
----------
 
121
 
 
122
split_mode
 
123
----------
 
124
 
 
125
.. image::  images/Wkf_split.png
 
126
 
 
127
 
 
128
* XOR: One necessary transition, takes the first one found (default).
 
129
* OR : Take only valid transitions (0 or more) in sequential order.
 
130
* AND: All valid transitions are launched at the same time (fork).
 
131
 
 
132
 
 
133
In the OR and AND separation mode, certain workitems can be generated.
 
134
 
 
135
In the AND mode, the activity waits for all transitions to be valid, even if some of them are already valid. They are all triggered at the same time.
 
136
join_mode
 
137
join_mode:
 
138
 
 
139
.. image:: images/Wkf_join.png
 
140
 
 
141
 
 
142
* **XOR**: One transition necessary to continue to the destination activity (default).
 
143
* **AND**: Waits for all transition conditions to be valid to execute the destination activity.
 
144
 
 
145
kind:
 
146
-----
 
147
 
 
148
:The type of the activity can take several values:
 
149
 
 
150
    * **DUMMY**: Do nothing (default).
 
151
    * **FUNCTION**: Execute the function selected by an action.
 
152
    * **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 !
 
153
    * **STOPALL**:
 
154
 
 
155
A sub-workflow is executed when an activity is of the type SUBFLOW. This activity ends when the sub-workflow has finished. While the sub-workflow is active, the workitem of this activity is frozen.
 
156
 
 
157
action:
 
158
-------
 
159
 
 
160
The action indicates the method to execute when a workitem comes into this activity. The method must be defined in a object which belongs this workflow and have the following signature:
 
161
 
 
162
    def object_method(self, cr, uid, ids):
 
163
 
 
164
In the action though, they will be called by a statement like:
 
165
 
 
166
    object_method()
 
167
 
 
168
::
 
169
 
 
170
        signal_send
 
171
 
 
172
::
 
173
 
 
174
        flow_start
 
175
 
 
176
 
 
177
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.
 
178
 
 
179
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 whith an activity which is tagged as "flow start = true", leaving u with a nasty hunt to find out where your workflowdesign could be wrong.
 
180
 
 
181
flow_stop
 
182
---------
 
183
 
 
184
Indicates if the node is an ending node. When all the active workitems for a given instance come in the node marked by flow_stop, the workflow is finished.
 
185
 
 
186
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 whith an activity which is tagged as "flow stop = true", leaving u with a nasty hunt to find out where your workflowdesign could be wrong.
 
187
 
 
188
wkf_id
 
189
------
 
190
 
 
191
The workflow which this activity belongs to.
 
192
Defining activities using XML files
 
193
 
 
194
The general structure of an activity record is as follows
 
195
---------------------------------------------------------
 
196
 
 
197
.. code-block:: xml
 
198
 
 
199
        <record model="workflow.activity" id="''activity_id''">
 
200
              <field name="wkf_id" ref="''workflow_id''"/>
 
201
              <field name="name">''activity.name''</field>::
 
202
 
 
203
              <field name="split_mode">XOR | OR | AND</field>
 
204
              <field name="join_mode">XOR | AND</field>
 
205
              <field name="kind">dummy | function | subflow | stopall</field>
 
206
 
 
207
              <field name="action">''(...)''</field>
 
208
              <field name="signal_send">''(...)''</field>
 
209
              <field name="flow_start">True | False</field>
 
210
              <field name="flow_stop">True | False</field>
 
211
          </record>
 
212
 
 
213
The first two arguments **wkf_id** and name are mandatory. 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".
 
214
 
 
215
Examples
 
216
 
 
217
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.
 
218
 
 
219
Transition
 
220
===========
 
221
 
 
222
Introduction
 
223
------------
 
224
 
 
225
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.
 
226
 
 
227
The conditions are of different types:
 
228
 
 
229
    * role to satisfy by the user
 
230
    * button pressed in the interface
 
231
    * end of a subflow through a selected activity of subflow
 
232
 
 
233
The roles and signals are evaluated before the expression. If a role or a signal is false, the expression will not be evaluated.
 
234
 
 
235
Transition tests may not write values in objects.
 
236
The fields
 
237
::
 
238
 
 
239
        act_from
 
240
 
 
241
Source activity. When this activity is over, the condition is tested to determine if we can start the ACT_TO activity.
 
242
 
 
243
::
 
244
 
 
245
        act_to
 
246
 
 
247
The destination activity.
 
248
 
 
249
::
 
250
 
 
251
        condition
 
252
 
 
253
**Expression** to be satisfied if we want the transition done.
 
254
 
 
255
::
 
256
 
 
257
        signal
 
258
 
 
259
When the operation of transition comes from a button pressed in the client form, signal tests the name of the pressed button.
 
260
 
 
261
If signal is NULL, no button is necessary to validate this transition.
 
262
 
 
263
::
 
264
 
 
265
        role_id
 
266
 
 
267
The **role** that a user must have to validate this transition.
 
268
Defining Transitions Using XML Files
 
269
 
 
270
The general structure of a transition record is as follows
 
271
 
 
272
.. code-block:: xml
 
273
 
 
274
    <record model="workflow.transition" id="transition_id">
 
275
 
 
276
        <field name="act_from" ref="activity_id'_1_'"/>
 
277
        <field name="act_to" ref="activity_id'_2_'"/>
 
278
 
 
279
        <field name="signal">(...)</field>
 
280
        <field name="role_id" ref="role_id'_1_'"/>
 
281
        <field name="condition">(...)</field>
 
282
 
 
283
        <field name="trigger_model">(...)</field>
 
284
        <field name="trigger_expr_id">(...)</field>
 
285
 
 
286
    </record>
 
287
 
 
288
Only the fields **act_from** and **act_to** are mandatory.
 
289
 
 
290
Expressions
 
291
===========
 
292
 
 
293
Expressions are written as in python:
 
294
 
 
295
    * True
 
296
    * 1==1
 
297
    * 'hello' in ['hello','bye']
 
298
 
 
299
Any field from the resource the workflow refers to can be used in these expressions. For example, if you were creating a workflow for partner addresses, you could use expressions like:
 
300
 
 
301
    * zip==1400
 
302
    * phone==mobile
 
303
 
 
304
User Role
 
305
=========
 
306
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.
 
307
 
 
308
Each user can have one or several roles. Roles are defined in a tree of roles, parent roles having the rights of all their children.
 
309
 
 
310
Example:
 
311
 
 
312
CEO
 
313
 
 
314
  * Technical manager
 
315
 
 
316
    - Lead developper
 
317
 
 
318
      + Developpers
 
319
      + Testers
 
320
 
 
321
  * Sales manager
 
322
 
 
323
    - Commercials
 
324
    - ...
 
325
 
 
326
Let's suppose we handle our own bug database and that the action of marking a bug as valid needs the Testers role. In the example tree above, marking a bug as valid could be done by all the users having the following roles: Testers, Lead developper, Technical manager, CEO.
 
327
 
 
328
Error handling
 
329
==============
 
330
 
 
331
As of this writing, there is no exception handling in workflows.
 
332
 
 
333
Workflows being made of several actions executed in batch, they can't trigger exceptions. In order to improve the execution efficiency and to release a maximum of locks, workflows commit at the end of each activity. This approach is reasonable because an activity is only started if the conditions of the transactions are satisfied.
 
334
 
 
335
The only problem comes from exceptions due to programming errors; in that case, only transactions belonging to the entirely terminated activities are executed. Other transactions are "rolled back". 
 
336
 
 
337
Creating a Workflow
 
338
-------------------
 
339
 
 
340
Steps for creating a simple state-changing workflow for a custom module called **mymod**
 
341
 
 
342
 
 
343
Define the States of your object
 
344
++++++++++++++++++++++++++++++++
 
345
 
 
346
The first step is to define the States your object can be in. We do this by adding a 'state' field to our object, in the _columns collection
 
347
 
 
348
.. code-block:: python
 
349
 
 
350
        _columns = {
 
351
         ...
 
352
            'state': fields.selection([
 
353
                ('new','New'),
 
354
                ('assigned','Assigned'),
 
355
                ('negotiation','Negotiation'),
 
356
                ('won','Won'),
 
357
                ('lost','Lost')], 'Stage', readonly=True),
 
358
        }
 
359
 
 
360
Define the State-change Handling Methods
 
361
++++++++++++++++++++++++++++++++++++++++
 
362
 
 
363
Add the following additional methods to your object. These will be called by our workflow buttons
 
364
 
 
365
.. code-block:: python
 
366
 
 
367
        def mymod_new(self, cr, uid, ids):
 
368
                 self.write(cr, uid, ids, { 'state' : 'new' })
 
369
                 return True
 
370
 
 
371
        def mymod_assigned(self, cr, uid, ids):
 
372
                 self.write(cr, uid, ids, { 'state' : 'assigned' })
 
373
                 return True
 
374
 
 
375
        def mymod_negotiation(self, cr, uid, ids):
 
376
                 self.write(cr, uid, ids, { 'state' : 'negotiation' })
 
377
                 return True
 
378
 
 
379
        def mymod_won(self, cr, uid, ids):
 
380
                 self.write(cr, uid, ids, { 'state' : 'won' })
 
381
                 return True
 
382
 
 
383
        def mymod_lost(self, cr, uid, ids):
 
384
                 self.write(cr, uid, ids, { 'state' : 'lost' })
 
385
                 return True
 
386
 
 
387
Obviously you would extend these methods in the future to do something more useful!
 
388
 
 
389
Create your Workflow XML file
 
390
+++++++++++++++++++++++++++++
 
391
 
 
392
There are three types of records we need to define in a file called mymod_workflow.xml
 
393
 
 
394
#. Workflow header record (only one of these)
 
395
 
 
396
        .. code-block:: xml
 
397
 
 
398
                <record model="workflow" id="wkf_mymod">
 
399
                    <field name="name">mymod.wkf</field>
 
400
                    <field name="osv">mymod.mymod</field>
 
401
                    <field name="on_create">True</field>
 
402
                </record>
 
403
 
 
404
#. Workflow Activity records
 
405
 
 
406
        These define the actions that should be executed when the workflow reaches a particular state
 
407
 
 
408
        .. code-block:: xml
 
409
 
 
410
                <record model="workflow.activity" id="act_new">
 
411
                        <field name="wkf_id" ref="wkf_mymod" />
 
412
                        <field name="flow_start">True</field>
 
413
                        <field name="name">new</field>
 
414
                        <field name="kind">function</field>
 
415
                        <field name="action">mymod_new()</field>
 
416
                </record>
 
417
 
 
418
                <record model="workflow.activity" id="act_assigned">
 
419
                        <field name="wkf_id" ref="wkf_mymod" />
 
420
                        <field name="name">assigned</field>
 
421
                        <field name="kind">function</field>
 
422
                        <field name="action">mymod_assigned()</field>
 
423
                </record>
 
424
 
 
425
                <record model="workflow.activity" id="act_negotiation">
 
426
                        <field name="wkf_id" ref="wkf_mymod" />
 
427
                        <field name="name">negotiation</field>
 
428
                        <field name="kind">function</field>
 
429
                        <field name="action">mymod_negotiation()</field>
 
430
                </record>
 
431
 
 
432
                <record model="workflow.activity" id="act_won">
 
433
                        <field name="wkf_id" ref="wkf_mymod" />
 
434
                        <field name="name">won</field>
 
435
                        <field name="kind">function</field>
 
436
                        <field name="action">mymod_won()</field>
 
437
                        <field name="flow_stop">True</field>
 
438
                </record>
 
439
 
 
440
                <record model="workflow.activity" id="act_lost">
 
441
                        <field name="wkf_id" ref="wkf_mymod" />
 
442
                        <field name="name">lost</field>
 
443
                        <field name="kind">function</field>
 
444
                        <field name="action">mymod_lost()</field>
 
445
                        <field name="flow_stop">True</field>
 
446
                </record>
 
447
 
 
448
#. Workflow Transition records
 
449
 
 
450
        These define the possible transitions between workflow states
 
451
 
 
452
        .. code-block:: xml
 
453
 
 
454
                <record model="workflow.transition" id="t1">
 
455
                        <field name="act_from" ref="act_new" />
 
456
                        <field name="act_to" ref="act_assigned" />
 
457
                        <field name="signal">mymod_assigned</field>
 
458
                </record>
 
459
 
 
460
                <record model="workflow.transition" id="t2">
 
461
                        <field name="act_from" ref="act_assigned" />
 
462
                        <field name="act_to" ref="act_negotiation" />
 
463
                        <field name="signal">mymod_negotiation</field>
 
464
                </record>
 
465
 
 
466
                <record model="workflow.transition" id="t3">
 
467
                        <field name="act_from" ref="act_negotiation" />
 
468
                        <field name="act_to" ref="act_won" />
 
469
                        <field name="signal">mymod_won</field>
 
470
                </record>
 
471
 
 
472
                <record model="workflow.transition" id="t4">
 
473
                        <field name="act_from" ref="act_negotiation" />
 
474
                        <field name="act_to" ref="act_lost" />
 
475
                        <field name="signal">mymod_lost</field>
 
476
                </record>
 
477
 
 
478
Add mymod_workflow.xml to __terp__.py
 
479
 
 
480
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.
 
481
Add Workflow Buttons to your View
 
482
 
 
483
The final step is to add the required buttons to mymod_views.xml file.
 
484
 
 
485
Add the following at the end of the <form> section of your object's view definition:
 
486
 
 
487
        .. code-block:: xml
 
488
 
 
489
                <separator string="Workflow Actions" colspan="4"/>
 
490
                <group colspan="4" col="3">
 
491
                    <button name="mymod_assigned" string="Assigned" states="new" />
 
492
                    <button name="mymod_negotiation" string="In Negotiation" states="assigned" />
 
493
                    <button name="mymod_won" string="Won" states="negotiating" />
 
494
                    <button name="mymod_lost" string="Lost" states="negotiating" />
 
495
                </group>
 
496
 
 
497
Testing
 
498
+++++++
 
499
 
 
500
Now use the Module Manager to install or update your module. If you have done everything correctly you shouldn't get any errors. You can check if your workflow is installed in Administration -> Customisation -> Workflow Definitions
 
501
 
 
502
When you are testing, remember that the workflow will only apply to NEW records that you create.
 
503
 
 
504
Troubleshooting
 
505
+++++++++++++++
 
506
 
 
507
If your buttons do not seem to be doing anything, one of the following two things are likely:
 
508
 
 
509
   1. The record you are working on does not have a Workflow Instance record associated with it (it was probably created before you defined your workflow)
 
510
   2. You have not set the "osv" field correctly in your workflow XML file
 
511