[FIX] fields: inherited fields get their attribute 'state' from their base field
[odoo/odoo.git] / openerp / fields.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2013-2014 OpenERP (<http://www.openerp.com>).
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 """ High-level objects for fields. """
23
24 from datetime import date, datetime
25 from functools import partial
26 from operator import attrgetter
27 from types import NoneType
28 import logging
29 import pytz
30 import xmlrpclib
31
32 from openerp.tools import float_round, ustr, html_sanitize
33 from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
34 from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
35
36 DATE_LENGTH = len(date.today().strftime(DATE_FORMAT))
37 DATETIME_LENGTH = len(datetime.now().strftime(DATETIME_FORMAT))
38
39 _logger = logging.getLogger(__name__)
40
41 class SpecialValue(object):
42     """ Encapsulates a value in the cache in place of a normal value. """
43     def __init__(self, value):
44         self.value = value
45     def get(self):
46         return self.value
47
48 class FailedValue(SpecialValue):
49     """ Special value that encapsulates an exception instead of a value. """
50     def __init__(self, exception):
51         self.exception = exception
52     def get(self):
53         raise self.exception
54
55 def _check_value(value):
56     """ Return `value`, or call its getter if `value` is a :class:`SpecialValue`. """
57     return value.get() if isinstance(value, SpecialValue) else value
58
59
60 def resolve_all_mro(cls, name, reverse=False):
61     """ Return the (successively overridden) values of attribute `name` in `cls`
62         in mro order, or inverse mro order if `reverse` is true.
63     """
64     klasses = reversed(cls.__mro__) if reverse else cls.__mro__
65     for klass in klasses:
66         if name in klass.__dict__:
67             yield klass.__dict__[name]
68
69
70 class MetaField(type):
71     """ Metaclass for field classes. """
72     by_type = {}
73
74     def __init__(cls, name, bases, attrs):
75         super(MetaField, cls).__init__(name, bases, attrs)
76         if cls.type:
77             cls.by_type[cls.type] = cls
78
79         # compute class attributes to avoid calling dir() on fields
80         cls.column_attrs = []
81         cls.related_attrs = []
82         cls.description_attrs = []
83         for attr in dir(cls):
84             if attr.startswith('_column_'):
85                 cls.column_attrs.append((attr[8:], attr))
86             elif attr.startswith('_related_'):
87                 cls.related_attrs.append((attr[9:], attr))
88             elif attr.startswith('_description_'):
89                 cls.description_attrs.append((attr[13:], attr))
90
91
92 class Field(object):
93     """ The field descriptor contains the field definition, and manages accesses
94         and assignments of the corresponding field on records. The following
95         attributes may be provided when instanciating a field:
96
97         :param string: the label of the field seen by users (string); if not
98             set, the ORM takes the field name in the class (capitalized).
99
100         :param help: the tooltip of the field seen by users (string)
101
102         :param readonly: whether the field is readonly (boolean, by default ``False``)
103
104         :param required: whether the value of the field is required (boolean, by
105             default ``False``)
106
107         :param index: whether the field is indexed in database (boolean, by
108             default ``False``)
109
110         :param default: the default value for the field; this is either a static
111             value, or a function taking a recordset and returning a value
112
113         :param states: a dictionary mapping state values to lists of UI attribute-value
114             pairs; possible attributes are: 'readonly', 'required', 'invisible'.
115             Note: Any state-based condition requires the ``state`` field value to be
116             available on the client-side UI. This is typically done by including it in
117             the relevant views, possibly made invisible if not relevant for the
118             end-user.
119
120         :param groups: comma-separated list of group xml ids (string); this
121             restricts the field access to the users of the given groups only
122
123         :param bool copy: whether the field value should be copied when the record
124             is duplicated (default: ``True`` for normal fields, ``False`` for
125             ``one2many`` and computed fields, including property fields and
126             related fields)
127
128         :param string oldname: the previous name of this field, so that ORM can rename
129             it automatically at migration
130
131         .. _field-computed:
132
133         .. rubric:: Computed fields
134
135         One can define a field whose value is computed instead of simply being
136         read from the database. The attributes that are specific to computed
137         fields are given below. To define such a field, simply provide a value
138         for the attribute `compute`.
139
140         :param compute: name of a method that computes the field
141
142         :param inverse: name of a method that inverses the field (optional)
143
144         :param search: name of a method that implement search on the field (optional)
145
146         :param store: whether the field is stored in database (boolean, by
147             default ``False`` on computed fields)
148
149         The methods given for `compute`, `inverse` and `search` are model
150         methods. Their signature is shown in the following example::
151
152             upper = fields.Char(compute='_compute_upper',
153                                 inverse='_inverse_upper',
154                                 search='_search_upper')
155
156             @api.depends('name')
157             def _compute_upper(self):
158                 for rec in self:
159                     self.upper = self.name.upper() if self.name else False
160
161             def _inverse_upper(self):
162                 for rec in self:
163                     self.name = self.upper.lower() if self.upper else False
164
165             def _search_upper(self, operator, value):
166                 if operator == 'like':
167                     operator = 'ilike'
168                 return [('name', operator, value)]
169
170         The compute method has to assign the field on all records of the invoked
171         recordset. The decorator :meth:`openerp.api.depends` must be applied on
172         the compute method to specify the field dependencies; those dependencies
173         are used to determine when to recompute the field; recomputation is
174         automatic and guarantees cache/database consistency. Note that the same
175         method can be used for several fields, you simply have to assign all the
176         given fields in the method; the method will be invoked once for all
177         those fields.
178
179         By default, a computed field is not stored to the database, and is
180         computed on-the-fly. Adding the attribute ``store=True`` will store the
181         field's values in the database. The advantage of a stored field is that
182         searching on that field is done by the database itself. The disadvantage
183         is that it requires database updates when the field must be recomputed.
184
185         The inverse method, as its name says, does the inverse of the compute
186         method: the invoked records have a value for the field, and you must
187         apply the necessary changes on the field dependencies such that the
188         computation gives the expected value. Note that a computed field without
189         an inverse method is readonly by default.
190
191         The search method is invoked when processing domains before doing an
192         actual search on the model. It must return a domain equivalent to the
193         condition: `field operator value`.
194
195         .. _field-related:
196
197         .. rubric:: Related fields
198
199         The value of a related field is given by following a sequence of
200         relational fields and reading a field on the reached model. The complete
201         sequence of fields to traverse is specified by the attribute
202
203         :param related: sequence of field names
204
205         Some field attributes are automatically copied from the source field if
206         they are not redefined: `string`, `help`, `readonly`, `required` (only
207         if all fields in the sequence are required), `groups`, `digits`, `size`,
208         `translate`, `sanitize`, `selection`, `comodel_name`, `domain`,
209         `context`. All semantic-free attributes are copied from the source
210         field.
211
212         By default, the values of related fields are not stored to the database.
213         Add the attribute ``store=True`` to make it stored, just like computed
214         fields. Related fields are automatically recomputed when their
215         dependencies are modified.
216
217         .. _field-company-dependent:
218
219         .. rubric:: Company-dependent fields
220
221         Formerly known as 'property' fields, the value of those fields depends
222         on the company. In other words, users that belong to different companies
223         may see different values for the field on a given record.
224
225         :param company_dependent: whether the field is company-dependent (boolean)
226
227         .. _field-incremental-definition:
228
229         .. rubric:: Incremental definition
230
231         A field is defined as class attribute on a model class. If the model
232         is extended (see :class:`~openerp.models.Model`), one can also extend
233         the field definition by redefining a field with the same name and same
234         type on the subclass. In that case, the attributes of the field are
235         taken from the parent class and overridden by the ones given in
236         subclasses.
237
238         For instance, the second class below only adds a tooltip on the field
239         ``state``::
240
241             class First(models.Model):
242                 _name = 'foo'
243                 state = fields.Selection([...], required=True)
244
245             class Second(models.Model):
246                 _inherit = 'foo'
247                 state = fields.Selection(help="Blah blah blah")
248
249     """
250     __metaclass__ = MetaField
251
252     _attrs = None               # dictionary with all field attributes
253     _free_attrs = None          # list of semantic-free attribute names
254
255     automatic = False           # whether the field is automatically created ("magic" field)
256     inherited = False           # whether the field is inherited (_inherits)
257     column = None               # the column corresponding to the field
258     setup_done = False          # whether the field has been set up
259
260     name = None                 # name of the field
261     type = None                 # type of the field (string)
262     relational = False          # whether the field is a relational one
263     model_name = None           # name of the model of this field
264     comodel_name = None         # name of the model of values (if relational)
265     inverse_fields = None       # list of inverse fields (objects)
266
267     store = True                # whether the field is stored in database
268     index = False               # whether the field is indexed in database
269     manual = False              # whether the field is a custom field
270     copy = True                 # whether the field is copied over by BaseModel.copy()
271     depends = ()                # collection of field dependencies
272     recursive = False           # whether self depends on itself
273     compute = None              # compute(recs) computes field on recs
274     inverse = None              # inverse(recs) inverses field on recs
275     search = None               # search(recs, operator, value) searches on self
276     related = None              # sequence of field names, for related fields
277     related_sudo = True         # whether related fields should be read as admin
278     company_dependent = False   # whether `self` is company-dependent (property field)
279     default = None              # default(recs) returns the default value
280
281     string = None               # field label
282     help = None                 # field tooltip
283     readonly = False
284     required = False
285     states = None
286     groups = False              # csv list of group xml ids
287     change_default = None       # whether the field may trigger a "user-onchange"
288     deprecated = None           # whether the field is ... deprecated
289
290     def __init__(self, string=None, **kwargs):
291         kwargs['string'] = string
292         self._attrs = {key: val for key, val in kwargs.iteritems() if val is not None}
293         self._free_attrs = []
294
295     def new(self, **kwargs):
296         """ Return a field of the same type as `self`, with its own parameters. """
297         return type(self)(**kwargs)
298
299     def set_class_name(self, cls, name):
300         """ Assign the model class and field name of `self`. """
301         self.model_name = cls._name
302         self.name = name
303
304         # determine all inherited field attributes
305         attrs = {}
306         for field in resolve_all_mro(cls, name, reverse=True):
307             if isinstance(field, type(self)):
308                 attrs.update(field._attrs)
309             else:
310                 attrs.clear()
311         attrs.update(self._attrs)       # necessary in case self is not in cls
312
313         # initialize `self` with `attrs`
314         if attrs.get('compute'):
315             # by default, computed fields are not stored, not copied and readonly
316             attrs['store'] = attrs.get('store', False)
317             attrs['copy'] = attrs.get('copy', False)
318             attrs['readonly'] = attrs.get('readonly', not attrs.get('inverse'))
319         if attrs.get('related'):
320             # by default, related fields are not stored
321             attrs['store'] = attrs.get('store', False)
322
323         # fix for function fields overridden by regular columns
324         if not isinstance(attrs.get('column'), (NoneType, fields.function)):
325             attrs.pop('store', None)
326
327         for attr, value in attrs.iteritems():
328             if not hasattr(self, attr):
329                 self._free_attrs.append(attr)
330             setattr(self, attr, value)
331
332         if not self.string and not self.related:
333             # related fields get their string from their parent field
334             self.string = name.replace('_', ' ').capitalize()
335
336         # determine self.default and cls._defaults in a consistent way
337         self._determine_default(cls, name)
338
339         self.reset()
340
341     def _determine_default(self, cls, name):
342         """ Retrieve the default value for `self` in the hierarchy of `cls`, and
343             determine `self.default` and `cls._defaults` accordingly.
344         """
345         self.default = None
346
347         # traverse the class hierarchy upwards, and take the first field
348         # definition with a default or _defaults for self
349         for klass in cls.__mro__:
350             if name in klass.__dict__:
351                 field = klass.__dict__[name]
352                 if not isinstance(field, type(self)):
353                     # klass contains another value overridden by self
354                     return
355
356                 if 'default' in field._attrs:
357                     # take the default in field, and adapt it for cls._defaults
358                     value = field._attrs['default']
359                     if callable(value):
360                         from openerp import api
361                         self.default = value
362                         cls._defaults[name] = api.model(
363                             lambda recs: self.convert_to_write(value(recs))
364                         )
365                     else:
366                         self.default = lambda recs: value
367                         cls._defaults[name] = value
368                     return
369
370             defaults = klass.__dict__.get('_defaults') or {}
371             if name in defaults:
372                 # take the value from _defaults, and adapt it for self.default
373                 value = defaults[name]
374                 if callable(value):
375                     func = lambda recs: value(recs._model, recs._cr, recs._uid, recs._context)
376                 else:
377                     func = lambda recs: value
378                 self.default = lambda recs: self.convert_to_cache(
379                     func(recs), recs, validate=False,
380                 )
381                 cls._defaults[name] = value
382                 return
383
384     def __str__(self):
385         return "%s.%s" % (self.model_name, self.name)
386
387     def __repr__(self):
388         return "%s.%s" % (self.model_name, self.name)
389
390     ############################################################################
391     #
392     # Field setup
393     #
394
395     def reset(self):
396         """ Prepare `self` for a new setup. """
397         self.setup_done = False
398         # self._triggers is a set of pairs (field, path) that represents the
399         # computed fields that depend on `self`. When `self` is modified, it
400         # invalidates the cache of each `field`, and registers the records to
401         # recompute based on `path`. See method `modified` below for details.
402         self._triggers = set()
403         self.inverse_fields = []
404
405     def setup(self, env):
406         """ Complete the setup of `self` (dependencies, recomputation triggers,
407             and other properties). This method is idempotent: it has no effect
408             if `self` has already been set up.
409         """
410         if not self.setup_done:
411             self._setup(env)
412             self.setup_done = True
413
414     def _setup(self, env):
415         """ Do the actual setup of `self`. """
416         if self.related:
417             self._setup_related(env)
418         else:
419             self._setup_regular(env)
420
421         # put invalidation/recomputation triggers on field dependencies
422         model = env[self.model_name]
423         for path in self.depends:
424             self._setup_dependency([], model, path.split('.'))
425
426         # put invalidation triggers on model dependencies
427         for dep_model_name, field_names in model._depends.iteritems():
428             dep_model = env[dep_model_name]
429             dep_model._setup_fields()
430             for field_name in field_names:
431                 field = dep_model._fields[field_name]
432                 field._triggers.add((self, None))
433
434     #
435     # Setup of related fields
436     #
437
438     def _setup_related(self, env):
439         """ Setup the attributes of a related field. """
440         # fix the type of self.related if necessary
441         if isinstance(self.related, basestring):
442             self.related = tuple(self.related.split('.'))
443
444         # determine the chain of fields, and make sure they are all set up
445         recs = env[self.model_name]
446         fields = []
447         for name in self.related:
448             recs._setup_fields()
449             field = recs._fields[name]
450             recs = recs[name]
451             fields.append(field)
452
453         self.related_field = field
454
455         # check type consistency
456         if self.type != field.type:
457             raise Warning("Type of related field %s is inconsistent with %s" % (self, field))
458
459         # determine dependencies, compute, inverse, and search
460         self.depends = ('.'.join(self.related),)
461         self.compute = self._compute_related
462         self.inverse = self._inverse_related
463         if field._description_searchable:
464             # allow searching on self only if the related field is searchable
465             self.search = self._search_related
466
467         # copy attributes from field to self (string, help, etc.)
468         for attr, prop in self.related_attrs:
469             if not getattr(self, attr):
470                 setattr(self, attr, getattr(field, prop))
471
472         for attr in field._free_attrs:
473             if attr not in self._free_attrs:
474                 self._free_attrs.append(attr)
475                 setattr(self, attr, getattr(field, attr))
476
477         # special case for states: copy it only for inherited fields
478         if not self.states and self.inherited:
479             self.states = field.states
480
481         # special case for required: check if all fields are required
482         if not self.store and not self.required:
483             self.required = all(field.required for field in fields)
484
485     def _compute_related(self, records):
486         """ Compute the related field `self` on `records`. """
487         # when related_sudo, bypass access rights checks when reading values
488         others = records.sudo() if self.related_sudo else records
489         for record, other in zip(records, others):
490             if not record.id:
491                 # draft record, do not switch to another environment
492                 other = record
493             # traverse the intermediate fields; follow the first record at each step
494             for name in self.related[:-1]:
495                 other = other[name][:1]
496             record[self.name] = other[self.related[-1]]
497
498     def _inverse_related(self, records):
499         """ Inverse the related field `self` on `records`. """
500         for record in records:
501             other = record
502             # traverse the intermediate fields, and keep at most one record
503             for name in self.related[:-1]:
504                 other = other[name][:1]
505             if other:
506                 other[self.related[-1]] = record[self.name]
507
508     def _search_related(self, records, operator, value):
509         """ Determine the domain to search on field `self`. """
510         return [('.'.join(self.related), operator, value)]
511
512     # properties used by _setup_related() to copy values from related field
513     _related_comodel_name = property(attrgetter('comodel_name'))
514     _related_string = property(attrgetter('string'))
515     _related_help = property(attrgetter('help'))
516     _related_readonly = property(attrgetter('readonly'))
517     _related_groups = property(attrgetter('groups'))
518
519     @property
520     def base_field(self):
521         """ Return the base field of an inherited field, or `self`. """
522         return self.related_field if self.inherited else self
523
524     #
525     # Setup of non-related fields
526     #
527
528     def _setup_regular(self, env):
529         """ Setup the attributes of a non-related field. """
530         recs = env[self.model_name]
531
532         def make_depends(deps):
533             return tuple(deps(recs) if callable(deps) else deps)
534
535         # convert compute into a callable and determine depends
536         if isinstance(self.compute, basestring):
537             # if the compute method has been overridden, concatenate all their _depends
538             self.depends = ()
539             for method in resolve_all_mro(type(recs), self.compute, reverse=True):
540                 self.depends += make_depends(getattr(method, '_depends', ()))
541             self.compute = getattr(type(recs), self.compute)
542         else:
543             self.depends = make_depends(getattr(self.compute, '_depends', ()))
544
545         # convert inverse and search into callables
546         if isinstance(self.inverse, basestring):
547             self.inverse = getattr(type(recs), self.inverse)
548         if isinstance(self.search, basestring):
549             self.search = getattr(type(recs), self.search)
550
551     def _setup_dependency(self, path0, model, path1):
552         """ Make `self` depend on `model`; `path0 + path1` is a dependency of
553             `self`, and `path0` is the sequence of field names from `self.model`
554             to `model`.
555         """
556         env = model.env
557         head, tail = path1[0], path1[1:]
558
559         model._setup_fields()
560         if head == '*':
561             # special case: add triggers on all fields of model (except self)
562             fields = set(model._fields.itervalues()) - set([self])
563         else:
564             fields = [model._fields[head]]
565
566         for field in fields:
567             if field == self:
568                 _logger.debug("Field %s is recursively defined", self)
569                 self.recursive = True
570                 continue
571
572             #_logger.debug("Add trigger on %s to recompute %s", field, self)
573             field._triggers.add((self, '.'.join(path0 or ['id'])))
574
575             # add trigger on inverse fields, too
576             for invf in field.inverse_fields:
577                 #_logger.debug("Add trigger on %s to recompute %s", invf, self)
578                 invf._triggers.add((self, '.'.join(path0 + [head])))
579
580             # recursively traverse the dependency
581             if tail:
582                 comodel = env[field.comodel_name]
583                 self._setup_dependency(path0 + [head], comodel, tail)
584
585     @property
586     def dependents(self):
587         """ Return the computed fields that depend on `self`. """
588         return (field for field, path in self._triggers)
589
590     ############################################################################
591     #
592     # Field description
593     #
594
595     def get_description(self, env):
596         """ Return a dictionary that describes the field `self`. """
597         desc = {'type': self.type}
598         for attr, prop in self.description_attrs:
599             value = getattr(self, prop)
600             if callable(value):
601                 value = value(env)
602             if value is not None:
603                 desc[attr] = value
604
605         return desc
606
607     # properties used by get_description()
608     _description_store = property(attrgetter('store'))
609     _description_manual = property(attrgetter('manual'))
610     _description_depends = property(attrgetter('depends'))
611     _description_related = property(attrgetter('related'))
612     _description_company_dependent = property(attrgetter('company_dependent'))
613     _description_readonly = property(attrgetter('readonly'))
614     _description_required = property(attrgetter('required'))
615     _description_states = property(attrgetter('states'))
616     _description_groups = property(attrgetter('groups'))
617     _description_change_default = property(attrgetter('change_default'))
618     _description_deprecated = property(attrgetter('deprecated'))
619
620     @property
621     def _description_searchable(self):
622         return bool(self.store or self.search or (self.column and self.column._fnct_search))
623
624     @property
625     def _description_sortable(self):
626         return self.store or (self.inherited and self.related_field._description_sortable)
627
628     def _description_string(self, env):
629         if self.string and env.lang:
630             field = self.base_field
631             name = "%s,%s" % (field.model_name, field.name)
632             trans = env['ir.translation']._get_source(name, 'field', env.lang)
633             return trans or self.string
634         return self.string
635
636     def _description_help(self, env):
637         if self.help and env.lang:
638             name = "%s,%s" % (self.model_name, self.name)
639             trans = env['ir.translation']._get_source(name, 'help', env.lang)
640             return trans or self.help
641         return self.help
642
643     ############################################################################
644     #
645     # Conversion to column instance
646     #
647
648     def to_column(self):
649         """ return a low-level field object corresponding to `self` """
650         assert self.store or self.column
651
652         # determine column parameters
653         _logger.debug("Create fields._column for Field %s", self)
654         args = {}
655         for attr, prop in self.column_attrs:
656             args[attr] = getattr(self, prop)
657         for attr in self._free_attrs:
658             args[attr] = getattr(self, attr)
659
660         if self.company_dependent:
661             # company-dependent fields are mapped to former property fields
662             args['type'] = self.type
663             args['relation'] = self.comodel_name
664             self.column = fields.property(**args)
665         elif self.column:
666             # let the column provide a valid column for the given parameters
667             self.column = self.column.new(**args)
668         else:
669             # create a fresh new column of the right type
670             self.column = getattr(fields, self.type)(**args)
671
672         return self.column
673
674     # properties used by to_column() to create a column instance
675     _column_copy = property(attrgetter('copy'))
676     _column_select = property(attrgetter('index'))
677     _column_manual = property(attrgetter('manual'))
678     _column_string = property(attrgetter('string'))
679     _column_help = property(attrgetter('help'))
680     _column_readonly = property(attrgetter('readonly'))
681     _column_required = property(attrgetter('required'))
682     _column_states = property(attrgetter('states'))
683     _column_groups = property(attrgetter('groups'))
684     _column_change_default = property(attrgetter('change_default'))
685     _column_deprecated = property(attrgetter('deprecated'))
686
687     ############################################################################
688     #
689     # Conversion of values
690     #
691
692     def null(self, env):
693         """ return the null value for this field in the given environment """
694         return False
695
696     def convert_to_cache(self, value, record, validate=True):
697         """ convert `value` to the cache level in `env`; `value` may come from
698             an assignment, or have the format of methods :meth:`BaseModel.read`
699             or :meth:`BaseModel.write`
700
701             :param record: the target record for the assignment, or an empty recordset
702
703             :param bool validate: when True, field-specific validation of
704                 `value` will be performed
705         """
706         return value
707
708     def convert_to_read(self, value, use_name_get=True):
709         """ convert `value` from the cache to a value as returned by method
710             :meth:`BaseModel.read`
711
712             :param bool use_name_get: when True, value's diplay name will
713                 be computed using :meth:`BaseModel.name_get`, if relevant
714                 for the field
715         """
716         return False if value is None else value
717
718     def convert_to_write(self, value, target=None, fnames=None):
719         """ convert `value` from the cache to a valid value for method
720             :meth:`BaseModel.write`.
721
722             :param target: optional, the record to be modified with this value
723             :param fnames: for relational fields only, an optional collection of
724                 field names to convert
725         """
726         return self.convert_to_read(value)
727
728     def convert_to_onchange(self, value):
729         """ convert `value` from the cache to a valid value for an onchange
730             method v7.
731         """
732         return self.convert_to_write(value)
733
734     def convert_to_export(self, value, env):
735         """ convert `value` from the cache to a valid value for export. The
736             parameter `env` is given for managing translations.
737         """
738         if env.context.get('export_raw_data'):
739             return value
740         return bool(value) and ustr(value)
741
742     def convert_to_display_name(self, value):
743         """ convert `value` from the cache to a suitable display name. """
744         return ustr(value)
745
746     ############################################################################
747     #
748     # Descriptor methods
749     #
750
751     def __get__(self, record, owner):
752         """ return the value of field `self` on `record` """
753         if record is None:
754             return self         # the field is accessed through the owner class
755
756         if not record:
757             # null record -> return the null value for this field
758             return self.null(record.env)
759
760         # only a single record may be accessed
761         record.ensure_one()
762
763         try:
764             return record._cache[self]
765         except KeyError:
766             pass
767
768         # cache miss, retrieve value
769         if record.id:
770             # normal record -> read or compute value for this field
771             self.determine_value(record)
772         else:
773             # draft record -> compute the value or let it be null
774             self.determine_draft_value(record)
775
776         # the result should be in cache now
777         return record._cache[self]
778
779     def __set__(self, record, value):
780         """ set the value of field `self` on `record` """
781         env = record.env
782
783         # only a single record may be updated
784         record.ensure_one()
785
786         # adapt value to the cache level
787         value = self.convert_to_cache(value, record)
788
789         if env.in_draft or not record.id:
790             # determine dependent fields
791             spec = self.modified_draft(record)
792
793             # set value in cache, inverse field, and mark record as dirty
794             record._cache[self] = value
795             if env.in_onchange:
796                 for invf in self.inverse_fields:
797                     invf._update(value, record)
798                 record._set_dirty(self.name)
799
800             # determine more dependent fields, and invalidate them
801             if self.relational:
802                 spec += self.modified_draft(record)
803             env.invalidate(spec)
804
805         else:
806             # simply write to the database, and update cache
807             record.write({self.name: self.convert_to_write(value)})
808             record._cache[self] = value
809
810     ############################################################################
811     #
812     # Computation of field values
813     #
814
815     def _compute_value(self, records):
816         """ Invoke the compute method on `records`. """
817         # initialize the fields to their corresponding null value in cache
818         for field in self.computed_fields:
819             records._cache[field] = field.null(records.env)
820             records.env.computed[field].update(records._ids)
821         self.compute(records)
822         for field in self.computed_fields:
823             records.env.computed[field].difference_update(records._ids)
824
825     def compute_value(self, records):
826         """ Invoke the compute method on `records`; the results are in cache. """
827         with records.env.do_in_draft():
828             try:
829                 self._compute_value(records)
830             except (AccessError, MissingError):
831                 # some record is forbidden or missing, retry record by record
832                 for record in records:
833                     try:
834                         self._compute_value(record)
835                     except Exception as exc:
836                         record._cache[self.name] = FailedValue(exc)
837
838     def determine_value(self, record):
839         """ Determine the value of `self` for `record`. """
840         env = record.env
841
842         if self.column and not (self.depends and env.in_draft):
843             # this is a stored field or an old-style function field
844             if self.depends:
845                 # this is a stored computed field, check for recomputation
846                 recs = record._recompute_check(self)
847                 if recs:
848                     # recompute the value (only in cache)
849                     self.compute_value(recs)
850                     # HACK: if result is in the wrong cache, copy values
851                     if recs.env != env:
852                         for source, target in zip(recs, recs.with_env(env)):
853                             try:
854                                 values = target._convert_to_cache({
855                                     f.name: source[f.name] for f in self.computed_fields
856                                 }, validate=False)
857                             except MissingError as e:
858                                 values = FailedValue(e)
859                             target._cache.update(values)
860                     # the result is saved to database by BaseModel.recompute()
861                     return
862
863             # read the field from database
864             record._prefetch_field(self)
865
866         elif self.compute:
867             # this is either a non-stored computed field, or a stored computed
868             # field in draft mode
869             if self.recursive:
870                 self.compute_value(record)
871             else:
872                 recs = record._in_cache_without(self)
873                 self.compute_value(recs)
874
875         else:
876             # this is a non-stored non-computed field
877             record._cache[self] = self.null(env)
878
879     def determine_draft_value(self, record):
880         """ Determine the value of `self` for the given draft `record`. """
881         if self.compute:
882             self._compute_value(record)
883         else:
884             record._cache[self] = SpecialValue(self.null(record.env))
885
886     def determine_inverse(self, records):
887         """ Given the value of `self` on `records`, inverse the computation. """
888         if self.inverse:
889             self.inverse(records)
890
891     def determine_domain(self, records, operator, value):
892         """ Return a domain representing a condition on `self`. """
893         if self.search:
894             return self.search(records, operator, value)
895         else:
896             return [(self.name, operator, value)]
897
898     ############################################################################
899     #
900     # Notification when fields are modified
901     #
902
903     def modified(self, records):
904         """ Notify that field `self` has been modified on `records`: prepare the
905             fields/records to recompute, and return a spec indicating what to
906             invalidate.
907         """
908         # invalidate the fields that depend on self, and prepare recomputation
909         spec = [(self, records._ids)]
910         for field, path in self._triggers:
911             if path and field.store:
912                 # don't move this line to function top, see log
913                 env = records.env(user=SUPERUSER_ID, context={'active_test': False})
914                 target = env[field.model_name].search([(path, 'in', records.ids)])
915                 if target:
916                     spec.append((field, target._ids))
917                     target.with_env(records.env)._recompute_todo(field)
918             else:
919                 spec.append((field, None))
920
921         return spec
922
923     def modified_draft(self, records):
924         """ Same as :meth:`modified`, but in draft mode. """
925         env = records.env
926
927         # invalidate the fields on the records in cache that depend on
928         # `records`, except fields currently being computed
929         spec = []
930         for field, path in self._triggers:
931             target = env[field.model_name]
932             computed = target.browse(env.computed[field])
933             if path == 'id':
934                 target = records - computed
935             elif path:
936                 target = (target.browse(env.cache[field]) - computed).filtered(
937                     lambda rec: rec._mapped_cache(path) & records
938                 )
939             else:
940                 target = target.browse(env.cache[field]) - computed
941
942             if target:
943                 spec.append((field, target._ids))
944
945         return spec
946
947
948 class Boolean(Field):
949     type = 'boolean'
950
951     def convert_to_cache(self, value, record, validate=True):
952         return bool(value)
953
954     def convert_to_export(self, value, env):
955         if env.context.get('export_raw_data'):
956             return value
957         return ustr(value)
958
959
960 class Integer(Field):
961     type = 'integer'
962     group_operator = None       # operator for aggregating values
963
964     _related_group_operator = property(attrgetter('group_operator'))
965
966     _column_group_operator = property(attrgetter('group_operator'))
967
968     def convert_to_cache(self, value, record, validate=True):
969         if isinstance(value, dict):
970             # special case, when an integer field is used as inverse for a one2many
971             return value.get('id', False)
972         return int(value or 0)
973
974     def convert_to_read(self, value, use_name_get=True):
975         # Integer values greater than 2^31-1 are not supported in pure XMLRPC,
976         # so we have to pass them as floats :-(
977         if value and value > xmlrpclib.MAXINT:
978             return float(value)
979         return value
980
981     def _update(self, records, value):
982         # special case, when an integer field is used as inverse for a one2many
983         records._cache[self] = value.id or 0
984
985
986 class Float(Field):
987     """ The precision digits are given by the attribute
988
989     :param digits: a pair (total, decimal), or a function taking a database
990                    cursor and returning a pair (total, decimal)
991     """
992     type = 'float'
993     _digits = None              # digits argument passed to class initializer
994     digits = None               # digits as computed by setup()
995     group_operator = None       # operator for aggregating values
996
997     def __init__(self, string=None, digits=None, **kwargs):
998         super(Float, self).__init__(string=string, _digits=digits, **kwargs)
999
1000     def _setup_digits(self, env):
1001         """ Setup the digits for `self` and its corresponding column """
1002         self.digits = self._digits(env.cr) if callable(self._digits) else self._digits
1003         if self.digits:
1004             assert isinstance(self.digits, (tuple, list)) and len(self.digits) >= 2, \
1005                 "Float field %s with digits %r, expecting (total, decimal)" % (self, self.digits)
1006         if self.column:
1007             self.column.digits_change(env.cr)
1008
1009     def _setup_regular(self, env):
1010         super(Float, self)._setup_regular(env)
1011         self._setup_digits(env)
1012
1013     _related_digits = property(attrgetter('digits'))
1014     _related_group_operator = property(attrgetter('group_operator'))
1015
1016     _description_digits = property(attrgetter('digits'))
1017
1018     _column_digits = property(lambda self: not callable(self._digits) and self._digits)
1019     _column_digits_compute = property(lambda self: callable(self._digits) and self._digits)
1020     _column_group_operator = property(attrgetter('group_operator'))
1021
1022     def convert_to_cache(self, value, record, validate=True):
1023         # apply rounding here, otherwise value in cache may be wrong!
1024         if self.digits:
1025             return float_round(float(value or 0.0), precision_digits=self.digits[1])
1026         else:
1027             return float(value or 0.0)
1028
1029
1030 class _String(Field):
1031     """ Abstract class for string fields. """
1032     translate = False
1033
1034     _column_translate = property(attrgetter('translate'))
1035     _related_translate = property(attrgetter('translate'))
1036     _description_translate = property(attrgetter('translate'))
1037
1038
1039 class Char(_String):
1040     """ Basic string field, can be length-limited, usually displayed as a
1041     single-line string in clients
1042
1043     :param int size: the maximum size of values stored for that field
1044     :param bool translate: whether the values of this field can be translated
1045     """
1046     type = 'char'
1047     size = None
1048
1049     def _setup(self, env):
1050         super(Char, self)._setup(env)
1051         assert isinstance(self.size, (NoneType, int)), \
1052             "Char field %s with non-integer size %r" % (self, self.size)
1053
1054     _column_size = property(attrgetter('size'))
1055     _related_size = property(attrgetter('size'))
1056     _description_size = property(attrgetter('size'))
1057
1058     def convert_to_cache(self, value, record, validate=True):
1059         if value is None or value is False:
1060             return False
1061         return ustr(value)[:self.size]
1062
1063 class Text(_String):
1064     """ Very similar to :class:`~.Char` but used for longer contents, does not
1065     have a size and usually displayed as a multiline text box.
1066
1067     :param translate: whether the value of this field can be translated
1068     """
1069     type = 'text'
1070
1071     def convert_to_cache(self, value, record, validate=True):
1072         if value is None or value is False:
1073             return False
1074         return ustr(value)
1075
1076 class Html(_String):
1077     type = 'html'
1078     sanitize = True                     # whether value must be sanitized
1079
1080     _column_sanitize = property(attrgetter('sanitize'))
1081     _related_sanitize = property(attrgetter('sanitize'))
1082     _description_sanitize = property(attrgetter('sanitize'))
1083
1084     def convert_to_cache(self, value, record, validate=True):
1085         if value is None or value is False:
1086             return False
1087         if validate and self.sanitize:
1088             return html_sanitize(value)
1089         return value
1090
1091
1092 class Date(Field):
1093     type = 'date'
1094
1095     @staticmethod
1096     def today(*args):
1097         """ Return the current day in the format expected by the ORM.
1098             This function may be used to compute default values.
1099         """
1100         return date.today().strftime(DATE_FORMAT)
1101
1102     @staticmethod
1103     def context_today(record, timestamp=None):
1104         """ Return the current date as seen in the client's timezone in a format
1105             fit for date fields. This method may be used to compute default
1106             values.
1107
1108             :param datetime timestamp: optional datetime value to use instead of
1109                 the current date and time (must be a datetime, regular dates
1110                 can't be converted between timezones.)
1111             :rtype: str
1112         """
1113         today = timestamp or datetime.now()
1114         context_today = None
1115         tz_name = record._context.get('tz') or record.env.user.tz
1116         if tz_name:
1117             try:
1118                 today_utc = pytz.timezone('UTC').localize(today, is_dst=False)  # UTC = no DST
1119                 context_today = today_utc.astimezone(pytz.timezone(tz_name))
1120             except Exception:
1121                 _logger.debug("failed to compute context/client-specific today date, using UTC value for `today`",
1122                               exc_info=True)
1123         return (context_today or today).strftime(DATE_FORMAT)
1124
1125     @staticmethod
1126     def from_string(value):
1127         """ Convert an ORM `value` into a :class:`date` value. """
1128         value = value[:DATE_LENGTH]
1129         return datetime.strptime(value, DATE_FORMAT).date()
1130
1131     @staticmethod
1132     def to_string(value):
1133         """ Convert a :class:`date` value into the format expected by the ORM. """
1134         return value.strftime(DATE_FORMAT)
1135
1136     def convert_to_cache(self, value, record, validate=True):
1137         if not value:
1138             return False
1139         if isinstance(value, basestring):
1140             if validate:
1141                 # force parsing for validation
1142                 self.from_string(value)
1143             return value[:DATE_LENGTH]
1144         return self.to_string(value)
1145
1146     def convert_to_export(self, value, env):
1147         if value and env.context.get('export_raw_data'):
1148             return self.from_string(value)
1149         return bool(value) and ustr(value)
1150
1151
1152 class Datetime(Field):
1153     type = 'datetime'
1154
1155     @staticmethod
1156     def now(*args):
1157         """ Return the current day and time in the format expected by the ORM.
1158             This function may be used to compute default values.
1159         """
1160         return datetime.now().strftime(DATETIME_FORMAT)
1161
1162     @staticmethod
1163     def context_timestamp(record, timestamp):
1164         """Returns the given timestamp converted to the client's timezone.
1165            This method is *not* meant for use as a _defaults initializer,
1166            because datetime fields are automatically converted upon
1167            display on client side. For _defaults you :meth:`fields.datetime.now`
1168            should be used instead.
1169
1170            :param datetime timestamp: naive datetime value (expressed in UTC)
1171                                       to be converted to the client timezone
1172            :rtype: datetime
1173            :return: timestamp converted to timezone-aware datetime in context
1174                     timezone
1175         """
1176         assert isinstance(timestamp, datetime), 'Datetime instance expected'
1177         tz_name = record._context.get('tz') or record.env.user.tz
1178         if tz_name:
1179             try:
1180                 utc = pytz.timezone('UTC')
1181                 context_tz = pytz.timezone(tz_name)
1182                 utc_timestamp = utc.localize(timestamp, is_dst=False)  # UTC = no DST
1183                 return utc_timestamp.astimezone(context_tz)
1184             except Exception:
1185                 _logger.debug("failed to compute context/client-specific timestamp, "
1186                               "using the UTC value",
1187                               exc_info=True)
1188         return timestamp
1189
1190     @staticmethod
1191     def from_string(value):
1192         """ Convert an ORM `value` into a :class:`datetime` value. """
1193         value = value[:DATETIME_LENGTH]
1194         if len(value) == DATE_LENGTH:
1195             value += " 00:00:00"
1196         return datetime.strptime(value, DATETIME_FORMAT)
1197
1198     @staticmethod
1199     def to_string(value):
1200         """ Convert a :class:`datetime` value into the format expected by the ORM. """
1201         return value.strftime(DATETIME_FORMAT)
1202
1203     def convert_to_cache(self, value, record, validate=True):
1204         if not value:
1205             return False
1206         if isinstance(value, basestring):
1207             if validate:
1208                 # force parsing for validation
1209                 self.from_string(value)
1210             value = value[:DATETIME_LENGTH]
1211             if len(value) == DATE_LENGTH:
1212                 value += " 00:00:00"
1213             return value
1214         return self.to_string(value)
1215
1216     def convert_to_export(self, value, env):
1217         if value and env.context.get('export_raw_data'):
1218             return self.from_string(value)
1219         return bool(value) and ustr(value)
1220
1221
1222 class Binary(Field):
1223     type = 'binary'
1224
1225
1226 class Selection(Field):
1227     """
1228     :param selection: specifies the possible values for this field.
1229         It is given as either a list of pairs (`value`, `string`), or a
1230         model method, or a method name.
1231     :param selection_add: provides an extension of the selection in the case
1232         of an overridden field. It is a list of pairs (`value`, `string`).
1233
1234     The attribute `selection` is mandatory except in the case of
1235     :ref:`related fields <field-related>` or :ref:`field extensions
1236     <field-incremental-definition>`.
1237     """
1238     type = 'selection'
1239     selection = None        # [(value, string), ...], function or method name
1240     selection_add = None    # [(value, string), ...]
1241
1242     def __init__(self, selection=None, string=None, **kwargs):
1243         if callable(selection):
1244             from openerp import api
1245             selection = api.expected(api.model, selection)
1246         super(Selection, self).__init__(selection=selection, string=string, **kwargs)
1247
1248     def _setup(self, env):
1249         super(Selection, self)._setup(env)
1250         assert self.selection is not None, "Field %s without selection" % self
1251
1252     def _setup_related(self, env):
1253         super(Selection, self)._setup_related(env)
1254         # selection must be computed on related field
1255         field = self.related_field
1256         self.selection = lambda model: field._description_selection(model.env)
1257
1258     def set_class_name(self, cls, name):
1259         super(Selection, self).set_class_name(cls, name)
1260         # determine selection (applying 'selection_add' extensions)
1261         selection = None
1262         for field in resolve_all_mro(cls, name, reverse=True):
1263             if isinstance(field, type(self)):
1264                 # We cannot use field.selection or field.selection_add here
1265                 # because those attributes are overridden by `set_class_name`.
1266                 if 'selection' in field._attrs:
1267                     selection = field._attrs['selection']
1268                 if 'selection_add' in field._attrs:
1269                     selection = selection + field._attrs['selection_add']
1270             else:
1271                 selection = None
1272         self.selection = selection
1273
1274     def _description_selection(self, env):
1275         """ return the selection list (pairs (value, label)); labels are
1276             translated according to context language
1277         """
1278         selection = self.selection
1279         if isinstance(selection, basestring):
1280             return getattr(env[self.model_name], selection)()
1281         if callable(selection):
1282             return selection(env[self.model_name])
1283
1284         # translate selection labels
1285         if env.lang:
1286             name = "%s,%s" % (self.model_name, self.name)
1287             translate = partial(
1288                 env['ir.translation']._get_source, name, 'selection', env.lang)
1289             return [(value, translate(label) if label else label) for value, label in selection]
1290         else:
1291             return selection
1292
1293     @property
1294     def _column_selection(self):
1295         if isinstance(self.selection, basestring):
1296             method = self.selection
1297             return lambda self, *a, **kw: getattr(self, method)(*a, **kw)
1298         else:
1299             return self.selection
1300
1301     def get_values(self, env):
1302         """ return a list of the possible values """
1303         selection = self.selection
1304         if isinstance(selection, basestring):
1305             selection = getattr(env[self.model_name], selection)()
1306         elif callable(selection):
1307             selection = selection(env[self.model_name])
1308         return [value for value, _ in selection]
1309
1310     def convert_to_cache(self, value, record, validate=True):
1311         if not validate:
1312             return value or False
1313         if value in self.get_values(record.env):
1314             return value
1315         elif not value:
1316             return False
1317         raise ValueError("Wrong value for %s: %r" % (self, value))
1318
1319     def convert_to_export(self, value, env):
1320         if not isinstance(self.selection, list):
1321             # FIXME: this reproduces an existing buggy behavior!
1322             return value
1323         for item in self._description_selection(env):
1324             if item[0] == value:
1325                 return item[1]
1326         return False
1327
1328
1329 class Reference(Selection):
1330     type = 'reference'
1331     size = None
1332
1333     def __init__(self, selection=None, string=None, **kwargs):
1334         super(Reference, self).__init__(selection=selection, string=string, **kwargs)
1335
1336     def _setup(self, env):
1337         super(Reference, self)._setup(env)
1338         assert isinstance(self.size, (NoneType, int)), \
1339             "Reference field %s with non-integer size %r" % (self, self.size)
1340
1341     _related_size = property(attrgetter('size'))
1342
1343     _column_size = property(attrgetter('size'))
1344
1345     def convert_to_cache(self, value, record, validate=True):
1346         if isinstance(value, BaseModel):
1347             if ((not validate or value._name in self.get_values(record.env))
1348                     and len(value) <= 1):
1349                 return value.with_env(record.env) or False
1350         elif isinstance(value, basestring):
1351             res_model, res_id = value.split(',')
1352             return record.env[res_model].browse(int(res_id))
1353         elif not value:
1354             return False
1355         raise ValueError("Wrong value for %s: %r" % (self, value))
1356
1357     def convert_to_read(self, value, use_name_get=True):
1358         return "%s,%s" % (value._name, value.id) if value else False
1359
1360     def convert_to_export(self, value, env):
1361         return bool(value) and value.name_get()[0][1]
1362
1363     def convert_to_display_name(self, value):
1364         return ustr(value and value.display_name)
1365
1366
1367 class _Relational(Field):
1368     """ Abstract class for relational fields. """
1369     relational = True
1370     domain = None                       # domain for searching values
1371     context = None                      # context for searching values
1372
1373     def _setup(self, env):
1374         super(_Relational, self)._setup(env)
1375         assert self.comodel_name in env.registry, \
1376             "Field %s with unknown comodel_name %r" % (self, self.comodel_name)
1377
1378     @property
1379     def _related_domain(self):
1380         if callable(self.domain):
1381             # will be called with another model than self's
1382             return lambda recs: self.domain(recs.env[self.model_name])
1383         else:
1384             # maybe not correct if domain is a string...
1385             return self.domain
1386
1387     _related_context = property(attrgetter('context'))
1388
1389     _description_relation = property(attrgetter('comodel_name'))
1390     _description_context = property(attrgetter('context'))
1391
1392     def _description_domain(self, env):
1393         return self.domain(env[self.model_name]) if callable(self.domain) else self.domain
1394
1395     _column_obj = property(attrgetter('comodel_name'))
1396     _column_domain = property(attrgetter('domain'))
1397     _column_context = property(attrgetter('context'))
1398
1399     def null(self, env):
1400         return env[self.comodel_name]
1401
1402     def modified(self, records):
1403         # Invalidate cache for self.inverse_fields, too. Note that recomputation
1404         # of fields that depend on self.inverse_fields is already covered by the
1405         # triggers (see above).
1406         spec = super(_Relational, self).modified(records)
1407         for invf in self.inverse_fields:
1408             spec.append((invf, None))
1409         return spec
1410
1411
1412 class Many2one(_Relational):
1413     """ The value of such a field is a recordset of size 0 (no
1414     record) or 1 (a single record).
1415
1416     :param comodel_name: name of the target model (string)
1417
1418     :param domain: an optional domain to set on candidate values on the
1419         client side (domain or string)
1420
1421     :param context: an optional context to use on the client side when
1422         handling that field (dictionary)
1423
1424     :param ondelete: what to do when the referred record is deleted;
1425         possible values are: ``'set null'``, ``'restrict'``, ``'cascade'``
1426
1427     :param auto_join: whether JOINs are generated upon search through that
1428         field (boolean, by default ``False``)
1429
1430     :param delegate: set it to ``True`` to make fields of the target model
1431         accessible from the current model (corresponds to ``_inherits``)
1432
1433     The attribute `comodel_name` is mandatory except in the case of related
1434     fields or field extensions.
1435     """
1436     type = 'many2one'
1437     ondelete = 'set null'               # what to do when value is deleted
1438     auto_join = False                   # whether joins are generated upon search
1439     delegate = False                    # whether self implements delegation
1440
1441     def __init__(self, comodel_name=None, string=None, **kwargs):
1442         super(Many2one, self).__init__(comodel_name=comodel_name, string=string, **kwargs)
1443
1444     def set_class_name(self, cls, name):
1445         super(Many2one, self).set_class_name(cls, name)
1446         # determine self.delegate
1447         if not self.delegate:
1448             self.delegate = name in cls._inherits.values()
1449
1450     _column_ondelete = property(attrgetter('ondelete'))
1451     _column_auto_join = property(attrgetter('auto_join'))
1452
1453     def _update(self, records, value):
1454         """ Update the cached value of `self` for `records` with `value`. """
1455         records._cache[self] = value
1456
1457     def convert_to_cache(self, value, record, validate=True):
1458         if isinstance(value, (NoneType, int, long)):
1459             return record.env[self.comodel_name].browse(value)
1460         if isinstance(value, BaseModel):
1461             if value._name == self.comodel_name and len(value) <= 1:
1462                 return value.with_env(record.env)
1463             raise ValueError("Wrong value for %s: %r" % (self, value))
1464         elif isinstance(value, tuple):
1465             return record.env[self.comodel_name].browse(value[0])
1466         elif isinstance(value, dict):
1467             return record.env[self.comodel_name].new(value)
1468         else:
1469             return self.null(record.env)
1470
1471     def convert_to_read(self, value, use_name_get=True):
1472         if use_name_get and value:
1473             # evaluate name_get() as superuser, because the visibility of a
1474             # many2one field value (id and name) depends on the current record's
1475             # access rights, and not the value's access rights.
1476             try:
1477                 return value.sudo().name_get()[0]
1478             except MissingError:
1479                 # Should not happen, unless the foreign key is missing.
1480                 return False
1481         else:
1482             return value.id
1483
1484     def convert_to_write(self, value, target=None, fnames=None):
1485         return value.id
1486
1487     def convert_to_onchange(self, value):
1488         return value.id
1489
1490     def convert_to_export(self, value, env):
1491         return bool(value) and value.name_get()[0][1]
1492
1493     def convert_to_display_name(self, value):
1494         return ustr(value.display_name)
1495
1496
1497 class UnionUpdate(SpecialValue):
1498     """ Placeholder for a value update; when this value is taken from the cache,
1499         it returns ``record[field.name] | value`` and stores it in the cache.
1500     """
1501     def __init__(self, field, record, value):
1502         self.args = (field, record, value)
1503
1504     def get(self):
1505         field, record, value = self.args
1506         # in order to read the current field's value, remove self from cache
1507         del record._cache[field]
1508         # read the current field's value, and update it in cache only
1509         record._cache[field] = new_value = record[field.name] | value
1510         return new_value
1511
1512
1513 class _RelationalMulti(_Relational):
1514     """ Abstract class for relational fields *2many. """
1515
1516     def _update(self, records, value):
1517         """ Update the cached value of `self` for `records` with `value`. """
1518         for record in records:
1519             if self in record._cache:
1520                 record._cache[self] = record[self.name] | value
1521             else:
1522                 record._cache[self] = UnionUpdate(self, record, value)
1523
1524     def convert_to_cache(self, value, record, validate=True):
1525         if isinstance(value, BaseModel):
1526             if value._name == self.comodel_name:
1527                 return value.with_env(record.env)
1528         elif isinstance(value, list):
1529             # value is a list of record ids or commands
1530             if not record.id:
1531                 record = record.browse()        # new record has no value
1532             result = record[self.name]
1533             # modify result with the commands;
1534             # beware to not introduce duplicates in result
1535             for command in value:
1536                 if isinstance(command, (tuple, list)):
1537                     if command[0] == 0:
1538                         result += result.new(command[2])
1539                     elif command[0] == 1:
1540                         result.browse(command[1]).update(command[2])
1541                         result += result.browse(command[1]) - result
1542                     elif command[0] == 2:
1543                         # note: the record will be deleted by write()
1544                         result -= result.browse(command[1])
1545                     elif command[0] == 3:
1546                         result -= result.browse(command[1])
1547                     elif command[0] == 4:
1548                         result += result.browse(command[1]) - result
1549                     elif command[0] == 5:
1550                         result = result.browse()
1551                     elif command[0] == 6:
1552                         result = result.browse(command[2])
1553                 elif isinstance(command, dict):
1554                     result += result.new(command)
1555                 else:
1556                     result += result.browse(command) - result
1557             return result
1558         elif not value:
1559             return self.null(record.env)
1560         raise ValueError("Wrong value for %s: %s" % (self, value))
1561
1562     def convert_to_read(self, value, use_name_get=True):
1563         return value.ids
1564
1565     def convert_to_write(self, value, target=None, fnames=None):
1566         # remove/delete former records
1567         if target is None:
1568             set_ids = []
1569             result = [(6, 0, set_ids)]
1570             add_existing = lambda id: set_ids.append(id)
1571         else:
1572             tag = 2 if self.type == 'one2many' else 3
1573             result = [(tag, record.id) for record in target[self.name] - value]
1574             add_existing = lambda id: result.append((4, id))
1575
1576         if fnames is None:
1577             # take all fields in cache, except the inverses of self
1578             fnames = set(value._fields) - set(MAGIC_COLUMNS)
1579             for invf in self.inverse_fields:
1580                 fnames.discard(invf.name)
1581
1582         # add new and existing records
1583         for record in value:
1584             if not record.id:
1585                 values = {k: v for k, v in record._cache.iteritems() if k in fnames}
1586                 values = record._convert_to_write(values)
1587                 result.append((0, 0, values))
1588             elif record._is_dirty():
1589                 values = {k: record._cache[k] for k in record._get_dirty() if k in fnames}
1590                 values = record._convert_to_write(values)
1591                 result.append((1, record.id, values))
1592             else:
1593                 add_existing(record.id)
1594
1595         return result
1596
1597     def convert_to_export(self, value, env):
1598         return bool(value) and ','.join(name for id, name in value.name_get())
1599
1600     def convert_to_display_name(self, value):
1601         raise NotImplementedError()
1602
1603     def _compute_related(self, records):
1604         """ Compute the related field `self` on `records`. """
1605         for record in records:
1606             value = record
1607             # traverse the intermediate fields, and keep at most one record
1608             for name in self.related[:-1]:
1609                 value = value[name][:1]
1610             record[self.name] = value[self.related[-1]]
1611
1612
1613 class One2many(_RelationalMulti):
1614     """ One2many field; the value of such a field is the recordset of all the
1615         records in `comodel_name` such that the field `inverse_name` is equal to
1616         the current record.
1617
1618         :param comodel_name: name of the target model (string)
1619
1620         :param inverse_name: name of the inverse `Many2one` field in
1621             `comodel_name` (string)
1622
1623         :param domain: an optional domain to set on candidate values on the
1624             client side (domain or string)
1625
1626         :param context: an optional context to use on the client side when
1627             handling that field (dictionary)
1628
1629         :param auto_join: whether JOINs are generated upon search through that
1630             field (boolean, by default ``False``)
1631
1632         :param limit: optional limit to use upon read (integer)
1633
1634         The attributes `comodel_name` and `inverse_name` are mandatory except in
1635         the case of related fields or field extensions.
1636     """
1637     type = 'one2many'
1638     inverse_name = None                 # name of the inverse field
1639     auto_join = False                   # whether joins are generated upon search
1640     limit = None                        # optional limit to use upon read
1641     copy = False                        # o2m are not copied by default
1642
1643     def __init__(self, comodel_name=None, inverse_name=None, string=None, **kwargs):
1644         super(One2many, self).__init__(
1645             comodel_name=comodel_name,
1646             inverse_name=inverse_name,
1647             string=string,
1648             **kwargs
1649         )
1650
1651     def _setup_regular(self, env):
1652         super(One2many, self)._setup_regular(env)
1653
1654         if self.inverse_name:
1655             # link self to its inverse field and vice-versa
1656             comodel = env[self.comodel_name]
1657             comodel._setup_fields()
1658             invf = comodel._fields[self.inverse_name]
1659             # In some rare cases, a `One2many` field can link to `Int` field
1660             # (res_model/res_id pattern). Only inverse the field if this is
1661             # a `Many2one` field.
1662             if isinstance(invf, Many2one):
1663                 self.inverse_fields.append(invf)
1664                 invf.inverse_fields.append(self)
1665
1666     _description_relation_field = property(attrgetter('inverse_name'))
1667
1668     _column_fields_id = property(attrgetter('inverse_name'))
1669     _column_auto_join = property(attrgetter('auto_join'))
1670     _column_limit = property(attrgetter('limit'))
1671
1672
1673 class Many2many(_RelationalMulti):
1674     """ Many2many field; the value of such a field is the recordset.
1675
1676         :param comodel_name: name of the target model (string)
1677
1678         The attribute `comodel_name` is mandatory except in the case of related
1679         fields or field extensions.
1680
1681         :param relation: optional name of the table that stores the relation in
1682             the database (string)
1683
1684         :param column1: optional name of the column referring to "these" records
1685             in the table `relation` (string)
1686
1687         :param column2: optional name of the column referring to "those" records
1688             in the table `relation` (string)
1689
1690         The attributes `relation`, `column1` and `column2` are optional. If not
1691         given, names are automatically generated from model names, provided
1692         `model_name` and `comodel_name` are different!
1693
1694         :param domain: an optional domain to set on candidate values on the
1695             client side (domain or string)
1696
1697         :param context: an optional context to use on the client side when
1698             handling that field (dictionary)
1699
1700         :param limit: optional limit to use upon read (integer)
1701
1702     """
1703     type = 'many2many'
1704     relation = None                     # name of table
1705     column1 = None                      # column of table referring to model
1706     column2 = None                      # column of table referring to comodel
1707     limit = None                        # optional limit to use upon read
1708
1709     def __init__(self, comodel_name=None, relation=None, column1=None, column2=None,
1710                  string=None, **kwargs):
1711         super(Many2many, self).__init__(
1712             comodel_name=comodel_name,
1713             relation=relation,
1714             column1=column1,
1715             column2=column2,
1716             string=string,
1717             **kwargs
1718         )
1719
1720     def _setup_regular(self, env):
1721         super(Many2many, self)._setup_regular(env)
1722
1723         if not self.relation:
1724             if isinstance(self.column, fields.many2many):
1725                 self.relation, self.column1, self.column2 = \
1726                     self.column._sql_names(env[self.model_name])
1727
1728         if self.relation:
1729             m2m = env.registry._m2m
1730             # if inverse field has already been setup, it is present in m2m
1731             invf = m2m.get((self.relation, self.column2, self.column1))
1732             if invf:
1733                 self.inverse_fields.append(invf)
1734                 invf.inverse_fields.append(self)
1735             else:
1736                 # add self in m2m, so that its inverse field can find it
1737                 m2m[(self.relation, self.column1, self.column2)] = self
1738
1739     _column_rel = property(attrgetter('relation'))
1740     _column_id1 = property(attrgetter('column1'))
1741     _column_id2 = property(attrgetter('column2'))
1742     _column_limit = property(attrgetter('limit'))
1743
1744
1745 class Id(Field):
1746     """ Special case for field 'id'. """
1747     store = True
1748     #: Can't write this!
1749     readonly = True
1750
1751     def __init__(self, string=None, **kwargs):
1752         super(Id, self).__init__(type='integer', string=string, **kwargs)
1753
1754     def to_column(self):
1755         self.column = fields.integer('ID')
1756         return self.column
1757
1758     def __get__(self, record, owner):
1759         if record is None:
1760             return self         # the field is accessed through the class owner
1761         if not record:
1762             return False
1763         return record.ensure_one()._ids[0]
1764
1765     def __set__(self, record, value):
1766         raise TypeError("field 'id' cannot be assigned")
1767
1768
1769 # imported here to avoid dependency cycle issues
1770 from openerp import SUPERUSER_ID
1771 from .exceptions import Warning, AccessError, MissingError
1772 from .models import BaseModel, MAGIC_COLUMNS
1773 from .osv import fields