From 2b9e288e1f4ea863acb0871ec7b080c98f8e7f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 2 Feb 2023 15:15:48 +0000 Subject: [PATCH] [IMP] mail: support email_layout_xmlid on template RATIONALE Currently email layout choice is done in code and is not controllable through any user interface. In this commit we prepare improvements in template management by allowing to choose the email layout directly from a given mail template. As number of layouts is going to grow better be able to choose the right one. SPECIFICATIONS Add a field on template to propagate email layout choice directly on template and propagate it to the composer, then post/notify process. We can now choose directly on a template which notification layout should be used in conjunction with this template. Composer model already holds a field 'email_layout_xmlid', used in various places in code to give a specific layout to use when sending notifications emails e.g. SO email layout. This can now be specified directly from the template itself. It allows to customize the look and feel of notifications without having to do it explicitly in a given code flow. Computation is coming either from template, either reset. When having a template with a value set, set it on composer. When removing the template reset it. Currently no standard template uses it as this task targets mainly a code cleaning that began with the composer code cleaning. It targets the near freeze to have the base code updated once, then functional templates will make use of it (hopefully). Note that currently notification layout is still not supported at composer level for mailings. It is simply ignored when generating outgoing mail records. This will be improved soon. Global followup of odoo/odoo#107356 / Task-2088884 (Mail: Use editable computed stored fields in composer). Prepares code for Task-3046371 (Mail: Better Language Support in Composer) see odoo/odoo#106177 . Task-3186426 (Mail: Support notification layout in template / email composer) closes odoo/odoo#114462 Related: odoo/upgrade#4404 Signed-off-by: Thibault Delavallee (tde) --- addons/mail/models/mail_template.py | 5 +++++ addons/mail/wizard/mail_compose_message.py | 16 +++++++++++++++- addons/test_mail/tests/test_mail_composer.py | 18 +++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index b14205a460b..a72cad177db 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -71,6 +71,7 @@ class MailTemplate(models.Model): column2='ir_actions_report_id', string='Dynamic Reports', domain="[('model', '=', model)]") + email_layout_xmlid = fields.Char('Email Notification Layout', copy=False) # options mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False, help="Optional preferred server for outgoing mails. If not set, the highest " @@ -424,6 +425,8 @@ class MailTemplate(models.Model): # technical settings if 'auto_delete' in render_fields: values['auto_delete'] = self.auto_delete + if 'email_layout_xmlid' in render_fields: + values['email_layout_xmlid'] = self.email_layout_xmlid if 'mail_server_id' in render_fields: values['mail_server_id'] = self.mail_server_id.id if 'model' in render_fields: @@ -461,6 +464,7 @@ class MailTemplate(models.Model): 'scheduled_date', # specific # not rendered (static) 'auto_delete', + 'email_layout_xmlid', 'mail_server_id', 'model', 'res_id', @@ -569,6 +573,7 @@ class MailTemplate(models.Model): if 'email_from' in values and not values.get('email_from'): values.pop('email_from') # encapsulate body + email_layout_xmlid = email_layout_xmlid or self.email_layout_xmlid if email_layout_xmlid and values['body_html']: record = self.env[self.model].browse(res_id) model = self.env['ir.model']._get(record._name) diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index c503f5213c9..1a4fe63bebc 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -92,7 +92,10 @@ class MailComposer(models.TransientModel): 'ir.attachment', 'mail_compose_message_ir_attachments_rel', 'wizard_id', 'attachment_id', string='Attachments', compute='_compute_attachment_ids', readonly=False, store=True) - email_layout_xmlid = fields.Char('Email Notification Layout', copy=False) + email_layout_xmlid = fields.Char( + 'Email Notification Layout', + compute='_compute_email_layout_xmlid', readonly=False, store=True, + copy=False) email_add_signature = fields.Boolean( 'Add signature', compute='_compute_email_add_signature', readonly=False, store=True) @@ -275,6 +278,17 @@ class MailComposer(models.TransientModel): else: composer.email_add_signature = not bool(composer.template_id) + @api.depends('template_id') + def _compute_email_layout_xmlid(self): + """ Computation is coming either from template, either reset. When + having a template with a value set, set it on composer.When removing + the template, reset it. """ + for composer in self: + if composer.template_id.email_layout_xmlid: + composer.email_layout_xmlid = composer.template_id.email_layout_xmlid + if not composer.template_id: + composer.email_layout_xmlid = False + @api.depends('composition_mode', 'email_from', 'model', 'res_domain', 'res_ids', 'template_id') def _compute_authorship(self): diff --git a/addons/test_mail/tests/test_mail_composer.py b/addons/test_mail/tests/test_mail_composer.py index 19d33643386..a399ee0521a 100644 --- a/addons/test_mail/tests/test_mail_composer.py +++ b/addons/test_mail/tests/test_mail_composer.py @@ -95,6 +95,13 @@ class TestMailComposer(TestMailCommon, TestRecipients): 'scheduled_date': '{{ (object.create_date or datetime.datetime(2022, 12, 26, 18, 0, 0)) + datetime.timedelta(days=2) }}', }) + # activate translations + cls._activate_multi_lang( + layout_arch_db=None, # use default mail.test_layout + test_record=cls.test_records, + test_template=cls.template, + ) + def _get_web_context(self, records, add_web=True, **values): """ Helper to generate composer context. Will make tests a bit less verbose. @@ -1332,13 +1339,17 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase): attachs = self.env['ir.attachment'].search([('name', 'in', [a['name'] for a in attachment_data])]) self.assertEqual(len(attachs), 2) - for batch_mode, scheduled_date in product( + for batch_mode, scheduled_date, email_layout_xmlid in product( (False, True, 'domain'), - (False, '{{ (object.create_date or datetime.datetime(2022, 12, 26, 18, 0, 0)) + datetime.timedelta(days=2) }}') + (False, '{{ (object.create_date or datetime.datetime(2022, 12, 26, 18, 0, 0)) + datetime.timedelta(days=2) }}'), + (False, 'mail.test_layout'), ): with self.subTest(batch_mode=batch_mode, scheduled_date=scheduled_date): batch = bool(batch_mode) - self.template.write({'scheduled_date': scheduled_date}) + self.template.write({ + 'scheduled_date': scheduled_date, + 'email_layout_xmlid': email_layout_xmlid, + }) test_records = self.test_records if batch else self.test_record # ensure initial data @@ -1361,6 +1372,7 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase): # open a composer and run it in comment mode composer_form = Form(self.env['mail.compose.message'].with_context(ctx)) composer = composer_form.save() + self.assertEqual(composer.email_layout_xmlid, email_layout_xmlid) # ensure some parameters used afterwards if batch: