From c2f8b03e3f8df2907c0dab9395da4db1a4dc14b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Feb 2023 17:44:37 +0000 Subject: [PATCH] [IMP] mail: support layouting in composer mailing mode RATIONALE Naming conventions * content = core message / subject (+ other fields); * email layout = layouting applied to messages when sent to recipients who receive notifications by email e.g. access button, ...; * comment mode / mailing mode: composer main composition mode: posting on record(s) / sending a mailing on records; Content situation when using a template to post on a composer * comment, monorecord mode: choose a template, content is rendered directly from template side according to 'lang' field definition -> ok; * comment, multirecord mode / mailing mode: choose a template, content is the raw content. At post / send, content is rendered and translated if matching template content -> ok; Email layout situation when posting / mailing * comment: layout translated based on recipient lang or fallback on template 'lang' field definition, or current user's lang; * mailing: no layout supported; PURPOSE Make those the two composer modes less different by supporting layouting in mailing mode of composer. Consider it a bit experimental. SPECIFICATIONS When using the composer in mailing mode, render email layout if given. This layout is used to encapsulate body. To simplify rendering and sending, consider all recipients to be 'customer' as defined in '_notify_get_recipients'. This means all recipients receive the same basic layouting currently as a first attempt to improve this situation. Considered lang is the one coming from the template 'lang' field, or fallback on current user's lang. Task-3186426 (Mail: Support notification layout in template / email composer) Part-of: odoo/odoo#106177 --- addons/mail/wizard/mail_compose_message.py | 40 ++++++++++++++++++- addons/test_mail/tests/test_mail_composer.py | 41 ++++++++------------ 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 1b5229cc73c..cbd83e193ae 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -877,7 +877,7 @@ class MailComposer(models.TransientModel): # langs, used currently only to propagate in comment mode for notification # layout translation - langs = self._render_field('lang', res_ids) if not email_mode else {} + langs = self._render_field('lang', res_ids) subjects = self._render_field('subject', res_ids, compute_lang=True) bodies = self._render_field( 'body', res_ids, compute_lang=True, @@ -979,7 +979,7 @@ class MailComposer(models.TransientModel): # recipients: transform partner_ids (field used in mail_message) into # recipient_ids, used by mail_mail if email_mode: - recipient_ids_all = mail_values.pop('partner_ids', []) + self.partner_ids.ids + recipient_ids_all = set(mail_values.pop('partner_ids', [])) | set(self.partner_ids.ids) mail_values['recipient_ids'] = [(4, pid) for pid in recipient_ids_all] # when having no specific reply_to -> fetch rendered email_from @@ -989,6 +989,42 @@ class MailComposer(models.TransientModel): reply_to = mail_values.get('email_from', False) mail_values['reply_to'] = reply_to + # body: render layout in email mode (comment mode is managed by the + # notification process, see @_notify_thread_by_email) + if email_mode and self.email_layout_xmlid and mail_values['recipient_ids']: + lang = langs[res_id] + recipient_ids = [command[1] for command in mail_values['recipient_ids']] + msg_vals = { + 'email_layout_xmlid': self.email_layout_xmlid, + 'model': self.model, + 'res_id': res_id, + } + message_inmem = self.env['mail.message'].new({ + 'body': mail_values['body'], + }) + for _lang, render_values, recipients_group_data in record._notify_get_classified_recipients_iterator( + message_inmem, + [{ + 'active': True, + 'id': pid, + 'lang': lang, + 'notif': 'email', + 'share': True, + 'type': 'customer', + 'ushare': False, + } for pid in recipient_ids], + msg_vals=msg_vals, + model_description=False, # force dynamic computation + force_email_lang=lang, + ): + mail_body = record._notify_by_email_render_layout( + message_inmem, + recipients_group_data, + msg_vals=msg_vals, + render_values=render_values, + ) + mail_values['body_html'] = mail_body + return mail_values_all def _prepare_mail_values_rendered(self, res_ids): diff --git a/addons/test_mail/tests/test_mail_composer.py b/addons/test_mail/tests/test_mail_composer.py index 1ed0a086087..fdc1114072b 100644 --- a/addons/test_mail/tests/test_mail_composer.py +++ b/addons/test_mail/tests/test_mail_composer.py @@ -2039,30 +2039,23 @@ class TestComposerResultsMass(TestMailComposer): email = self._find_sent_email(self.partner_employee_2.email_formatted, [record.customer_id.email_formatted]) self.assertTrue(bool(email), 'Email not found, check recipients') - # Currently layouting in mailing mode is not supported. - # Hence no translations. - self.assertEqual( - email['body'], - f'

{exp_body}

' - ) - # exp_layout_content_en = 'English Layout for Ticket-like model' - # exp_layout_content_es = 'Spanish Layout para Spanish Model Description' - # exp_button_en = 'View Ticket-like model' - # exp_button_es = 'zefView Ticket-like model' - # if email_layout_xmlid: - # if exp_lang == 'es_ES': - # self.assertIn(exp_layout_content_es, email['body']) - # self.assertIn(exp_button_en, email['body']) - # else: - # self.assertIn(exp_layout_content_en, email['body']) - # # self.assertIn(exp_button_es, email['body']) - # self.assertIn(exp_button_en, email['body']) - # else: - # # check default layouting applies - # if exp_lang == 'es_ES': - # self.assertIn('html lang="es_ES"', email['body']) - # else: - # self.assertIn('html lang="en_US"', email['body']) + if not email_layout_xmlid: + self.assertEqual( + email['body'], + f'

{exp_body}

' + ) + else: + exp_layout_content_en = 'English Layout for Ticket-like model' + exp_layout_content_es = 'Spanish Layout para Spanish Model Description' + exp_button_en = 'View Ticket-like model' + exp_button_es = 'Spanish Layout para Spanish Model Description' + if exp_lang == 'es_ES': + self.assertIn(exp_layout_content_es, email['body']) + self.assertIn(exp_button_es, email['body']) + else: + self.assertIn(exp_layout_content_en, email['body']) + # self.assertIn(exp_button_es, email['body']) + self.assertIn(exp_button_en, email['body']) @users('employee') @mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')