[IMP] use model._fields instead of model._all_columns to cover all fields
[odoo/odoo.git] / openerp / addons / base / ir / ir_values.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 import pickle
22
23 from openerp import tools
24 from openerp.osv import osv, fields
25 from openerp.osv.orm import except_orm
26
27 EXCLUDED_FIELDS = set((
28     'report_sxw_content', 'report_rml_content', 'report_sxw', 'report_rml',
29     'report_sxw_content_data', 'report_rml_content_data', 'search_view', ))
30
31 #: Possible slots to bind an action to with :meth:`~.set_action`
32 ACTION_SLOTS = [
33                 "client_action_multi",  # sidebar wizard action
34                 "client_print_multi",   # sidebar report printing button
35                 "client_action_relate", # sidebar related link
36                 "tree_but_open",        # double-click on item in tree view
37                 "tree_but_action",      # deprecated: same as tree_but_open
38                ]
39
40
41 class ir_values(osv.osv):
42     """Holds internal model-specific action bindings and user-defined default
43        field values. definitions. This is a legacy internal model, mixing
44        two different concepts, and will likely be updated or replaced in a
45        future version by cleaner, separate models. You should not depend
46        explicitly on it.
47
48        The purpose of each ``ir.values`` entry depends on its type, defined
49        by the ``key`` column:
50
51         * 'default': user-defined default values, used when creating new
52           records of this model:
53         * 'action': binding of an action to a particular *action slot* of
54           this model, making the action easily available in the user
55           interface for this model.
56
57        The ``key2`` column acts as a qualifier, further refining the type
58        of the entry. The possible values are:
59
60         * for 'default' entries: an optional condition restricting the
61           cases where this particular default value will be applicable,
62           or ``False`` for no condition
63         * for 'action' entries: the ``key2`` qualifier is one of the available
64           action slots, defining how this action can be invoked:
65
66             * ``'client_print_multi'`` for report printing actions that will
67               be available on views displaying items from this model
68             * ``'client_action_multi'`` for assistants (wizards) actions
69               that will be available in views displaying objects of this model
70             * ``'client_action_relate'`` for links towards related documents
71               that should be available in views displaying objects of this model
72             * ``'tree_but_open'`` for actions that will be triggered when
73               double-clicking an item from this model in a hierarchical tree view
74
75        Each entry is specific to a model (``model`` column), and for ``'actions'``
76        type, may even be made specific to a given record of that model when the
77        ``res_id`` column contains a record ID (``False`` means it's global for
78        all records).
79
80        The content of the entry is defined by the ``value`` column, which may either
81        contain an arbitrary value, or a reference string defining the action that
82        should be executed.
83
84        .. rubric:: Usage: default values
85        
86        The ``'default'`` entries are usually defined manually by the
87        users, and set by their UI clients calling :meth:`~.set_default`.
88        These default values are then automatically used by the
89        ORM every time a new record is about to be created, i.e. when
90        :meth:`~openerp.osv.osv.osv.default_get`
91        or :meth:`~openerp.osv.osv.osv.create` are called.
92
93        .. rubric:: Usage: action bindings
94
95        Business applications will usually bind their actions during
96        installation, and OpenERP UI clients will apply them as defined,
97        based on the list of actions included in the result of
98        :meth:`~openerp.osv.osv.osv.fields_view_get`,
99        or directly returned by explicit calls to :meth:`~.get_actions`.
100     """
101     _name = 'ir.values'
102
103     def _value_unpickle(self, cursor, user, ids, name, arg, context=None):
104         res = {}
105         for record in self.browse(cursor, user, ids, context=context):
106             value = record[name[:-9]]
107             if record.key == 'default' and value:
108                 # default values are pickled on the fly
109                 try:
110                     value = str(pickle.loads(value))
111                 except Exception:
112                     pass
113             res[record.id] = value
114         return res
115
116     def _value_pickle(self, cursor, user, id, name, value, arg, context=None):
117         if context is None:
118             context = {}
119         ctx = context.copy()
120         if self.CONCURRENCY_CHECK_FIELD in ctx:
121             del ctx[self.CONCURRENCY_CHECK_FIELD]
122         record = self.browse(cursor, user, id, context=context)
123         if record.key == 'default':
124             # default values are pickled on the fly
125             value = pickle.dumps(value)
126         self.write(cursor, user, id, {name[:-9]: value}, context=ctx)
127
128     def onchange_object_id(self, cr, uid, ids, object_id, context=None):
129         if not object_id: return {}
130         act = self.pool.get('ir.model').browse(cr, uid, object_id, context=context)
131         return {
132                 'value': {'model': act.model}
133         }
134
135     def onchange_action_id(self, cr, uid, ids, action_id, context=None):
136         if not action_id: return {}
137         act = self.pool.get('ir.actions.actions').browse(cr, uid, action_id, context=context)
138         return {
139                 'value': {'value_unpickle': act.type+','+str(act.id)}
140         }
141
142     _columns = {
143         'name': fields.char('Name', required=True),
144         'model': fields.char('Model Name', select=True, required=True,
145                              help="Model to which this entry applies"),
146
147         # TODO: model_id and action_id should be read-write function fields
148         'model_id': fields.many2one('ir.model', 'Model (change only)', size=128,
149                                     help="Model to which this entry applies - "
150                                          "helper field for setting a model, will "
151                                          "automatically set the correct model name"),
152         'action_id': fields.many2one('ir.actions.actions', 'Action (change only)',
153                                      help="Action bound to this entry - "
154                                          "helper field for binding an action, will "
155                                          "automatically set the correct reference"),
156
157         'value': fields.text('Value', help="Default value (pickled) or reference to an action"),
158         'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
159                                           type='text',
160                                           string='Default value or action reference'),
161         'key': fields.selection([('action','Action'),('default','Default')],
162                                 'Type', select=True, required=True,
163                                 help="- Action: an action attached to one slot of the given model\n"
164                                      "- Default: a default value for a model field"),
165         'key2' : fields.char('Qualifier', select=True,
166                              help="For actions, one of the possible action slots: \n"
167                                   "  - client_action_multi\n"
168                                   "  - client_print_multi\n"
169                                   "  - client_action_relate\n"
170                                   "  - tree_but_open\n"
171                                   "For defaults, an optional condition"
172                              ,),
173         'res_id': fields.integer('Record ID', select=True,
174                                  help="Database identifier of the record to which this applies. "
175                                       "0 = for all records"),
176         'user_id': fields.many2one('res.users', 'User', ondelete='cascade', select=True,
177                                    help="If set, action binding only applies for this user."),
178         'company_id': fields.many2one('res.company', 'Company', ondelete='cascade', select=True,
179                                       help="If set, action binding only applies for this company")
180     }
181     _defaults = {
182         'key': 'action',
183         'key2': 'tree_but_open',
184     }
185
186     def _auto_init(self, cr, context=None):
187         super(ir_values, self)._auto_init(cr, context)
188         cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'ir_values_key_model_key2_res_id_user_id_idx\'')
189         if not cr.fetchone():
190             cr.execute('CREATE INDEX ir_values_key_model_key2_res_id_user_id_idx ON ir_values (key, model, key2, res_id, user_id)')
191
192     def create(self, cr, uid, vals, context=None):
193         res = super(ir_values, self).create(cr, uid, vals, context=context)
194         self.get_defaults_dict.clear_cache(self)
195         return res
196
197     def write(self, cr, uid, ids, vals, context=None):
198         res = super(ir_values, self).write(cr, uid, ids, vals, context=context)
199         self.get_defaults_dict.clear_cache(self)
200         return res
201
202     def unlink(self, cr, uid, ids, context=None):
203         res = super(ir_values, self).unlink(cr, uid, ids, context=context)
204         self.get_defaults_dict.clear_cache(self)
205         return res
206
207     def set_default(self, cr, uid, model, field_name, value, for_all_users=True, company_id=False, condition=False):
208         """Defines a default value for the given model and field_name. Any previous
209            default for the same scope (model, field_name, value, for_all_users, company_id, condition)
210            will be replaced and lost in the process.
211
212            Defaults can be later retrieved via :meth:`~.get_defaults`, which will return
213            the highest priority default for any given field. Defaults that are more specific
214            have a higher priority, in the following order (highest to lowest):
215
216                * specific to user and company
217                * specific to user only
218                * specific to company only
219                * global to everyone
220
221            :param string model: model name
222            :param string field_name: field name to which the default applies
223            :param value: the default field value to set
224            :type value: any serializable Python value
225            :param bool for_all_users: whether the default should apply to everybody or only
226                                       the user calling the method
227            :param int company_id: optional ID of the company to which the default should
228                                   apply. If omitted, the default will be global. If True
229                                   is passed, the current user's company will be used.
230            :param string condition: optional condition specification that can be used to
231                                     restrict the applicability of the default values
232                                     (e.g. based on another field's value). This is an
233                                     opaque string as far as the API is concerned, but client
234                                     stacks typically use single-field conditions in the
235                                     form ``'key=stringified_value'``.
236                                     (Currently, the condition is trimmed to 200 characters,
237                                     so values that share the same first 200 characters always
238                                     match)
239            :return: id of the newly created ir.values entry
240         """
241         if isinstance(value, unicode):
242             value = value.encode('utf8')
243         if company_id is True:
244             # should be company-specific, need to get company id
245             user = self.pool.get('res.users').browse(cr, uid, uid)
246             company_id = user.company_id.id
247
248         # remove existing defaults for the same scope
249         search_criteria = [
250             ('key', '=', 'default'),
251             ('key2', '=', condition and condition[:200]),
252             ('model', '=', model),
253             ('name', '=', field_name),
254             ('user_id', '=', False if for_all_users else uid),
255             ('company_id','=', company_id)
256             ]
257         self.unlink(cr, uid, self.search(cr, uid, search_criteria))
258
259         return self.create(cr, uid, {
260             'name': field_name,
261             'value': pickle.dumps(value),
262             'model': model,
263             'key': 'default',
264             'key2': condition and condition[:200],
265             'user_id': False if for_all_users else uid,
266             'company_id': company_id,
267         })
268
269     def get_default(self, cr, uid, model, field_name, for_all_users=True, company_id=False, condition=False):
270         """ Return the default value defined for model, field_name, users, company and condition.
271             Return ``None`` if no such default exists.
272         """
273         search_criteria = [
274             ('key', '=', 'default'),
275             ('key2', '=', condition and condition[:200]),
276             ('model', '=', model),
277             ('name', '=', field_name),
278             ('user_id', '=', False if for_all_users else uid),
279             ('company_id','=', company_id)
280             ]
281         defaults = self.browse(cr, uid, self.search(cr, uid, search_criteria))
282         return pickle.loads(defaults[0].value.encode('utf-8')) if defaults else None
283
284     def get_defaults(self, cr, uid, model, condition=False):
285         """Returns any default values that are defined for the current model and user,
286            (and match ``condition``, if specified), previously registered via
287            :meth:`~.set_default`.
288
289            Defaults are global to a model, not field-specific, but an optional
290            ``condition`` can be provided to restrict matching default values
291            to those that were defined for the same condition (usually based
292            on another field's value).
293
294            Default values also have priorities depending on whom they apply
295            to: only the highest priority value will be returned for any
296            field. See :meth:`~.set_default` for more details.
297
298            :param string model: model name
299            :param string condition: optional condition specification that can be used to
300                                     restrict the applicability of the default values
301                                     (e.g. based on another field's value). This is an
302                                     opaque string as far as the API is concerned, but client
303                                     stacks typically use single-field conditions in the
304                                     form ``'key=stringified_value'``.
305                                     (Currently, the condition is trimmed to 200 characters,
306                                     so values that share the same first 200 characters always
307                                     match)
308            :return: list of default values tuples of the form ``(id, field_name, value)``
309                     (``id`` is the ID of the default entry, usually irrelevant)
310         """
311         # use a direct SQL query for performance reasons,
312         # this is called very often
313         query = """SELECT v.id, v.name, v.value FROM ir_values v
314                       LEFT JOIN res_users u ON (v.user_id = u.id)
315                    WHERE v.key = %%s AND v.model = %%s
316                       AND (v.user_id = %%s OR v.user_id IS NULL)
317                       AND (v.company_id IS NULL OR
318                            v.company_id =
319                              (SELECT company_id from res_users where id = %%s)
320                           )
321                       %s
322                    ORDER BY v.user_id, u.company_id"""
323         params = ('default', model, uid, uid)
324         if condition:
325             query %= 'AND v.key2 = %s'
326             params += (condition[:200],)
327         else:
328             query %= 'AND v.key2 is NULL'
329         cr.execute(query, params)
330
331         # keep only the highest priority default for each field
332         defaults = {}
333         for row in cr.dictfetchall():
334             defaults.setdefault(row['name'],
335                 (row['id'], row['name'], pickle.loads(row['value'].encode('utf-8'))))
336         return defaults.values()
337
338     # use ormcache: this is called a lot by BaseModel.default_get()!
339     @tools.ormcache(skiparg=2)
340     def get_defaults_dict(self, cr, uid, model, condition=False):
341         """ Returns a dictionary mapping field names with their corresponding
342             default value. This method simply improves the returned value of
343             :meth:`~.get_defaults`.
344         """
345         return dict((f, v) for i, f, v in self.get_defaults(cr, uid, model, condition))
346
347     def set_action(self, cr, uid, name, action_slot, model, action, res_id=False):
348         """Binds an the given action to the given model's action slot - for later
349            retrieval via :meth:`~.get_actions`. Any existing binding of the same action
350            to the same slot is first removed, allowing an update of the action's name.
351            See the class description for more details about the various action
352            slots: :class:`~ir_values`.
353
354            :param string name: action label, usually displayed by UI client
355            :param string action_slot: the action slot to which the action should be
356                                       bound to - one of ``client_action_multi``,
357                                       ``client_print_multi``, ``client_action_relate``,
358                                       ``tree_but_open``.
359            :param string model: model name
360            :param string action: action reference, in the form ``'model,id'``
361            :param int res_id: optional record id - will bind the action only to a
362                               specific record of the model, not all records.
363            :return: id of the newly created ir.values entry
364         """
365         assert isinstance(action, basestring) and ',' in action, \
366                'Action definition must be an action reference, e.g. "ir.actions.act_window,42"'
367         assert action_slot in ACTION_SLOTS, \
368                'Action slot (%s) must be one of: %r' % (action_slot, ACTION_SLOTS)
369
370         # remove existing action definition of same slot and value
371         search_criteria = [
372             ('key', '=', 'action'),
373             ('key2', '=', action_slot),
374             ('model', '=', model),
375             ('res_id', '=', res_id or 0), # int field -> NULL == 0
376             ('value', '=', action),
377             ]
378         self.unlink(cr, uid, self.search(cr, uid, search_criteria))
379
380         return self.create(cr, uid, {
381             'key': 'action',
382             'key2': action_slot,
383             'model': model,
384             'res_id': res_id,
385             'name': name,
386             'value': action,
387         })
388
389     def get_actions(self, cr, uid, action_slot, model, res_id=False, context=None):
390         """Retrieves the list of actions bound to the given model's action slot.
391            See the class description for more details about the various action
392            slots: :class:`~.ir_values`.
393
394            :param string action_slot: the action slot to which the actions should be
395                                       bound to - one of ``client_action_multi``,
396                                       ``client_print_multi``, ``client_action_relate``,
397                                       ``tree_but_open``.
398            :param string model: model name
399            :param int res_id: optional record id - will bind the action only to a
400                               specific record of the model, not all records.
401            :return: list of action tuples of the form ``(id, name, action_def)``,
402                     where ``id`` is the ID of the default entry, ``name`` is the
403                     action label, and ``action_def`` is a dict containing the
404                     action definition as obtained by calling
405                     :meth:`~openerp.osv.osv.osv.read` on the action record.
406         """
407         assert action_slot in ACTION_SLOTS, 'Illegal action slot value: %s' % action_slot
408         # use a direct SQL query for performance reasons,
409         # this is called very often
410         query = """SELECT v.id, v.name, v.value FROM ir_values v
411                    WHERE v.key = %s AND v.key2 = %s
412                         AND v.model = %s
413                         AND (v.res_id = %s
414                              OR v.res_id IS NULL
415                              OR v.res_id = 0)
416                    ORDER BY v.id"""
417         cr.execute(query, ('action', action_slot, model, res_id or None))
418         results = {}
419         for action in cr.dictfetchall():
420             if not action['value']:
421                 continue    # skip if undefined
422             action_model_name, action_id = action['value'].split(',')
423             if action_model_name not in self.pool:
424                 continue    # unknow model? skip it
425             action_model = self.pool[action_model_name]
426             fields = [field for field in action_model._fields if field not in EXCLUDED_FIELDS]
427             # FIXME: needs cleanup
428             try:
429                 action_def = action_model.read(cr, uid, int(action_id), fields, context)
430                 if action_def:
431                     if action_model_name in ('ir.actions.report.xml', 'ir.actions.act_window'):
432                         groups = action_def.get('groups_id')
433                         if groups:
434                             cr.execute('SELECT 1 FROM res_groups_users_rel WHERE gid IN %s AND uid=%s',
435                                        (tuple(groups), uid))
436                             if not cr.fetchone():
437                                 if action['name'] == 'Menuitem':
438                                     raise osv.except_osv('Error!',
439                                                          'You do not have the permission to perform this operation!!!')
440                                 continue
441                 # keep only the first action registered for each action name
442                 results[action['name']] = (action['id'], action['name'], action_def)
443             except except_orm:
444                 continue
445         return sorted(results.values())
446
447     def _map_legacy_model_list(self, model_list, map_fn, merge_results=False):
448         """Apply map_fn to the various models passed, according to
449            legacy way to specify models/records.
450         """
451         assert isinstance(model_list, (list, tuple)), \
452             "model_list should be in the form [model,..] or [(model,res_id), ..]"
453         results = []
454         for model in model_list:
455             res_id = False
456             if isinstance(model, (list, tuple)):
457                 model, res_id = model
458             result = map_fn(model, res_id)
459             # some of the functions return one result at a time (tuple or id)
460             # and some return a list of many of them - care for both
461             if merge_results:
462                 results.extend(result)
463             else:
464                 results.append(result)
465         return results
466
467     # Backards-compatibility adapter layer to retrofit into split API
468     def set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=False, preserve_user=False, company=False):
469         """Deprecated legacy method to set default values and bind actions to models' action slots.
470            Now dispatches to the newer API methods according to the value of ``key``: :meth:`~.set_default`
471            (``key=='default'``) or :meth:`~.set_action` (``key == 'action'``).
472
473           :deprecated: As of v6.1, ``set_default()`` or ``set_action()`` should be used directly.
474         """
475         assert key in ['default', 'action'], "ir.values entry keys must be in ['default','action']"
476         if key == 'default':
477             def do_set(model,res_id):
478                 return self.set_default(cr, uid, model, field_name=name, value=value,
479                                         for_all_users=(not preserve_user), company_id=company,
480                                         condition=key2)
481         elif key == 'action':
482             def do_set(model,res_id):
483                 return self.set_action(cr, uid, name, action_slot=key2, model=model, action=value, res_id=res_id)
484         return self._map_legacy_model_list(models, do_set)
485
486     def get(self, cr, uid, key, key2, models, meta=False, context=None, res_id_req=False, without_user=True, key2_req=True):
487         """Deprecated legacy method to get the list of default values or actions bound to models' action slots.
488            Now dispatches to the newer API methods according to the value of ``key``: :meth:`~.get_defaults`
489            (``key=='default'``) or :meth:`~.get_actions` (``key == 'action'``)
490
491           :deprecated: As of v6.1, ``get_defaults()`` or ``get_actions()`` should be used directly.
492
493         """
494         assert key in ['default', 'action'], "ir.values entry keys must be in ['default','action']"
495         if key == 'default':
496             def do_get(model,res_id):
497                 return self.get_defaults(cr, uid, model, condition=key2)
498         elif key == 'action':
499             def do_get(model,res_id):
500                 return self.get_actions(cr, uid, action_slot=key2, model=model, res_id=res_id, context=context)
501         return self._map_legacy_model_list(models, do_get, merge_results=True)
502
503 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: