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 @@
-
@@ -54,11 +53,12 @@
-
-
+
+
+
-
+
@@ -208,8 +208,9 @@
-
-
+
+
+
@@ -698,8 +699,9 @@
-
-
+
+
+
@@ -734,8 +736,9 @@
-
-
+
+
+
ill configured, skip and avoid crash
- if not scheduler.sms_template_id:
+ if not scheduler.template_ref:
continue
# Do not send SMS if the communication 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):
self.env['event.registration']._message_sms_schedule_mass(
- template=scheduler.sms_template_id,
+ template=scheduler.template_ref,
active_domain=[('event_id', '=', scheduler.event_id.id), ('state', '!=', 'cancel')],
mass_keep_log=True
)
@@ -69,7 +75,7 @@ class EventMailRegistration(models.Model):
)
for reg_mail in todo:
reg_mail.registration_id._message_sms_schedule_mass(
- template=reg_mail.scheduler_id.sms_template_id,
+ template=reg_mail.scheduler_id.template_ref,
mass_keep_log=True
)
todo.write({'mail_sent': True})
diff --git a/addons/event_sms/models/sms_template.py b/addons/event_sms/models/sms_template.py
new file mode 100644
index 00000000000..fbb666da1d2
--- /dev/null
+++ b/addons/event_sms/models/sms_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 SmsTemplate(models.Model):
+ _inherit = 'sms.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 SMS templates.
+ """
+ if self.env.context.get('filter_template_on_event'):
+ args = expression.AND([[('model', '=', 'event.registration')], args])
+ return super(SmsTemplate, self)._name_search(name, args, operator, limit, name_get_uid)
diff --git a/addons/event_sms/tests/test_sms_schedule.py b/addons/event_sms/tests/test_sms_schedule.py
index 0ad5dd5a9f2..b9ecbeeb6c2 100644
--- a/addons/event_sms/tests/test_sms_schedule.py
+++ b/addons/event_sms/tests/test_sms_schedule.py
@@ -33,13 +33,13 @@ class TestSMSSchedule(TestEventCommon, SMSCase):
'interval_unit': 'now',
'interval_type': 'after_sub',
'notification_type': 'sms',
- 'sms_template_id': cls.sms_template_sub.id}),
+ 'template_ref': 'sms.template,%i' % cls.sms_template_sub.id}),
(0, 0, { # 3 days before event
'interval_nbr': 3,
'interval_unit': 'days',
'interval_type': 'before_event',
'notification_type': 'sms',
- 'sms_template_id': cls.sms_template_rem.id}),
+ 'template_ref': 'sms.template,%i' % cls.sms_template_rem.id}),
]
})
diff --git a/addons/event_sms/views/event_mail_views.xml b/addons/event_sms/views/event_mail_views.xml
deleted file mode 100644
index 430eef7dfef..00000000000
--- a/addons/event_sms/views/event_mail_views.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- event.mail.view.form.inherit.sms
- event.mail
-
-
-
- 0
-
-
- {'readonly': [('notification_type', '!=', 'mail')], 'required': [('notification_type', '=', 'mail')]}
-
-
-
-
-
-
-
-
- event.mail.view.tree.inherit.sms
- event.mail
-
-
-
- 0
-
-
- {'readonly': [('notification_type', '!=', 'mail')], 'required': [('notification_type', '=', 'mail')]}
-
-
-
-
-
-
-
-
diff --git a/addons/event_sms/views/event_views.xml b/addons/event_sms/views/event_views.xml
deleted file mode 100644
index fb49147c973..00000000000
--- a/addons/event_sms/views/event_views.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- event.type.view.form.inherit.sms
- event.type
-
-
-
- 0
-
-
- {'readonly': [('notification_type', '!=', 'mail')], 'required': [('notification_type', '=', 'mail')]}
-
-
-
-
-
-
-
-
- event.event.view.form
- event.event
-
-
-
- 0
-
-
- {'readonly': [('notification_type', '!=', 'mail')], 'required': [('notification_type', '=', 'mail')]}
-
-
-
-
-
-
-
-
diff --git a/addons/test_event_full/tests/test_event_security.py b/addons/test_event_full/tests/test_event_security.py
index 1c4cdd32d26..0dfe2a7a0db 100644
--- a/addons/test_event_full/tests/test_event_security.py
+++ b/addons/test_event_full/tests/test_event_security.py
@@ -94,7 +94,7 @@ class TestEventSecurity(TestEventCommon):
'name': 'ManagerEventType',
'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')})]
})
@users('user_eventmanager')
@@ -105,7 +105,7 @@ class TestEventSecurity(TestEventCommon):
'name': 'ManagerEventType',
'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.write({'name': 'New Name'})