172 lines
4.9 KiB
ReStructuredText
172 lines
4.9 KiB
ReStructuredText
.. _tutorial-module-wizard:
|
|
|
|
Create wizard
|
|
=============
|
|
|
|
Sometime you want to add functionalities to a model that do not suite the use
|
|
of a button.
|
|
For this kind of use case the :ref:`wizard <topics-wizard>` is the preferred
|
|
solution.
|
|
A wizard is a kind of `state machine`_ where states can be a form view, an
|
|
action or transition.
|
|
|
|
.. _state machine: https://en.wikipedia.org/wiki/Finite-state_machine
|
|
|
|
Let's create a wizard that converts the opportunities by asking for the end date.
|
|
|
|
First we define a :class:`~trytond.model.ModelView` class in
|
|
:file:`opportunity.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
class ConvertStart(ModelView):
|
|
"Convert Opportunities"
|
|
__name__ = 'training.opportunity.convert.start'
|
|
|
|
end_date = fields.Date("End Date", required=True)
|
|
|
|
And we register it in the :class:`~trytond.pool.Pool` in :file:`__init__.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
def register():
|
|
Pool.register(
|
|
...,
|
|
opportunity.ConvertStart,
|
|
module='opportunity', type_='model')
|
|
|
|
Then the form view record in :file:`opportunity.xml`:
|
|
|
|
.. code-block:: xml
|
|
|
|
<tryton>
|
|
<data>
|
|
...
|
|
|
|
<record model="ir.ui.view" id="opportunity_convert_start_view_form">
|
|
<field name="model">training.opportunity.convert.start</field>
|
|
<field name="type">form</field>
|
|
<field name="name">opportunity_convert_start_form</field>
|
|
</record>
|
|
</data>
|
|
</tryton>
|
|
|
|
And the view in :file:`view/opportunity_convert_start_form.xml`:
|
|
|
|
.. code-block:: xml
|
|
|
|
<form col="2">
|
|
<label string="Convert Opportunities?" id="convert_opportunities" colspan="2" xalign="0"/>
|
|
<label name="end_date"/>
|
|
<field name="end_date"/>
|
|
</form>
|
|
|
|
Now we can define the :class:`~trytond.wizard.Wizard` with a ``start``
|
|
:class:`~trytond.wizard.StateView` for the form and a ``convert``
|
|
:class:`~trytond.wizard.StateTransition` in :file:`opportunity.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
from trytond.wizard import Wizard, StateView, StateTransition, Button
|
|
...
|
|
class Opportunity(...):
|
|
...
|
|
@classmethod
|
|
@Workflow.transition('converted')
|
|
def convert(cls, opportunities, end_date=None):
|
|
pool = Pool()
|
|
Date = pool.get('ir.date')
|
|
cls.write(opportunities, {
|
|
'end_date': end_date or Date.today(),
|
|
})
|
|
...
|
|
class Convert(Wizard):
|
|
"Convert Opportunities"
|
|
__name__ = 'training.opportunity.convert'
|
|
|
|
start = StateView(
|
|
'training.opportunity.convert.start',
|
|
'opportunity.opportunity_convert_start_view_form', [
|
|
Button("Cancel", 'end', 'tryton-cancel'),
|
|
Button("Convert", 'convert', 'tryton-ok', default=True),
|
|
])
|
|
convert = StateTransition()
|
|
|
|
def transition_convert(self):
|
|
self.model.convert(self.records, self.start.end_date)
|
|
return 'end'
|
|
|
|
.. note::
|
|
We added an optional ``end_date`` to the convert method.
|
|
|
|
And we register it in the :class:`~trytond.pool.Pool` as type ``wizard`` in
|
|
:file:`__init__.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
def register():
|
|
...
|
|
Pool.register(
|
|
opportunity.Convert,
|
|
module='opportunity', type_='wizard')
|
|
|
|
Finally we just need to create a ``ir.action.wizard`` and ``ir.action.keyword``
|
|
in :file:`opportunity.xml`:
|
|
|
|
.. code-block:: xml
|
|
|
|
<tryton>
|
|
<data>
|
|
...
|
|
<record model="ir.action.wizard" id="act_convert_opportunities">
|
|
<field name="name">Convert Opportunities</field>
|
|
<field name="wiz_name">training.opportunity.convert</field>
|
|
<field name="model">training.opportunity</field>
|
|
</record>
|
|
<record model="ir.action.keyword" id="act_convert_opportunities_keyword">
|
|
<field name="keyword">form_action</field>
|
|
<field name="model">training.opportunity,-1</field>
|
|
<field name="action" ref="act_convert_opportunities"/>
|
|
</record>
|
|
</data>
|
|
</tryton>
|
|
|
|
The ``ir.action.wizard`` links the :class:`~trytond.wizard.Wizard` with the
|
|
:class:`~trytond.model.Model`.
|
|
|
|
``name``
|
|
The string that is shown on the menu.
|
|
``wiz_name``
|
|
The name of the :class:`~trytond.wizard.Wizard`.
|
|
``model``
|
|
The name of the :class:`~trytond.model.Model`.
|
|
|
|
And the ``ir.action.keyword`` makes the :class:`~trytond.wizard.Wizard`
|
|
available as action to any ``training.opportunity``.
|
|
|
|
``keyword``
|
|
The type of `keyword <topics-actions>`.
|
|
``model``
|
|
The model or record for which the action must be displayed.
|
|
Use ``-1`` as id for any record.
|
|
``action``
|
|
The link to the action.
|
|
|
|
Update database
|
|
---------------
|
|
|
|
As we have defined new fields and XML records, we need to update the database
|
|
with:
|
|
|
|
.. code-block:: console
|
|
|
|
$ trytond-admin -d test --all
|
|
|
|
And restart the server and reconnect with the client to test the wizard:
|
|
|
|
.. code-block:: console
|
|
|
|
$ trytond
|
|
|
|
Let's create a :ref:`a report to print opportunities <tutorial-module-report>`.
|