diff --git a/addons/mail/__manifest__.py b/addons/mail/__manifest__.py index bfc0d78008b..c68b3ee7e16 100644 --- a/addons/mail/__manifest__.py +++ b/addons/mail/__manifest__.py @@ -50,6 +50,7 @@ Main Features 'wizard/email_template_preview_view.xml', 'views/mail_template_views.xml', 'views/ir_actions_views.xml', + 'views/ir_model_views.xml', 'views/res_partner_views.xml', ], 'demo': [ diff --git a/addons/mail/models/__init__.py b/addons/mail/models/__init__.py index 486b687eeb2..43caa97b6f9 100644 --- a/addons/mail/models/__init__.py +++ b/addons/mail/models/__init__.py @@ -18,4 +18,5 @@ import res_config import update import ir_actions import ir_autovacuum +import ir_model import html2text diff --git a/addons/mail/models/ir_model.py b/addons/mail/models/ir_model.py new file mode 100644 index 00000000000..57df668fcfd --- /dev/null +++ b/addons/mail/models/ir_model.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class IrModel(models.Model): + _inherit = 'ir.model' + _order = 'is_mail_thread DESC, name ASC' + + is_mail_thread = fields.Boolean( + string="Mail Thread", oldname='mail_thread', default=False, + help="Whether this model supports messages and notifications.", + ) + + @api.multi + def write(self, vals): + if self and 'is_mail_thread' in vals: + if not all(rec.state == 'manual' for rec in self): + raise UserError(_('Only custom models can be modified.')) + if not all(rec.is_mail_thread <= vals['is_mail_thread'] for rec in self): + raise UserError(_('Field "Mail Thread" cannot be changed to "False".')) + res = super(IrModel, self).write(vals) + # setup models; this reloads custom models in registry + self.pool.setup_models(self._cr, partial=(not self.pool.ready)) + # update database schema of models + models = self.pool.descendants(self.mapped('model'), '_inherits') + self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True)) + self.pool.signal_registry_change() + else: + res = super(IrModel, self).write(vals) + return res + + def _reflect_model_params(self, model): + vals = super(IrModel, self)._reflect_model_params(model) + vals['is_mail_thread'] = issubclass(type(model), self.pool['mail.thread']) + return vals + + @api.model + def _instanciate(self, model_data): + model_class = super(IrModel, self)._instanciate(model_data) + if model_data.get('is_mail_thread') and model_class._name != 'mail.thread': + parents = model_class._inherit or [] + parents = [parents] if isinstance(parents, basestring) else parents + model_class._inherit = parents + ['mail.thread'] + return model_class + + +class IrModelField(models.Model): + _inherit = 'ir.model.fields' + + track_visibility = fields.Selection( + [('onchange', "On Change"), ('always', "Always")], string="Tracking", + help="When set, every modification to this field will be tracked in the chatter.", + ) + + def _reflect_field_params(self, field): + vals = super(IrModelField, self)._reflect_field_params(field) + vals['track_visibility'] = getattr(field, 'track_visibility', None) + return vals + + def _instanciate_attrs(self, field_data, partial): + attrs = super(IrModelField, self)._instanciate_attrs(field_data, partial) + if field_data.get('track_visibility'): + attrs['track_visibility'] = field_data['track_visibility'] + return attrs diff --git a/addons/mail/views/ir_model_views.xml b/addons/mail/views/ir_model_views.xml new file mode 100644 index 00000000000..564a0c63465 --- /dev/null +++ b/addons/mail/views/ir_model_views.xml @@ -0,0 +1,37 @@ + + + + + ir.model + + + + + + + + + + + + + ir.model + + + + + + + + + + ir.model.fields + + + + + + + + + diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py index e5acaee9d87..a0cf5d3f933 100644 --- a/odoo/addons/base/ir/ir_model.py +++ b/odoo/addons/base/ir/ir_model.py @@ -129,7 +129,14 @@ class IrModel(models.Model): """ Return the (sudoed) `ir.model` record with the given name. The result may be an empty recordset if the model is not found. """ - return self.sudo().search([('model', '=', name)]) + model_id = self._get_id(name) if name else False + return self.sudo().browse(model_id) + + @tools.ormcache('name') + def _get_id(self, name): + self.env.cr.execute("SELECT id FROM ir_model WHERE model=%s", (name,)) + result = self.env.cr.fetchone() + return result and result[0] # overridden to allow searching both on model name (field 'model') and model # description (field 'name') @@ -455,7 +462,15 @@ class IrModelFields(models.Model): """ Return the (sudoed) `ir.model.fields` record with the given model and name. The result may be an empty recordset if the model is not found. """ - return self.sudo().search([('model', '=', model_name), ('name', '=', name)]) + field_id = self._get_id(model_name, name) if model_name and name else False + return self.sudo().browse(field_id) + + @tools.ormcache('model_name', 'name') + def _get_id(self, model_name, name): + self.env.cr.execute("SELECT id FROM ir_model_fields WHERE model=%s AND name=%s", + (model_name, name)) + result = self.env.cr.fetchone() + return result and result[0] @api.multi def _drop_column(self):