[IMP] test_mail: add composer tests for email layout support and translation
Purpose is to add some tests about email layout support in both comment and
email mode, as well as language support in those two modes. They are added
in a test targeting a complete template usage, testing globally the results
(outgoing notifications or emails, buttons, language, recipients, ...).
Posting in multi-languages environment with notification layout is also
tested. Finally a test about reply-to is moved into its own subtest to
avoid polluting core template tests. Other low level details should already
sufficiently tested. Normally.
Main observations
* translations are quite broken in mass mode (either batch comment either
mass mailing). Indeed translations are fetched based on <mail.compose.
message> body and subject fields, which are probably not translated
as they are linked to a transient model. Real translations are stored
at <mail.template> level when users translate their templates;
* layout translation is partly supported in comment mode, due to a small
context-based hack. However access buttons are not translated and some
use case (like using a 'res_domain') are not supported;
* mass_mail mode does not support layouting at all;
* when posting manually ('message_post') current users' language determines
the language of notification email layout e.g. a user using Odoo in French
will send a french layout to all followers, whatever their language and
whatever the language of the post (which is not known as user input);
Most of those use cases will be fixed soon.
Also update some query counters while passing by.
Task-3046371 (Mail: Better Language Support in Composer)
Part-of: odoo/odoo#114511
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools import email_normalize
|
||||
from odoo.tools.translate import _
|
||||
|
||||
|
||||
class MailTestSimple(models.Model):
|
||||
@@ -164,10 +163,22 @@ class MailTestTicket(models.Model):
|
||||
def _notify_get_recipients_groups(self, msg_vals=None):
|
||||
""" Activate more groups to test query counters notably (and be backward
|
||||
compatible for tests). """
|
||||
groups = super(MailTestTicket, self)._notify_get_recipients_groups(msg_vals=msg_vals)
|
||||
local_msg_vals = dict(msg_vals or {})
|
||||
groups = super()._notify_get_recipients_groups(msg_vals=msg_vals)
|
||||
for group_name, _group_method, group_data in groups:
|
||||
if group_name == 'portal':
|
||||
group_data['active'] = True
|
||||
elif group_name == 'customer':
|
||||
group_data['active'] = True
|
||||
group_data['has_button_access'] = True
|
||||
group_data['actions'] = [{
|
||||
'url': self._notify_get_action_link(
|
||||
'controller',
|
||||
controller='/test_mail/do_stuff',
|
||||
**local_msg_vals
|
||||
),
|
||||
'title': _('NotificationButtonTitle')
|
||||
}]
|
||||
|
||||
return groups
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ class TestMailComposer(TestMailCommon, TestRecipients):
|
||||
'partner_to': '{{ object.customer_id.id if object.customer_id else "" }}',
|
||||
'email_to': '{{ (object.email_from if not object.customer_id else "") }}',
|
||||
'email_from': '{{ (object.user_id.email_formatted or user.email_formatted) }}',
|
||||
'lang': '{{ object.customer_id.lang }}',
|
||||
'mail_server_id': cls.mail_server_domain.id,
|
||||
'model_id': cls.env['ir.model']._get('mail.test.ticket').id,
|
||||
'reply_to': '{{ ctx.get("custom_reply_to") or "info@test.example.com" }}',
|
||||
@@ -129,6 +130,14 @@ class TestMailComposer(TestMailCommon, TestRecipients):
|
||||
@tagged('mail_composer')
|
||||
class TestComposerForm(TestMailComposer):
|
||||
|
||||
def test_assert_initial_data(self):
|
||||
""" Ensure class initial data to ease understanding """
|
||||
self.assertTrue(self.template.auto_delete)
|
||||
|
||||
self.assertEqual(len(self.test_records), 2)
|
||||
self.assertEqual(self.test_records.user_id, self.user_employee_2)
|
||||
self.assertEqual(self.test_records.message_partner_ids, self.partner_employee_2)
|
||||
|
||||
@users('employee')
|
||||
def test_mail_composer_comment(self):
|
||||
composer_form = Form(self.env['mail.compose.message'].with_context(
|
||||
@@ -1153,11 +1162,26 @@ class TestComposerInternals(TestMailComposer):
|
||||
self.assertEqual(template.body_html, '<p>Template Body</p>', 'email_template incorrect body_html')
|
||||
|
||||
|
||||
@tagged('mail_composer')
|
||||
@tagged('mail_composer', 'multi_lang')
|
||||
class TestComposerResultsComment(TestMailComposer, CronMixinCase):
|
||||
""" Test global output of composer used in comment mode. Test notably
|
||||
notification and emails generated during this process. """
|
||||
|
||||
def test_assert_initial_data(self):
|
||||
""" Ensure class initial data to ease understanding """
|
||||
self.assertTrue(self.template.auto_delete)
|
||||
|
||||
self.assertEqual(len(self.test_records), 2)
|
||||
self.assertEqual(self.test_records.user_id, self.user_employee_2)
|
||||
self.assertEqual(self.test_records.message_partner_ids, self.partner_employee_2)
|
||||
self.assertEqual(self.test_records[0].customer_id.lang, 'en_US')
|
||||
self.assertEqual(self.test_records[1].customer_id.lang, 'en_US')
|
||||
|
||||
self.assertEqual(len(self.test_partners), 2)
|
||||
|
||||
self.assertEqual(self.user_employee.lang, 'en_US')
|
||||
self.assertEqual(self.user_employee_2.lang, 'en_US')
|
||||
|
||||
@users('employee')
|
||||
def test_mail_composer_default_subject(self):
|
||||
""" Make sure the default subject is applied in the composer. """
|
||||
@@ -1322,6 +1346,10 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
|
||||
* scheduled_date: creates mail.message.schedule (no email sent), then
|
||||
scheduling send notifications with notification parameters kept
|
||||
* otherwise: global behavior
|
||||
|
||||
Test with and without notification layout specified.
|
||||
|
||||
Test with and without languages.
|
||||
"""
|
||||
attachment_data = self._generate_attachments_data(2, self.template._name, self.template.id)
|
||||
email_to_1 = 'test.to.1@test.example.com'
|
||||
@@ -1339,17 +1367,37 @@ 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, email_layout_xmlid in product(
|
||||
for batch_mode, scheduled_date, email_layout_xmlid, use_lang in product(
|
||||
(False, True, 'domain'),
|
||||
(False, '{{ (object.create_date or datetime.datetime(2022, 12, 26, 18, 0, 0)) + datetime.timedelta(days=2) }}'),
|
||||
(False, 'mail.test_layout'),
|
||||
(False, True),
|
||||
):
|
||||
with self.subTest(batch_mode=batch_mode, scheduled_date=scheduled_date):
|
||||
with self.subTest(batch_mode=batch_mode,
|
||||
scheduled_date=scheduled_date,
|
||||
email_layout_xmlid=email_layout_xmlid,
|
||||
use_lang=use_lang):
|
||||
# update test configuration
|
||||
batch = bool(batch_mode)
|
||||
self.template.write({
|
||||
'scheduled_date': scheduled_date,
|
||||
'email_layout_xmlid': email_layout_xmlid,
|
||||
})
|
||||
if use_lang:
|
||||
if batch:
|
||||
langs = ('es_ES', 'en_US')
|
||||
self.test_partners[0].lang = langs[0]
|
||||
self.test_partners[1].lang = langs[1]
|
||||
else:
|
||||
langs = ('es_ES',)
|
||||
self.partner_1.lang = langs[0]
|
||||
if not use_lang:
|
||||
if batch:
|
||||
langs = (False, False)
|
||||
self.test_partners.lang = False
|
||||
else:
|
||||
langs = (False,)
|
||||
self.partner_1.lang = False
|
||||
test_records = self.test_records if batch else self.test_record
|
||||
|
||||
# ensure initial data
|
||||
@@ -1383,7 +1431,7 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
|
||||
else:
|
||||
author = self.partner_employee_2
|
||||
self.assertEqual(composer.author_id, author,
|
||||
'Author cannot be synchronized with a raw email_from')
|
||||
'Author is synchronized with rendered email_from')
|
||||
self.assertEqual(composer.email_from, self.partner_employee_2.email_formatted)
|
||||
self.assertFalse(composer.reply_to_force_new, 'Mail: thread-enabled models should use auto thread by default')
|
||||
|
||||
@@ -1426,7 +1474,11 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
|
||||
self.assertEqual(len(new_partners), 3)
|
||||
self.assertEqual(
|
||||
set(new_partners.mapped('email')),
|
||||
set(['test.to.1@test.example.com', 'test.to.2@test.example.com', 'test.cc.1@test.example.com'])
|
||||
{'test.to.1@test.example.com', 'test.to.2@test.example.com', 'test.cc.1@test.example.com'},
|
||||
)
|
||||
self.assertEqual(
|
||||
set(new_partners.mapped('lang')),
|
||||
{'en_US'},
|
||||
)
|
||||
|
||||
# if scheduled_date is set: simulate cron for sending notifications
|
||||
@@ -1453,15 +1505,31 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
|
||||
self.env['mail.mail'].sudo().process_email_queue()
|
||||
|
||||
# template is sent only to partners (email_to are transformed)
|
||||
for test_record in test_records:
|
||||
for test_record, exp_lang in zip(test_records, langs):
|
||||
message = test_record.message_ids[0]
|
||||
|
||||
# check created mail.mail and outgoing emails. In comment
|
||||
# 2 mails are generated (due to group-based layouting):
|
||||
# - one for recipient that is a user
|
||||
# - one for recipients that are customers
|
||||
# Then each recipient receives its own outging email. See
|
||||
# 'assertMailMail' for more details.
|
||||
|
||||
# TDE FIXME: lang not supported in batch mode, translations
|
||||
# are fetched on composer-side, not template-side
|
||||
if exp_lang == 'es_ES' and not batch:
|
||||
exp_body = f'SpanishBody for {test_record.name}'
|
||||
exp_subject = f'SpanishSubject for {test_record.name}'
|
||||
else:
|
||||
exp_body = f'TemplateBody {test_record.name}'
|
||||
exp_subject = f'TemplateSubject {test_record.name}'
|
||||
self.assertMailMail(self.partner_employee_2, 'sent',
|
||||
mail_message=message,
|
||||
author=author, # author is different in batch and monorecord mode (raw or rendered email_from)
|
||||
email_values={
|
||||
'body_content': f'TemplateBody {test_record.name}',
|
||||
'body_content': exp_body,
|
||||
'email_from': test_record.user_id.email_formatted, # set by template
|
||||
'subject': f'TemplateSubject {test_record.name}',
|
||||
'subject': exp_subject,
|
||||
'attachments_info': [
|
||||
{'name': 'AttFileName_00.txt', 'raw': b'AttContent_00', 'type': 'text/plain'},
|
||||
{'name': 'AttFileName_01.txt', 'raw': b'AttContent_01', 'type': 'text/plain'},
|
||||
@@ -1477,9 +1545,9 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
|
||||
mail_message=message,
|
||||
author=author, # author is different in batch and monorecord mode (raw or rendered email_from)
|
||||
email_values={
|
||||
'body_content': f'TemplateBody {test_record.name}',
|
||||
'body_content': exp_body,
|
||||
'email_from': test_record.user_id.email_formatted, # set by template
|
||||
'subject': f'TemplateSubject {test_record.name}',
|
||||
'subject': exp_subject,
|
||||
'attachments_info': [
|
||||
{'name': 'AttFileName_00.txt', 'raw': b'AttContent_00', 'type': 'text/plain'},
|
||||
{'name': 'AttFileName_01.txt', 'raw': b'AttContent_01', 'type': 'text/plain'},
|
||||
@@ -1492,6 +1560,36 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
|
||||
},
|
||||
)
|
||||
|
||||
# Low-level checks on outgoing email for the recipient to
|
||||
# check layouting and language. Note that standard layout
|
||||
# is not tested against translations, only the custom one
|
||||
# to ease translations checks.
|
||||
email = self._find_sent_email(test_record.user_id.email_formatted, [test_record.customer_id.email_formatted])
|
||||
self.assertTrue(bool(email), 'Email not found, check recipients')
|
||||
|
||||
# TDE FIXME: as it currently depends on a context-based hack
|
||||
# translation is not supported when scheduling notifications
|
||||
# or when a domain is given. Moreover access buttons are not
|
||||
# translated
|
||||
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 = 'SpanishView Spanish Model Description'
|
||||
if email_layout_xmlid:
|
||||
if exp_lang == 'es_ES' and batch_mode != 'domain' and not scheduled_date:
|
||||
self.assertIn(exp_layout_content_es, email['body'])
|
||||
self.assertIn(exp_button_en, email['body'],
|
||||
'TODO: buttons should be translated')
|
||||
else:
|
||||
self.assertIn(exp_layout_content_en, email['body'])
|
||||
self.assertIn(exp_button_en, email['body'])
|
||||
else:
|
||||
# check default layouting applies
|
||||
if exp_lang == 'es_ES' and batch_mode != 'domain' and not scheduled_date:
|
||||
self.assertIn('html lang="es_ES"', email['body'])
|
||||
else:
|
||||
self.assertIn('html lang="en_US"', email['body'])
|
||||
|
||||
# message is posted and notified admin
|
||||
self.assertEqual(message.subtype_id, self.env.ref('mail.mt_comment'))
|
||||
self.assertNotified(message, [{'partner': self.partner_admin, 'is_read': False, 'type': 'inbox'}])
|
||||
@@ -1560,7 +1658,7 @@ class TestComposerResultsCommentStatus(TestMailComposer):
|
||||
'model_id': cls.env['ir.model']._get_id(cls.test_records._name),
|
||||
})
|
||||
|
||||
def test_initial_data(self):
|
||||
def test_assert_initial_data(self):
|
||||
""" Ensure class initial data to ease understanding """
|
||||
self.assertFalse(self.template.auto_delete)
|
||||
|
||||
@@ -1603,7 +1701,7 @@ class TestComposerResultsCommentStatus(TestMailComposer):
|
||||
self.assertEqual(len(self._mails), 2, 'Should have sent 2 emails, skipping the exclusion list')
|
||||
|
||||
|
||||
@tagged('mail_composer')
|
||||
@tagged('mail_composer', 'multi_lang')
|
||||
class TestComposerResultsMass(TestMailComposer):
|
||||
|
||||
@classmethod
|
||||
@@ -1718,7 +1816,10 @@ class TestComposerResultsMass(TestMailComposer):
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_mail_composer_wtpl_complete(self):
|
||||
""" Test a composer in mass mode with a quite complete template, containing
|
||||
notably email-based recipients and attachments. """
|
||||
notably email-based recipients and attachments.
|
||||
|
||||
Translations and email layout supported are also tested.
|
||||
"""
|
||||
# as we use the email queue, don't have failing tests due to other outgoing emails
|
||||
self.env['mail.mail'].sudo().search([]).unlink()
|
||||
|
||||
@@ -1742,109 +1843,155 @@ class TestComposerResultsMass(TestMailComposer):
|
||||
self.assertEqual(self.test_records.user_id, self.user_employee_2)
|
||||
self.assertEqual(self.test_records.message_partner_ids, self.partner_employee_2)
|
||||
|
||||
# launch composer in mass mode
|
||||
composer_form = Form(self.env['mail.compose.message'].with_context(
|
||||
self._get_web_context(self.test_records, add_web=True,
|
||||
default_template_id=self.template.id)
|
||||
))
|
||||
composer = composer_form.save()
|
||||
# ensure some parameters used afterwards
|
||||
author = self.env.user.partner_id
|
||||
self.assertEqual(composer.author_id, author,
|
||||
'Author cannot be synchronized with a raw email_from')
|
||||
self.assertEqual(composer.email_from, self.template.email_from)
|
||||
for use_domain, scheduled_date, email_layout_xmlid, use_lang in product(
|
||||
(False, True),
|
||||
(False, '{{ (object.create_date or datetime.datetime(2022, 12, 26, 18, 0, 0)) + datetime.timedelta(days=2) }}'),
|
||||
(False, 'mail.test_layout'),
|
||||
(False, True),
|
||||
):
|
||||
with self.subTest(use_domain=use_domain,
|
||||
scheduled_date=scheduled_date,
|
||||
email_layout_xmlid=email_layout_xmlid,
|
||||
use_lang=use_lang):
|
||||
# update test configuration
|
||||
self.template.write({
|
||||
'scheduled_date': scheduled_date,
|
||||
})
|
||||
if use_lang:
|
||||
langs = ('es_ES', 'en_US')
|
||||
self.test_partners[0].lang = langs[0]
|
||||
self.test_partners[1].lang = langs[1]
|
||||
else:
|
||||
langs = (False, False)
|
||||
self.test_partners.lang = False
|
||||
|
||||
with self.mock_mail_gateway(mail_unlink_sent=False), \
|
||||
freeze_time(self.reference_now):
|
||||
composer._action_send_mail()
|
||||
ctx = {
|
||||
'default_model': self.test_records._name,
|
||||
'default_composition_mode': 'mass_mail',
|
||||
'default_template_id': self.template.id,
|
||||
}
|
||||
if use_domain:
|
||||
ctx['default_res_domain'] = [('id', 'in', self.test_records.ids)]
|
||||
else:
|
||||
ctx['default_res_ids'] = self.test_records.ids
|
||||
if email_layout_xmlid:
|
||||
ctx['default_email_layout_xmlid'] = email_layout_xmlid
|
||||
|
||||
new_partners = self.env['res.partner'].search([
|
||||
('email', 'in', [email_to_1, email_to_2, email_to_3, email_cc_1])
|
||||
])
|
||||
self.assertEqual(len(new_partners), 3)
|
||||
# launch composer in mass mode
|
||||
composer_form = Form(self.env['mail.compose.message'].with_context(ctx))
|
||||
composer = composer_form.save()
|
||||
|
||||
# global outgoing: emails not sent due to scheduled_date
|
||||
self.assertEqual(len(self._new_mails), 2, 'Should have created 1 mail.mail per record')
|
||||
self.assertEqual(len(self._mails), 0, 'Should not send emails, scheduled in the future')
|
||||
self.assertEqual(self._new_mails.mapped('scheduled_date'),
|
||||
[self.reference_now + timedelta(days=2)] * 2)
|
||||
# ensure some parameters used afterwards
|
||||
author = self.env.user.partner_id
|
||||
self.assertEqual(composer.author_id, author,
|
||||
'Author is not synchronized, as template email_from does not match existing partner')
|
||||
self.assertEqual(composer.email_from, self.template.email_from)
|
||||
|
||||
# simulate cron queue at right time for sending
|
||||
with freeze_time(self.reference_now + timedelta(days=2)):
|
||||
self.env['mail.mail'].sudo().process_email_queue()
|
||||
with self.mock_mail_gateway(mail_unlink_sent=False), \
|
||||
freeze_time(self.reference_now):
|
||||
composer._action_send_mail()
|
||||
|
||||
self.assertEqual(len(self._mails), 10, 'Should have sent 5 emails per record')
|
||||
# partners created from raw emails
|
||||
new_partners = self.env['res.partner'].search([
|
||||
('email', 'in', [email_to_1, email_to_2, email_to_3, email_cc_1])
|
||||
])
|
||||
self.assertEqual(len(new_partners), 3)
|
||||
self.assertEqual(new_partners.mapped('lang'), ['en_US'] * 3,
|
||||
'New partners lang is always the default DB one, whatever the context')
|
||||
|
||||
# hack to use assertEmails: filtering on from/to only is not sufficient to distinguish emails
|
||||
_mails_records = [
|
||||
[mail for mail in self._mails if '%s-%s' % (record.id, record._name) in mail['message_id']]
|
||||
for record in self.test_records
|
||||
]
|
||||
# check global outgoing
|
||||
self.assertEqual(len(self._new_mails), 2, 'Should have created 1 mail.mail per record')
|
||||
if not scheduled_date:
|
||||
# emails sent directly
|
||||
self.assertEqual(len(self._mails), 10, 'Should have sent emails')
|
||||
self.assertEqual(self._new_mails.mapped('scheduled_date'),
|
||||
[False] * 2)
|
||||
else:
|
||||
# emails not sent due to scheduled_date
|
||||
self.assertEqual(len(self._mails), 0, 'Should not send emails, scheduled in the future')
|
||||
self.assertEqual(self._new_mails.mapped('scheduled_date'),
|
||||
[self.reference_now + timedelta(days=2)] * 2)
|
||||
|
||||
for record, _mails in zip(self.test_records, _mails_records):
|
||||
# message copy is kept
|
||||
message = record.message_ids[0]
|
||||
# simulate cron queue at right time for sending
|
||||
with freeze_time(self.reference_now + timedelta(days=2)):
|
||||
self.env['mail.mail'].sudo().process_email_queue()
|
||||
|
||||
# template is sent only to partners (email_to are transformed)
|
||||
self._mails = _mails
|
||||
self.assertMailMail(record.customer_id + new_partners + self.partner_admin,
|
||||
'sent',
|
||||
mail_message=message,
|
||||
author=author,
|
||||
email_values={
|
||||
'attachments_info': [
|
||||
{'name': 'AttFileName_00.txt', 'raw': b'AttContent_00', 'type': 'text/plain'},
|
||||
{'name': 'AttFileName_01.txt', 'raw': b'AttContent_01', 'type': 'text/plain'},
|
||||
{'name': 'TestReport for %s.html' % record.name, 'type': 'text/plain'},
|
||||
],
|
||||
'body_content': 'TemplateBody %s' % record.name,
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'subject': 'TemplateSubject %s' % record.name,
|
||||
},
|
||||
fields_values={
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'mail_server_id': self.mail_server_domain,
|
||||
'reply_to': formataddr((
|
||||
f'{self.env.user.company_id.name} {record.name}',
|
||||
f'{self.alias_catchall}@{self.alias_domain}'
|
||||
)),
|
||||
'subject': 'TemplateSubject %s' % record.name,
|
||||
},
|
||||
)
|
||||
# everything should be sent now
|
||||
self.assertEqual(len(self._mails), 10, 'Should have sent 5 emails per record')
|
||||
|
||||
# test without catchall filling reply-to
|
||||
composer_form = Form(self.env['mail.compose.message'].with_context(
|
||||
self._get_web_context(self.test_records, add_web=True,
|
||||
default_template_id=self.template.id)
|
||||
))
|
||||
composer = composer_form.save()
|
||||
with self.mock_mail_gateway(mail_unlink_sent=True):
|
||||
# remove alias so that _notify_get_reply_to will return the default value instead of alias
|
||||
self.env['ir.config_parameter'].sudo().set_param("mail.catchall.domain", None)
|
||||
composer.action_send_mail()
|
||||
# check email content
|
||||
for record, exp_lang in zip(self.test_records, langs):
|
||||
# message copy is kept
|
||||
message = record.message_ids[0]
|
||||
|
||||
# hack to use assertEmails: filtering on from/to only is not sufficient to distinguish emails
|
||||
_mails_records = [
|
||||
[mail for mail in self._mails if '%s-%s' % (record.id, record._name) in mail['message_id']]
|
||||
for record in self.test_records
|
||||
]
|
||||
# Translations are currently not really supported as they
|
||||
# are fetched composer side. As it is a wizard people use
|
||||
# and discard they are not translated. Only templates are
|
||||
# translated as they are master data.
|
||||
if False and exp_lang == 'es_ES': # remove False when improving support
|
||||
exp_body = f'SpanishBody for {record.name}'
|
||||
exp_subject = f'SpanishSubject for {record.name}'
|
||||
else:
|
||||
exp_body = f'TemplateBody {record.name}'
|
||||
exp_subject = f'TemplateSubject {record.name}'
|
||||
|
||||
for record, _mails in zip(self.test_records, _mails_records):
|
||||
# template is sent only to partners (email_to are transformed)
|
||||
self._mails = _mails
|
||||
self.assertMailMail(record.customer_id + new_partners + self.partner_admin,
|
||||
'sent',
|
||||
mail_message=record.message_ids[0],
|
||||
author=author,
|
||||
email_values={
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'reply_to': self.partner_employee_2.email_formatted,
|
||||
},
|
||||
fields_values={
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'reply_to': self.partner_employee_2.email_formatted,
|
||||
},
|
||||
)
|
||||
# template is sent only to partners (email_to are transformed)
|
||||
self.assertMailMail(record.customer_id + new_partners + self.partner_admin,
|
||||
'sent',
|
||||
mail_message=message,
|
||||
author=author,
|
||||
email_values={
|
||||
'attachments_info': [
|
||||
{'name': 'AttFileName_00.txt', 'raw': b'AttContent_00', 'type': 'text/plain'},
|
||||
{'name': 'AttFileName_01.txt', 'raw': b'AttContent_01', 'type': 'text/plain'},
|
||||
{'name': 'TestReport for %s.html' % record.name, 'type': 'text/plain'},
|
||||
],
|
||||
'body_content': exp_body,
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'subject': exp_subject,
|
||||
},
|
||||
fields_values={
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'mail_server_id': self.mail_server_domain,
|
||||
'reply_to': formataddr((
|
||||
f'{self.env.user.company_id.name} {record.name}',
|
||||
f'{self.alias_catchall}@{self.alias_domain}'
|
||||
)),
|
||||
'subject': exp_subject,
|
||||
},
|
||||
)
|
||||
|
||||
# Low-level checks on outgoing email for the recipient to
|
||||
# check layouting and language. Note that standard layout
|
||||
# is not tested against translations, only the custom one
|
||||
# to ease translations checks.
|
||||
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>TemplateBody {record.name}</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'])
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
@@ -2020,6 +2167,36 @@ class TestComposerResultsMass(TestMailComposer):
|
||||
self.assertSentEmail(self.partner_employee_2.email_formatted,
|
||||
self.test_records[0].customer_id)
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_mail_composer_wtpl_reply_to(self):
|
||||
# test without catchall filling reply-to
|
||||
composer_form = Form(self.env['mail.compose.message'].with_context(
|
||||
self._get_web_context(self.test_records, add_web=True,
|
||||
default_template_id=self.template.id)
|
||||
))
|
||||
composer = composer_form.save()
|
||||
with self.mock_mail_gateway(mail_unlink_sent=False):
|
||||
# remove alias so that _notify_get_reply_to will return the default value instead of alias
|
||||
self.env['ir.config_parameter'].sudo().set_param("mail.catchall.domain", None)
|
||||
composer.action_send_mail()
|
||||
|
||||
for record in self.test_records:
|
||||
# template is sent only to partners (email_to are transformed)
|
||||
self.assertMailMail(record.customer_id,
|
||||
'sent',
|
||||
mail_message=record.message_ids[0],
|
||||
author=self.partner_employee,
|
||||
email_values={
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'reply_to': self.partner_employee_2.email_formatted,
|
||||
},
|
||||
fields_values={
|
||||
'email_from': self.partner_employee_2.email_formatted,
|
||||
'reply_to': self.partner_employee_2.email_formatted,
|
||||
},
|
||||
)
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_mail_composer_wtpl_reply_to_force_new(self):
|
||||
@@ -2111,7 +2288,7 @@ class TestComposerResultsMassStatus(TestMailComposer):
|
||||
'model_id': cls.env['ir.model']._get_id(cls.test_records._name),
|
||||
})
|
||||
|
||||
def test_initial_data(self):
|
||||
def test_assert_initial_data(self):
|
||||
""" Ensure class initial data to ease understanding """
|
||||
self.assertTrue(self.template.auto_delete)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import base64
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from freezegun import freeze_time
|
||||
from itertools import product
|
||||
from markupsafe import escape
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -201,12 +202,14 @@ class TestMailNotifyAPI(TestMessagePostCommon):
|
||||
template_values = test_record._notify_by_email_prepare_rendering_context(test_record.message_ids, {})
|
||||
self.assertEqual(template_values.get('company').id, main_company.id)
|
||||
|
||||
@users('employee')
|
||||
def test_notify_recipients_internals(self):
|
||||
base_record = self.test_record.with_env(self.env)
|
||||
pdata = self._generate_notify_recipients(self.partner_1 | self.partner_employee)
|
||||
msg_vals = {
|
||||
'body': 'Message body',
|
||||
'model': self.test_record._name,
|
||||
'res_id': self.test_record.id,
|
||||
'model': base_record._name,
|
||||
'res_id': base_record.id,
|
||||
'subject': 'Message subject',
|
||||
}
|
||||
link_vals = {
|
||||
@@ -216,49 +219,58 @@ class TestMailNotifyAPI(TestMessagePostCommon):
|
||||
'auth_login': 'auth_login_val',
|
||||
}
|
||||
notify_msg_vals = dict(msg_vals, **link_vals)
|
||||
classify_res = self.env[self.test_record._name]._notify_get_recipients_classify(pdata, 'My Custom Model Name', msg_vals=notify_msg_vals)
|
||||
|
||||
# test notifying the class (void recordset)
|
||||
classify_res = self.env[base_record._name]._notify_get_recipients_classify(
|
||||
pdata, 'My Custom Model Name', msg_vals=notify_msg_vals
|
||||
)
|
||||
# find back information for each recipients
|
||||
partner_info = next(item for item in classify_res if item['recipients'] == self.partner_1.ids)
|
||||
emp_info = next(item for item in classify_res if item['recipients'] == self.partner_employee.ids)
|
||||
|
||||
# partner: no access button
|
||||
self.assertFalse(partner_info['has_button_access'])
|
||||
|
||||
# employee: access button and link
|
||||
self.assertTrue(emp_info['has_button_access'])
|
||||
for param, value in link_vals.items():
|
||||
self.assertIn('%s=%s' % (param, value), emp_info['button_access']['url'])
|
||||
self.assertIn('model=%s' % self.test_record._name, emp_info['button_access']['url'])
|
||||
self.assertIn('res_id=%s' % self.test_record.id, emp_info['button_access']['url'])
|
||||
self.assertIn('model=%s' % base_record._name, emp_info['button_access']['url'])
|
||||
self.assertIn('res_id=%s' % base_record.id, emp_info['button_access']['url'])
|
||||
self.assertNotIn('body', emp_info['button_access']['url'])
|
||||
self.assertNotIn('subject', emp_info['button_access']['url'])
|
||||
|
||||
# test when notifying on non-records (e.g. MailThread._message_notify())
|
||||
for model, res_id in ((self.test_record._name, False),
|
||||
(self.test_record._name, 0), # browse(0) does not return a valid recordset
|
||||
(False, self.test_record.id),
|
||||
for model, res_id in ((base_record._name, False),
|
||||
(base_record._name, 0), # browse(0) does not return a valid recordset
|
||||
('mail.thread', False),
|
||||
('mail.thread', base_record.id)):
|
||||
with self.subTest(model=model, res_id=res_id):
|
||||
notify_msg_vals.update({
|
||||
'model': model,
|
||||
'res_id': res_id,
|
||||
})
|
||||
classify_res = self.env[model].browse(res_id)._notify_get_recipients_classify(
|
||||
pdata, 'Test', msg_vals=notify_msg_vals)
|
||||
# find back information for partner
|
||||
partner_info = next(item for item in classify_res if item['recipients'] == self.partner_1.ids)
|
||||
emp_info = next(item for item in classify_res if item['recipients'] == self.partner_employee.ids)
|
||||
# check there is no access button
|
||||
self.assertFalse(partner_info['has_button_access'])
|
||||
self.assertFalse(emp_info['has_button_access'])
|
||||
|
||||
# test when notifying based a valid record, but asking for a falsy record in msg_vals
|
||||
for model, res_id in ((base_record._name, False),
|
||||
(base_record._name, 0), # browse(0) does not return a valid recordset
|
||||
(False, base_record.id),
|
||||
(False, False),
|
||||
('mail.thread', False),
|
||||
('mail.thread', self.test_record.id)):
|
||||
msg_vals.update({
|
||||
'model': model,
|
||||
'res_id': res_id,
|
||||
})
|
||||
# note that msg_vals wins over record on which method is called
|
||||
notify_msg_vals = dict(msg_vals, **link_vals)
|
||||
classify_res = self.test_record._notify_get_recipients_classify(
|
||||
pdata, 'Test', msg_vals=notify_msg_vals)
|
||||
# find back information for partner
|
||||
partner_info = next(item for item in classify_res if item['recipients'] == self.partner_1.ids)
|
||||
emp_info = next(item for item in classify_res if item['recipients'] == self.partner_employee.ids)
|
||||
# check there is no access button
|
||||
self.assertFalse(partner_info['has_button_access'])
|
||||
self.assertFalse(emp_info['has_button_access'])
|
||||
|
||||
# test on falsy records (False model cannot be browsed, skipped)
|
||||
if model:
|
||||
record_falsy = self.env[model].browse(res_id)
|
||||
classify_res = record_falsy._notify_get_recipients_classify(
|
||||
('mail.thread', base_record.id)):
|
||||
with self.subTest(model=model, res_id=res_id):
|
||||
# note that msg_vals wins over record on which method is called
|
||||
notify_msg_vals.update({
|
||||
'model': model,
|
||||
'res_id': res_id,
|
||||
})
|
||||
classify_res = base_record._notify_get_recipients_classify(
|
||||
pdata, 'Test', msg_vals=notify_msg_vals)
|
||||
# find back information for partner
|
||||
partner_info = next(item for item in classify_res if item['recipients'] == self.partner_1.ids)
|
||||
@@ -436,7 +448,7 @@ class TestMessageNotify(TestMessagePostCommon):
|
||||
)
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail', 'odoo.tests')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail', 'odoo.models.unlink', 'odoo.tests')
|
||||
def test_notify_parameters(self):
|
||||
""" Test usage of parameters in notify, both for unwanted side effects
|
||||
and magic parameters. """
|
||||
@@ -591,7 +603,8 @@ class TestMessageLog(TestMessagePostCommon):
|
||||
@tagged('mail_post')
|
||||
class TestMessagePost(TestMessagePostCommon, CronMixinCase):
|
||||
|
||||
def test_initial_values(self):
|
||||
def test_assert_initial_values(self):
|
||||
""" Be sure of what we are testing """
|
||||
self.assertFalse(self.test_record.message_ids)
|
||||
self.assertFalse(self.test_record.message_follower_ids)
|
||||
self.assertFalse(self.test_record.message_partner_ids)
|
||||
@@ -662,7 +675,7 @@ class TestMessagePost(TestMessagePostCommon, CronMixinCase):
|
||||
partner_ids=self.partner_portal.ids,
|
||||
)
|
||||
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail', 'odoo.models.unlink')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail', 'odoo.models.unlink', 'odoo.tests')
|
||||
@users('employee')
|
||||
def test_message_post_author(self):
|
||||
""" Test author recognition """
|
||||
@@ -765,6 +778,7 @@ class TestMessagePost(TestMessagePostCommon, CronMixinCase):
|
||||
)
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.models.unlink')
|
||||
def test_message_post_inactive_follower(self):
|
||||
""" Test posting with inactive followers does not notify them (e.g. odoobot) """
|
||||
test_record = self.env['mail.test.simple'].browse(self.test_record.ids)
|
||||
@@ -1480,46 +1494,103 @@ class TestMessagePostLang(TestMailCommon, TestRecipients):
|
||||
|
||||
cls.partner_2.write({'lang': 'es_ES'})
|
||||
|
||||
def test_assert_initial_values(self):
|
||||
""" Be sure of what we are testing """
|
||||
self.assertEqual(self.partner_1.lang, 'en_US')
|
||||
self.assertEqual(self.partner_2.lang, 'es_ES')
|
||||
|
||||
self.assertEqual(self.test_records[0].lang, 'es_ES')
|
||||
self.assertEqual(self.test_records[0].customer_id.lang, False)
|
||||
self.assertEqual(self.test_records[1].lang, False)
|
||||
self.assertEqual(self.test_records[1].customer_id.lang, 'es_ES')
|
||||
|
||||
self.assertFalse(self.test_records[0].message_follower_ids)
|
||||
self.assertFalse(self.test_records[1].message_follower_ids)
|
||||
|
||||
self.assertEqual(self.user_employee.lang, 'en_US')
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail')
|
||||
def test_composer_lang_template_comment(self):
|
||||
""" When posting in comment mode, content is rendered using the lang
|
||||
field of template. Notification layout lang is partly coming from
|
||||
template, partly from environment (to be improved). """
|
||||
test_record = self.test_records[0].with_user(self.env.user)
|
||||
test_template = self.test_template.with_user(self.env.user)
|
||||
|
||||
with self.mock_mail_gateway():
|
||||
test_record.message_post_with_source(
|
||||
test_template,
|
||||
email_layout_xmlid='mail.test_layout',
|
||||
message_type='comment',
|
||||
subtype_id=self.env.ref('mail.mt_comment').id,
|
||||
)
|
||||
for partner in self.env['res.partner'] + self.partner_1 + self.partner_2:
|
||||
with self.subTest(partner=partner):
|
||||
test_record.write({
|
||||
'customer_id': partner.id,
|
||||
})
|
||||
with self.mock_mail_gateway():
|
||||
test_record.message_post_with_source(
|
||||
test_template,
|
||||
email_layout_xmlid='mail.test_layout',
|
||||
message_type='comment',
|
||||
subtype_id=self.env.ref('mail.mt_comment').id,
|
||||
)
|
||||
|
||||
record0_customer = self.env['res.partner'].search([('email_normalized', '=', 'test.record.1@test.customer.com')], limit=1)
|
||||
self.assertTrue(record0_customer, 'Template usage should have created a contact based on record email')
|
||||
# expected languages: content depend on template (lang field) aka
|
||||
# customer.lang or record.lang (see template); notif lang is
|
||||
# partner lang or default DB lang
|
||||
exp_content_lang = partner.lang if partner.lang else 'es_ES'
|
||||
exp_notif_lang = partner.lang if partner.lang else 'en_US'
|
||||
|
||||
customer_email = self._find_sent_mail_wemail(record0_customer.email_formatted)
|
||||
self.assertTrue(customer_email)
|
||||
body = customer_email['body']
|
||||
# check content
|
||||
self.assertIn(f'SpanishBody for {test_record.name}', body,
|
||||
'Body based on template should be translated')
|
||||
# check subject
|
||||
self.assertEqual(f'SpanishSubject for {test_record.name}', customer_email['subject'],
|
||||
'Subject based on template should be translated')
|
||||
# check notification layout content
|
||||
self.assertIn('Spanish Layout para', body, 'Layout content should be translated')
|
||||
self.assertNotIn('English Layout for', body)
|
||||
self.assertIn('Spanish Layout para Spanish Model Description', body, 'Model name should be translated')
|
||||
# check notification layout strings
|
||||
self.assertIn('View Lang Chatter Model', body,
|
||||
'Fixme: "View document" should be translated')
|
||||
# self.assertIn('SpanishView Spanish Model Description', body,
|
||||
# '"View document" should be translated')
|
||||
# self.assertNotIn(f'View {test_record._description}', body,
|
||||
# '"View document" should be translated')
|
||||
# self.assertIn('SpanishButtonTitle', body,
|
||||
# 'Groups-based action names should be translated')
|
||||
self.assertIn('NotificationButtonTitle', body, 'Fixme: Groups-based action names should be translated')
|
||||
if partner:
|
||||
customer = partner
|
||||
else:
|
||||
customer = self.env['res.partner'].search([('email_normalized', '=', 'test.record.1@test.customer.com')], limit=1)
|
||||
self.assertTrue(customer, 'Template usage should have created a contact based on record email')
|
||||
self.assertEqual(customer.lang, exp_notif_lang)
|
||||
|
||||
customer_email = self._find_sent_mail_wemail(customer.email_formatted)
|
||||
self.assertTrue(customer_email)
|
||||
body = customer_email['body']
|
||||
# check content: depends on object.lang / object.customer_id.lang
|
||||
if exp_content_lang == 'en_US':
|
||||
self.assertIn(f'EnglishBody for {test_record.name}', body,
|
||||
'Body based on template should be translated')
|
||||
else:
|
||||
self.assertIn(f'SpanishBody for {test_record.name}', body,
|
||||
'Body based on template should be translated')
|
||||
# check subject
|
||||
if exp_content_lang == 'en_US':
|
||||
self.assertEqual(f'EnglishSubject for {test_record.name}', customer_email['subject'],
|
||||
'Subject based on template should be translated')
|
||||
else:
|
||||
self.assertEqual(f'SpanishSubject for {test_record.name}', customer_email['subject'],
|
||||
'Subject based on template should be translated')
|
||||
# check notification layout content: currently partly translated
|
||||
# based only on template definition
|
||||
if exp_content_lang == 'en_US':
|
||||
self.assertNotIn('Spanish Layout para', body, 'Layout translation failed')
|
||||
self.assertIn('English Layout for Lang Chatter Model', body,
|
||||
'Layout / model translation failed')
|
||||
self.assertNotIn('Spanish Model Description', body, 'Model translation failed')
|
||||
# check notification layout strings
|
||||
self.assertNotIn('SpanishView Spanish Model Description', body,
|
||||
'"View document" translation failed')
|
||||
self.assertIn(f'View {test_record._description}', body,
|
||||
'"View document" translation failed')
|
||||
self.assertNotIn('SpanishButtonTitle', body,
|
||||
'Groups-based action names translation failed')
|
||||
self.assertIn('NotificationButtonTitle', body,
|
||||
'Groups-based action names translation failed')
|
||||
else:
|
||||
self.assertIn('Spanish Layout para', body, 'Layout content should be translated')
|
||||
self.assertNotIn('English Layout for', body)
|
||||
self.assertIn('Spanish Layout para Spanish Model Description', body, 'Model name should be translated')
|
||||
# check notification layout strings
|
||||
self.assertIn('View Lang Chatter Model', body,
|
||||
'Fixme: "View document" should be translated')
|
||||
# self.assertIn('SpanishView Spanish Model Description', body,
|
||||
# '"View document" should be translated')
|
||||
# self.assertNotIn(f'View {test_record._description}', body,
|
||||
# '"View document" should be translated')
|
||||
# self.assertIn('SpanishButtonTitle', body,
|
||||
# 'Groups-based action names should be translated')
|
||||
self.assertIn('NotificationButtonTitle', body, 'Fixme: Groups-based action names should be translated')
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail')
|
||||
@@ -1589,6 +1660,8 @@ class TestMessagePostLang(TestMailCommon, TestRecipients):
|
||||
@users('employee')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail')
|
||||
def test_layout_email_lang_template(self):
|
||||
""" Test language support when posting in batch using a template.
|
||||
Content and layout are is translated based on template definition. """
|
||||
test_records = self.test_records.with_user(self.env.user)
|
||||
test_template = self.test_template.with_user(self.env.user)
|
||||
|
||||
@@ -1606,6 +1679,10 @@ class TestMessagePostLang(TestMailCommon, TestRecipients):
|
||||
for record, customer in zip(test_records, record0_customer + self.partner_2):
|
||||
customer_email = self._find_sent_mail_wemail(customer.email_formatted)
|
||||
self.assertTrue(customer_email)
|
||||
|
||||
# body and layouting are translated partly based on template. Bits
|
||||
# of layout are not translated due to lang not being correctly
|
||||
# propagate everywhere we need it
|
||||
body = customer_email['body']
|
||||
# check content
|
||||
self.assertIn(f'SpanishBody for {record.name}', body,
|
||||
@@ -1627,3 +1704,90 @@ class TestMessagePostLang(TestMailCommon, TestRecipients):
|
||||
# 'Groups-based action names should be translated')
|
||||
self.assertIn('NotificationButtonTitle', body,
|
||||
'Fixme: groups-based action names should be translated')
|
||||
|
||||
@users('employee')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail')
|
||||
def test_post_multi_lang_recipients(self):
|
||||
""" Test posting on a document in a multilang environment. Currently
|
||||
current user's lang determines completely language used for notification
|
||||
layout notably, when no template is involved.
|
||||
|
||||
Lang layout for this test (to better check various configuration and
|
||||
check which lang wins the final output, if any)
|
||||
|
||||
* current users: various between en and es;
|
||||
* partner1: es
|
||||
* partner2: en
|
||||
"""
|
||||
test_records = self.test_records.with_env(self.env)
|
||||
test_records.message_subscribe(partner_ids=(self.partner_1 + self.partner_2).ids)
|
||||
|
||||
for employee_lang, email_layout_xmlid in product(
|
||||
('en_US', 'es_ES'),
|
||||
(False, 'mail.test_layout'),
|
||||
):
|
||||
with self.subTest(employee_lang=employee_lang, email_layout_xmlid=email_layout_xmlid):
|
||||
self.user_employee.write({
|
||||
'lang': employee_lang,
|
||||
})
|
||||
for record in test_records:
|
||||
with self.mock_mail_gateway(mail_unlink_sent=False), \
|
||||
self.mock_mail_app():
|
||||
record.message_post(
|
||||
body='<p>Hi there</p>',
|
||||
email_layout_xmlid=email_layout_xmlid,
|
||||
message_type='comment',
|
||||
subject='TeDeum',
|
||||
subtype_xmlid='mail.mt_comment',
|
||||
)
|
||||
message = record.message_ids[0]
|
||||
self.assertEqual(
|
||||
message.notified_partner_ids, self.partner_1 + self.partner_2
|
||||
)
|
||||
|
||||
# check created mail.mail and outgoing emails. One email
|
||||
# is generated for 'partner_1' and 'partner_2' (same email
|
||||
# as same configuration (aka all customers)).
|
||||
_mail = self.assertMailMail(
|
||||
self.partner_1 + self.partner_2, 'sent',
|
||||
mail_message=message,
|
||||
author=self.partner_employee,
|
||||
email_values={
|
||||
'body_content': '<p>Hi there</p>',
|
||||
'email_from': self.partner_employee.email_formatted,
|
||||
'subject': 'TeDeum',
|
||||
},
|
||||
)
|
||||
|
||||
# Low-level checks on outgoing email for the recipient to
|
||||
# check layouting and language. Note that standard layout
|
||||
# is not tested against translations, only the custom one
|
||||
# to ease translations checks.
|
||||
for partner in self.partner_1 + self.partner_2:
|
||||
email = self._find_sent_email(
|
||||
self.partner_employee.email_formatted,
|
||||
[partner.email_formatted]
|
||||
)
|
||||
self.assertTrue(bool(email), 'Email not found, check recipients')
|
||||
|
||||
exp_layout_content_en = 'English Layout for Lang Chatter Model'
|
||||
exp_layout_content_es = 'Spanish Layout para Spanish Model Description'
|
||||
exp_button_en = 'View Lang Chatter Model'
|
||||
exp_button_es = 'SpanishView Spanish Model Description'
|
||||
exp_action_en = 'NotificationButtonTitle'
|
||||
exp_action_es = 'SpanishButtonTitle'
|
||||
if email_layout_xmlid:
|
||||
if employee_lang == 'es_ES':
|
||||
self.assertIn(exp_layout_content_es, email['body'])
|
||||
self.assertIn(exp_button_es, email['body'])
|
||||
self.assertIn(exp_action_es, email['body'])
|
||||
else:
|
||||
self.assertIn(exp_layout_content_en, email['body'])
|
||||
self.assertIn(exp_button_en, email['body'])
|
||||
self.assertIn(exp_action_en, email['body'])
|
||||
else:
|
||||
# check default layouting applies
|
||||
if employee_lang == 'es_ES':
|
||||
self.assertIn('html lang="es_ES"', email['body'])
|
||||
else:
|
||||
self.assertIn('html lang="en_US"', email['body'])
|
||||
|
||||
Reference in New Issue
Block a user