[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
This commit is contained in:
Thibault Delavallée
2023-03-09 15:54:15 +01:00
parent b4d210b245
commit c2f8b03e3f
2 changed files with 55 additions and 26 deletions
+38 -2
View File
@@ -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):
+17 -24
View File
@@ -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'<p>{exp_body}</p>'
)
# 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'<p>{exp_body}</p>'
)
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')