~openerp-community/openobject-doc/ksa-openobject-doc-6.0

« back to all changes in this revision

Viewing changes to i18n/ru/source/developer/3_10_wizard/index.rst

  • Committer: Don Kirkby
  • Date: 2011-02-21 20:46:11 UTC
  • mfrom: (433.1.53 openobject-doc)
  • Revision ID: donkirkby+launpd@gmail.com-20110221204611-1ykt6dmg4k3gh5dh
[MERGE] revisions 477 to 486 from the 5.0 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
.. i18n: ===============================
 
3
.. i18n: Creating Wizard - (The Process)
 
4
.. i18n: ===============================
 
5
..
 
6
 
 
7
===============================
 
8
Creating Wizard - (The Process)
 
9
===============================
 
10
 
 
11
.. i18n: Introduction
 
12
.. i18n: ============
 
13
.. i18n: Wizards describe interaction sequences between the client and the server.
 
14
..
 
15
 
 
16
Introduction
 
17
============
 
18
Wizards describe interaction sequences between the client and the server.
 
19
 
 
20
.. i18n: Here is, as an example, a typical process for a wizard:
 
21
..
 
22
 
 
23
Here is, as an example, a typical process for a wizard:
 
24
 
 
25
.. i18n:    1. A window is sent to the client (a form to be completed)
 
26
.. i18n:    2. The client sends back the data from the fields which were filled in
 
27
.. i18n:    3. The server gets the result, usually execute a function and possibly sends another window/form to the client 
 
28
..
 
29
 
 
30
   1. A window is sent to the client (a form to be completed)
 
31
   2. The client sends back the data from the fields which were filled in
 
32
   3. The server gets the result, usually execute a function and possibly sends another window/form to the client 
 
33
 
 
34
.. i18n: .. image:: images/Wizard.png
 
35
..
 
36
 
 
37
.. image:: images/Wizard.png
 
38
 
 
39
.. i18n: Here is a screenshot of the wizard used to reconcile transactions (when you click on the gear icon in an account chart):
 
40
..
 
41
 
 
42
Here is a screenshot of the wizard used to reconcile transactions (when you click on the gear icon in an account chart):
 
43
 
 
44
.. i18n: .. image:: images/Wizard_screenshot.png 
 
45
.. i18n:    :width: 100% 
 
46
..
 
47
 
 
48
.. image:: images/Wizard_screenshot.png 
 
49
   :width: 100% 
 
50
 
 
51
.. i18n: Wizards - Principles
 
52
.. i18n: ====================
 
53
.. i18n: A wizard is a succession of steps. A step is composed of several actions;
 
54
..
 
55
 
 
56
Wizards - Principles
 
57
====================
 
58
A wizard is a succession of steps. A step is composed of several actions;
 
59
 
 
60
.. i18n: #. send a form to the client and some buttons
 
61
.. i18n: #. get the form result and the button pressed from the client
 
62
.. i18n: #. execute some actions
 
63
.. i18n: #. send a new action to the client (form, print, ...) 
 
64
..
 
65
 
 
66
#. send a form to the client and some buttons
 
67
#. get the form result and the button pressed from the client
 
68
#. execute some actions
 
69
#. send a new action to the client (form, print, ...) 
 
70
 
 
71
.. i18n: To define a wizard, you have to create a class inheriting from **wizard.interface** and instantiate it. Each wizard must have a unique name, which can be chosen arbitrarily except for the fact it has to start with the module name (for example: account.move.line.reconcile). The wizard must define a dictionary named **states** which defines all its steps.
 
72
.. i18n: A full example of a simple wizard can be found at  http://www.openobject.com/forum/post43900.html#43900
 
73
..
 
74
 
 
75
To define a wizard, you have to create a class inheriting from **wizard.interface** and instantiate it. Each wizard must have a unique name, which can be chosen arbitrarily except for the fact it has to start with the module name (for example: account.move.line.reconcile). The wizard must define a dictionary named **states** which defines all its steps.
 
76
A full example of a simple wizard can be found at  http://www.openobject.com/forum/post43900.html#43900
 
77
 
 
78
.. i18n: Here is an example of such a class:
 
79
..
 
80
 
 
81
Here is an example of such a class:
 
82
 
 
83
.. i18n: .. code-block:: python
 
84
.. i18n: 
 
85
.. i18n:        class wiz_reconcile(wizard.interface):
 
86
.. i18n:              states = {
 
87
.. i18n:                   'init': {
 
88
.. i18n:                        'actions': [_trans_rec_get],
 
89
.. i18n:                        'result': {'type': 'form', 
 
90
.. i18n:                                   'arch': _transaction_form, 
 
91
.. i18n:                                   'fields': _transaction_fields,  
 
92
.. i18n:                                   'state':[('reconcile','Reconcile'),('end','Cancel')]}
 
93
.. i18n:                  },
 
94
.. i18n:                   'reconcile': {
 
95
.. i18n:                        'actions': [_trans_rec_reconcile],
 
96
.. i18n:                        'result': {'type': 'state', 'state':'end'}
 
97
.. i18n:                  }
 
98
.. i18n:             }
 
99
.. i18n:        wiz_reconcile('account.move.line.reconcile');
 
100
..
 
101
 
 
102
.. code-block:: python
 
103
 
 
104
        class wiz_reconcile(wizard.interface):
 
105
              states = {
 
106
                   'init': {
 
107
                        'actions': [_trans_rec_get],
 
108
                        'result': {'type': 'form', 
 
109
                                   'arch': _transaction_form, 
 
110
                                   'fields': _transaction_fields,  
 
111
                                   'state':[('reconcile','Reconcile'),('end','Cancel')]}
 
112
                  },
 
113
                   'reconcile': {
 
114
                        'actions': [_trans_rec_reconcile],
 
115
                        'result': {'type': 'state', 'state':'end'}
 
116
                  }
 
117
             }
 
118
        wiz_reconcile('account.move.line.reconcile');
 
119
 
 
120
.. i18n: The 'states' dictionary define all the states of the wizard. In this example; **init** and **reconcile**. There is another state which is named end which is implicit.
 
121
..
 
122
 
 
123
The 'states' dictionary define all the states of the wizard. In this example; **init** and **reconcile**. There is another state which is named end which is implicit.
 
124
 
 
125
.. i18n: A wizard always starts in the **init** state and ends in the **end** state.
 
126
..
 
127
 
 
128
A wizard always starts in the **init** state and ends in the **end** state.
 
129
 
 
130
.. i18n: A state define two things:
 
131
..
 
132
 
 
133
A state define two things:
 
134
 
 
135
.. i18n:        #. a list of actions
 
136
.. i18n:        #. a result 
 
137
..
 
138
 
 
139
        #. a list of actions
 
140
        #. a result 
 
141
 
 
142
.. i18n: The list of actions
 
143
.. i18n: -------------------
 
144
.. i18n: Each step/state of a wizard defines a list of actions which are executed when the wizard enters the state. This list can be empty.
 
145
..
 
146
 
 
147
The list of actions
 
148
-------------------
 
149
Each step/state of a wizard defines a list of actions which are executed when the wizard enters the state. This list can be empty.
 
150
 
 
151
.. i18n: The function (actions) must have the following signatures:
 
152
..
 
153
 
 
154
The function (actions) must have the following signatures:
 
155
 
 
156
.. i18n: .. code-block:: python
 
157
.. i18n: 
 
158
.. i18n:        def _trans_rec_get(self, uid, data, res_get=False):
 
159
..
 
160
 
 
161
.. code-block:: python
 
162
 
 
163
        def _trans_rec_get(self, uid, data, res_get=False):
 
164
 
 
165
.. i18n: Where:
 
166
..
 
167
 
 
168
Where:
 
169
 
 
170
.. i18n:     * **self** is the pointer to the wizard object
 
171
.. i18n:     * **uid** is the user ID of the user which is executing the wizard
 
172
.. i18n:     * **data** is a dictionary containing the following data:
 
173
.. i18n:            * **ids**: the list of ids of resources selected when the user executed the wizard
 
174
.. i18n:            * **id**: the id highlighted when the user executed the wizard
 
175
.. i18n:            * **form**: a dictionary containing all the values the user completed in the preceding forms. If you change values in this dictionary, the following forms will be pre-completed. 
 
176
..
 
177
 
 
178
    * **self** is the pointer to the wizard object
 
179
    * **uid** is the user ID of the user which is executing the wizard
 
180
    * **data** is a dictionary containing the following data:
 
181
           * **ids**: the list of ids of resources selected when the user executed the wizard
 
182
           * **id**: the id highlighted when the user executed the wizard
 
183
           * **form**: a dictionary containing all the values the user completed in the preceding forms. If you change values in this dictionary, the following forms will be pre-completed. 
 
184
 
 
185
.. i18n: Each action function must return a dictionary. Any entries in this dictionary
 
186
.. i18n: will be merged with the data that is passed to the form when it's displayed.
 
187
..
 
188
 
 
189
Each action function must return a dictionary. Any entries in this dictionary
 
190
will be merged with the data that is passed to the form when it's displayed.
 
191
 
 
192
.. i18n: The result
 
193
.. i18n: ----------
 
194
..
 
195
 
 
196
The result
 
197
----------
 
198
 
 
199
.. i18n: Here are some result examples:
 
200
..
 
201
 
 
202
Here are some result examples:
 
203
 
 
204
.. i18n: Result: next step
 
205
..
 
206
 
 
207
Result: next step
 
208
 
 
209
.. i18n: .. code-block:: python
 
210
.. i18n: 
 
211
.. i18n:        'result': {'type': 'state', 
 
212
.. i18n:                   'state':'end'}
 
213
..
 
214
 
 
215
.. code-block:: python
 
216
 
 
217
        'result': {'type': 'state', 
 
218
                   'state':'end'}
 
219
 
 
220
.. i18n: Indicate that the wizard has to continue to the next state: 'end'. If this is the 'end' state, the wizard stops.
 
221
..
 
222
 
 
223
Indicate that the wizard has to continue to the next state: 'end'. If this is the 'end' state, the wizard stops.
 
224
 
 
225
.. i18n: Result: new dialog for the client
 
226
..
 
227
 
 
228
Result: new dialog for the client
 
229
 
 
230
.. i18n: .. code-block:: python
 
231
.. i18n: 
 
232
.. i18n:        'result': {'type': 'form', 
 
233
.. i18n:                   'arch': _form, 
 
234
.. i18n:                   'fields': _fields, 
 
235
.. i18n:                   'state':[('reconcile','Reconcile'),('end','Cancel')]}
 
236
..
 
237
 
 
238
.. code-block:: python
 
239
 
 
240
        'result': {'type': 'form', 
 
241
                   'arch': _form, 
 
242
                   'fields': _fields, 
 
243
                   'state':[('reconcile','Reconcile'),('end','Cancel')]}
 
244
 
 
245
.. i18n: The type=form indicate that this step is a dialog to the client. The dialog is composed of:
 
246
..
 
247
 
 
248
The type=form indicate that this step is a dialog to the client. The dialog is composed of:
 
249
 
 
250
.. i18n: #. a form : with fields description and a form description
 
251
.. i18n: #. some buttons : on which the user press after completing the form 
 
252
..
 
253
 
 
254
#. a form : with fields description and a form description
 
255
#. some buttons : on which the user press after completing the form 
 
256
 
 
257
.. i18n: The form description (arch) is like in the views objects. Here is an example of form:
 
258
..
 
259
 
 
260
The form description (arch) is like in the views objects. Here is an example of form:
 
261
 
 
262
.. i18n: .. code-block:: xml
 
263
.. i18n: 
 
264
.. i18n:        _form = """<?xml version="1.0"?>
 
265
.. i18n:                <form title="Reconciliation">
 
266
.. i18n:                  <separator string="Reconciliation transactions" colspan="4"/>
 
267
.. i18n:                  <field name="trans_nbr"/>
 
268
.. i18n:                  <newline/>
 
269
.. i18n:                  <field name="credit"/>
 
270
.. i18n:                  <field name="debit"/>
 
271
.. i18n:                  <field name="state"/>
 
272
.. i18n:                  <separator string="Write-Off" colspan="4"/>
 
273
.. i18n:                  <field name="writeoff"/>
 
274
.. i18n:                  <newline/>
 
275
.. i18n:                  <field name="writeoff_acc_id" colspan="3"/>
 
276
.. i18n:                </form>
 
277
.. i18n:                """
 
278
..
 
279
 
 
280
.. code-block:: xml
 
281
 
 
282
        _form = """<?xml version="1.0"?>
 
283
                <form title="Reconciliation">
 
284
                  <separator string="Reconciliation transactions" colspan="4"/>
 
285
                  <field name="trans_nbr"/>
 
286
                  <newline/>
 
287
                  <field name="credit"/>
 
288
                  <field name="debit"/>
 
289
                  <field name="state"/>
 
290
                  <separator string="Write-Off" colspan="4"/>
 
291
                  <field name="writeoff"/>
 
292
                  <newline/>
 
293
                  <field name="writeoff_acc_id" colspan="3"/>
 
294
                </form>
 
295
                """
 
296
 
 
297
.. i18n: The fields description is similar to the fields described in the python ORM objects. Example:
 
298
..
 
299
 
 
300
The fields description is similar to the fields described in the python ORM objects. Example:
 
301
 
 
302
.. i18n: .. code-block:: python
 
303
.. i18n: 
 
304
.. i18n:        _transaction_fields = {
 
305
.. i18n:              'trans_nbr': {'string':'# of Transaction', 'type':'integer', 'readonly':True},
 
306
.. i18n:              'credit': {'string':'Credit amount', 'type':'float', 'readonly':True},
 
307
.. i18n:              'debit': {'string':'Debit amount', 'type':'float', 'readonly':True},
 
308
.. i18n:              'state': { 
 
309
.. i18n:                        'string':"Date/Period Filter", 
 
310
.. i18n:                        'type':'selection', 
 
311
.. i18n:                        'selection':[('bydate','By Date'),
 
312
.. i18n:                                     ('byperiod','By Period'),
 
313
.. i18n:                                     ('all','By Date and Period'),
 
314
.. i18n:                                     ('none','No Filter')], 
 
315
.. i18n:                        'default': lambda *a:'none' 
 
316
.. i18n:                        }, 
 
317
.. i18n:              'writeoff': {'string':'Write-Off amount', 'type':'float', 'readonly':True},
 
318
.. i18n:              'writeoff_acc_id': {'string':'Write-Off account', 
 
319
.. i18n:                                    'type':'many2one', 
 
320
.. i18n:                                    'relation':'account.account'
 
321
.. i18n:                                  },
 
322
.. i18n:        }
 
323
..
 
324
 
 
325
.. code-block:: python
 
326
 
 
327
        _transaction_fields = {
 
328
              'trans_nbr': {'string':'# of Transaction', 'type':'integer', 'readonly':True},
 
329
              'credit': {'string':'Credit amount', 'type':'float', 'readonly':True},
 
330
              'debit': {'string':'Debit amount', 'type':'float', 'readonly':True},
 
331
              'state': { 
 
332
                        'string':"Date/Period Filter", 
 
333
                        'type':'selection', 
 
334
                        'selection':[('bydate','By Date'),
 
335
                                     ('byperiod','By Period'),
 
336
                                     ('all','By Date and Period'),
 
337
                                     ('none','No Filter')], 
 
338
                        'default': lambda *a:'none' 
 
339
                        }, 
 
340
              'writeoff': {'string':'Write-Off amount', 'type':'float', 'readonly':True},
 
341
              'writeoff_acc_id': {'string':'Write-Off account', 
 
342
                                   'type':'many2one', 
 
343
                                   'relation':'account.account'
 
344
                                 },
 
345
        }
 
346
 
 
347
.. i18n: Each step/state of a wizard can have several buttons. Those are located on the bottom right of the dialog box. The list of buttons for each step of the wizard is declared in the state key of its result dictionary.
 
348
..
 
349
 
 
350
Each step/state of a wizard can have several buttons. Those are located on the bottom right of the dialog box. The list of buttons for each step of the wizard is declared in the state key of its result dictionary.
 
351
 
 
352
.. i18n: For example:
 
353
..
 
354
 
 
355
For example:
 
356
 
 
357
.. i18n: .. code-block:: python
 
358
.. i18n: 
 
359
.. i18n:        'state':[('end', 'Cancel', 'gtk-cancel'), ('reconcile', 'Reconcile', '', True)]
 
360
..
 
361
 
 
362
.. code-block:: python
 
363
 
 
364
        'state':[('end', 'Cancel', 'gtk-cancel'), ('reconcile', 'Reconcile', '', True)]
 
365
 
 
366
.. i18n: #. the next step name (determine which state will be next)
 
367
.. i18n: #. the button string (to display for the client)
 
368
.. i18n: #. the gtk stock item without the stock prefix (since 4.2)
 
369
.. i18n: #. a boolean, if true the button is set as the default action (since 4.2) 
 
370
..
 
371
 
 
372
#. the next step name (determine which state will be next)
 
373
#. the button string (to display for the client)
 
374
#. the gtk stock item without the stock prefix (since 4.2)
 
375
#. a boolean, if true the button is set as the default action (since 4.2) 
 
376
 
 
377
.. i18n: Here is a screenshot of this form:
 
378
..
 
379
 
 
380
Here is a screenshot of this form:
 
381
 
 
382
.. i18n: .. image:: images/Wizard_screenshot1.png
 
383
.. i18n:    :width: 100%
 
384
..
 
385
 
 
386
.. image:: images/Wizard_screenshot1.png
 
387
   :width: 100%
 
388
 
 
389
.. i18n: Result: call a method to determine which state is next
 
390
..
 
391
 
 
392
Result: call a method to determine which state is next
 
393
 
 
394
.. i18n: .. code-block:: python
 
395
.. i18n: 
 
396
.. i18n:        def _check_refund(self, cr, uid, data, context):
 
397
.. i18n:            ...
 
398
.. i18n:            return datas['form']['refund_id'] and 'wait_invoice' or 'end'
 
399
.. i18n:         
 
400
.. i18n:            ...
 
401
.. i18n:         
 
402
.. i18n:            'result': {'type':'choice', 'next_state':_check_refund}
 
403
..
 
404
 
 
405
.. code-block:: python
 
406
 
 
407
        def _check_refund(self, cr, uid, data, context):
 
408
            ...
 
409
            return datas['form']['refund_id'] and 'wait_invoice' or 'end'
 
410
         
 
411
            ...
 
412
         
 
413
            'result': {'type':'choice', 'next_state':_check_refund}
 
414
 
 
415
.. i18n: Result: print a report
 
416
..
 
417
 
 
418
Result: print a report
 
419
 
 
420
.. i18n: .. code-block:: python
 
421
.. i18n: 
 
422
.. i18n:        def _get_invoice_id(self, uid, datas):
 
423
.. i18n:              ...
 
424
.. i18n:              return {'ids': [...]}
 
425
.. i18n:         
 
426
.. i18n:              ...
 
427
.. i18n:         
 
428
.. i18n:              'actions': [_get_invoice_id],
 
429
.. i18n:              'result': {'type':'print', 
 
430
.. i18n:                         'report':'account.invoice', 
 
431
.. i18n:                         'get_id_from_action': True, 
 
432
.. i18n:                         'state':'check_refund'}
 
433
..
 
434
 
 
435
.. code-block:: python
 
436
 
 
437
        def _get_invoice_id(self, uid, datas):
 
438
              ...
 
439
              return {'ids': [...]}
 
440
         
 
441
              ...
 
442
         
 
443
              'actions': [_get_invoice_id],
 
444
              'result': {'type':'print', 
 
445
                         'report':'account.invoice', 
 
446
                         'get_id_from_action': True, 
 
447
                         'state':'check_refund'}
 
448
 
 
449
.. i18n: Result: client run an action
 
450
..
 
451
 
 
452
Result: client run an action
 
453
 
 
454
.. i18n: .. code-block:: python
 
455
.. i18n: 
 
456
.. i18n:        def _makeInvoices(self, cr, uid, data, context):
 
457
.. i18n:            ...
 
458
.. i18n:            return {
 
459
.. i18n:                        'domain': "[('id','in', ["+','.join(map(str,newinv))+"])]",
 
460
.. i18n:                        'name': 'Invoices',
 
461
.. i18n:                        'view_type': 'form',
 
462
.. i18n:                        'view_mode': 'tree,form',
 
463
.. i18n:                        'res_model': 'account.invoice',
 
464
.. i18n:                        'view_id': False,
 
465
.. i18n:                        'context': "{'type':'out_refund'}",
 
466
.. i18n:                        'type': 'ir.actions.act_window'
 
467
.. i18n:                }
 
468
.. i18n:         
 
469
.. i18n:                ...
 
470
.. i18n:         
 
471
.. i18n:                'result': {'type': 'action', 
 
472
.. i18n:                'action': _makeInvoices, 
 
473
.. i18n:                'state': 'end'}
 
474
..
 
475
 
 
476
.. code-block:: python
 
477
 
 
478
        def _makeInvoices(self, cr, uid, data, context):
 
479
            ...
 
480
            return {
 
481
                        'domain': "[('id','in', ["+','.join(map(str,newinv))+"])]",
 
482
                        'name': 'Invoices',
 
483
                        'view_type': 'form',
 
484
                        'view_mode': 'tree,form',
 
485
                        'res_model': 'account.invoice',
 
486
                        'view_id': False,
 
487
                        'context': "{'type':'out_refund'}",
 
488
                        'type': 'ir.actions.act_window'
 
489
                }
 
490
         
 
491
                ...
 
492
         
 
493
                'result': {'type': 'action', 
 
494
                'action': _makeInvoices, 
 
495
                'state': 'end'}
 
496
 
 
497
.. i18n: The result of the function must be an all the fields of an ir.actions.* Here it is an ir.action.act_window, so the client will open an new tab for the objects account.invoice For more information about the fields used click here.
 
498
..
 
499
 
 
500
The result of the function must be an all the fields of an ir.actions.* Here it is an ir.action.act_window, so the client will open an new tab for the objects account.invoice For more information about the fields used click here.
 
501
 
 
502
.. i18n: It is recommended to use the result of a read on the ir.actions object like this:
 
503
..
 
504
 
 
505
It is recommended to use the result of a read on the ir.actions object like this:
 
506
 
 
507
.. i18n: .. code-block:: python
 
508
.. i18n: 
 
509
.. i18n:        def _account_chart_open_window(self, cr, uid, data, context):
 
510
.. i18n:                mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
 
511
.. i18n:                act_obj = pooler.get_pool(cr.dbname).get('ir.actions.act_window')
 
512
.. i18n:         
 
513
.. i18n:                result = mod_obj._get_id(cr, uid, 'account', 'action_account_tree')
 
514
.. i18n:                id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
 
515
.. i18n:                result = act_obj.read(cr, uid, [id])[0]
 
516
.. i18n:                result['context'] = str({'fiscalyear': data['form']['fiscalyear']})
 
517
.. i18n:                return result
 
518
.. i18n:         
 
519
.. i18n:                ...
 
520
.. i18n:         
 
521
.. i18n:                'result': {'type': 'action', 
 
522
.. i18n:                           'action': _account_chart_open_window, 
 
523
.. i18n:                           'state':'end'}
 
524
..
 
525
 
 
526
.. code-block:: python
 
527
 
 
528
        def _account_chart_open_window(self, cr, uid, data, context):
 
529
                mod_obj = pooler.get_pool(cr.dbname).get('ir.model.data')
 
530
                act_obj = pooler.get_pool(cr.dbname).get('ir.actions.act_window')
 
531
         
 
532
                result = mod_obj._get_id(cr, uid, 'account', 'action_account_tree')
 
533
                id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
 
534
                result = act_obj.read(cr, uid, [id])[0]
 
535
                result['context'] = str({'fiscalyear': data['form']['fiscalyear']})
 
536
                return result
 
537
         
 
538
                ...
 
539
         
 
540
                'result': {'type': 'action', 
 
541
                           'action': _account_chart_open_window, 
 
542
                           'state':'end'}
 
543
 
 
544
.. i18n: Specification
 
545
.. i18n: =============
 
546
..
 
547
 
 
548
Specification
 
549
=============
 
550
 
 
551
.. i18n: Form
 
552
.. i18n: ----
 
553
..
 
554
 
 
555
Form
 
556
----
 
557
 
 
558
.. i18n: .. code-block:: xml
 
559
.. i18n: 
 
560
.. i18n:        _form = '''<?xml version="1.0"?>
 
561
.. i18n:        <form string="Your String">
 
562
.. i18n:            <field name="Field 1"/>
 
563
.. i18n:            <newline/>
 
564
.. i18n:            <field name="Field 2"/>
 
565
.. i18n:        </form>'''
 
566
..
 
567
 
 
568
.. code-block:: xml
 
569
 
 
570
        _form = '''<?xml version="1.0"?>
 
571
        <form string="Your String">
 
572
            <field name="Field 1"/>
 
573
            <newline/>
 
574
            <field name="Field 2"/>
 
575
        </form>'''
 
576
 
 
577
.. i18n: Fields
 
578
.. i18n: ------
 
579
..
 
580
 
 
581
Fields
 
582
------
 
583
 
 
584
.. i18n: Standard
 
585
.. i18n: +++++++++
 
586
..
 
587
 
 
588
Standard
 
589
+++++++++
 
590
 
 
591
.. i18n: .. code-block:: python
 
592
.. i18n: 
 
593
.. i18n:        Field type: char, integer, boolean, float, date, datetime
 
594
.. i18n: 
 
595
.. i18n:        _fields = {
 
596
.. i18n:              'str_field': {'string':'product name', 'type':'char', 'readonly':True},
 
597
.. i18n:        }
 
598
..
 
599
 
 
600
.. code-block:: python
 
601
 
 
602
        Field type: char, integer, boolean, float, date, datetime
 
603
 
 
604
        _fields = {
 
605
              'str_field': {'string':'product name', 'type':'char', 'readonly':True},
 
606
        }
 
607
 
 
608
.. i18n: * **string**: Field label (required)
 
609
.. i18n: * **type**: (required)
 
610
.. i18n: * **readonly**: (optional) 
 
611
..
 
612
 
 
613
* **string**: Field label (required)
 
614
* **type**: (required)
 
615
* **readonly**: (optional) 
 
616
 
 
617
.. i18n: Relational
 
618
.. i18n: ++++++++++
 
619
..
 
620
 
 
621
Relational
 
622
++++++++++
 
623
 
 
624
.. i18n: .. code-block:: python
 
625
.. i18n: 
 
626
.. i18n:        Field type: one2one,many2one,one2many,many2many
 
627
.. i18n: 
 
628
.. i18n:        _fields = {
 
629
.. i18n:            'field_id': {'string':'Write-Off account', 'type':'many2one', 'relation':'account.account'}
 
630
.. i18n:        }
 
631
..
 
632
 
 
633
.. code-block:: python
 
634
 
 
635
        Field type: one2one,many2one,one2many,many2many
 
636
 
 
637
        _fields = {
 
638
            'field_id': {'string':'Write-Off account', 'type':'many2one', 'relation':'account.account'}
 
639
        }
 
640
 
 
641
.. i18n: * **string**: Field label (required)
 
642
.. i18n: * **type**: (required)
 
643
.. i18n: * **relation**: name of the relation object 
 
644
..
 
645
 
 
646
* **string**: Field label (required)
 
647
* **type**: (required)
 
648
* **relation**: name of the relation object 
 
649
 
 
650
.. i18n: Selection
 
651
.. i18n: ++++++++++
 
652
..
 
653
 
 
654
Selection
 
655
++++++++++
 
656
 
 
657
.. i18n: .. code-block:: python
 
658
.. i18n:        
 
659
.. i18n:        Field type: selection
 
660
.. i18n:        
 
661
.. i18n:        _fields = {
 
662
.. i18n:            'field_id':  { 
 
663
.. i18n:                        'string':"Date/Period Filter", 
 
664
.. i18n:                        'type':'selection', 
 
665
.. i18n:                        'selection':[('bydate','By Date'),
 
666
.. i18n:                                     ('byperiod','By Period'),
 
667
.. i18n:                                     ('all','By Date and Period'),
 
668
.. i18n:                                     ('none','No Filter')], 
 
669
.. i18n:                        'default': lambda *a:'none' 
 
670
.. i18n:                        },
 
671
..
 
672
 
 
673
.. code-block:: python
 
674
       
 
675
       Field type: selection
 
676
       
 
677
       _fields = {
 
678
           'field_id':  { 
 
679
                        'string':"Date/Period Filter", 
 
680
                        'type':'selection', 
 
681
                        'selection':[('bydate','By Date'),
 
682
                                     ('byperiod','By Period'),
 
683
                                     ('all','By Date and Period'),
 
684
                                     ('none','No Filter')], 
 
685
                        'default': lambda *a:'none' 
 
686
                        },
 
687
 
 
688
.. i18n: * **string**: Field label (required)
 
689
.. i18n: * **type**: (required)
 
690
.. i18n: * **selection**: key and values for the selection field   
 
691
..
 
692
 
 
693
* **string**: Field label (required)
 
694
* **type**: (required)
 
695
* **selection**: key and values for the selection field   
 
696
 
 
697
.. i18n: Add A New Wizard
 
698
.. i18n: ================
 
699
..
 
700
 
 
701
Add A New Wizard
 
702
================
 
703
 
 
704
.. i18n: To create a new wizard, you must:
 
705
..
 
706
 
 
707
To create a new wizard, you must:
 
708
 
 
709
.. i18n:     * create the wizard definition in a .py file
 
710
.. i18n:           * wizards are usually defined in the wizard subdirectory of their module as in server/bin/addons/module_name/wizard/your_wizard_name.py 
 
711
.. i18n:     * add your wizard to the list of import statements in the __init__.py file of your module's wizard subdirectory.
 
712
.. i18n:     * declare your wizard in the database 
 
713
..
 
714
 
 
715
    * create the wizard definition in a .py file
 
716
          * wizards are usually defined in the wizard subdirectory of their module as in server/bin/addons/module_name/wizard/your_wizard_name.py 
 
717
    * add your wizard to the list of import statements in the __init__.py file of your module's wizard subdirectory.
 
718
    * declare your wizard in the database 
 
719
 
 
720
.. i18n: The declaration is needed to map the wizard with a key of the client; when to launch which client. To declare a new wizard, you need to add it to the module_name_wizard.xml file, which contains all the wizard declarations for the module. If that file does not exist, you need to create it first.
 
721
..
 
722
 
 
723
The declaration is needed to map the wizard with a key of the client; when to launch which client. To declare a new wizard, you need to add it to the module_name_wizard.xml file, which contains all the wizard declarations for the module. If that file does not exist, you need to create it first.
 
724
 
 
725
.. i18n: Here is an example of the account_wizard.xml file;
 
726
..
 
727
 
 
728
Here is an example of the account_wizard.xml file;
 
729
 
 
730
.. i18n: .. code-block:: python
 
731
.. i18n: 
 
732
.. i18n:        <?xml version="1.0"?>
 
733
.. i18n:        <openerp>
 
734
.. i18n:            <data>
 
735
.. i18n:                <delete model="ir.actions.wizard" search="[('wiz_name','like','account.')]" />
 
736
.. i18n:                <wizard string="Reconcile Transactions" model="account.move.line" 
 
737
.. i18n:                         name="account.move.line.reconcile" />
 
738
.. i18n:                <wizard string="Verify Transac steptions" model="account.move.line" 
 
739
.. i18n:                         name="account.move.line.check" keyword="tree_but_action" /> 
 
740
.. i18n:                <wizard string="Verify Transactions" model="account.move.line"  
 
741
.. i18n:                         name="account.move.line.check" />
 
742
.. i18n:                <wizard string="Print Journal" model="account.account" 
 
743
.. i18n:                         name="account.journal" />
 
744
.. i18n:                <wizard string="Split Invoice" model="account.invoice" 
 
745
.. i18n:                         name="account.invoice.split" />
 
746
.. i18n:                <wizard string="Refund Invoice" model="account.invoice" 
 
747
.. i18n:                         name="account.invoice.refund" />
 
748
.. i18n:            </data>
 
749
.. i18n:        </openerp>
 
750
..
 
751
 
 
752
.. code-block:: python
 
753
 
 
754
        <?xml version="1.0"?>
 
755
        <openerp>
 
756
            <data>
 
757
                <delete model="ir.actions.wizard" search="[('wiz_name','like','account.')]" />
 
758
                <wizard string="Reconcile Transactions" model="account.move.line" 
 
759
                        name="account.move.line.reconcile" />
 
760
                <wizard string="Verify Transac steptions" model="account.move.line" 
 
761
                        name="account.move.line.check" keyword="tree_but_action" /> 
 
762
                <wizard string="Verify Transactions" model="account.move.line"  
 
763
                        name="account.move.line.check" />
 
764
                <wizard string="Print Journal" model="account.account" 
 
765
                        name="account.journal" />
 
766
                <wizard string="Split Invoice" model="account.invoice" 
 
767
                        name="account.invoice.split" />
 
768
                <wizard string="Refund Invoice" model="account.invoice" 
 
769
                        name="account.invoice.refund" />
 
770
            </data>
 
771
        </openerp>
 
772
 
 
773
.. i18n: Attributes for the wizard tag:
 
774
..
 
775
 
 
776
Attributes for the wizard tag:
 
777
 
 
778
.. i18n:     * **id**: Unique identifier for this wizard.
 
779
.. i18n:     * **string**: The string which will be displayed if there are several wizards for one resource. (The user will be presented a list with the wizards' names).
 
780
.. i18n:     * **model**: The name of the **model** where the data needed by the wizard is.
 
781
.. i18n:     * **name**: The name of the wizard. It is used internally and should be unique.
 
782
.. i18n:     * **replace** (optional): Whether or not the wizard should override **all** existing wizards for this model. Default value: False.
 
783
.. i18n:     * **menu** (optional): Whether or not (True|False) to link the wizard with the 'gears' button (i.e. show the button or not). Default value: True.
 
784
.. i18n:     * **keyword** (optional): Bind the wizard to another action (print icon, gear icon, ...). Possible values for the keyword attribute are:
 
785
.. i18n:           * **client_print_multi**: the print icon in a form
 
786
.. i18n:           * **client_action_multi**: the 'gears' icon in a form
 
787
.. i18n:           * **tree_but_action**: the 'gears' icon in a tree view (with the shortcuts on the left)
 
788
.. i18n:           * **tree_but_open**: the double click on a branch of a tree (with the shortcuts on the left). For example, this is used, to bind wizards in the menu. 
 
789
..
 
790
 
 
791
    * **id**: Unique identifier for this wizard.
 
792
    * **string**: The string which will be displayed if there are several wizards for one resource. (The user will be presented a list with the wizards' names).
 
793
    * **model**: The name of the **model** where the data needed by the wizard is.
 
794
    * **name**: The name of the wizard. It is used internally and should be unique.
 
795
    * **replace** (optional): Whether or not the wizard should override **all** existing wizards for this model. Default value: False.
 
796
    * **menu** (optional): Whether or not (True|False) to link the wizard with the 'gears' button (i.e. show the button or not). Default value: True.
 
797
    * **keyword** (optional): Bind the wizard to another action (print icon, gear icon, ...). Possible values for the keyword attribute are:
 
798
          * **client_print_multi**: the print icon in a form
 
799
          * **client_action_multi**: the 'gears' icon in a form
 
800
          * **tree_but_action**: the 'gears' icon in a tree view (with the shortcuts on the left)
 
801
          * **tree_but_open**: the double click on a branch of a tree (with the shortcuts on the left). For example, this is used, to bind wizards in the menu. 
 
802
 
 
803
.. i18n: **__terp__.py**
 
804
..
 
805
 
 
806
**__terp__.py**
 
807
 
 
808
.. i18n: If the wizard you created is the first one of its module, you probably had to create the modulename_wizard.xml file yourself. In that case, it should be added to the update_xml field of the __terp__.py file of the module.
 
809
..
 
810
 
 
811
If the wizard you created is the first one of its module, you probably had to create the modulename_wizard.xml file yourself. In that case, it should be added to the update_xml field of the __terp__.py file of the module.
 
812
 
 
813
.. i18n: Here is, for example, the **__terp__.py** file for the account module.
 
814
..
 
815
 
 
816
Here is, for example, the **__terp__.py** file for the account module.
 
817
 
 
818
.. i18n: .. code-block:: python
 
819
.. i18n: 
 
820
.. i18n:        {
 
821
.. i18n:            "name": OpenERP Accounting",
 
822
.. i18n:            "version": "0.1",
 
823
.. i18n:            "depends": ["base"],
 
824
.. i18n:            "init_xml": ["account_workflow.xml", "account_data.xml"],
 
825
.. i18n:            "update_xml": ["account_view.xml","account_report.xml", "account_wizard.xml"],
 
826
.. i18n:        }
 
827
..
 
828
 
 
829
.. code-block:: python
 
830
 
 
831
        {
 
832
            "name": OpenERP Accounting",
 
833
            "version": "0.1",
 
834
            "depends": ["base"],
 
835
            "init_xml": ["account_workflow.xml", "account_data.xml"],
 
836
            "update_xml": ["account_view.xml","account_report.xml", "account_wizard.xml"],
 
837
        }
 
838
 
 
839
.. i18n: osv_memory Wizard System
 
840
.. i18n: ========================
 
841
.. i18n: To develop osv_memory wizard, just create a normal object, But instead of inheriting from osv.osv, Inherit from osv.osv_memory. Methods of "wizard" are in object and if the wizard is complex, You can define workflow on object. osv_memory object is managed in memory instead of storing in postgresql.
 
842
..
 
843
 
 
844
osv_memory Wizard System
 
845
========================
 
846
To develop osv_memory wizard, just create a normal object, But instead of inheriting from osv.osv, Inherit from osv.osv_memory. Methods of "wizard" are in object and if the wizard is complex, You can define workflow on object. osv_memory object is managed in memory instead of storing in postgresql.
 
847
 
 
848
.. i18n: That's all, nothing more than just changing the inherit. These wizards can be defined at any location unlike addons/modulename/modulename_wizard.py. 
 
849
.. i18n: Historically, the _wizard prefix is for actual (old-style) wizards, so there might be a connotation there, the "new-style" osv_memory based "wizards" are perfectly normal objects (just used to emulate the old wizards, so they don't really match the old separations. 
 
850
.. i18n: Furthermore, osv_memory based "wizards" tend to need more than one object (e.g. one osv_memory object for each state of the original wizard) so the correspondance is not exactly 1:1.
 
851
..
 
852
 
 
853
That's all, nothing more than just changing the inherit. These wizards can be defined at any location unlike addons/modulename/modulename_wizard.py. 
 
854
Historically, the _wizard prefix is for actual (old-style) wizards, so there might be a connotation there, the "new-style" osv_memory based "wizards" are perfectly normal objects (just used to emulate the old wizards, so they don't really match the old separations. 
 
855
Furthermore, osv_memory based "wizards" tend to need more than one object (e.g. one osv_memory object for each state of the original wizard) so the correspondance is not exactly 1:1.
 
856
 
 
857
.. i18n: So what makes them looks like 'old' wizards?
 
858
..
 
859
 
 
860
So what makes them looks like 'old' wizards?
 
861
 
 
862
.. i18n:     * In the action that opens the object, you can put 
 
863
..
 
864
 
 
865
    * In the action that opens the object, you can put 
 
866
 
 
867
.. i18n: .. code-block:: python
 
868
.. i18n: 
 
869
.. i18n:        <field name="target">new</field>
 
870
..
 
871
 
 
872
.. code-block:: python
 
873
 
 
874
        <field name="target">new</field>
 
875
 
 
876
.. i18n: It means the object will open in a new window instead of the current one.
 
877
..
 
878
 
 
879
It means the object will open in a new window instead of the current one.
 
880
 
 
881
.. i18n:     * On a button, you can use <button special="cancel" .../> to close the window. 
 
882
..
 
883
 
 
884
    * On a button, you can use <button special="cancel" .../> to close the window. 
 
885
 
 
886
.. i18n: Example : In project.py file.
 
887
..
 
888
 
 
889
Example : In project.py file.
 
890
 
 
891
.. i18n: .. code-block:: python
 
892
.. i18n: 
 
893
.. i18n:        class config_compute_remaining(osv.osv_memory):
 
894
.. i18n:            _name='config.compute.remaining'
 
895
.. i18n:            def _get_remaining(self,cr, uid, ctx):
 
896
.. i18n:                if 'active_id' in ctx:
 
897
.. i18n:                    return self.pool.get('project.task').browse(cr,uid,ctx['active_id']).remaining_hours
 
898
.. i18n:                return False
 
899
.. i18n:            _columns = {
 
900
.. i18n:                'remaining_hours' : fields.float('Remaining Hours', digits=(16,2),),
 
901
.. i18n:                    }
 
902
.. i18n:            _defaults = {
 
903
.. i18n:                'remaining_hours': _get_remaining
 
904
.. i18n:                }
 
905
.. i18n:            def compute_hours(self, cr, uid, ids, context=None):
 
906
.. i18n:                if 'active_id' in context:
 
907
.. i18n:                    remaining_hrs=self.browse(cr,uid,ids)[0].remaining_hours
 
908
.. i18n:                    self.pool.get('project.task').write(cr,uid,context['active_id'],
 
909
.. i18n:                                                          {'remaining_hours' : remaining_hrs})
 
910
.. i18n:                return {
 
911
.. i18n:                        'type': 'ir.actions.act_window_close',
 
912
.. i18n:                 }
 
913
.. i18n:        config_compute_remaining()
 
914
..
 
915
 
 
916
.. code-block:: python
 
917
 
 
918
        class config_compute_remaining(osv.osv_memory):
 
919
            _name='config.compute.remaining'
 
920
            def _get_remaining(self,cr, uid, ctx):
 
921
                if 'active_id' in ctx:
 
922
                    return self.pool.get('project.task').browse(cr,uid,ctx['active_id']).remaining_hours
 
923
                return False
 
924
            _columns = {
 
925
                'remaining_hours' : fields.float('Remaining Hours', digits=(16,2),),
 
926
                    }
 
927
            _defaults = {
 
928
                'remaining_hours': _get_remaining
 
929
                }
 
930
            def compute_hours(self, cr, uid, ids, context=None):
 
931
                if 'active_id' in context:
 
932
                    remaining_hrs=self.browse(cr,uid,ids)[0].remaining_hours
 
933
                    self.pool.get('project.task').write(cr,uid,context['active_id'],
 
934
                                                         {'remaining_hours' : remaining_hrs})
 
935
                return {
 
936
                        'type': 'ir.actions.act_window_close',
 
937
                 }
 
938
        config_compute_remaining()
 
939
 
 
940
.. i18n: * View is same as normal view (Note buttons). 
 
941
..
 
942
 
 
943
* View is same as normal view (Note buttons). 
 
944
 
 
945
.. i18n: Example :
 
946
..
 
947
 
 
948
Example :
 
949
 
 
950
.. i18n: .. code-block:: xml
 
951
.. i18n: 
 
952
.. i18n:        <record id="view_config_compute_remaining" model="ir.ui.view">
 
953
.. i18n:                    <field name="name">Compute Remaining Hours </field>
 
954
.. i18n:                    <field name="model">config.compute.remaining</field>
 
955
.. i18n:                    <field name="type">form</field>
 
956
.. i18n:                    <field name="arch" type="xml">
 
957
.. i18n:                        <form string="Remaining Hours">
 
958
.. i18n:                            <separator colspan="4" string="Change Remaining Hours"/>
 
959
.. i18n:                            <newline/>
 
960
.. i18n:                            <field name="remaining_hours" widget="float_time"/>
 
961
.. i18n:                            <group col="4" colspan="4">
 
962
.. i18n:                                <button icon="gtk-cancel" special="cancel" string="Cancel"/>
 
963
.. i18n:                                <button icon="gtk-ok" name="compute_hours" string="Update" type="object"/>
 
964
.. i18n:                            </group>
 
965
.. i18n:                        </form>
 
966
.. i18n:                    </field>
 
967
.. i18n:                </record>
 
968
..
 
969
 
 
970
.. code-block:: xml
 
971
 
 
972
        <record id="view_config_compute_remaining" model="ir.ui.view">
 
973
                    <field name="name">Compute Remaining Hours </field>
 
974
                    <field name="model">config.compute.remaining</field>
 
975
                    <field name="type">form</field>
 
976
                    <field name="arch" type="xml">
 
977
                        <form string="Remaining Hours">
 
978
                            <separator colspan="4" string="Change Remaining Hours"/>
 
979
                            <newline/>
 
980
                            <field name="remaining_hours" widget="float_time"/>
 
981
                            <group col="4" colspan="4">
 
982
                                <button icon="gtk-cancel" special="cancel" string="Cancel"/>
 
983
                                <button icon="gtk-ok" name="compute_hours" string="Update" type="object"/>
 
984
                            </group>
 
985
                        </form>
 
986
                    </field>
 
987
                </record>
 
988
 
 
989
.. i18n: * Action is also same as normal action (don't forget to add target attribute) 
 
990
..
 
991
 
 
992
* Action is also same as normal action (don't forget to add target attribute) 
 
993
 
 
994
.. i18n: Example :
 
995
..
 
996
 
 
997
Example :
 
998
 
 
999
.. i18n: .. code-block:: xml
 
1000
.. i18n: 
 
1001
.. i18n:        <record id="action_config_compute_remaining" model="ir.actions.act_window">
 
1002
.. i18n:            <field name="name">Compute Remaining Hours</field>
 
1003
.. i18n:            <field name="type">ir.actions.act_window</field>
 
1004
.. i18n:            <field name="res_model">config.compute.remaining</field>
 
1005
.. i18n:            <field name="view_type">form</field>
 
1006
.. i18n:            <field name="view_mode">form</field>
 
1007
.. i18n:            <field name="target">new</field>
 
1008
.. i18n:        </record>
 
1009
..
 
1010
 
 
1011
.. code-block:: xml
 
1012
 
 
1013
        <record id="action_config_compute_remaining" model="ir.actions.act_window">
 
1014
            <field name="name">Compute Remaining Hours</field>
 
1015
            <field name="type">ir.actions.act_window</field>
 
1016
            <field name="res_model">config.compute.remaining</field>
 
1017
            <field name="view_type">form</field>
 
1018
            <field name="view_mode">form</field>
 
1019
            <field name="target">new</field>
 
1020
        </record>
 
1021
 
 
1022
.. i18n: osv_memory configuration item
 
1023
.. i18n: =============================
 
1024
..
 
1025
 
 
1026
osv_memory configuration item
 
1027
=============================
 
1028
 
 
1029
.. i18n: Sometimes, your addon can't do with configurable defaults and needs
 
1030
.. i18n: upfront configuration settings to work correctly. In these cases, you
 
1031
.. i18n: want to provide a configuration wizard right after installation, and
 
1032
.. i18n: potentially one which can be re-run later if needed.
 
1033
..
 
1034
 
 
1035
Sometimes, your addon can't do with configurable defaults and needs
 
1036
upfront configuration settings to work correctly. In these cases, you
 
1037
want to provide a configuration wizard right after installation, and
 
1038
potentially one which can be re-run later if needed.
 
1039
 
 
1040
.. i18n: Up until 5.0, OpenERP had such a facility but it was hardly documented
 
1041
.. i18n: and a very manual, arduous process. A simpler, more straightforward
 
1042
.. i18n: solution has been implemented for those needs.
 
1043
..
 
1044
 
 
1045
Up until 5.0, OpenERP had such a facility but it was hardly documented
 
1046
and a very manual, arduous process. A simpler, more straightforward
 
1047
solution has been implemented for those needs.
 
1048
 
 
1049
.. i18n: The basic concepts
 
1050
.. i18n: ------------------
 
1051
..
 
1052
 
 
1053
The basic concepts
 
1054
------------------
 
1055
 
 
1056
.. i18n: The new implementation provides a base behavior ``osv_memory`` object
 
1057
.. i18n: from which you need to inherit. This behavior handles the flow between
 
1058
.. i18n: the configuration items of the various extensions, and inheriting from
 
1059
.. i18n: it is therefore mandatory.
 
1060
..
 
1061
 
 
1062
The new implementation provides a base behavior ``osv_memory`` object
 
1063
from which you need to inherit. This behavior handles the flow between
 
1064
the configuration items of the various extensions, and inheriting from
 
1065
it is therefore mandatory.
 
1066
 
 
1067
.. i18n: There is also an inheritable view which provides a basic canvas,
 
1068
.. i18n: through mechanisms which will be explained later it's highly
 
1069
.. i18n: customizable. It's therefore strongly suggested that you should
 
1070
.. i18n: inherit from that view from yours as well.
 
1071
..
 
1072
 
 
1073
There is also an inheritable view which provides a basic canvas,
 
1074
through mechanisms which will be explained later it's highly
 
1075
customizable. It's therefore strongly suggested that you should
 
1076
inherit from that view from yours as well.
 
1077
 
 
1078
.. i18n: Creating a basic configuration item
 
1079
.. i18n: -----------------------------------
 
1080
..
 
1081
 
 
1082
Creating a basic configuration item
 
1083
-----------------------------------
 
1084
 
 
1085
.. i18n: Your configuration model
 
1086
.. i18n: ++++++++++++++++++++++++
 
1087
..
 
1088
 
 
1089
Your configuration model
 
1090
++++++++++++++++++++++++
 
1091
 
 
1092
.. i18n: First comes the creation of the configuration item itself. This is a
 
1093
.. i18n: normal ``osv_memory`` object with a few constraints:
 
1094
..
 
1095
 
 
1096
First comes the creation of the configuration item itself. This is a
 
1097
normal ``osv_memory`` object with a few constraints:
 
1098
 
 
1099
.. i18n: * it has to inherit from ``res.config``, which provides the basic
 
1100
.. i18n:   configuration behaviors as well as the base event handlers and
 
1101
.. i18n:   extension points
 
1102
.. i18n: 
 
1103
.. i18n: * it has to provide an ``execute`` method.[#]_ This method will be called
 
1104
.. i18n:   when validating the configuration form and contains the validation
 
1105
.. i18n:   logic. It shouldn't return anything.
 
1106
..
 
1107
 
 
1108
* it has to inherit from ``res.config``, which provides the basic
 
1109
  configuration behaviors as well as the base event handlers and
 
1110
  extension points
 
1111
 
 
1112
* it has to provide an ``execute`` method.[#]_ This method will be called
 
1113
  when validating the configuration form and contains the validation
 
1114
  logic. It shouldn't return anything.
 
1115
 
 
1116
.. i18n: .. code-block:: python
 
1117
.. i18n: 
 
1118
.. i18n:     class my_item_config(osv.osv_memory):
 
1119
.. i18n:         _name = 'my.model.config'
 
1120
.. i18n:         _inherit = 'res.config' # mandatory
 
1121
.. i18n: 
 
1122
.. i18n:         _columns = {
 
1123
.. i18n:             'my_field': fields.char('Field', size=64, required=True),
 
1124
.. i18n:         }
 
1125
.. i18n: 
 
1126
.. i18n:         def execute(self, cr, uid, ids, context=None):
 
1127
.. i18n:             'do whatever configuration work you need here'
 
1128
.. i18n:     my_item_config()
 
1129
..
 
1130
 
 
1131
.. code-block:: python
 
1132
 
 
1133
    class my_item_config(osv.osv_memory):
 
1134
        _name = 'my.model.config'
 
1135
        _inherit = 'res.config' # mandatory
 
1136
 
 
1137
        _columns = {
 
1138
            'my_field': fields.char('Field', size=64, required=True),
 
1139
        }
 
1140
 
 
1141
        def execute(self, cr, uid, ids, context=None):
 
1142
            'do whatever configuration work you need here'
 
1143
    my_item_config()
 
1144
 
 
1145
.. i18n: Your configuration view
 
1146
.. i18n: +++++++++++++++++++++++
 
1147
..
 
1148
 
 
1149
Your configuration view
 
1150
+++++++++++++++++++++++
 
1151
 
 
1152
.. i18n: Then comes the configuration form. OpenERP provides a base view which
 
1153
.. i18n: you can inherit so you don't have to deal with creating buttons and
 
1154
.. i18n: handling the progress bar (which should be displayed at the bottom
 
1155
.. i18n: left of all initial configuration dialogs). It's very strongly
 
1156
.. i18n: recommended that you use this base view.
 
1157
..
 
1158
 
 
1159
Then comes the configuration form. OpenERP provides a base view which
 
1160
you can inherit so you don't have to deal with creating buttons and
 
1161
handling the progress bar (which should be displayed at the bottom
 
1162
left of all initial configuration dialogs). It's very strongly
 
1163
recommended that you use this base view.
 
1164
 
 
1165
.. i18n: Simply add an ``inherit_id`` field to a regular ``ir.ui.view`` and
 
1166
.. i18n: set its value to ``res_config_view_base``:
 
1167
..
 
1168
 
 
1169
Simply add an ``inherit_id`` field to a regular ``ir.ui.view`` and
 
1170
set its value to ``res_config_view_base``:
 
1171
 
 
1172
.. i18n: .. code-block:: xml
 
1173
.. i18n: 
 
1174
.. i18n:     <record id="my_config_view_form" model="ir.ui.view">
 
1175
.. i18n:         <field name="name">my.item.config.view</field>
 
1176
.. i18n:         <!-- this is the model defined above -->
 
1177
.. i18n:         <field name="model">my.model.config</field>
 
1178
.. i18n:         <field name="type">form</field>
 
1179
.. i18n:         <field name="inherit_id" ref="base.res_config_view_base"/>
 
1180
.. i18n:         ...
 
1181
.. i18n:     </record>
 
1182
..
 
1183
 
 
1184
.. code-block:: xml
 
1185
 
 
1186
    <record id="my_config_view_form" model="ir.ui.view">
 
1187
        <field name="name">my.item.config.view</field>
 
1188
        <!-- this is the model defined above -->
 
1189
        <field name="model">my.model.config</field>
 
1190
        <field name="type">form</field>
 
1191
        <field name="inherit_id" ref="base.res_config_view_base"/>
 
1192
        ...
 
1193
    </record>
 
1194
 
 
1195
.. i18n: While this could be used as-is, it would display an empty dialog with
 
1196
.. i18n: a progress bar and two buttons which isn't of much
 
1197
.. i18n: interest. ``res_config_view_base`` has a special group hook which you
 
1198
.. i18n: should replace with your own content like so:
 
1199
..
 
1200
 
 
1201
While this could be used as-is, it would display an empty dialog with
 
1202
a progress bar and two buttons which isn't of much
 
1203
interest. ``res_config_view_base`` has a special group hook which you
 
1204
should replace with your own content like so:
 
1205
 
 
1206
.. i18n: .. code-block:: xml
 
1207
.. i18n: 
 
1208
.. i18n:     <field name="arch" type="xml">
 
1209
.. i18n:         <group string="res_config_contents" position="replace">
 
1210
.. i18n:             <!-- your content should be inserted within this, the string
 
1211
.. i18n:                  attribute of the previous group is used to easily find
 
1212
.. i18n:                  it for replacement -->
 
1213
.. i18n:             <label colspan="4" align="0.0" string="
 
1214
.. i18n:                 Configure this item by defining its field"/>
 
1215
.. i18n:             <field colspan="2" name="my_field"/>
 
1216
.. i18n:         </group>
 
1217
.. i18n:     </field>
 
1218
..
 
1219
 
 
1220
.. code-block:: xml
 
1221
 
 
1222
    <field name="arch" type="xml">
 
1223
        <group string="res_config_contents" position="replace">
 
1224
            <!-- your content should be inserted within this, the string
 
1225
                 attribute of the previous group is used to easily find
 
1226
                 it for replacement -->
 
1227
            <label colspan="4" align="0.0" string="
 
1228
                Configure this item by defining its field"/>
 
1229
            <field colspan="2" name="my_field"/>
 
1230
        </group>
 
1231
    </field>
 
1232
 
 
1233
.. i18n: Opening your window
 
1234
.. i18n: +++++++++++++++++++
 
1235
..
 
1236
 
 
1237
Opening your window
 
1238
+++++++++++++++++++
 
1239
 
 
1240
.. i18n: The next step is to create the ``act_window`` which links to the
 
1241
.. i18n: configuration model and the view:
 
1242
..
 
1243
 
 
1244
The next step is to create the ``act_window`` which links to the
 
1245
configuration model and the view:
 
1246
 
 
1247
.. i18n: .. code-block:: xml
 
1248
.. i18n: 
 
1249
.. i18n:     <record id="my_config_window" model="ir.actions.act_window">
 
1250
.. i18n:         <field name="name">My config window</field>
 
1251
.. i18n:         <field name="type">ir.actions.act_window</field>
 
1252
.. i18n:         <field name="res_model">my.model.config</field>
 
1253
.. i18n:         <field name="view_type">form</field>
 
1254
.. i18n:         <field name="view_id" ref="my_config_view_form"/>
 
1255
.. i18n:         <field name="view_mode">form</field>
 
1256
.. i18n:         <field name="target">new</field>
 
1257
.. i18n:     </record>
 
1258
..
 
1259
 
 
1260
.. code-block:: xml
 
1261
 
 
1262
    <record id="my_config_window" model="ir.actions.act_window">
 
1263
        <field name="name">My config window</field>
 
1264
        <field name="type">ir.actions.act_window</field>
 
1265
        <field name="res_model">my.model.config</field>
 
1266
        <field name="view_type">form</field>
 
1267
        <field name="view_id" ref="my_config_view_form"/>
 
1268
        <field name="view_mode">form</field>
 
1269
        <field name="target">new</field>
 
1270
    </record>
 
1271
 
 
1272
.. i18n: Note that the ``name`` field of this ``act_window`` will be displayed
 
1273
.. i18n: when listing the various configuration items in the Config Wizard
 
1274
.. i18n: Steps submenu (in Administration > Configuration > Configuration
 
1275
.. i18n: Wizards).
 
1276
..
 
1277
 
 
1278
Note that the ``name`` field of this ``act_window`` will be displayed
 
1279
when listing the various configuration items in the Config Wizard
 
1280
Steps submenu (in Administration > Configuration > Configuration
 
1281
Wizards).
 
1282
 
 
1283
.. i18n: Registering your action
 
1284
.. i18n: +++++++++++++++++++++++
 
1285
..
 
1286
 
 
1287
Registering your action
 
1288
+++++++++++++++++++++++
 
1289
 
 
1290
.. i18n: Finally comes actually registering the configuration item with
 
1291
.. i18n: OpenERP. This is done with an ``ir.actions.todo`` object, which
 
1292
.. i18n: mandates a single ``action_id`` field referencing the ``act_window``
 
1293
.. i18n: created previously:
 
1294
..
 
1295
 
 
1296
Finally comes actually registering the configuration item with
 
1297
OpenERP. This is done with an ``ir.actions.todo`` object, which
 
1298
mandates a single ``action_id`` field referencing the ``act_window``
 
1299
created previously:
 
1300
 
 
1301
.. i18n: .. code-block:: xml
 
1302
.. i18n: 
 
1303
.. i18n:     <record id="my_config_step" model="ir.actions.todo">
 
1304
.. i18n:         <field name="action_id" ref="my_config_window"/>
 
1305
.. i18n:     </record>
 
1306
..
 
1307
 
 
1308
.. code-block:: xml
 
1309
 
 
1310
    <record id="my_config_step" model="ir.actions.todo">
 
1311
        <field name="action_id" ref="my_config_window"/>
 
1312
    </record>
 
1313
 
 
1314
.. i18n: ``ir.actions.todo`` also has 3 optional fields:
 
1315
..
 
1316
 
 
1317
``ir.actions.todo`` also has 3 optional fields:
 
1318
 
 
1319
.. i18n: ``sequence`` (default: ``10``)
 
1320
.. i18n:     The order in which the different steps are to be
 
1321
.. i18n:     executed, lowest first.
 
1322
..
 
1323
 
 
1324
``sequence`` (default: ``10``)
 
1325
    The order in which the different steps are to be
 
1326
    executed, lowest first.
 
1327
 
 
1328
.. i18n: ``active`` (default: ``True``)
 
1329
.. i18n:     An inactive step will not be executed on the next round of
 
1330
.. i18n:     configuration.
 
1331
..
 
1332
 
 
1333
``active`` (default: ``True``)
 
1334
    An inactive step will not be executed on the next round of
 
1335
    configuration.
 
1336
 
 
1337
.. i18n: ``state`` (default: ``'open'``)
 
1338
.. i18n:     The current state for the configuration step, mostly used to
 
1339
.. i18n:     register what happened during its execution. The possible
 
1340
.. i18n:     values are ``'open'``, ``'done'``, ``'skip'`` and
 
1341
.. i18n:     ``'cancel'``.
 
1342
..
 
1343
 
 
1344
``state`` (default: ``'open'``)
 
1345
    The current state for the configuration step, mostly used to
 
1346
    register what happened during its execution. The possible
 
1347
    values are ``'open'``, ``'done'``, ``'skip'`` and
 
1348
    ``'cancel'``.
 
1349
 
 
1350
.. i18n: The result at this point is the following:
 
1351
..
 
1352
 
 
1353
The result at this point is the following:
 
1354
 
 
1355
.. i18n: .. image:: images/config_wizard_base.png
 
1356
.. i18n:    :width: 100%
 
1357
..
 
1358
 
 
1359
.. image:: images/config_wizard_base.png
 
1360
   :width: 100%
 
1361
 
 
1362
.. i18n: Customizing your configuration item
 
1363
.. i18n: -----------------------------------
 
1364
..
 
1365
 
 
1366
Customizing your configuration item
 
1367
-----------------------------------
 
1368
 
 
1369
.. i18n: While your current knowledge is certainly enough to configure your
 
1370
.. i18n: addon, a bit of good customization can be the difference between a
 
1371
.. i18n: good user experience and a great user experience.
 
1372
..
 
1373
 
 
1374
While your current knowledge is certainly enough to configure your
 
1375
addon, a bit of good customization can be the difference between a
 
1376
good user experience and a great user experience.
 
1377
 
 
1378
.. i18n: More extensive view customization
 
1379
.. i18n: +++++++++++++++++++++++++++++++++
 
1380
..
 
1381
 
 
1382
More extensive view customization
 
1383
+++++++++++++++++++++++++++++++++
 
1384
 
 
1385
.. i18n: As you might have noticed from the previous screen shot, by default
 
1386
.. i18n: your configuration window doesn't have a *title*, which isn't a
 
1387
.. i18n: problem but doesn't look very good either.
 
1388
..
 
1389
 
 
1390
As you might have noticed from the previous screen shot, by default
 
1391
your configuration window doesn't have a *title*, which isn't a
 
1392
problem but doesn't look very good either.
 
1393
 
 
1394
.. i18n: Before setting a title, a small modification to the existing view is
 
1395
.. i18n: needed though: the existing ``group`` needs to be wrapped in a
 
1396
.. i18n: ``data`` element so it's possible to customize more than one item of
 
1397
.. i18n: the parent view:
 
1398
..
 
1399
 
 
1400
Before setting a title, a small modification to the existing view is
 
1401
needed though: the existing ``group`` needs to be wrapped in a
 
1402
``data`` element so it's possible to customize more than one item of
 
1403
the parent view:
 
1404
 
 
1405
.. i18n: .. code-block:: xml
 
1406
.. i18n: 
 
1407
.. i18n:     <record id="my_config_view_form" model="ir.ui.view">
 
1408
.. i18n:         <field name="name">my.item.config.view</field>
 
1409
.. i18n:         <!-- this is the model defined above -->
 
1410
.. i18n:         <field name="model">my.model.config</field>
 
1411
.. i18n:         <field name="type">form</field>
 
1412
.. i18n:         <field name="inherit_id">res_config_view_base</field>
 
1413
.. i18n:         <field name="arch" type="xml">
 
1414
.. i18n:             <data>
 
1415
.. i18n:                 <group string="res_config_contents" position="replace">
 
1416
.. i18n:                     <!-- your content should be inserted within this, the
 
1417
.. i18n:                          string attribute of the previous group is used to
 
1418
.. i18n:                          easily find it for replacement
 
1419
.. i18n:                      -->
 
1420
.. i18n:                      <label colspan="4" align="0.0" string="
 
1421
.. i18n:                             Configure this item by defining its field
 
1422
.. i18n:                      ">
 
1423
.. i18n:                      <field colspan="2" name="my_field"/>
 
1424
.. i18n:                  </group>
 
1425
.. i18n:              </data>
 
1426
.. i18n:          </field>
 
1427
.. i18n:     </record>
 
1428
..
 
1429
 
 
1430
.. code-block:: xml
 
1431
 
 
1432
    <record id="my_config_view_form" model="ir.ui.view">
 
1433
        <field name="name">my.item.config.view</field>
 
1434
        <!-- this is the model defined above -->
 
1435
        <field name="model">my.model.config</field>
 
1436
        <field name="type">form</field>
 
1437
        <field name="inherit_id">res_config_view_base</field>
 
1438
        <field name="arch" type="xml">
 
1439
            <data>
 
1440
                <group string="res_config_contents" position="replace">
 
1441
                    <!-- your content should be inserted within this, the
 
1442
                         string attribute of the previous group is used to
 
1443
                         easily find it for replacement
 
1444
                     -->
 
1445
                     <label colspan="4" align="0.0" string="
 
1446
                            Configure this item by defining its field
 
1447
                     ">
 
1448
                     <field colspan="2" name="my_field"/>
 
1449
                 </group>
 
1450
             </data>
 
1451
         </field>
 
1452
    </record>
 
1453
 
 
1454
.. i18n: Then it becomes possible to alter the ``string`` attribute of the
 
1455
.. i18n: original ``form`` by adding the following code within the ``data``
 
1456
.. i18n: element (in this case, probably before ``group``):
 
1457
..
 
1458
 
 
1459
Then it becomes possible to alter the ``string`` attribute of the
 
1460
original ``form`` by adding the following code within the ``data``
 
1461
element (in this case, probably before ``group``):
 
1462
 
 
1463
.. i18n: .. code-block:: xml
 
1464
.. i18n: 
 
1465
.. i18n:     <!-- position=attributes is new and is used to alter the
 
1466
.. i18n:          element's attributes, instead of its content -->
 
1467
.. i18n:     <form position="attributes">
 
1468
.. i18n:         <!-- set the value of the 'string' attribute -->
 
1469
.. i18n:         <attribute name="string">Set item field</attribute>
 
1470
.. i18n:     </form>
 
1471
..
 
1472
 
 
1473
.. code-block:: xml
 
1474
 
 
1475
    <!-- position=attributes is new and is used to alter the
 
1476
         element's attributes, instead of its content -->
 
1477
    <form position="attributes">
 
1478
        <!-- set the value of the 'string' attribute -->
 
1479
        <attribute name="string">Set item field</attribute>
 
1480
    </form>
 
1481
 
 
1482
.. i18n: .. warning:: Comments in view overload
 
1483
.. i18n: 
 
1484
.. i18n:    At this point (December 2009) OpenERP cannot handle comments at the
 
1485
.. i18n:    toplevel of the view element overload. When testing or reusing
 
1486
.. i18n:    these examples, remember to strip out the comments or you will get
 
1487
.. i18n:    runtime errors when testing the addon.
 
1488
..
 
1489
 
 
1490
.. warning:: Comments in view overload
 
1491
 
 
1492
   At this point (December 2009) OpenERP cannot handle comments at the
 
1493
   toplevel of the view element overload. When testing or reusing
 
1494
   these examples, remember to strip out the comments or you will get
 
1495
   runtime errors when testing the addon.
 
1496
 
 
1497
.. i18n: With this, the configuration form gets a nice title:
 
1498
..
 
1499
 
 
1500
With this, the configuration form gets a nice title:
 
1501
 
 
1502
.. i18n: .. image:: images/config_wizard_title.png
 
1503
.. i18n:    :width: 100%
 
1504
..
 
1505
 
 
1506
.. image:: images/config_wizard_title.png
 
1507
   :width: 100%
 
1508
 
 
1509
.. i18n: More interesting customizations might be to alter the buttons provided
 
1510
.. i18n: by ``res_config_view_base`` at the bottom of the dialog: remove a
 
1511
.. i18n: button (if the configuration action shouldn't be skippable), change
 
1512
.. i18n: the button labels, ...
 
1513
..
 
1514
 
 
1515
More interesting customizations might be to alter the buttons provided
 
1516
by ``res_config_view_base`` at the bottom of the dialog: remove a
 
1517
button (if the configuration action shouldn't be skippable), change
 
1518
the button labels, ...
 
1519
 
 
1520
.. i18n: Since no specific hooks are provided for these alterations, they
 
1521
.. i18n: require the use of xpath selectors (using the ``xpath`` element).
 
1522
..
 
1523
 
 
1524
Since no specific hooks are provided for these alterations, they
 
1525
require the use of xpath selectors (using the ``xpath`` element).
 
1526
 
 
1527
.. i18n: Removing the Skip button and changing the label of the Record button
 
1528
.. i18n: to Set, for instance, would be done by adding the following after the
 
1529
.. i18n: ``group`` element:
 
1530
..
 
1531
 
 
1532
Removing the Skip button and changing the label of the Record button
 
1533
to Set, for instance, would be done by adding the following after the
 
1534
``group`` element:
 
1535
 
 
1536
.. i18n: .. code-block:: xml
 
1537
.. i18n: 
 
1538
.. i18n:     <!-- select the button 'action_skip' of the original template
 
1539
.. i18n:          and replace it by nothing, removing it -->
 
1540
.. i18n:     <xpath expr="//button[@name='action_skip']"
 
1541
.. i18n:         position="replace"/>
 
1542
..
 
1543
 
 
1544
.. code-block:: xml
 
1545
 
 
1546
    <!-- select the button 'action_skip' of the original template
 
1547
         and replace it by nothing, removing it -->
 
1548
    <xpath expr="//button[@name='action_skip']"
 
1549
        position="replace"/>
 
1550
 
 
1551
.. i18n: .. code-block:: xml
 
1552
.. i18n: 
 
1553
.. i18n:     <!-- select the button 'action_next' -->
 
1554
.. i18n:     <xpath expr="//button[@name='action_next']"
 
1555
.. i18n:            position="attributes">
 
1556
.. i18n:         <!-- and change the attribute 'string' to 'Set' -->
 
1557
.. i18n:         <attribute name="string">Set</attribute>
 
1558
.. i18n:     </xpath>
 
1559
..
 
1560
 
 
1561
.. code-block:: xml
 
1562
 
 
1563
    <!-- select the button 'action_next' -->
 
1564
    <xpath expr="//button[@name='action_next']"
 
1565
           position="attributes">
 
1566
        <!-- and change the attribute 'string' to 'Set' -->
 
1567
        <attribute name="string">Set</attribute>
 
1568
    </xpath>
 
1569
 
 
1570
.. i18n: and yield:
 
1571
..
 
1572
 
 
1573
and yield:
 
1574
 
 
1575
.. i18n: .. image:: images/config_wizard_buttons.png
 
1576
.. i18n:    :width: 100%
 
1577
..
 
1578
 
 
1579
.. image:: images/config_wizard_buttons.png
 
1580
   :width: 100%
 
1581
 
 
1582
.. i18n: It is also possible to use this method to change the name of the
 
1583
.. i18n: button, and thus the method invoked on the object (though that isn't
 
1584
.. i18n: necessarily recommended).
 
1585
..
 
1586
 
 
1587
It is also possible to use this method to change the name of the
 
1588
button, and thus the method invoked on the object (though that isn't
 
1589
necessarily recommended).
 
1590
 
 
1591
.. i18n: Model customization
 
1592
.. i18n: +++++++++++++++++++
 
1593
..
 
1594
 
 
1595
Model customization
 
1596
+++++++++++++++++++
 
1597
 
 
1598
.. i18n: Though most of the requirements should be easy to fulfill using the
 
1599
.. i18n: provided ``execute`` method hook, some addon-specific requirements
 
1600
.. i18n: are a bit more complex. ``res.config`` should be able to provide all
 
1601
.. i18n: the hooks necessary for more complex behaviors.
 
1602
..
 
1603
 
 
1604
Though most of the requirements should be easy to fulfill using the
 
1605
provided ``execute`` method hook, some addon-specific requirements
 
1606
are a bit more complex. ``res.config`` should be able to provide all
 
1607
the hooks necessary for more complex behaviors.
 
1608
 
 
1609
.. i18n: Ignoring the next step
 
1610
.. i18n: ~~~~~~~~~~~~~~~~~~~~~~
 
1611
..
 
1612
 
 
1613
Ignoring the next step
 
1614
~~~~~~~~~~~~~~~~~~~~~~
 
1615
 
 
1616
.. i18n: Ultimately, the switch to the next configuration item is done by
 
1617
.. i18n: calling the ``self.next`` method of ``res.config`` [#]_. This is the
 
1618
.. i18n: last thing the base implementations of ``action_next`` and
 
1619
.. i18n: ``action_skip`` do. But in some cases, looping on the current view or
 
1620
.. i18n: implementing a workflow-like behavior is needed. In these cases, you
 
1621
.. i18n: can simply return a dictionary from ``execute``, and ``res.config``
 
1622
.. i18n: will jump to that view instead of the one returned by ``self.next``.
 
1623
..
 
1624
 
 
1625
Ultimately, the switch to the next configuration item is done by
 
1626
calling the ``self.next`` method of ``res.config`` [#]_. This is the
 
1627
last thing the base implementations of ``action_next`` and
 
1628
``action_skip`` do. But in some cases, looping on the current view or
 
1629
implementing a workflow-like behavior is needed. In these cases, you
 
1630
can simply return a dictionary from ``execute``, and ``res.config``
 
1631
will jump to that view instead of the one returned by ``self.next``.
 
1632
 
 
1633
.. i18n: This is what the user creation item does, for instance, to let the
 
1634
.. i18n: user create several new users in a row.
 
1635
..
 
1636
 
 
1637
This is what the user creation item does, for instance, to let the
 
1638
user create several new users in a row.
 
1639
 
 
1640
.. i18n: Performing an action on skipping
 
1641
.. i18n: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
1642
..
 
1643
 
 
1644
Performing an action on skipping
 
1645
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
1646
 
 
1647
.. i18n: As opposed to ``action_next`` which requires that ``execute`` be
 
1648
.. i18n: implemented by the children classes, ``action_skip`` comes fully
 
1649
.. i18n: implemented in ``res.config``. But in the case where the child model
 
1650
.. i18n: needs to perform an action upon skipping discovery, it also provides a
 
1651
.. i18n: hook method called ``cancel`` which you can overload in a way similar
 
1652
.. i18n: to ``execute``. Its behavior is identical to ``execute``'s: not only
 
1653
.. i18n: is ``next`` called automatically at the end of ``cancel`` but it also
 
1654
.. i18n: gives the possibility of `ignoring the next step`_.
 
1655
..
 
1656
 
 
1657
As opposed to ``action_next`` which requires that ``execute`` be
 
1658
implemented by the children classes, ``action_skip`` comes fully
 
1659
implemented in ``res.config``. But in the case where the child model
 
1660
needs to perform an action upon skipping discovery, it also provides a
 
1661
hook method called ``cancel`` which you can overload in a way similar
 
1662
to ``execute``. Its behavior is identical to ``execute``'s: not only
 
1663
is ``next`` called automatically at the end of ``cancel`` but it also
 
1664
gives the possibility of `ignoring the next step`_.
 
1665
 
 
1666
.. i18n: Alternative actions
 
1667
.. i18n: ~~~~~~~~~~~~~~~~~~~
 
1668
..
 
1669
 
 
1670
Alternative actions
 
1671
~~~~~~~~~~~~~~~~~~~
 
1672
 
 
1673
.. i18n: It's also possible to either overload ``action_next`` and
 
1674
.. i18n: ``action_skip`` or, more useful, to implement more actions than these
 
1675
.. i18n: two, if more than two buttons are needed for instance.
 
1676
..
 
1677
 
 
1678
It's also possible to either overload ``action_next`` and
 
1679
``action_skip`` or, more useful, to implement more actions than these
 
1680
two, if more than two buttons are needed for instance.
 
1681
 
 
1682
.. i18n: In this case, please remember that you should always provide a way to
 
1683
.. i18n: reach ``self.next`` to the user, in order for him to be able to
 
1684
.. i18n: configure the rest of his addons.
 
1685
..
 
1686
 
 
1687
In this case, please remember that you should always provide a way to
 
1688
reach ``self.next`` to the user, in order for him to be able to
 
1689
configure the rest of his addons.
 
1690
 
 
1691
.. i18n: ``res.config``'s public API
 
1692
.. i18n: ---------------------------
 
1693
..
 
1694
 
 
1695
``res.config``'s public API
 
1696
---------------------------
 
1697
 
 
1698
.. i18n: All of the public API methods take the standard OpenERP set of
 
1699
.. i18n: arguments: ``self``, ``cr``, ``uid``, ``ids`` and ``context``.
 
1700
..
 
1701
 
 
1702
All of the public API methods take the standard OpenERP set of
 
1703
arguments: ``self``, ``cr``, ``uid``, ``ids`` and ``context``.
 
1704
 
 
1705
.. i18n: ``execute``
 
1706
.. i18n: +++++++++++
 
1707
..
 
1708
 
 
1709
``execute``
 
1710
+++++++++++
 
1711
 
 
1712
.. i18n: Hook method called in case the ``action_next`` button
 
1713
.. i18n: (default label: Record) is clicked. Should not return *anything*
 
1714
.. i18n: unless you want to display another view than the next configuration
 
1715
.. i18n: item. Returning anything other than a view dictionary will lead to
 
1716
.. i18n: undefined behaviors.
 
1717
..
 
1718
 
 
1719
Hook method called in case the ``action_next`` button
 
1720
(default label: Record) is clicked. Should not return *anything*
 
1721
unless you want to display another view than the next configuration
 
1722
item. Returning anything other than a view dictionary will lead to
 
1723
undefined behaviors.
 
1724
 
 
1725
.. i18n: It is mandatory to overload it. Failure to do so will result in a
 
1726
.. i18n: ``NotImplementedError`` being raised at runtime.
 
1727
..
 
1728
 
 
1729
It is mandatory to overload it. Failure to do so will result in a
 
1730
``NotImplementedError`` being raised at runtime.
 
1731
 
 
1732
.. i18n: The default ``res.config`` implementation should not be called in the
 
1733
.. i18n: overload (don't use ``super``).
 
1734
..
 
1735
 
 
1736
The default ``res.config`` implementation should not be called in the
 
1737
overload (don't use ``super``).
 
1738
 
 
1739
.. i18n: ``cancel``
 
1740
.. i18n: ++++++++++
 
1741
..
 
1742
 
 
1743
``cancel``
 
1744
++++++++++
 
1745
 
 
1746
.. i18n: Hook method called in case the ``action_skip`` button
 
1747
.. i18n: (default label: Skip) is clicked. Its behavior is the same as
 
1748
.. i18n: `execute`_'s, except it's not mandatory to overload it.
 
1749
..
 
1750
 
 
1751
Hook method called in case the ``action_skip`` button
 
1752
(default label: Skip) is clicked. Its behavior is the same as
 
1753
`execute`_'s, except it's not mandatory to overload it.
 
1754
 
 
1755
.. i18n: ``next``
 
1756
.. i18n: ++++++++
 
1757
..
 
1758
 
 
1759
``next``
 
1760
++++++++
 
1761
 
 
1762
.. i18n: Method called to fetch the todo (and the corresponding action) for the
 
1763
.. i18n: next configuration item. It can be overloaded if the configuration
 
1764
.. i18n: item needs custom behavior common to all events.
 
1765
..
 
1766
 
 
1767
Method called to fetch the todo (and the corresponding action) for the
 
1768
next configuration item. It can be overloaded if the configuration
 
1769
item needs custom behavior common to all events.
 
1770
 
 
1771
.. i18n: If overloaded, the default ``res.config`` implementation must be
 
1772
.. i18n: called and its result returned in order to get and execute the next
 
1773
.. i18n: configuration item.
 
1774
..
 
1775
 
 
1776
If overloaded, the default ``res.config`` implementation must be
 
1777
called and its result returned in order to get and execute the next
 
1778
configuration item.
 
1779
 
 
1780
.. i18n: ``action_next`` and ``action_skip``
 
1781
.. i18n: +++++++++++++++++++++++++++++++++++
 
1782
..
 
1783
 
 
1784
``action_next`` and ``action_skip``
 
1785
+++++++++++++++++++++++++++++++++++
 
1786
 
 
1787
.. i18n: Event handler for the buttons of the base view, overloading them
 
1788
.. i18n: should never be necessary but in case it's needed the default
 
1789
.. i18n: ``res.config`` implementation should be called (via ``super``) and its
 
1790
.. i18n: result returned.
 
1791
..
 
1792
 
 
1793
Event handler for the buttons of the base view, overloading them
 
1794
should never be necessary but in case it's needed the default
 
1795
``res.config`` implementation should be called (via ``super``) and its
 
1796
result returned.
 
1797
 
 
1798
.. i18n: .. [#] This isn't completely true, as you will see when `Customizing
 
1799
.. i18n:        your configuration item`_
 
1800
..
 
1801
 
 
1802
.. [#] This isn't completely true, as you will see when `Customizing
 
1803
       your configuration item`_
 
1804
 
 
1805
.. i18n: .. [#] this method is part of the official API and you're free to
 
1806
.. i18n:        overload it if needed, but you should always call
 
1807
.. i18n:        ``res.config``'s through ``super`` when your work is
 
1808
.. i18n:        done. Overloading ``next`` is also probably overkill in most
 
1809
.. i18n:        situations.
 
1810
.. i18n:        
 
1811
.. i18n: ======================================================================
 
1812
.. i18n: Guidelines on how to convert old-style wizard to new osv_memory style
 
1813
.. i18n: ======================================================================
 
1814
..
 
1815
 
 
1816
.. [#] this method is part of the official API and you're free to
 
1817
       overload it if needed, but you should always call
 
1818
       ``res.config``'s through ``super`` when your work is
 
1819
       done. Overloading ``next`` is also probably overkill in most
 
1820
       situations.
 
1821
       
 
1822
======================================================================
 
1823
Guidelines on how to convert old-style wizard to new osv_memory style
 
1824
======================================================================
 
1825
 
 
1826
.. i18n: OSV Memory Wizard
 
1827
.. i18n: =================
 
1828
.. i18n: provide important advantages over the pre-5.0 wizard system, with support features that were difficult to implement in wizards previously, such as:
 
1829
..
 
1830
 
 
1831
OSV Memory Wizard
 
1832
=================
 
1833
provide important advantages over the pre-5.0 wizard system, with support features that were difficult to implement in wizards previously, such as:
 
1834
 
 
1835
.. i18n: #. inheritance
 
1836
.. i18n: #. workflows
 
1837
.. i18n: #. complex relation fields
 
1838
.. i18n: #. computed fields
 
1839
.. i18n: #. all kind of views (lists, graphs, ...)
 
1840
..
 
1841
 
 
1842
#. inheritance
 
1843
#. workflows
 
1844
#. complex relation fields
 
1845
#. computed fields
 
1846
#. all kind of views (lists, graphs, ...)
 
1847
 
 
1848
.. i18n: The new wizards are also easier and more intuitive to write as they make use of the same syntax as other osv objects and views.
 
1849
..
 
1850
 
 
1851
The new wizards are also easier and more intuitive to write as they make use of the same syntax as other osv objects and views.
 
1852
 
 
1853
.. i18n: This section will highlight the main steps usually required when porting a classical wizard to the new osv_memory wizard system.
 
1854
.. i18n: For more details about the osv_memory wizard see also section XXX.
 
1855
..
 
1856
 
 
1857
This section will highlight the main steps usually required when porting a classical wizard to the new osv_memory wizard system.
 
1858
For more details about the osv_memory wizard see also section XXX.
 
1859
 
 
1860
.. i18n: Basically the idea is to create a regular osv object to hold the data structures and the logic of the wizard, but instead of inheriting from osv.osv, you inherit from osv.osv_memory. The methods of the old-style wizard will be moved as methods of the osv_memory object, and the various views changed into real views defined on the model of the wizard.
 
1861
..
 
1862
 
 
1863
Basically the idea is to create a regular osv object to hold the data structures and the logic of the wizard, but instead of inheriting from osv.osv, you inherit from osv.osv_memory. The methods of the old-style wizard will be moved as methods of the osv_memory object, and the various views changed into real views defined on the model of the wizard.
 
1864
 
 
1865
.. i18n: If the wizard is complex, you could even define a workflow on the wizard object (see section XXX for details about workflows)
 
1866
..
 
1867
 
 
1868
If the wizard is complex, you could even define a workflow on the wizard object (see section XXX for details about workflows)
 
1869
 
 
1870
.. i18n: Using a very simple wizard as an example, here is a step-by-step conversion to the new osv_memory system:
 
1871
..
 
1872
 
 
1873
Using a very simple wizard as an example, here is a step-by-step conversion to the new osv_memory system:
 
1874
 
 
1875
.. i18n: Steps
 
1876
.. i18n: =====
 
1877
..
 
1878
 
 
1879
Steps
 
1880
=====
 
1881
 
 
1882
.. i18n: 1. Create a new object that extends osv_memory, including the required fields and methods: 
 
1883
..
 
1884
 
 
1885
1. Create a new object that extends osv_memory, including the required fields and methods: 
 
1886
 
 
1887
.. i18n: .. image:: images/wizard_window.png
 
1888
..
 
1889
 
 
1890
.. image:: images/wizard_window.png
 
1891
 
 
1892
.. i18n: .. code-block:: python
 
1893
.. i18n: 
 
1894
.. i18n:     def _action_open_window(self, cr, uid, data, context): 
 
1895
.. i18n:     .
 
1896
.. i18n:     .
 
1897
.. i18n:     
 
1898
.. i18n:     class product_margins(wizard.interface): 
 
1899
.. i18n:         form1 = '''<?xml version="1.0"?> 
 
1900
.. i18n:         <form string="View Stock of Products"> 
 
1901
.. i18n:             <separator string="Select " colspan="4"/> 
 
1902
.. i18n:             <field name="from_date"/> 
 
1903
.. i18n:             <field name="to_date"/> 
 
1904
.. i18n:             <field name="invoice_state"/> 
 
1905
.. i18n:         </form>''' 
 
1906
.. i18n: 
 
1907
.. i18n:         form1_fields = { 
 
1908
.. i18n:            'from_date': { 
 
1909
.. i18n:                     'string': 'From', 
 
1910
.. i18n:                     'type': 'date', 
 
1911
.. i18n:                     'default': lambda *a:time.strftime('%Y-01-01'), 
 
1912
.. i18n: 
 
1913
.. i18n:             }, 
 
1914
.. i18n:            'to_date': { 
 
1915
.. i18n:                     'string': 'To', 
 
1916
.. i18n:                     'type': 'date', 
 
1917
.. i18n:                     'default': lambda *a:time.strftime('%Y-12-31'), 
 
1918
.. i18n: 
 
1919
.. i18n:             }, 
 
1920
.. i18n:            'invoice_state': { 
 
1921
.. i18n:                     'string': 'Invoice State', 
 
1922
.. i18n:                     'type': 'selection', 
 
1923
.. i18n:                     'selection': [('paid','Paid'),('open_paid','Open and Paid'),('draft_open_paid','Draft, Open and Paid'),], 
 
1924
.. i18n:                     'required': True, 
 
1925
.. i18n:                     'default': lambda *a:"open_paid", 
 
1926
.. i18n:             }, 
 
1927
.. i18n:         } 
 
1928
.. i18n: 
 
1929
.. i18n:         states = { 
 
1930
.. i18n:           'init': { 
 
1931
.. i18n:                 'actions': [], 
 
1932
.. i18n:                 'result': {'type': 'form', 'arch':form1, 'fields':form1_fields, 'state': [('end', 'Cancel','gtk-cancel'),('open', 'Open Margins','gtk-ok')]} 
 
1933
.. i18n:             }, 
 
1934
.. i18n:         'open': { 
 
1935
.. i18n:                 'actions': [], 
 
1936
.. i18n:                 'result': {'type': 'action', 'action': _action_open_window, 'state':'end'} 
 
1937
.. i18n:             } 
 
1938
.. i18n:         } 
 
1939
.. i18n:     product_margins('product.margins')
 
1940
..
 
1941
 
 
1942
.. code-block:: python
 
1943
 
 
1944
    def _action_open_window(self, cr, uid, data, context): 
 
1945
    .
 
1946
    .
 
1947
    
 
1948
    class product_margins(wizard.interface): 
 
1949
        form1 = '''<?xml version="1.0"?> 
 
1950
        <form string="View Stock of Products"> 
 
1951
            <separator string="Select " colspan="4"/> 
 
1952
            <field name="from_date"/> 
 
1953
            <field name="to_date"/> 
 
1954
            <field name="invoice_state"/> 
 
1955
        </form>''' 
 
1956
 
 
1957
        form1_fields = { 
 
1958
            'from_date': { 
 
1959
                    'string': 'From', 
 
1960
                    'type': 'date', 
 
1961
                    'default': lambda *a:time.strftime('%Y-01-01'), 
 
1962
 
 
1963
            }, 
 
1964
            'to_date': { 
 
1965
                    'string': 'To', 
 
1966
                    'type': 'date', 
 
1967
                    'default': lambda *a:time.strftime('%Y-12-31'), 
 
1968
 
 
1969
            }, 
 
1970
            'invoice_state': { 
 
1971
                    'string': 'Invoice State', 
 
1972
                    'type': 'selection', 
 
1973
                    'selection': [('paid','Paid'),('open_paid','Open and Paid'),('draft_open_paid','Draft, Open and Paid'),], 
 
1974
                    'required': True, 
 
1975
                    'default': lambda *a:"open_paid", 
 
1976
            }, 
 
1977
        } 
 
1978
 
 
1979
        states = { 
 
1980
          'init': { 
 
1981
                'actions': [], 
 
1982
                'result': {'type': 'form', 'arch':form1, 'fields':form1_fields, 'state': [('end', 'Cancel','gtk-cancel'),('open', 'Open Margins','gtk-ok')]} 
 
1983
            }, 
 
1984
        'open': { 
 
1985
                'actions': [], 
 
1986
                'result': {'type': 'action', 'action': _action_open_window, 'state':'end'} 
 
1987
            } 
 
1988
        } 
 
1989
    product_margins('product.margins')
 
1990
 
 
1991
.. i18n: New Wizard File : <<module_name>>_<<filename>>.py
 
1992
.. i18n: =================================================
 
1993
..
 
1994
 
 
1995
New Wizard File : <<module_name>>_<<filename>>.py
 
1996
=================================================
 
1997
 
 
1998
.. i18n: .. code-block:: python
 
1999
.. i18n: 
 
2000
.. i18n:     class product_margin(osv.osv_memory): 
 
2001
.. i18n:         ''' 
 
2002
.. i18n:         Product Margin 
 
2003
.. i18n:         ''' 
 
2004
.. i18n:         _name = 'product.margin' 
 
2005
.. i18n:         _description = 'Product Margin' 
 
2006
.. i18n: 
 
2007
.. i18n:         def _action_open_window(self, cr, uid, ids, context): 
 
2008
.. i18n:            . 
 
2009
.. i18n:            . 
 
2010
.. i18n:            . 
 
2011
.. i18n: 
 
2012
.. i18n:         _columns = { 
 
2013
.. i18n:             #TODO : import time required to get currect date 
 
2014
.. i18n:             'from_date': fields.date('From'), 
 
2015
.. i18n:             #TODO : import time required to get currect date 
 
2016
.. i18n:             'to_date': fields.date('To'), 
 
2017
.. i18n:             'invoice_state':fields.selection([ 
 
2018
.. i18n:                ('paid','Paid'), 
 
2019
.. i18n:                ('open_paid','Open and Paid'), 
 
2020
.. i18n:                ('draft_open_paid','Draft, Open and Paid'), 
 
2021
.. i18n:             ],'Invoice State', select=True, required=True), 
 
2022
.. i18n:         } 
 
2023
.. i18n:         _defaults = { 
 
2024
.. i18n:             'from_date':  lambda *a:time.strftime('%Y-01-01'), 
 
2025
.. i18n:             'to_date': lambda *a:time.strftime('%Y-01-01'), 
 
2026
.. i18n:             'invoice_state': lambda *a:"open_paid", 
 
2027
.. i18n:         } 
 
2028
.. i18n:     product_margin()
 
2029
..
 
2030
 
 
2031
.. code-block:: python
 
2032
 
 
2033
    class product_margin(osv.osv_memory): 
 
2034
        ''' 
 
2035
        Product Margin 
 
2036
        ''' 
 
2037
        _name = 'product.margin' 
 
2038
        _description = 'Product Margin' 
 
2039
 
 
2040
        def _action_open_window(self, cr, uid, ids, context): 
 
2041
            . 
 
2042
            . 
 
2043
            . 
 
2044
 
 
2045
        _columns = { 
 
2046
            #TODO : import time required to get currect date 
 
2047
            'from_date': fields.date('From'), 
 
2048
            #TODO : import time required to get currect date 
 
2049
            'to_date': fields.date('To'), 
 
2050
            'invoice_state':fields.selection([ 
 
2051
               ('paid','Paid'), 
 
2052
               ('open_paid','Open and Paid'), 
 
2053
               ('draft_open_paid','Draft, Open and Paid'), 
 
2054
            ],'Invoice State', select=True, required=True), 
 
2055
        } 
 
2056
        _defaults = { 
 
2057
            'from_date':  lambda *a:time.strftime('%Y-01-01'), 
 
2058
            'to_date': lambda *a:time.strftime('%Y-01-01'), 
 
2059
            'invoice_state': lambda *a:"open_paid", 
 
2060
        } 
 
2061
    product_margin()
 
2062
 
 
2063
.. i18n: Convert the views into real view records defined on the model of your wizard: 
 
2064
..
 
2065
 
 
2066
Convert the views into real view records defined on the model of your wizard: 
 
2067
 
 
2068
.. i18n: Old Wizard File : wizard_product_margin.py
 
2069
.. i18n: ==========================================
 
2070
..
 
2071
 
 
2072
Old Wizard File : wizard_product_margin.py
 
2073
==========================================
 
2074
 
 
2075
.. i18n: .. code-block:: python
 
2076
.. i18n: 
 
2077
.. i18n:     form1 = '''<?xml version="1.0"?> 
 
2078
.. i18n:     <form string="View Stock of Products"> 
 
2079
.. i18n:         <separator string="Select " colspan="4"/> 
 
2080
.. i18n:         <field name="date"/> 
 
2081
.. i18n:         <field name="invoice_state"/> 
 
2082
.. i18n:     </form>''' 
 
2083
..
 
2084
 
 
2085
.. code-block:: python
 
2086
 
 
2087
    form1 = '''<?xml version="1.0"?> 
 
2088
    <form string="View Stock of Products"> 
 
2089
        <separator string="Select " colspan="4"/> 
 
2090
        <field name="date"/> 
 
2091
        <field name="invoice_state"/> 
 
2092
    </form>''' 
 
2093
 
 
2094
.. i18n: New Wizard File : wizard/<<module_name>>_<<filename>>_view.xml
 
2095
.. i18n: ==============================================================
 
2096
..
 
2097
 
 
2098
New Wizard File : wizard/<<module_name>>_<<filename>>_view.xml
 
2099
==============================================================
 
2100
 
 
2101
.. i18n: .. code-block:: xml
 
2102
.. i18n: 
 
2103
.. i18n:     <record id="product_margin_form_view" model="ir.ui.view"> 
 
2104
.. i18n:         <field name="name">product.margin.form</field> 
 
2105
.. i18n:         <field name="model">product.margin</field> 
 
2106
.. i18n:         <field name="type">form</field> 
 
2107
.. i18n:         <field name="arch" type="xml"> 
 
2108
.. i18n:             <form string="Properties categories"> 
 
2109
.. i18n:                    <separator colspan="4" string="General Information"/> 
 
2110
.. i18n:                    <field name="from_date" /> 
 
2111
.. i18n:                    <field name="to_date" /> 
 
2112
.. i18n:                    <field name="invoice_state" /> 
 
2113
.. i18n:                    <group col="4" colspan="2"> 
 
2114
.. i18n:                                <button special="cancel" string="Cancel" type="object"/> 
 
2115
.. i18n:                                <button name="_action_open_window" string="Open Margins" type="object" default_focus=”1”/> 
 
2116
.. i18n:                    </group> 
 
2117
.. i18n:             </form> 
 
2118
.. i18n:         </field> 
 
2119
.. i18n:     </record> 
 
2120
..
 
2121
 
 
2122
.. code-block:: xml
 
2123
 
 
2124
    <record id="product_margin_form_view" model="ir.ui.view"> 
 
2125
        <field name="name">product.margin.form</field> 
 
2126
        <field name="model">product.margin</field> 
 
2127
        <field name="type">form</field> 
 
2128
        <field name="arch" type="xml"> 
 
2129
            <form string="Properties categories"> 
 
2130
                    <separator colspan="4" string="General Information"/> 
 
2131
                    <field name="from_date" /> 
 
2132
                    <field name="to_date" /> 
 
2133
                    <field name="invoice_state" /> 
 
2134
                    <group col="4" colspan="2"> 
 
2135
                                <button special="cancel" string="Cancel" type="object"/> 
 
2136
                                <button name="_action_open_window" string="Open Margins" type="object" default_focus=”1”/> 
 
2137
                    </group> 
 
2138
            </form> 
 
2139
        </field> 
 
2140
    </record> 
 
2141
 
 
2142
.. i18n: Default_focus attribute :
 
2143
.. i18n: =========================
 
2144
..
 
2145
 
 
2146
Default_focus attribute :
 
2147
=========================
 
2148
 
 
2149
.. i18n: .. code-block:: xml
 
2150
.. i18n: 
 
2151
.. i18n:     <button name="_action_open_window" string="Open Margins" type="object" default_focus=”1”/> 
 
2152
..
 
2153
 
 
2154
.. code-block:: xml
 
2155
 
 
2156
    <button name="_action_open_window" string="Open Margins" type="object" default_focus=”1”/> 
 
2157
 
 
2158
.. i18n: **defaule_focus="1"** is a new attribute added in 5.2. While opening wizard default control will be on the widget having this attribute. There must be only one widget on a view having this attribute = 1 otherwise it will raise exception.
 
2159
..
 
2160
 
 
2161
**defaule_focus="1"** is a new attribute added in 5.2. While opening wizard default control will be on the widget having this attribute. There must be only one widget on a view having this attribute = 1 otherwise it will raise exception.
 
2162
 
 
2163
.. i18n: Note: For all states in the old wizard, we need to create buttons in new approach.      
 
2164
..
 
2165
 
 
2166
Note: For all states in the old wizard, we need to create buttons in new approach.      
 
2167
 
 
2168
.. i18n: 2. To open the new wizard, you need to register an action that opens the first view on your wizard object. You will need to do the same for each view if your wizard contains several views. To make the view open in a pop-up window you can add a special target='new' field in the action: 
 
2169
..
 
2170
 
 
2171
2. To open the new wizard, you need to register an action that opens the first view on your wizard object. You will need to do the same for each view if your wizard contains several views. To make the view open in a pop-up window you can add a special target='new' field in the action: 
 
2172
 
 
2173
.. i18n: .. code-block:: xml
 
2174
.. i18n: 
 
2175
.. i18n:     <act_window name="Open Margin" 
 
2176
.. i18n:            res_model="product.margin" 
 
2177
.. i18n:            src_model="product.product" 
 
2178
.. i18n:            view_mode="form" 
 
2179
.. i18n:            target="new" 
 
2180
.. i18n:            key2="client_action_multi"    
 
2181
.. i18n:            id="product_margin_act_window"/>
 
2182
..
 
2183
 
 
2184
.. code-block:: xml
 
2185
 
 
2186
    <act_window name="Open Margin" 
 
2187
            res_model="product.margin" 
 
2188
            src_model="product.product" 
 
2189
            view_mode="form" 
 
2190
            target="new" 
 
2191
            key2="client_action_multi"    
 
2192
            id="product_margin_act_window"/>
 
2193
 
 
2194
.. i18n: key2="client_action_multi" : While using it in the act_window, wizard will be added in the
 
2195
..
 
2196
 
 
2197
key2="client_action_multi" : While using it in the act_window, wizard will be added in the
 
2198
 
 
2199
.. i18n: 1. Action
 
2200
..
 
2201
 
 
2202
1. Action
 
2203
 
 
2204
.. i18n: .. image:: images/wizard_button.png
 
2205
..
 
2206
 
 
2207
.. image:: images/wizard_button.png
 
2208
 
 
2209
.. i18n: 2. Sidebar
 
2210
..
 
2211
 
 
2212
2. Sidebar
 
2213
 
 
2214
.. i18n: .. image:: images/wizard_panel.png
 
2215
..
 
2216
 
 
2217
.. image:: images/wizard_panel.png
 
2218
 
 
2219
.. i18n: If key2 is ommited then it will be displayed only in sidebar.
 
2220
..
 
2221
 
 
2222
If key2 is ommited then it will be displayed only in sidebar.
 
2223
 
 
2224
.. i18n: Note: The "src_model" attribute is only required if you want to put the
 
2225
.. i18n: wizard in the side bar of an object, you can leave it out, for example
 
2226
.. i18n: if you define an action to open the second view of a wizard.
 
2227
..
 
2228
 
 
2229
Note: The "src_model" attribute is only required if you want to put the
 
2230
wizard in the side bar of an object, you can leave it out, for example
 
2231
if you define an action to open the second view of a wizard.
 
2232
 
 
2233
.. i18n: 3. You can register this new action as a menuitem or in the context bar of any object by using a <menuitem> or <act_window> record instead of the old <wizard> tag that can be removed:
 
2234
..
 
2235
 
 
2236
3. You can register this new action as a menuitem or in the context bar of any object by using a <menuitem> or <act_window> record instead of the old <wizard> tag that can be removed:
 
2237
 
 
2238
.. i18n: In Menu Item:
 
2239
.. i18n: =============
 
2240
..
 
2241
 
 
2242
In Menu Item:
 
2243
=============
 
2244
 
 
2245
.. i18n: To open a wizard view via a menuitem you can use the following syntax for the menu, using the XML id of the corresponding act_window.
 
2246
..
 
2247
 
 
2248
To open a wizard view via a menuitem you can use the following syntax for the menu, using the XML id of the corresponding act_window.
 
2249
 
 
2250
.. i18n: .. code-block:: xml
 
2251
.. i18n: 
 
2252
.. i18n:        <menuitem id="main" name="OSV Memory Wizard Test"/>
 
2253
.. i18n:        <menuitem
 
2254
.. i18n:             action="product_margin_act_window"
 
2255
.. i18n:             id="menu_product_act"
 
2256
.. i18n:             parent="main" />
 
2257
..
 
2258
 
 
2259
.. code-block:: xml
 
2260
 
 
2261
        <menuitem id="main" name="OSV Memory Wizard Test"/>
 
2262
        <menuitem
 
2263
            action="product_margin_act_window"
 
2264
            id="menu_product_act"
 
2265
            parent="main" />
 
2266
 
 
2267
.. i18n: 4. To open a wizard view via a button in another form you can use the following syntax for the button, using the XML id of the corresponding act_window. This can be used to have multiple steps in your wizard:
 
2268
..
 
2269
 
 
2270
4. To open a wizard view via a button in another form you can use the following syntax for the button, using the XML id of the corresponding act_window. This can be used to have multiple steps in your wizard:
 
2271
 
 
2272
.. i18n: .. code-block:: xml
 
2273
.. i18n: 
 
2274
.. i18n:     <button name="%(product_margin.product_margin_act_window)d" 
 
2275
.. i18n:             string="Test Wizard" type="action" states="draft"/>                                                
 
2276
..
 
2277
 
 
2278
.. code-block:: xml
 
2279
 
 
2280
    <button name="%(product_margin.product_margin_act_window)d" 
 
2281
            string="Test Wizard" type="action" states="draft"/>                                         
 
2282
 
 
2283
.. i18n: 5. Finally, you need to cleanup the module, update the python __init__.py files if you have changed the python file name for the wizard, and add your new XML files in the update_xml list in the __terp__.py file.
 
2284
..
 
2285
 
 
2286
5. Finally, you need to cleanup the module, update the python __init__.py files if you have changed the python file name for the wizard, and add your new XML files in the update_xml list in the __terp__.py file.