Files
tryton/trytond/doc/tutorial/module/workflow.rst
T

167 lines
4.7 KiB
ReStructuredText

.. _tutorial-module-workflow:
Define workflow
===============
Often records follow a workflow to change their state.
For example the opportunity can be converted or lost.
Tryton has a :class:`~trytond.model.Workflow` class that provides the tooling
to follow a workflow based on the field defined in
:attr:`~trytond.model.Workflow._transition_state` which is by default
``state``.
First we need to inherit from :class:`~trytond.model.Workflow` and add a
:class:`~trytond.model.fields.Selection` field to store the state of the
record:
.. code-block:: python
from trytond.model import Workflow
...
class Opportunity(Workflow, ModelSQL, ModelView):
...
state = fields.Selection([
('draft', "Draft"),
('converted', "Converted"),
('lost', "Lost"),
], "State",
required=True, readonly=True, sort=False)
@classmethod
def default_state(cls):
return 'draft'
We must define the allowed transitions between states by filling the
:attr:`~trytond.model.Workflow._transitions` set with tuples using the
:meth:`~trytond.model.Model.__setup__` method:
.. code-block:: python
class Opportunity(Workflow, ModelSQL, ModelView):
...
@classmethod
def __setup__(cls):
super().__setup__()
cls._transitions.update({
('draft', 'converted'),
('draft', 'lost'),
})
For each target state, we must define a
:meth:`~trytond.model.Workflow.transition` method.
For example when the opportunity is converted we fill the ``end_date`` field
with today:
.. code-block:: python
class Opportunity(Workflow, ModelSQL, ModelView):
...
@classmethod
@Workflow.transition('converted')
def convert(cls, opportunities):
pool = Pool()
Date = pool.get('ir.date')
cls.write(opportunities, {
'end_date': Date.today(),
})
.. note::
We let you define the transition method for lost.
Now we need to add a button for each transition so the user can trigger them.
We must declare the button in the :attr:`~trytond.model.ModelView._buttons`
dictionary and decorate the transition method with the
:meth:`~trytond.model.ModelView.button` to be callable from the client:
.. code-block:: python
class Opportunity(Workflow, ModelSQL, ModelView):
...
@classmethod
def __setup__(cls):
...
cls._buttons.update({
'convert': {},
'lost': {},
})
@classmethod
@ModelView.button
@Workflow.transition('converted')
def convert(cls, opportunities):
...
@classmethod
@ModelView.button
@Workflow.transition('lost')
def lost(cls, opportunities):
...
Every button must also be recorded in ``ir.model.button`` to define its label
(and also the :ref:`access right <topics-access_rights>`).
We must add to the ``opportunity.xml`` file:
.. code-block:: xml
<tryton>
<data>
...
<record model="ir.model.button" id="opportunity_convert_button">
<field name="name">convert</field>
<field name="string">Convert</field>
<field name="model" search="[('model', '=', 'training.opportunity')]"/>
</record>
<record model="ir.model.button" id="opportunity_lost_button">
<field name="name">lost</field>
<field name="string">Lost</field>
<field name="model" search="[('model', '=', 'training.opportunity')]"/>
</record>
</data>
</tryton>
Now we can add the ``state`` field and the buttons in the form view.
The buttons can be grouped under a ``group`` tag.
This is how the ``view/opportunity_form.xml`` must be adapted:
.. code-block:: xml
<form>
...
<label name="state"/>
<field name="state"/>
<group col="2" colspan="2" id="button">
<button name="lost" icon="tryton-cancel"/>
<button name="convert" icon="tryton-forward"/>
</group>
</form>
.. note::
We let you add the ``state`` field on the list view.
Update database
---------------
As we have defined new fields and XML records, we need to update the database
with:
.. code-block:: shell
$ trytond-admin -d test --all
And restart the server and reconnect with the client to test the workflow:
.. code-block:: shell
$ trytond
Exercise
---------
As exercise we let you add a transition between ``lost`` and ``draft`` which
will clear the ``end_date``.
Let's continue with :ref:`adding more reaction with dynamic state
<tutorial-module-states>`.