[IMP] doc: add some diagrams to workflow doc
Also move transitions to the bottom of the document, and try to clarify the documentation for split, join and activity kinds.
|
@ -0,0 +1,20 @@
|
||||||
|
DOTFILES:=$(wildcard *.dot)
|
||||||
|
SVGFILES:=$(patsubst %.dot,%.svg,$(DOTFILES))
|
||||||
|
PNGFILES:=$(patsubst %.dot,%.png,$(DOTFILES))
|
||||||
|
|
||||||
|
# try to disable implicit rules
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: $(SVGFILES) $(PNGFILES)
|
||||||
|
|
||||||
|
# must -f to ignore errors when running clean multiple times in a row
|
||||||
|
clean:
|
||||||
|
rm -f *.png *.svg
|
||||||
|
|
||||||
|
%.svg: %.dot
|
||||||
|
dot -Tsvg $< > $@
|
||||||
|
|
||||||
|
%.png: %.dot
|
||||||
|
dot -Tpng $< > $@
|
|
@ -0,0 +1,10 @@
|
||||||
|
digraph join {
|
||||||
|
// dummy sources as support for edges, make invisible and height 0
|
||||||
|
a [style=invis height=0 fontsize=0]
|
||||||
|
b [style=invis height=0 fontsize=0]
|
||||||
|
c [style=invis height=0 fontsize=0]
|
||||||
|
|
||||||
|
a -> Activity
|
||||||
|
b -> Activity
|
||||||
|
c -> Activity
|
||||||
|
}
|
After Width: | Height: | Size: 6.7 KiB |
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
|
||||||
|
-->
|
||||||
|
<!-- Title: join Pages: 1 -->
|
||||||
|
<svg width="206pt" height="93pt"
|
||||||
|
viewBox="0.00 0.00 206.00 92.73" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 88.7279)">
|
||||||
|
<title>join</title>
|
||||||
|
<polygon fill="white" stroke="none" points="-4,4 -4,-88.7279 202,-88.7279 202,4 -4,4"/>
|
||||||
|
<!-- a -->
|
||||||
|
<!-- Activity -->
|
||||||
|
<g id="node4" class="node"><title>Activity</title>
|
||||||
|
<ellipse fill="none" stroke="black" cx="99" cy="-18" rx="40.0939" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="99" y="-14.3" font-family="Times,serif" font-size="14.00">Activity</text>
|
||||||
|
</g>
|
||||||
|
<!-- a->Activity -->
|
||||||
|
<g id="edge1" class="edge"><title>a->Activity</title>
|
||||||
|
<path fill="none" stroke="black" d="M33.6445,-71.9778C42.4332,-64.8537 58.4442,-51.875 72.4186,-40.5472"/>
|
||||||
|
<polygon fill="black" stroke="black" points="74.7768,-43.1411 80.3411,-34.1251 70.3688,-37.7033 74.7768,-43.1411"/>
|
||||||
|
</g>
|
||||||
|
<!-- b -->
|
||||||
|
<!-- b->Activity -->
|
||||||
|
<g id="edge2" class="edge"><title>b->Activity</title>
|
||||||
|
<path fill="none" stroke="black" d="M99,-71.9778C99,-66.0508 99,-56.0715 99,-46.3619"/>
|
||||||
|
<polygon fill="black" stroke="black" points="102.5,-46.1364 99,-36.1364 95.5001,-46.1365 102.5,-46.1364"/>
|
||||||
|
</g>
|
||||||
|
<!-- c -->
|
||||||
|
<!-- c->Activity -->
|
||||||
|
<g id="edge3" class="edge"><title>c->Activity</title>
|
||||||
|
<path fill="none" stroke="black" d="M164.355,-71.9778C155.567,-64.8537 139.556,-51.875 125.581,-40.5472"/>
|
||||||
|
<polygon fill="black" stroke="black" points="127.631,-37.7033 117.659,-34.1251 123.223,-43.1411 127.631,-37.7033"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,9 @@
|
||||||
|
digraph order {
|
||||||
|
Draft [style=filled fillcolor="#73fa79"]
|
||||||
|
Closed [style=filled fillcolor="#98c7df"]
|
||||||
|
Canceled [style=filled fillcolor="#98c7df"]
|
||||||
|
|
||||||
|
Draft -> Confirmed
|
||||||
|
Confirmed -> Closed
|
||||||
|
Confirmed -> Canceled
|
||||||
|
}
|
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
|
||||||
|
-->
|
||||||
|
<!-- Title: order Pages: 1 -->
|
||||||
|
<svg width="188pt" height="188pt"
|
||||||
|
viewBox="0.00 0.00 188.24 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
|
||||||
|
<title>order</title>
|
||||||
|
<polygon fill="white" stroke="none" points="-4,4 -4,-184 184.243,-184 184.243,4 -4,4"/>
|
||||||
|
<!-- Draft -->
|
||||||
|
<g id="node1" class="node"><title>Draft</title>
|
||||||
|
<ellipse fill="#73fa79" stroke="black" cx="85.3968" cy="-162" rx="30.5947" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="85.3968" y="-158.3" font-family="Times,serif" font-size="14.00">Draft</text>
|
||||||
|
</g>
|
||||||
|
<!-- Confirmed -->
|
||||||
|
<g id="node4" class="node"><title>Confirmed</title>
|
||||||
|
<ellipse fill="none" stroke="black" cx="85.3968" cy="-90" rx="51.9908" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="85.3968" y="-86.3" font-family="Times,serif" font-size="14.00">Confirmed</text>
|
||||||
|
</g>
|
||||||
|
<!-- Draft->Confirmed -->
|
||||||
|
<g id="edge1" class="edge"><title>Draft->Confirmed</title>
|
||||||
|
<path fill="none" stroke="black" d="M85.3968,-143.697C85.3968,-135.983 85.3968,-126.712 85.3968,-118.112"/>
|
||||||
|
<polygon fill="black" stroke="black" points="88.8969,-118.104 85.3968,-108.104 81.8969,-118.104 88.8969,-118.104"/>
|
||||||
|
</g>
|
||||||
|
<!-- Closed -->
|
||||||
|
<g id="node2" class="node"><title>Closed</title>
|
||||||
|
<ellipse fill="#98c7df" stroke="black" cx="36.3968" cy="-18" rx="36.2938" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="36.3968" y="-14.3" font-family="Times,serif" font-size="14.00">Closed</text>
|
||||||
|
</g>
|
||||||
|
<!-- Canceled -->
|
||||||
|
<g id="node3" class="node"><title>Canceled</title>
|
||||||
|
<ellipse fill="#98c7df" stroke="black" cx="135.397" cy="-18" rx="44.6926" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="135.397" y="-14.3" font-family="Times,serif" font-size="14.00">Canceled</text>
|
||||||
|
</g>
|
||||||
|
<!-- Confirmed->Closed -->
|
||||||
|
<g id="edge2" class="edge"><title>Confirmed->Closed</title>
|
||||||
|
<path fill="none" stroke="black" d="M73.7845,-72.411C67.8042,-63.8677 60.3917,-53.2785 53.7479,-43.7874"/>
|
||||||
|
<polygon fill="black" stroke="black" points="56.5277,-41.6552 47.9257,-35.4699 50.7931,-45.6694 56.5277,-41.6552"/>
|
||||||
|
</g>
|
||||||
|
<!-- Confirmed->Canceled -->
|
||||||
|
<g id="edge3" class="edge"><title>Confirmed->Canceled</title>
|
||||||
|
<path fill="none" stroke="black" d="M97.2461,-72.411C103.348,-63.8677 110.912,-53.2785 117.692,-43.7874"/>
|
||||||
|
<polygon fill="black" stroke="black" points="120.668,-45.6416 123.633,-35.4699 114.972,-41.573 120.668,-45.6416"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
digraph order {
|
||||||
|
Draft [style=filled fillcolor="#73fa79"]
|
||||||
|
Closed [style=filled fillcolor="#98c7df"]
|
||||||
|
Canceled [style=filled fillcolor="#98c7df"]
|
||||||
|
|
||||||
|
Draft -> Confirmed [label="discount <= 15%"]
|
||||||
|
Draft -> Validation [label="discount > 15%"]
|
||||||
|
Validation -> Confirmed [label="Accept"]
|
||||||
|
Confirmed -> Closed
|
||||||
|
Confirmed -> Canceled
|
||||||
|
}
|
After Width: | Height: | Size: 28 KiB |
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
|
||||||
|
-->
|
||||||
|
<!-- Title: order Pages: 1 -->
|
||||||
|
<svg width="260pt" height="291pt"
|
||||||
|
viewBox="0.00 0.00 259.79 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
|
||||||
|
<title>order</title>
|
||||||
|
<polygon fill="white" stroke="none" points="-4,4 -4,-287 255.792,-287 255.792,4 -4,4"/>
|
||||||
|
<!-- Draft -->
|
||||||
|
<g id="node1" class="node"><title>Draft</title>
|
||||||
|
<ellipse fill="#73fa79" stroke="black" cx="85.3968" cy="-265" rx="30.5947" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="85.3968" y="-261.3" font-family="Times,serif" font-size="14.00">Draft</text>
|
||||||
|
</g>
|
||||||
|
<!-- Confirmed -->
|
||||||
|
<g id="node4" class="node"><title>Confirmed</title>
|
||||||
|
<ellipse fill="none" stroke="black" cx="85.3968" cy="-91" rx="51.9908" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="85.3968" y="-87.3" font-family="Times,serif" font-size="14.00">Confirmed</text>
|
||||||
|
</g>
|
||||||
|
<!-- Draft->Confirmed -->
|
||||||
|
<g id="edge1" class="edge"><title>Draft->Confirmed</title>
|
||||||
|
<path fill="none" stroke="black" d="M72.5816,-248.399C62.7132,-235.312 49.8641,-215.656 44.3968,-196 40.1092,-180.585 40.1092,-175.415 44.3968,-160 48.7071,-144.503 57.6054,-129.007 66.0142,-116.73"/>
|
||||||
|
<polygon fill="black" stroke="black" points="68.9995,-118.572 71.9779,-108.405 63.3089,-114.496 68.9995,-118.572"/>
|
||||||
|
<text text-anchor="middle" x="94.3968" y="-174.3" font-family="Times,serif" font-size="14.00">discount <= 15%</text>
|
||||||
|
</g>
|
||||||
|
<!-- Validation -->
|
||||||
|
<g id="node5" class="node"><title>Validation</title>
|
||||||
|
<ellipse fill="none" stroke="black" cx="202.397" cy="-178" rx="49.2915" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="202.397" y="-174.3" font-family="Times,serif" font-size="14.00">Validation</text>
|
||||||
|
</g>
|
||||||
|
<!-- Draft->Validation -->
|
||||||
|
<g id="edge2" class="edge"><title>Draft->Validation</title>
|
||||||
|
<path fill="none" stroke="black" d="M103.936,-250.531C122.48,-237.059 151.286,-216.131 172.959,-200.386"/>
|
||||||
|
<polygon fill="black" stroke="black" points="175.139,-203.129 181.172,-194.42 171.024,-197.466 175.139,-203.129"/>
|
||||||
|
<text text-anchor="middle" x="195.897" y="-217.8" font-family="Times,serif" font-size="14.00">discount > 15%</text>
|
||||||
|
</g>
|
||||||
|
<!-- Closed -->
|
||||||
|
<g id="node2" class="node"><title>Closed</title>
|
||||||
|
<ellipse fill="#98c7df" stroke="black" cx="36.3968" cy="-18" rx="36.2938" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="36.3968" y="-14.3" font-family="Times,serif" font-size="14.00">Closed</text>
|
||||||
|
</g>
|
||||||
|
<!-- Canceled -->
|
||||||
|
<g id="node3" class="node"><title>Canceled</title>
|
||||||
|
<ellipse fill="#98c7df" stroke="black" cx="135.397" cy="-18" rx="44.6926" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="135.397" y="-14.3" font-family="Times,serif" font-size="14.00">Canceled</text>
|
||||||
|
</g>
|
||||||
|
<!-- Confirmed->Closed -->
|
||||||
|
<g id="edge4" class="edge"><title>Confirmed->Closed</title>
|
||||||
|
<path fill="none" stroke="black" d="M73.7845,-73.174C67.7175,-64.3831 60.1766,-53.4564 53.4596,-43.7236"/>
|
||||||
|
<polygon fill="black" stroke="black" points="56.1491,-41.4588 47.5884,-35.2165 50.3879,-45.4348 56.1491,-41.4588"/>
|
||||||
|
</g>
|
||||||
|
<!-- Confirmed->Canceled -->
|
||||||
|
<g id="edge5" class="edge"><title>Confirmed->Canceled</title>
|
||||||
|
<path fill="none" stroke="black" d="M97.2461,-73.174C103.348,-64.5087 110.912,-53.7682 117.692,-44.1415"/>
|
||||||
|
<polygon fill="black" stroke="black" points="120.736,-45.8965 123.633,-35.7052 115.013,-41.8661 120.736,-45.8965"/>
|
||||||
|
</g>
|
||||||
|
<!-- Validation->Confirmed -->
|
||||||
|
<g id="edge3" class="edge"><title>Validation->Confirmed</title>
|
||||||
|
<path fill="none" stroke="black" d="M181.209,-161.607C162.688,-148.152 135.604,-128.475 114.953,-113.472"/>
|
||||||
|
<polygon fill="black" stroke="black" points="116.97,-110.612 106.822,-107.566 112.856,-116.275 116.97,-110.612"/>
|
||||||
|
<text text-anchor="middle" x="170.397" y="-130.8" font-family="Times,serif" font-size="14.00">Accept</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,10 @@
|
||||||
|
digraph split {
|
||||||
|
// dummy destinations as support for edges, make invisible and height 0
|
||||||
|
a [style=invis height=0 fontsize=0]
|
||||||
|
b [style=invis height=0 fontsize=0]
|
||||||
|
c [style=invis height=0 fontsize=0]
|
||||||
|
|
||||||
|
Activity -> a
|
||||||
|
Activity -> b
|
||||||
|
Activity -> c
|
||||||
|
}
|
After Width: | Height: | Size: 6.8 KiB |
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
|
||||||
|
-->
|
||||||
|
<!-- Title: split Pages: 1 -->
|
||||||
|
<svg width="206pt" height="93pt"
|
||||||
|
viewBox="0.00 0.00 206.00 92.73" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 88.7279)">
|
||||||
|
<title>split</title>
|
||||||
|
<polygon fill="white" stroke="none" points="-4,4 -4,-88.7279 202,-88.7279 202,4 -4,4"/>
|
||||||
|
<!-- a -->
|
||||||
|
<!-- b -->
|
||||||
|
<!-- c -->
|
||||||
|
<!-- Activity -->
|
||||||
|
<g id="node4" class="node"><title>Activity</title>
|
||||||
|
<ellipse fill="none" stroke="black" cx="99" cy="-66.7279" rx="40.0939" ry="18"/>
|
||||||
|
<text text-anchor="middle" x="99" y="-63.0279" font-family="Times,serif" font-size="14.00">Activity</text>
|
||||||
|
</g>
|
||||||
|
<!-- Activity->a -->
|
||||||
|
<g id="edge1" class="edge"><title>Activity->a</title>
|
||||||
|
<path fill="none" stroke="black" d="M80.4582,-50.6978C68.3594,-40.8903 52.7894,-28.2691 41.577,-19.1802"/>
|
||||||
|
<polygon fill="black" stroke="black" points="43.641,-16.3478 33.6687,-12.7696 39.233,-21.7857 43.641,-16.3478"/>
|
||||||
|
</g>
|
||||||
|
<!-- Activity->b -->
|
||||||
|
<g id="edge2" class="edge"><title>Activity->b</title>
|
||||||
|
<path fill="none" stroke="black" d="M99,-48.5325C99,-40.494 99,-30.9869 99,-23.1351"/>
|
||||||
|
<polygon fill="black" stroke="black" points="102.5,-22.8941 99,-12.8941 95.5001,-22.8942 102.5,-22.8941"/>
|
||||||
|
</g>
|
||||||
|
<!-- Activity->c -->
|
||||||
|
<g id="edge3" class="edge"><title>Activity->c</title>
|
||||||
|
<path fill="none" stroke="black" d="M117.542,-50.6978C129.641,-40.8903 145.211,-28.2691 156.423,-19.1802"/>
|
||||||
|
<polygon fill="black" stroke="black" points="158.767,-21.7857 164.331,-12.7696 154.359,-16.3478 158.767,-21.7857"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -3,14 +3,14 @@
|
||||||
Workflows
|
Workflows
|
||||||
=========
|
=========
|
||||||
|
|
||||||
In OpenERP, a workflow is a technical artefact to manage a set of "things to
|
In Odoo, a workflow is a technical artefact to manage a set of "things to
|
||||||
do" associated to the records of some data model. The workflow provides a
|
do" associated to the records of a model. The workflow provides a higher-level
|
||||||
higher- level way to organize the things to do on a record.
|
way to organize tasks to perform with or on a record.
|
||||||
|
|
||||||
More specifically, a workflow is a directed graph where the nodes are called
|
More specifically, a workflow is a directed graph where the nodes are called
|
||||||
"activities" and the arcs are called "transitions".
|
"activities" and the arcs are called "transitions".
|
||||||
|
|
||||||
- Activities define work that should be done within the OpenERP server, such
|
- Activities define work that should be done within the Odoo server, such
|
||||||
as changing the state of some records, or sending emails.
|
as changing the state of some records, or sending emails.
|
||||||
- Transitions control how the workflow progresses from activity to activity.
|
- Transitions control how the workflow progresses from activity to activity.
|
||||||
|
|
||||||
|
@ -19,6 +19,40 @@ triggers to transitions, so that the behavior of the workflow depends on user
|
||||||
actions (such as clicking on a button), changes to records, or arbitrary
|
actions (such as clicking on a button), changes to records, or arbitrary
|
||||||
Python code.
|
Python code.
|
||||||
|
|
||||||
|
All in all, Odoo's workflow system provides:
|
||||||
|
|
||||||
|
* a description of the evolution of a record (document) over time
|
||||||
|
* automatic actions based on various and flexible conditions
|
||||||
|
* management of company roles and validation steps
|
||||||
|
* management of interactions between objects
|
||||||
|
* a visual representation of document flows through their lifecycle
|
||||||
|
|
||||||
|
For instance, a basic order could have the following flow:
|
||||||
|
|
||||||
|
.. sphinx.ext.graphviz would be nice, but it requires ``dot`` on any machine
|
||||||
|
.. where the doc is compiled... otoh this is a pain in the ass because you
|
||||||
|
.. need 2 compilation steps (dot -> image and rst -> html) every time
|
||||||
|
|
||||||
|
.. image:: workflow/order_0.*
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Orders start in the *Draft* state, can be *Confirmed* by a user, and then
|
||||||
|
either shipped (*Closed*) or *Canceled*.
|
||||||
|
|
||||||
|
A company using Odoo may want to add discount support to orders, where sales
|
||||||
|
staff has discretionary discounting powers up to 15%, but manager validation
|
||||||
|
is required for discounts beyond 15%. The workflow can be altered online to
|
||||||
|
add the relevant steps without editing Python or XML files:
|
||||||
|
|
||||||
|
.. image:: workflow/order_1.*
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
Because Activities can perform arbitrary actions, the *Validation* can
|
||||||
|
automatically send a validation request to the relevant employee.
|
||||||
|
|
||||||
|
.. note:: the order view needs to be modified to add an *Accept Discount*
|
||||||
|
button for managers
|
||||||
|
|
||||||
Basics
|
Basics
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -63,7 +97,7 @@ made up of two activies, named "a" and "b", and one transition, going from "a"
|
||||||
to "b".
|
to "b".
|
||||||
|
|
||||||
The first activity has its attribute ``flow_start`` set to ``True`` so that
|
The first activity has its attribute ``flow_start`` set to ``True`` so that
|
||||||
OpenERP knows where to start the workflow traversal after it is instanciated.
|
Odoo knows where to start the workflow traversal after it is instanciated.
|
||||||
Because ``on_create`` is set to True on the workflow record, the workflow is
|
Because ``on_create`` is set to True on the workflow record, the workflow is
|
||||||
instanciated for each newly created record. (Otherwise, the workflow should be
|
instanciated for each newly created record. (Otherwise, the workflow should be
|
||||||
instanciated by other means, such as from some module Python code.)
|
instanciated by other means, such as from some module Python code.)
|
||||||
|
@ -77,6 +111,142 @@ The transition between "a" and "b" does not specify any condition. This means
|
||||||
that the workflow instance immediately goes from "a" to "b" after "a" has been
|
that the workflow instance immediately goes from "a" to "b" after "a" has been
|
||||||
processed, and thus also processes activity "b".
|
processed, and thus also processes activity "b".
|
||||||
|
|
||||||
|
Activities
|
||||||
|
----------
|
||||||
|
|
||||||
|
While the transitions can be seen as the control structures of the workflows,
|
||||||
|
activities are the places where everything happens, from changing record
|
||||||
|
states to sending email.
|
||||||
|
|
||||||
|
Different kinds of activities exist: ``Dummy``, ``Function``, ``Subflow``, and
|
||||||
|
``Stop all``, each doing different things when the activity is processed. In
|
||||||
|
addition to their kind, activies have other properties, detailed in the next
|
||||||
|
sections.
|
||||||
|
|
||||||
|
Flow start and flow stop
|
||||||
|
''''''''''''''''''''''''
|
||||||
|
|
||||||
|
The attribute ``flow_start`` is a boolean value specifying whether the activity
|
||||||
|
is processed when the workflow is instanciated. Multiple activities can have
|
||||||
|
their attribute ``flow_start`` set to ``True``. When instanciating a workflow
|
||||||
|
for a record, Odoo simply processes all of them, and evaluate all their
|
||||||
|
outgoing transitions afterwards.
|
||||||
|
|
||||||
|
The attribute ``flow_stop`` is a boolean value specifying whether the activity
|
||||||
|
stops the workflow instance. A workflow instance is considered completed when
|
||||||
|
all its activities with the attribute ``flow_stop`` set to ``True`` are
|
||||||
|
completed.
|
||||||
|
|
||||||
|
It is important for Odoo to know when a workflow instance is completed. A
|
||||||
|
workflow can have an activity that is actually another workflow (called a
|
||||||
|
subflow); that activity is completed when the subflow is completed.
|
||||||
|
|
||||||
|
Subflow
|
||||||
|
'''''''
|
||||||
|
|
||||||
|
An activity can embed a complete workflow, called a subflow (the embedding
|
||||||
|
workflow is called the parent workflow). The workflow to instanciate is
|
||||||
|
specified by attribute ``subflow_id``.
|
||||||
|
|
||||||
|
.. note:: In the GUI, that attribute can not be set unless the kind of the
|
||||||
|
activity is ``Subflow``.
|
||||||
|
|
||||||
|
The activity is considered completed (and its outgoing transitions ready to be
|
||||||
|
evaluated) when the subflow is completed (see attribute ``flow_stop`` above).
|
||||||
|
|
||||||
|
Sending a signal from a subflow
|
||||||
|
'''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
|
When a workflow is embedded in an activity (as a subflow) of a workflow, the
|
||||||
|
sublow can send a signal from its own activities to the parent workflow by
|
||||||
|
giving a signal name in the attribute ``signal_send``. Odoo processes those
|
||||||
|
activities by sending the value of ``signal_send`` prefixed by "subflow." to
|
||||||
|
the parent workflow instance.
|
||||||
|
|
||||||
|
In other words, it is possible to react and get transitions in the parent
|
||||||
|
workflow as activities are executed in the sublow.
|
||||||
|
|
||||||
|
Server actions
|
||||||
|
''''''''''''''
|
||||||
|
|
||||||
|
An activity can run a "Server Action" by specifying its ID in the attribute
|
||||||
|
``action_id``.
|
||||||
|
|
||||||
|
Python action
|
||||||
|
'''''''''''''
|
||||||
|
|
||||||
|
An activity can execute some Python code, given by the attribute ``action``.
|
||||||
|
The evaluation environment is the same as the one explained in the section
|
||||||
|
`Conditions`_.
|
||||||
|
|
||||||
|
Split mode
|
||||||
|
''''''''''
|
||||||
|
|
||||||
|
After an activity has been processed, Odoo evaluates its transition to reach
|
||||||
|
the next activity in the flow.
|
||||||
|
|
||||||
|
However if an activity has more than one transition, Odoo must decide which
|
||||||
|
activity or activities to follow.
|
||||||
|
|
||||||
|
.. image:: workflow/split.*
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
This choice is controlled by the ``split_mode`` attribute:
|
||||||
|
|
||||||
|
``XOR`` (default)
|
||||||
|
By default, Odoo will use the first transition (in ``sequence`` order)
|
||||||
|
whose condition is satisfied. All other transitions are ignored.
|
||||||
|
``OR``
|
||||||
|
In ``OR`` mode, all transitions with a satisfied condition are traversed
|
||||||
|
simultanously. Transitions not yet valid will be ignored, even if they
|
||||||
|
become valid later.
|
||||||
|
``AND``
|
||||||
|
In ``AND`` mode, Odoo will wait until *all* transitions are satisfied, and
|
||||||
|
will traverse all of them (much like the ``OR`` mode).
|
||||||
|
|
||||||
|
Both ``OR`` and ``AND`` mode will lead to activities being active in the same
|
||||||
|
workflow.
|
||||||
|
|
||||||
|
Join mode
|
||||||
|
'''''''''
|
||||||
|
|
||||||
|
Just like outgoing transition conditions can be combined together to decide
|
||||||
|
whether they can be traversed or not, incoming transitions can be combined
|
||||||
|
together to decide if and when an activity may be processed.
|
||||||
|
|
||||||
|
.. image:: workflow/join.*
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
The ``join_mode`` attribute controls that behavior:
|
||||||
|
|
||||||
|
``XOR`` (default)
|
||||||
|
Any incoming transition enables the activity and starts its processing.
|
||||||
|
``AND``
|
||||||
|
The activity is enabled and processed only once *all* incoming transitions
|
||||||
|
have been traversed.
|
||||||
|
|
||||||
|
Kinds
|
||||||
|
'''''
|
||||||
|
|
||||||
|
An activity's kind defines the type of work an activity can perform.
|
||||||
|
|
||||||
|
Dummy (``dummy``, default)
|
||||||
|
Do nothing at all, or call a server action. Often used as dispatch or
|
||||||
|
gather "hubs" for transitions.
|
||||||
|
Function (``function``)
|
||||||
|
Run some python code, execute a server action.
|
||||||
|
Stop all (``stopall``)
|
||||||
|
Completely stops the workflow instance and marks it as completed.
|
||||||
|
Subflow (``subflow``)
|
||||||
|
Starts executing an other workflow, once that workflow is completed the
|
||||||
|
activity is done processing.
|
||||||
|
|
||||||
|
By default, the subflow is instanciated for the same record as the parent
|
||||||
|
workflow. It is possible to change that behavior by providing Python code
|
||||||
|
that returns a record ID (of the same data model as the subflow). The
|
||||||
|
embedded subflow instance is then the one of the given record.
|
||||||
|
|
||||||
|
|
||||||
Transitions
|
Transitions
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -98,7 +268,7 @@ Conditions
|
||||||
When an activity has been completed, its outgoing transitions are inspected to
|
When an activity has been completed, its outgoing transitions are inspected to
|
||||||
determine whether it is possible for the workflow instance to proceed through
|
determine whether it is possible for the workflow instance to proceed through
|
||||||
them and reach the next activities. When only a condition is defined (i.e., no
|
them and reach the next activities. When only a condition is defined (i.e., no
|
||||||
signal or trigger is defined), the condition is evaluated by OpenERP, and if
|
signal or trigger is defined), the condition is evaluated by Odoo, and if
|
||||||
it evaluates to ``True``, the worklfow instance progresses through the
|
it evaluates to ``True``, the worklfow instance progresses through the
|
||||||
transition. If the condition is not met, it will be reevaluated every time
|
transition. If the condition is not met, it will be reevaluated every time
|
||||||
the associated record is modified, or by an explicit method call to do it.
|
the associated record is modified, or by an explicit method call to do it.
|
||||||
|
@ -109,7 +279,7 @@ may be several lines long; in that case, the value of the last one determines
|
||||||
whether the transition can be taken.
|
whether the transition can be taken.
|
||||||
|
|
||||||
In the condition evaluation environment, several symbols are conveniently
|
In the condition evaluation environment, several symbols are conveniently
|
||||||
defined (in addition to the OpenERP ``safe_eval`` environment):
|
defined (in addition to the Odoo ``safe_eval`` environment):
|
||||||
|
|
||||||
- all the model column names, and
|
- all the model column names, and
|
||||||
- all the browse record's attributes.
|
- all the browse record's attributes.
|
||||||
|
@ -152,151 +322,3 @@ record IDs in the given model. Any of those records can wake up the workflow
|
||||||
instance they are associated with.
|
instance they are associated with.
|
||||||
|
|
||||||
.. note:: triggers are not re-installed whenever the transition is re-tried.
|
.. note:: triggers are not re-installed whenever the transition is re-tried.
|
||||||
|
|
||||||
Splitting and joining transitions
|
|
||||||
'''''''''''''''''''''''''''''''''
|
|
||||||
|
|
||||||
When multiple transitions leave the same activity, or lead to the same
|
|
||||||
activity, OpenERP provides some control over which transitions are actually
|
|
||||||
taken, or how the reached activity will be processed. The attributes
|
|
||||||
``split_mode`` and ``join_mode`` on the activity are used for such
|
|
||||||
control. The possible values of those attributes are explained below.
|
|
||||||
|
|
||||||
Activities
|
|
||||||
----------
|
|
||||||
|
|
||||||
While the transitions can be seen as the control structures of the workflows,
|
|
||||||
activities are the places where everything happens, from changing record
|
|
||||||
states to sending email.
|
|
||||||
|
|
||||||
Different kinds of activities exist: ``Dummy``, ``Function``, ``Subflow``, and
|
|
||||||
``Stop all``, each doing different things when the activity is processed. In
|
|
||||||
addition to their kind, activies have other properties, detailed in the next
|
|
||||||
sections.
|
|
||||||
|
|
||||||
Flow start and flow stop
|
|
||||||
''''''''''''''''''''''''
|
|
||||||
|
|
||||||
The attribute ``flow_start`` is a boolean value specifying whether the activity
|
|
||||||
is processed when the workflow is instanciated. Multiple activities can have
|
|
||||||
their attribute ``flow_start`` set to ``True``. When instanciating a workflow
|
|
||||||
for a record, OpenERP simply processes all of them, and evaluate all their
|
|
||||||
outgoing transitions afterwards.
|
|
||||||
|
|
||||||
The attribute ``flow_stop`` is a boolean value specifying whether the activity
|
|
||||||
stops the workflow instance. A workflow instance is considered completed when
|
|
||||||
all its activities with the attribute ``flow_stop`` set to ``True`` are
|
|
||||||
completed.
|
|
||||||
|
|
||||||
It is important for OpenERP to know when a workflow instance is completed. A
|
|
||||||
workflow can have an activity that is actually another workflow (called a
|
|
||||||
subflow); that activity is completed when the subflow is completed.
|
|
||||||
|
|
||||||
Subflow
|
|
||||||
'''''''
|
|
||||||
|
|
||||||
An activity can embed a complete workflow, called a subflow (the embedding
|
|
||||||
workflow is called the parent workflow). The workflow to instanciate is
|
|
||||||
specified by attribute ``subflow_id``.
|
|
||||||
|
|
||||||
.. note:: In the GUI, that attribute can not be set unless the kind of the
|
|
||||||
activity is ``Subflow``.
|
|
||||||
|
|
||||||
The activity is considered completed (and its outgoing transitions ready to be
|
|
||||||
evaluated) when the subflow is completed (see attribute ``flow_stop`` above).
|
|
||||||
|
|
||||||
Sending a signal from a subflow
|
|
||||||
'''''''''''''''''''''''''''''''
|
|
||||||
|
|
||||||
When a workflow is embedded in an activity (as a subflow) of a workflow, the
|
|
||||||
sublow can send a signal from its own activities to the parent workflow by
|
|
||||||
giving a signal name in the attribute ``signal_send``. OpenERP processes those
|
|
||||||
activities by sending the value of ``signal_send`` prefixed by "subflow." to
|
|
||||||
the parent workflow instance.
|
|
||||||
|
|
||||||
In other words, it is possible to react and get transitions in the parent
|
|
||||||
workflow as activities are executed in the sublow.
|
|
||||||
|
|
||||||
Server actions
|
|
||||||
''''''''''''''
|
|
||||||
|
|
||||||
An activity can run a "Server Action" by specifying its ID in the attribute
|
|
||||||
``action_id``.
|
|
||||||
|
|
||||||
Python action
|
|
||||||
'''''''''''''
|
|
||||||
|
|
||||||
An activity can execute some Python code, given by the attribute ``action``.
|
|
||||||
The evaluation environment is the same as the one explained in the section
|
|
||||||
`Conditions`_.
|
|
||||||
|
|
||||||
Split mode
|
|
||||||
''''''''''
|
|
||||||
|
|
||||||
After an activity has been processed, its outgoing transitions are evaluated.
|
|
||||||
Normally, if a transition can be taken, OpenERP traverses it and proceed to
|
|
||||||
the activity the transition leads to.
|
|
||||||
|
|
||||||
Actually, when more than a single transition is leaving an activity, OpenERP
|
|
||||||
may proceed or not, depending on the other transitions. That is, the
|
|
||||||
conditions on the transitions can be combined together, and the combined
|
|
||||||
result instructs OpenERP to traverse zero, one, or all the transitions. The
|
|
||||||
way they are combined is controlled by the attribute ``split_mode``.
|
|
||||||
|
|
||||||
There are three possible split modes: ``XOR``, ``OR`` and ``AND``.
|
|
||||||
|
|
||||||
``XOR``
|
|
||||||
When the transitions are combined with a ``XOR`` split mode, as soon as a
|
|
||||||
transition has a satisfied condition, the transition is traversed and the
|
|
||||||
others are skipped.
|
|
||||||
``OR``
|
|
||||||
With the ``OR`` mode, all the transitions with a satisfied condition are
|
|
||||||
traversed. The remaining transitions will not be evaluated later.
|
|
||||||
``AND``
|
|
||||||
With the ``AND`` mode, OpenERP will wait for all outgoing transition
|
|
||||||
conditions to be satisfied, then traverse all of them at once.
|
|
||||||
|
|
||||||
Join mode
|
|
||||||
'''''''''
|
|
||||||
|
|
||||||
Just like outgoing transition conditions can be combined together to decide
|
|
||||||
whether they can be traversed or not, incoming transitions can be combined
|
|
||||||
together to decide if and when an activity may be processed. The attribute
|
|
||||||
``join_mode`` controls that behavior.
|
|
||||||
|
|
||||||
There are two possible join modes: ``XOR`` and ``AND``.
|
|
||||||
|
|
||||||
``XOR``
|
|
||||||
With the ``XOR`` mode, an incoming transition with a satisfied condition
|
|
||||||
is traversed immediately, and enables the processing of the activity.
|
|
||||||
|
|
||||||
``AND``
|
|
||||||
With the ``AND`` mode, OpenERP will wait until all incoming transitions
|
|
||||||
have been traversed before enabling the processing of the activity.
|
|
||||||
|
|
||||||
Kinds
|
|
||||||
'''''
|
|
||||||
|
|
||||||
Activities can be of different kinds: ``dummy``, ``function``, ``subflow``, or
|
|
||||||
``stopall``. The kind defines what type of work an activity can do.
|
|
||||||
|
|
||||||
Dummy
|
|
||||||
The ``dummy`` kind is for activities that do nothing, or for activities
|
|
||||||
that only call a server action. Activities that do nothing can be used as
|
|
||||||
hubs to gather/dispatch transitions.
|
|
||||||
Function
|
|
||||||
The ``function`` kind is for activities that only need to run some Python
|
|
||||||
code, and possibly a server action.
|
|
||||||
Stop all
|
|
||||||
The ``stopall`` kind is for activities that will completely stop the
|
|
||||||
workflow instance and mark it as completed. In addition they can also run
|
|
||||||
some Python code.
|
|
||||||
Subflow
|
|
||||||
When the kind of the activity is ``subflow``, the activity embeds another
|
|
||||||
workflow instance. When the subflow is completed, the activity is also
|
|
||||||
considered completed.
|
|
||||||
|
|
||||||
By default, the subflow is instanciated for the same record as the parent
|
|
||||||
workflow. It is possible to change that behavior by providing Python code
|
|
||||||
that returns a record ID (of the same data model as the subflow). The
|
|
||||||
embedded subflow instance is then the one of the given record.
|
|
||||||
|
|