[REF] mail: improve composer call to template values generation

Now that template generation methods have been cleaned we can cleanup calls
done in composer. We notably

  * make methods private, improve their naming and docstrings;
  * better support input / output of asked fields;
  * be more coherent with composer fields and template fields usage;

Task-2710804 (Mail: Clean MailThread Posting API)
Prepares Task-2088884 (Mail: Composer Onchange to Editable Computed Stored)

Part-of: odoo/odoo#99482
This commit is contained in:
Thibault Delavallée
2023-01-17 20:58:38 +01:00
parent 041e9924c7
commit 09a1647c64
2 changed files with 59 additions and 30 deletions
+57 -27
View File
@@ -203,12 +203,11 @@ class MailComposer(models.TransientModel):
-> for x2many field, this onchange return command instead of ids
"""
if template_id and composition_mode == 'mass_mail':
# copy raw template values (not rendered due to mass mode)
template = self.env['mail.template'].browse(template_id)
values = dict(
(field, template[field])
for field in ('body_html',
'email_from',
'mail_server_id',
for field in ('email_from',
'reply_to',
'subject',
)
@@ -218,16 +217,20 @@ class MailComposer(models.TransientModel):
values['attachment_ids'] = [att.id for att in template.attachment_ids]
if template.mail_server_id:
values['mail_server_id'] = template.mail_server_id.id
if not tools.is_html_empty(template.body_html):
values['body'] = template.body_html
elif template_id:
values = self._generate_email_for_composer(
template_id, [res_id],
# render template (mono record, comment mode) and set it as composer values
values = self._generate_template_for_composer(
self.env['mail.template'].browse(template_id),
[res_id],
('attachment_ids',
'body_html',
'email_cc',
'email_from',
'email_to',
'mail_server_id',
'partner_to',
'partner_ids',
'reply_to',
'report_template',
'subject',
@@ -276,9 +279,6 @@ class MailComposer(models.TransientModel):
'subject',
) if key in default_values)
if values.get('body_html'):
values['body'] = values.pop('body_html')
# This onchange should return command instead of ids for x2many field.
values = self._convert_to_write(values)
@@ -642,13 +642,14 @@ class MailComposer(models.TransientModel):
# generate template-based values
if self.template_id:
template_values = self._generate_email_for_composer(
self.template_id.id, res_ids,
template_values = self._generate_template_for_composer(
self.template_id,
res_ids,
('attachment_ids',
'email_to',
'email_cc',
'mail_server_id',
'partner_to',
'partner_ids',
'report_template',
)
)
@@ -670,26 +671,55 @@ class MailComposer(models.TransientModel):
return template_values
@api.model
def _generate_email_for_composer(self, template_id, res_ids, render_fields):
""" Call email_template._generate_template(), get fields relevant for
mail.compose.message, transform email_cc and email_to into partner_ids """
returned_fields = list(render_fields) + ['partner_ids']
if 'report_template' in render_fields:
returned_fields.append('attachments')
values = dict.fromkeys(res_ids, False)
def _generate_template_for_composer(self, template, res_ids, render_fields,
find_or_create_partners=True):
""" Generate values based on template and relevant values for the
mail.compose.message wizard.
template_values = self.env['mail.template'].browse(template_id)._generate_template(
:param record template: a mail template, as during onchange mode it
may not be set on self (to remove when removing the onchange);
:param list res_ids: list of record IDs on which template is rendered;
:param list render_fields: list of fields to render on template;
:param boolean find_or_create_partners: transform emails into partners
(see ``Template._generate_template_recipients``);
:returns: a dict containing all asked fields for each record ID given by
res_ids. Note that
* 'body' comes from template 'body_html' generation;
* 'attachments' is an additional key coming with 'attachment_ids' due
to report generation (in the format [(report_name, data)] where data
is base64 encoded);
* 'partner_ids' is returned due to recipients generation that gives
partner ids coming from default computation as well as from email
to partner convert (see ``find_or_create_partners``);
"""
self.ensure_one()
# some fields behave / are named differently on template model
mapping = {
'attachments': 'report_template',
'body': 'body_html',
'partner_ids': 'partner_to',
}
template_fields = {mapping.get(fname, fname) for fname in render_fields}
template_values = template._generate_template(
res_ids,
render_fields,
template_fields,
find_or_create_partners=True
)
for res_id in res_ids:
res_id_values = dict((field, template_values[res_id][field]) for field in returned_fields if template_values[res_id].get(field))
res_id_values['body'] = res_id_values.pop('body_html', '')
values[res_id] = res_id_values
return values
exclusion_list = ('email_cc', 'email_to') if find_or_create_partners else ()
mapping = {'body_html': 'body'}
render_results = {}
for res_id in res_ids:
render_results[res_id] = {
mapping.get(fname, fname): value
for fname, value in template_values[res_id].items()
if fname not in exclusion_list and value
}
return render_results
# ----------------------------------------------------------------------
# EMAIL MANAGEMENT
+2 -3
View File
@@ -593,14 +593,13 @@ class TestComposerInternals(TestMailComposer):
self.assertEqual(composer.subject, 'Back to my amazing subject for {{ record.name }}')
# update with template with void values: void value is not forced in
# rendering mode as well as when copying template values, except for
# body in rendering mode
# rendering mode as well as when copying template values
composer.write({'template_id': template_void.id})
# currently onchange necessary
composer._onchange_template_id_wrapper()
if composition_mode == 'comment':
self.assertFalse(composer.body, 'Void template body resets while other fields not, maybe to fix')
self.assertEqual(composer.body, 'Back to my amazing body')
self.assertEqual(composer.mail_server_id, self.mail_server_global)
self.assertEqual(composer.record_name, 'Manual update')
self.assertEqual(composer.subject, 'Back to my amazing subject for {{ record.name }}')