diff options
Diffstat (limited to 'odoo/addons/test_new_api/models.py')
| -rw-r--r-- | odoo/addons/test_new_api/models.py | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py new file mode 100644 index 00000000000..f94eea8a4f9 --- /dev/null +++ b/odoo/addons/test_new_api/models.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import datetime + +from openerp import models, fields, api, _ +from openerp.exceptions import AccessError + + +class Category(models.Model): + _name = 'test_new_api.category' + + name = fields.Char(required=True) + color = fields.Integer('Color Index') + parent = fields.Many2one('test_new_api.category') + display_name = fields.Char(compute='_compute_display_name', inverse='_inverse_display_name') + dummy = fields.Char(store=False) + discussions = fields.Many2many('test_new_api.discussion', 'test_new_api_discussion_category', + 'category', 'discussion') + + @api.one + @api.depends('name', 'parent.display_name') # this definition is recursive + def _compute_display_name(self): + if self.parent: + self.display_name = self.parent.display_name + ' / ' + self.name + else: + self.display_name = self.name + + @api.one + def _inverse_display_name(self): + names = self.display_name.split('/') + # determine sequence of categories + categories = [] + for name in names[:-1]: + category = self.search([('name', 'ilike', name.strip())]) + categories.append(category[0]) + categories.append(self) + # assign parents following sequence + for parent, child in zip(categories, categories[1:]): + if parent and child: + child.parent = parent + # assign name of last category, and reassign display_name (to normalize it) + self.name = names[-1].strip() + + @api.multi + def read(self, fields=None, load='_classic_read'): + if self.search_count([('id', 'in', self._ids), ('name', '=', 'NOACCESS')]): + raise AccessError('Sorry') + return super(Category, self).read(fields=fields, load=load) + + +class Discussion(models.Model): + _name = 'test_new_api.discussion' + + name = fields.Char(string='Title', required=True, + help="General description of what this discussion is about.") + moderator = fields.Many2one('res.users') + categories = fields.Many2many('test_new_api.category', + 'test_new_api_discussion_category', 'discussion', 'category') + participants = fields.Many2many('res.users') + messages = fields.One2many('test_new_api.message', 'discussion') + message_concat = fields.Text(string='Message concatenate') + important_messages = fields.One2many('test_new_api.message', 'discussion', + domain=[('important', '=', True)]) + emails = fields.One2many('test_new_api.emailmessage', 'discussion') + important_emails = fields.One2many('test_new_api.emailmessage', 'discussion', + domain=[('important', '=', True)]) + + @api.onchange('moderator') + def _onchange_moderator(self): + self.participants |= self.moderator + + @api.onchange('messages') + def _onchange_messages(self): + self.message_concat = "\n".join(["%s:%s" % (m.name, m.body) for m in self.messages]) + + +class Message(models.Model): + _name = 'test_new_api.message' + + discussion = fields.Many2one('test_new_api.discussion', ondelete='cascade') + body = fields.Text() + author = fields.Many2one('res.users', default=lambda self: self.env.user) + name = fields.Char(string='Title', compute='_compute_name', store=True) + display_name = fields.Char(string='Abstract', compute='_compute_display_name') + size = fields.Integer(compute='_compute_size', search='_search_size') + double_size = fields.Integer(compute='_compute_double_size') + discussion_name = fields.Char(related='discussion.name', string="Discussion Name") + author_partner = fields.Many2one( + 'res.partner', compute='_compute_author_partner', + search='_search_author_partner') + important = fields.Boolean() + + @api.one + @api.constrains('author', 'discussion') + def _check_author(self): + if self.discussion and self.author not in self.discussion.participants: + raise ValidationError(_("Author must be among the discussion participants.")) + + @api.one + @api.depends('author.name', 'discussion.name') + def _compute_name(self): + self.name = "[%s] %s" % (self.discussion.name or '', self.author.name or '') + + @api.one + @api.depends('author.name', 'discussion.name', 'body') + def _compute_display_name(self): + stuff = "[%s] %s: %s" % (self.author.name, self.discussion.name or '', self.body or '') + self.display_name = stuff[:80] + + @api.one + @api.depends('body') + def _compute_size(self): + self.size = len(self.body or '') + + def _search_size(self, operator, value): + if operator not in ('=', '!=', '<', '<=', '>', '>=', 'in', 'not in'): + return [] + # retrieve all the messages that match with a specific SQL query + query = """SELECT id FROM "%s" WHERE char_length("body") %s %%s""" % \ + (self._table, operator) + self.env.cr.execute(query, (value,)) + ids = [t[0] for t in self.env.cr.fetchall()] + return [('id', 'in', ids)] + + @api.one + @api.depends('size') + def _compute_double_size(self): + # This illustrates a subtle situation: self.double_size depends on + # self.size. When size is computed, self.size is assigned, which should + # normally invalidate self.double_size. However, this may not happen + # while self.double_size is being computed: the last statement below + # would fail, because self.double_size would be undefined. + self.double_size = 0 + size = self.size + self.double_size = self.double_size + size + + @api.one + @api.depends('author', 'author.partner_id') + def _compute_author_partner(self): + self.author_partner = author.partner_id + + @api.model + def _search_author_partner(self, operator, value): + return [('author.partner_id', operator, value)] + + +class EmailMessage(models.Model): + _name = 'test_new_api.emailmessage' + _inherits = {'test_new_api.message': 'message'} + + message = fields.Many2one('test_new_api.message', 'Message', + required=True, ondelete='cascade') + email_to = fields.Char('To') + + +class Multi(models.Model): + """ Model for testing multiple onchange methods in cascade that modify a + one2many field several times. + """ + _name = 'test_new_api.multi' + + name = fields.Char(related='partner.name', readonly=True) + partner = fields.Many2one('res.partner') + lines = fields.One2many('test_new_api.multi.line', 'multi') + + @api.onchange('name') + def _onchange_name(self): + for line in self.lines: + line.name = self.name + + @api.onchange('partner') + def _onchange_partner(self): + for line in self.lines: + line.partner = self.partner + + +class MultiLine(models.Model): + _name = 'test_new_api.multi.line' + + multi = fields.Many2one('test_new_api.multi', ondelete='cascade') + name = fields.Char() + partner = fields.Many2one('res.partner') + + +class MixedModel(models.Model): + _name = 'test_new_api.mixed' + + number = fields.Float(digits=(10, 2), default=3.14) + date = fields.Date() + now = fields.Datetime(compute='_compute_now') + lang = fields.Selection(string='Language', selection='_get_lang') + reference = fields.Reference(string='Related Document', + selection='_reference_models') + comment1 = fields.Html(sanitize=False) + comment2 = fields.Html(sanitize_attributes=True, strip_classes=False) + comment3 = fields.Html(sanitize_attributes=True, strip_classes=True) + comment4 = fields.Html(sanitize_attributes=True, strip_style=True) + + currency_id = fields.Many2one('res.currency', default=lambda self: self.env.ref('base.EUR')) + amount = fields.Monetary() + + @api.one + def _compute_now(self): + # this is a non-stored computed field without dependencies + self.now = fields.Datetime.now() + + @api.model + def _get_lang(self): + return self.env['res.lang'].get_installed() + + @api.model + def _reference_models(self): + models = self.env['ir.model'].search([('state', '!=', 'manual')]) + return [(model.model, model.name) + for model in models + if not model.model.startswith('ir.')] + + +class BoolModel(models.Model): + _name = 'domain.bool' + + bool_true = fields.Boolean('b1', default=True) + bool_false = fields.Boolean('b2', default=False) + bool_undefined = fields.Boolean('b3') + + +class Foo(models.Model): + _name = 'test_new_api.foo' + + name = fields.Char() + value1 = fields.Integer() + value2 = fields.Integer() + + +class Bar(models.Model): + _name = 'test_new_api.bar' + + name = fields.Char() + foo = fields.Many2one('test_new_api.foo', compute='_compute_foo') + value1 = fields.Integer(related='foo.value1') + value2 = fields.Integer(related='foo.value2') + + @api.depends('name') + def _compute_foo(self): + for bar in self: + bar.foo = self.env['test_new_api.foo'].search([('name', '=', bar.name)], limit=1) + + +class Related(models.Model): + _name = 'test_new_api.related' + + name = fields.Char() + # related fields with a single field + related_name = fields.Char(related='name') + related_related_name = fields.Char(related='related_name') + + +class ComputeInverse(models.Model): + _name = 'test_new_api.compute.inverse' + + counts = {'compute': 0, 'inverse': 0} + + foo = fields.Char() + bar = fields.Char(compute='_compute_bar', inverse='_inverse_bar', store=True) + + @api.depends('foo') + def _compute_bar(self): + self.counts['compute'] += 1 + for record in self: + record.bar = record.foo + + def _inverse_bar(self): + self.counts['inverse'] += 1 + for record in self: + record.foo = record.bar + + +class CompanyDependent(models.Model): + _name = 'test_new_api.company' + + foo = fields.Char(company_dependent=True) + + +class Sparse(models.Model): + _name = 'test_new_api.sparse' + + data = fields.Serialized() + boolean = fields.Boolean(sparse='data') + integer = fields.Integer(sparse='data') + float = fields.Float(sparse='data') + char = fields.Char(sparse='data') + selection = fields.Selection([('one', 'One'), ('two', 'Two')], sparse='data') + partner = fields.Many2one('res.partner', sparse='data') |
