From d9ffbe9e89423ebf18fb8e03f5abd8fb7c2f5c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Debauche=20St=C3=A9phane?= Date: Wed, 12 Feb 2020 16:19:44 +0000 Subject: [PATCH] [IMP] event: merge the SMS template and the mail template into one field Purpose ======= A new module "Event Social" will be added in the enterprise PR. This new module will use a new template type, the "Social Post Template" adding one more column in the communication tab... We want to have only one column to select the template (Mail, SMS or Post template) and therefor we need to use a reference field. Technical ========= As we can not set a domain on a reference field, we added a context key and in the `_name_search` of the `mail/sms.template` we filter with the domain we want if the key exists. Links ===== Task-2127615 See odoo/odoo/pull/46304 See odoo/enterprise/pull/7701 See odoo/upgrade/pull/848 --- addons/event/data/event_demo.xml | 4 +- addons/event/models/__init__.py | 1 + addons/event/models/event_event.py | 6 +-- addons/event/models/event_mail.py | 54 +++++++++++++------ addons/event/models/event_registration.py | 2 +- addons/event/models/mail_template.py | 22 ++++++++ addons/event/tests/common.py | 4 +- addons/event/tests/test_event_internals.py | 21 ++++++-- .../event/tests/test_event_mail_schedule.py | 8 +-- addons/event/views/event_views.xml | 23 ++++---- addons/event_sms/__manifest__.py | 2 - addons/event_sms/models/__init__.py | 1 + addons/event_sms/models/event_mail.py | 46 +++++++++------- addons/event_sms/models/sms_template.py | 22 ++++++++ addons/event_sms/tests/test_sms_schedule.py | 4 +- addons/event_sms/views/event_mail_views.xml | 41 -------------- addons/event_sms/views/event_views.xml | 42 --------------- .../tests/test_event_security.py | 4 +- 18 files changed, 154 insertions(+), 153 deletions(-) create mode 100644 addons/event/models/mail_template.py create mode 100644 addons/event_sms/models/sms_template.py delete mode 100644 addons/event_sms/views/event_mail_views.xml delete mode 100644 addons/event_sms/views/event_views.xml diff --git a/addons/event/data/event_demo.xml b/addons/event/data/event_demo.xml index 8c434201649..7ab534cbf32 100644 --- a/addons/event/data/event_demo.xml +++ b/addons/event/data/event_demo.xml @@ -128,7 +128,7 @@ - + @@ -164,7 +164,7 @@ - + diff --git a/addons/event/models/__init__.py b/addons/event/models/__init__.py index 6dcac1874dd..3de00d4b7b9 100644 --- a/addons/event/models/__init__.py +++ b/addons/event/models/__init__.py @@ -7,5 +7,6 @@ from . import event_registration from . import event_stage from . import event_tag from . import event_ticket +from . import mail_template from . import res_config_settings from . import res_partner diff --git a/addons/event/models/event_event.py b/addons/event/models/event_event.py index b8336668947..332c132e6b1 100644 --- a/addons/event/models/event_event.py +++ b/addons/event/models/event_event.py @@ -380,10 +380,8 @@ class EventEvent(models.Model): command = [Command.unlink(mail.id) for mail in mails_to_remove] if event.event_type_id.event_type_mail_ids: command += [ - Command.create({ - attribute_name: line[attribute_name] if not isinstance(line[attribute_name], models.BaseModel) else line[attribute_name].id - for attribute_name in self.env['event.type.mail']._get_event_mail_fields_whitelist() - }) for line in event.event_type_id.event_type_mail_ids + Command.create(line._prepare_event_mail_values()) + for line in event.event_type_id.event_type_mail_ids ] if command: event.event_mail_ids = command diff --git a/addons/event/models/event_mail.py b/addons/event/models/event_mail.py index 70207bd8ac9..9bdfa4cd7a8 100644 --- a/addons/event/models/event_mail.py +++ b/addons/event/models/event_mail.py @@ -29,6 +29,10 @@ class EventTypeMail(models.Model): _name = 'event.type.mail' _description = 'Mail Scheduling on Event Category' + @api.model + def _selection_template_model(self): + return [('mail.template', 'Mail')] + event_type_id = fields.Many2one( 'event.type', string='Event Type', ondelete='cascade', required=True) @@ -44,16 +48,24 @@ class EventTypeMail(models.Model): ('before_event', 'Before the event'), ('after_event', 'After the event')], string='Trigger', default="before_event", required=True) - template_id = fields.Many2one( - 'mail.template', string='Email Template', - domain=[('model', '=', 'event.registration')], ondelete='restrict', - help='This field contains the template of the mail that will be automatically sent') + template_model_id = fields.Many2one('ir.model', string='Template Model', compute='_compute_template_model_id', compute_sudo=True) + template_ref = fields.Reference(string='Template', selection='_selection_template_model', required=True) - @api.model - def _get_event_mail_fields_whitelist(self): - """ Whitelist of fields that are copied from event_type_mail_ids to event_mail_ids when - changing the event_type_id field of event.event """ - return ['notification_type', 'template_id', 'interval_nbr', 'interval_unit', 'interval_type'] + @api.depends('notification_type') + def _compute_template_model_id(self): + mail_model = self.env['ir.model']._get('mail.template') + for mail in self: + mail.template_model_id = mail_model if mail.notification_type == 'mail' else False + + def _prepare_event_mail_values(self): + self.ensure_one() + return { + 'notification_type': self.notification_type, + 'interval_nbr': self.interval_nbr, + 'interval_unit': self.interval_unit, + 'interval_type': self.interval_type, + 'template_ref': '%s,%i' % (self.template_ref._name, self.template_ref.id) + } class EventMailScheduler(models.Model): @@ -64,6 +76,10 @@ class EventMailScheduler(models.Model): _rec_name = 'event_id' _description = 'Event Automated Mailing' + @api.model + def _selection_template_model(self): + return [('mail.template', 'Mail')] + event_id = fields.Many2one('event.event', string='Event', required=True, ondelete='cascade') sequence = fields.Integer('Display order') notification_type = fields.Selection([('mail', 'Mail')], string='Send', default='mail', required=True) @@ -78,10 +94,6 @@ class EventMailScheduler(models.Model): ('before_event', 'Before the event'), ('after_event', 'After the event')], string='Trigger ', default="before_event", required=True) - template_id = fields.Many2one( - 'mail.template', string='Email Template', - domain=[('model', '=', 'event.registration')], ondelete='restrict', - help='This field contains the template of the mail that will be automatically sent') scheduled_date = fields.Datetime('Schedule Date', compute='_compute_scheduled_date', store=True) # contact and status mail_registration_ids = fields.One2many( @@ -92,6 +104,14 @@ class EventMailScheduler(models.Model): [('running', 'Running'), ('scheduled', 'Scheduled'), ('sent', 'Sent')], string='Global communication Status', compute='_compute_mail_state') mail_count_done = fields.Integer('# Sent', copy=False, readonly=True) + template_model_id = fields.Many2one('ir.model', string='Template Model', compute='_compute_template_model_id', compute_sudo=True) + template_ref = fields.Reference(string='Template', selection='_selection_template_model', required=True) + + @api.depends('notification_type') + def _compute_template_model_id(self): + mail_model = self.env['ir.model']._get('mail.template') + for mail in self: + mail.template_model_id = mail_model if mail.notification_type == 'mail' else False @api.depends('event_id.date_begin', 'event_id.date_end', 'interval_type', 'interval_unit', 'interval_nbr') def _compute_scheduled_date(self): @@ -140,11 +160,11 @@ class EventMailScheduler(models.Model): if scheduler.mail_done or scheduler.notification_type != 'mail': continue # no template -> ill configured, skip and avoid crash - if not scheduler.template_id: + if not scheduler.template_ref: continue # do not send emails if the mailing was scheduled before the event but the event is over if scheduler.scheduled_date <= now and (scheduler.interval_type != 'before_event' or scheduler.event_id.date_end > now): - scheduler.event_id.mail_attendees(scheduler.template_id.id) + scheduler.event_id.mail_attendees(scheduler.template_ref.id) scheduler.update({ 'mail_done': True, 'mail_count_done': scheduler.event_id.seats_reserved + scheduler.event_id.seats_used, @@ -168,7 +188,7 @@ class EventMailScheduler(models.Model): if random.random() < 0.1666 or scheduler.interval_unit in ('now', 'hours'): ex_s = exception_to_unicode(exception) try: - event, template = scheduler.event_id, scheduler.template_id + event, template = scheduler.event_id, scheduler.template_ref emails = list(set([event.organizer_id.email, event.user_id.email, template.write_uid.email])) subject = _("WARNING: Event Scheduler Error for event: %s", event.name) body = _("""Event Scheduler for: @@ -248,7 +268,7 @@ class EventMailRegistration(models.Model): reg_mail.scheduler_id.notification_type == 'mail' ) for reg_mail in todo: - reg_mail.scheduler_id.template_id.send_mail(reg_mail.registration_id.id) + reg_mail.scheduler_id.template_ref.send_mail(reg_mail.registration_id.id) todo.write({'mail_sent': True}) @api.depends('registration_id', 'scheduler_id.interval_unit', 'scheduler_id.interval_type') diff --git a/addons/event/models/event_registration.py b/addons/event/models/event_registration.py index 563eca16616..7a9429e3e1e 100644 --- a/addons/event/models/event_registration.py +++ b/addons/event/models/event_registration.py @@ -227,7 +227,7 @@ class EventRegistration(models.Model): default_model='event.registration', default_res_id=self.id, default_use_template=bool(template), - default_template_id=template.id, + default_template_ref='mail.template,%i' % template.id, default_composition_mode='comment', custom_layout="mail.mail_notification_light", ) diff --git a/addons/event/models/mail_template.py b/addons/event/models/mail_template.py new file mode 100644 index 00000000000..f62f737bb4b --- /dev/null +++ b/addons/event/models/mail_template.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models +from odoo.osv import expression + + +class MailTemplate(models.Model): + _inherit = 'mail.template' + + @api.model + def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): + """Context-based hack to filter reference field in a m2o search box to emulate a domain the ORM currently does not support. + + As we can not specify a domain on a reference field, we added a context + key `filter_template_on_event` on the template reference field. If this + key is set, we add our domain in the `args` in the `_name_search` + method to filtrate the mail templates. + """ + if self.env.context.get('filter_template_on_event'): + args = expression.AND([[('model', '=', 'event.registration')], args]) + return super(MailTemplate, self)._name_search(name, args, operator, limit, name_get_uid) diff --git a/addons/event/tests/common.py b/addons/event/tests/common.py index ad3252dc0f2..0a2855d8ba7 100644 --- a/addons/event/tests/common.py +++ b/addons/event/tests/common.py @@ -80,12 +80,12 @@ class TestEventCommon(common.TransactionCase): (0, 0, { # right at subscription 'interval_unit': 'now', 'interval_type': 'after_sub', - 'template_id': cls.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')}), + 'template_ref': 'mail.template,%i' % cls.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')}), (0, 0, { # 1 days before event 'interval_nbr': 1, 'interval_unit': 'days', 'interval_type': 'before_event', - 'template_id': cls.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')}), + 'template_ref': 'mail.template,%i' % cls.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')}), ], }) cls.event_0 = cls.env['event.event'].create({ diff --git a/addons/event/tests/test_event_internals.py b/addons/event/tests/test_event_internals.py index 49b02f24141..9ea121503f1 100644 --- a/addons/event/tests/test_event_internals.py +++ b/addons/event/tests/test_event_internals.py @@ -104,7 +104,8 @@ class TestEventData(TestEventCommon): event_type.write({ 'event_type_mail_ids': [(5, 0), (0, 0, { 'interval_nbr': 1, 'interval_unit': 'days', 'interval_type': 'before_event', - 'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')})], + 'template_ref': 'mail.template,%i' % self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')}) + ], 'event_type_ticket_ids': [(5, 0), (0, 0, {'name': 'TestRegistration'})], }) event.write({'event_type_id': event_type.id}) @@ -117,7 +118,7 @@ class TestEventData(TestEventCommon): self.assertEqual(event.event_mail_ids.interval_nbr, 1) self.assertEqual(event.event_mail_ids.interval_unit, 'days') self.assertEqual(event.event_mail_ids.interval_type, 'before_event') - self.assertEqual(event.event_mail_ids.template_id, self.env.ref('event.event_reminder')) + self.assertEqual(event.event_mail_ids.template_ref, self.env.ref('event.event_reminder')) self.assertEqual(len(event.event_ticket_ids), 1) # update template, unlink from event -> should not impact event @@ -161,7 +162,7 @@ class TestEventData(TestEventCommon): 'interval_nbr': 77, 'interval_unit': 'days', 'interval_type': 'after_event', - 'template_id': self.env.ref('event.event_reminder').id, + 'template_ref': 'mail.template,%i' % self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder'), }) ] }) @@ -178,7 +179,7 @@ class TestEventData(TestEventCommon): 'notification_type': 'mail', 'interval_unit': 'now', 'interval_type': 'after_sub', - 'template_id': self.env.ref('event.event_subscription').id, + 'template_ref': 'mail.template,%i' % self.env['ir.model.data'].xmlid_to_res_id('event.event_subscription'), }) ] }) @@ -306,6 +307,18 @@ class TestEventData(TestEventCommon): set(['Registration Ticket']) ) + def test_event_mail_filter_template_on_event(self): + """Test that the mail template are filtered to show only those which are related to the event registration model. + + This is important to be able to show only relevant mail templates on the related + field "template_ref". + """ + self.env['mail.template'].search([('model', '=', 'event.registration')]).unlink() + self.env['mail.template'].create({'model_id': self.env['ir.model']._get('event.registration').id, 'name': 'test template'}) + self.env['mail.template'].create({'model_id': self.env['ir.model']._get('res.partner').id, 'name': 'test template'}) + templates = self.env['mail.template'].with_context(filter_template_on_event=True).name_search('test template') + self.assertEqual(len(templates), 1, 'Should return only mail templates related to the event registration model') + @users('user_eventmanager') def test_event_registrable(self): """Test if `_compute_event_registrations_open` works properly.""" diff --git a/addons/event/tests/test_event_mail_schedule.py b/addons/event/tests/test_event_mail_schedule.py index 34eacf1d701..1889e167010 100644 --- a/addons/event/tests/test_event_mail_schedule.py +++ b/addons/event/tests/test_event_mail_schedule.py @@ -39,22 +39,22 @@ class TestMailSchedule(TestEventCommon, MockEmail): (0, 0, { # right at subscription 'interval_unit': 'now', 'interval_type': 'after_sub', - 'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')}), + 'template_ref': 'mail.template,%i' % self.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')}), (0, 0, { # one day after subscription 'interval_nbr': 1, 'interval_unit': 'hours', 'interval_type': 'after_sub', - 'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')}), + 'template_ref': 'mail.template,%i' % self.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')}), (0, 0, { # 1 days before event 'interval_nbr': 1, 'interval_unit': 'days', 'interval_type': 'before_event', - 'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')}), + 'template_ref': 'mail.template,%i' % self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')}), (0, 0, { # immediately after event 'interval_nbr': 1, 'interval_unit': 'hours', 'interval_type': 'after_event', - 'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')}), + 'template_ref': 'mail.template,%i' % self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')}), ] }) self.assertEqual(test_event.create_date, now) diff --git a/addons/event/views/event_views.xml b/addons/event/views/event_views.xml index 289d0f49673..fdbae5777a1 100644 --- a/addons/event/views/event_views.xml +++ b/addons/event/views/event_views.xml @@ -13,7 +13,6 @@