[MERGE] demo data: remove salesman on customers
[odoo/odoo.git] / openerp / wizard / __init__.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #    
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
19 #
20 ##############################################################################
21
22 import openerp.netsvc as netsvc
23 from openerp.tools import copy
24 from openerp.tools.misc import UpdateableStr, UpdateableDict
25 from openerp.tools.translate import translate
26 from lxml import etree
27
28 import openerp.pooler as pooler
29
30 from openerp.osv.osv import except_osv
31 from openerp.osv.orm import except_orm
32 from openerp.netsvc import Logger, LOG_ERROR
33 import sys
34 import warnings
35
36 class except_wizard(Exception):
37     def __init__(self, name, value):
38         self.name = name
39         self.value = value
40         self.args = (name, value)
41
42 class interface(netsvc.Service):
43     """
44     This is the base class used to implement Wizards. This class is deprecated
45     and `openerp.osv.TransientModel` must be used instead.
46     """
47     states = {}
48
49     def __init__(self, name):
50         assert not self.exists('wizard.'+name), 'The wizard "%s" already exists!' % (name,)
51         warnings.warn(
52             "The wizard %s uses the deprecated openerp.wizard.interface class.\n"
53             "It must use the openerp.osv.TransientModel class instead." % \
54             name, DeprecationWarning, stacklevel=3)
55         super(interface, self).__init__('wizard.'+name)
56         self.wiz_name = name
57
58     def translate_view(self, cr, node, state, lang):
59         if node.get('string'):
60             trans = translate(cr, self.wiz_name+','+state, 'wizard_view', lang, node.get('string').encode('utf8'))
61             if trans:
62                 node.set('string', trans)
63         for n in node:
64             self.translate_view(cr, n, state, lang)
65
66     def execute_cr(self, cr, uid, data, state='init', context=None):
67         if not context:
68             context={}
69         res = {}
70         try:
71             state_def = self.states[state]
72
73             result_def = state_def.get('result', {})
74             
75             actions_res = {}
76             # iterate through the list of actions defined for this state
77             for action in state_def.get('actions', []):
78                 # execute them
79                 action_res = action(self, cr, uid, data, context)
80                 assert isinstance(action_res, dict), 'The return value of wizard actions should be a dictionary'
81                 actions_res.update(action_res)
82                 
83             res = copy.copy(result_def)
84             res['datas'] = actions_res
85             
86             lang = context.get('lang', False)
87             if result_def['type'] == 'action':
88                 res['action'] = result_def['action'](self, cr, uid, data, context)
89             elif result_def['type'] == 'form':
90                 fields = copy.deepcopy(result_def['fields'])
91                 arch = copy.copy(result_def['arch'])
92                 button_list = copy.copy(result_def['state'])
93
94                 if isinstance(fields, UpdateableDict):
95                     fields = fields.dict
96                 if isinstance(arch, UpdateableStr):
97                     arch = arch.string
98
99                 # fetch user-set defaut values for the field... shouldn't we pass it the uid?
100                 ir_values_obj = pooler.get_pool(cr.dbname).get('ir.values')
101                 defaults = ir_values_obj.get(cr, uid, 'default', False, [('wizard.'+self.wiz_name, False)])
102                 default_values = dict([(x[1], x[2]) for x in defaults])
103                 for val in fields.keys():
104                     if 'default' in fields[val]:
105                         # execute default method for this field
106                         if callable(fields[val]['default']):
107                             fields[val]['value'] = fields[val]['default'](uid, data, state)
108                         else:
109                             fields[val]['value'] = fields[val]['default']
110                         del fields[val]['default']
111                     else:
112                         # if user has set a default value for the field, use it
113                         if val in default_values:
114                             fields[val]['value'] = default_values[val]
115                     if 'selection' in fields[val]:
116                         if not isinstance(fields[val]['selection'], (tuple, list)):
117                             fields[val] = copy.copy(fields[val])
118                             fields[val]['selection'] = fields[val]['selection'](self, cr, uid, context)
119                         elif lang:
120                             res_name = "%s,%s,%s" % (self.wiz_name, state, val)
121                             trans = lambda x: translate(cr, res_name, 'selection', lang, x) or x
122                             for idx, (key, val2) in enumerate(fields[val]['selection']):
123                                 fields[val]['selection'][idx] = (key, trans(val2))
124
125                 if lang:
126                     # translate fields
127                     for field in fields:
128                         res_name = "%s,%s,%s" % (self.wiz_name, state, field)
129
130                         trans = translate(cr, res_name, 'wizard_field', lang)
131                         if trans:
132                             fields[field]['string'] = trans
133
134                         if 'help' in fields[field]:
135                             t = translate(cr, res_name, 'help', lang, fields[field]['help']) 
136                             if t:
137                                 fields[field]['help'] = t
138
139                     # translate arch
140                     if not isinstance(arch, UpdateableStr):
141                         doc = etree.XML(arch)
142                         self.translate_view(cr, doc, state, lang)
143                         arch = etree.tostring(doc)
144
145                     # translate buttons
146                     button_list = list(button_list)
147                     for i, aa  in enumerate(button_list):
148                         button_name = aa[0]
149                         trans = translate(cr, self.wiz_name+','+state+','+button_name, 'wizard_button', lang)
150                         if trans:
151                             aa = list(aa)
152                             aa[1] = trans
153                             button_list[i] = aa
154                     
155                 res['fields'] = fields
156                 res['arch'] = arch
157                 res['state'] = button_list
158
159             elif result_def['type'] == 'choice':
160                 next_state = result_def['next_state'](self, cr, uid, data, context)
161                 return self.execute_cr(cr, uid, data, next_state, context)
162         
163         except Exception, e:
164             if isinstance(e, except_wizard) \
165                 or isinstance(e, except_osv) \
166                 or isinstance(e, except_orm):
167                 netsvc.abort_response(2, e.name, 'warning', e.value)
168             else:
169                 import traceback
170                 tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
171                     sys.exc_type, sys.exc_value, sys.exc_traceback))
172                 logger = Logger()
173                 logger.notifyChannel("web-services", LOG_ERROR,
174                         'Exception in call: ' + tb_s)
175                 raise
176
177         return res
178
179     def execute(self, db, uid, data, state='init', context=None):
180         if not context:
181             context={}
182         cr = pooler.get_db(db).cursor()
183         try:
184             try:
185                 res = self.execute_cr(cr, uid, data, state, context)
186                 cr.commit()
187             except Exception:
188                 cr.rollback()
189                 raise
190         finally:
191             cr.close()
192         return res
193
194 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
195