~openerp-community/openobject-doc/6.1

« back to all changes in this revision

Viewing changes to i18n/zh_CN/source/developer/04_wizard.rst

  • Committer: JoshuaJan
  • Date: 2012-12-04 01:36:44 UTC
  • Revision ID: popkar77@gmail.com-20121204013644-k25kpyac672wxe22
Chinese initialization

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