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