From 230b8258a551010080dd582923afe5a2f91d644b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 26 Apr 2021 08:49:21 +0000 Subject: [PATCH 1/6] [IMP] test_mass_mailing: improve test data management and test users, merge mailing tests In this commit we try to simplify tests organization by * merging mailing_internals and mass_mailing tests, as they globally handle mailing-related tests (blacklist, opt-out, gateway update through replies and clicks); * move wizard (mailing.test) tests in their own file as they target a specific model; * add some loggers to reduce noise; * add some users wrappers to test using real users; LINKS Task ID-2117639 COM PR odoo/odoo#40931 --- addons/test_mass_mailing/tests/__init__.py | 4 +- addons/test_mass_mailing/tests/common.py | 8 + .../{test_mass_mailing.py => test_mailing.py} | 103 +++++++++++ .../tests/test_mailing_internals.py | 163 ------------------ .../tests/test_mailing_test.py | 50 ++++++ 5 files changed, 163 insertions(+), 165 deletions(-) rename addons/test_mass_mailing/tests/{test_mass_mailing.py => test_mailing.py} (63%) delete mode 100644 addons/test_mass_mailing/tests/test_mailing_internals.py create mode 100644 addons/test_mass_mailing/tests/test_mailing_test.py diff --git a/addons/test_mass_mailing/tests/__init__.py b/addons/test_mass_mailing/tests/__init__.py index 2391896e3e4..978ceb47d01 100644 --- a/addons/test_mass_mailing/tests/__init__.py +++ b/addons/test_mass_mailing/tests/__init__.py @@ -5,6 +5,6 @@ from . import test_blacklist from . import test_blacklist_behavior from . import test_blacklist_mixin from . import test_link_tracker -from . import test_mailing_internals -from . import test_mass_mailing +from . import test_mailing_test +from . import test_mailing from . import test_performance diff --git a/addons/test_mass_mailing/tests/common.py b/addons/test_mass_mailing/tests/common.py index 43b1ad27ea1..ff368bf59be 100644 --- a/addons/test_mass_mailing/tests/common.py +++ b/addons/test_mass_mailing/tests/common.py @@ -11,6 +11,13 @@ class TestMassMailCommon(MassMailCommon, TestMailCommon): def setUpClass(cls): super(TestMassMailCommon, cls).setUpClass() + cls.test_alias = cls.env['mail.alias'].create({ + 'alias_name': 'test.alias', + 'alias_user_id': False, + 'alias_model_id': cls.env['ir.model']._get('mailing.test.simple').id, + 'alias_contact': 'everyone' + }) + # enforce last update by user_marketing to match _process_mass_mailing_queue # taking last writer as user running a batch cls.mailing_bl = cls.env['mailing.mailing'].with_user(cls.user_marketing).create({ @@ -32,6 +39,7 @@ class TestMassMailCommon(MassMailCommon, TestMailCommon): """, 'mailing_type': 'mail', 'mailing_model_id': cls.env['ir.model']._get('mailing.test.blacklist').id, + 'reply_to_mode': 'thread', }) @classmethod diff --git a/addons/test_mass_mailing/tests/test_mass_mailing.py b/addons/test_mass_mailing/tests/test_mailing.py similarity index 63% rename from addons/test_mass_mailing/tests/test_mass_mailing.py rename to addons/test_mass_mailing/tests/test_mailing.py index 0a2f45f0e17..4179327de94 100644 --- a/addons/test_mass_mailing/tests/test_mass_mailing.py +++ b/addons/test_mass_mailing/tests/test_mailing.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.addons.test_mass_mailing.data.mail_test_data import MAIL_TEMPLATE from odoo.addons.test_mass_mailing.tests.common import TestMassMailCommon from odoo.tests import tagged from odoo.tests.common import users @@ -14,6 +15,62 @@ class TestMassMailing(TestMassMailCommon): def setUpClass(cls): super(TestMassMailing, cls).setUpClass() + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_mailing_gateway_reply(self): + customers = self.env['res.partner'] + for x in range(0, 3): + customers |= self.env['res.partner'].create({ + 'name': 'Customer_%02d' % x, + 'email': '"Customer_%02d" Hello ${object.name}

', + 'reply_to_mode': 'email', + 'reply_to': '%s@%s' % (self.test_alias.alias_name, self.test_alias.alias_domain), + 'keep_archives': True, + 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, + 'contact_list_ids': [(4, self.mailing_list_1.id)], + 'source_id': source.id, + 'medium_id': medium.id, + 'campaign_id': campaign.id + }) + + mailing.action_put_in_queue() + with self.mock_mail_gateway(mail_unlink_sent=False): + mailing._process_mass_mailing_queue() + + traces = self.env['mailing.trace'].search([('model', '=', self.mailing_list_1.contact_ids._name), ('res_id', 'in', self.mailing_list_1.contact_ids.ids)]) + self.assertEqual(len(traces), 3) + + # simulate response to mailing + self.gateway_mail_reply_wrecord(MAIL_TEMPLATE, self.mailing_list_1.contact_ids[0], use_in_reply_to=True) + self.gateway_mail_reply_wrecord(MAIL_TEMPLATE, self.mailing_list_1.contact_ids[1], use_in_reply_to=False) + + mailing_test_utms = self.env['mailing.test.utm'].search([('name', '=', 'Re: %s' % subject)]) + self.assertEqual(len(mailing_test_utms), 2) + for test_utm in mailing_test_utms: + self.assertEqual(test_utm.campaign_id, campaign) + self.assertEqual(test_utm.source_id, source) + self.assertEqual(test_utm.medium_id, medium) + @users('user_marketing') @mute_logger('odoo.addons.mail.models.mail_mail') def test_mailing_w_blacklist(self): diff --git a/addons/test_mass_mailing/tests/test_mailing_internals.py b/addons/test_mass_mailing/tests/test_mailing_internals.py deleted file mode 100644 index 555578e492d..00000000000 --- a/addons/test_mass_mailing/tests/test_mailing_internals.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo.addons.test_mass_mailing.tests.common import TestMassMailCommon -from odoo.addons.test_mass_mailing.data.mail_test_data import MAIL_TEMPLATE -from odoo.tests.common import users -from odoo.tools import mute_logger - - -class TestMailingInternals(TestMassMailCommon): - - def setUp(self): - super(TestMailingInternals, self).setUp() - - self.env['ir.config_parameter'].set_param('mail.bounce.alias', 'bounce.test') - self.env['ir.config_parameter'].set_param('mail.catchall.alias', 'catchall.test') - self.env['ir.config_parameter'].set_param('mail.catchall.domain', 'test.example.com') - - self.test_alias = self.env['mail.alias'].create({ - 'alias_name': 'test.alias', - 'alias_user_id': False, - 'alias_model_id': self.env['ir.model']._get('mailing.test.simple').id, - 'alias_contact': 'everyone' - }) - - @mute_logger('odoo.addons.mail.models.mail_render_mixin') - def test_mailing_test_button(self): - mailing = self.env['mailing.mailing'].create({ - 'name': 'TestButton', - 'subject': 'Subject ${object.name}', - 'preview': 'Preview ${object.name}', - 'state': 'draft', - 'mailing_type': 'mail', - 'body_html': '

Hello ${object.name}

', - 'mailing_model_id': self.env['ir.model']._get('res.partner').id, - }) - mailing_test = self.env['mailing.mailing.test'].create({ - 'email_to': 'test@test.com', - 'mass_mailing_id': mailing.id, - }) - - with self.mock_mail_gateway(): - mailing_test.send_mail_test() - - # Test if bad jinja in the subject raises an error - mailing.write({'subject': 'Subject ${object.name_id.id}'}) - with self.mock_mail_gateway(), self.assertRaises(Exception): - mailing_test.send_mail_test() - - # Test if bad jinja in the body raises an error - mailing.write({ - 'subject': 'Subject ${object.name}', - 'body_html': '

Hello ${object.name_id.id}

', - }) - with self.mock_mail_gateway(), self.assertRaises(Exception): - mailing_test.send_mail_test() - - # Test if bad jinja in the preview raises an error - mailing.write({ - 'body_html': '

Hello ${object.name}

', - 'preview': 'Preview ${object.name_id.id}', - }) - with self.mock_mail_gateway(), self.assertRaises(Exception): - mailing_test.send_mail_test() - - def test_mailing_trace_update(self): - customers = self.env['res.partner'] - for x in range(0, 3): - customers |= self.env['res.partner'].create({ - 'name': 'Customer_%02d' % x, - 'email': '"Customer_%02d" Hello ${object.name}

', - 'reply_to_mode': 'email', - 'reply_to': '%s@%s' % (self.test_alias.alias_name, self.test_alias.alias_domain), - 'keep_archives': True, - 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, - 'contact_list_ids': [(4, self.mailing_list_1.id)], - 'source_id': source.id, - 'medium_id': medium.id, - 'campaign_id': campaign.id - }) - - mailing.action_put_in_queue() - with self.mock_mail_gateway(mail_unlink_sent=False): - mailing._process_mass_mailing_queue() - - traces = self.env['mailing.trace'].search([('model', '=', self.mailing_list_1.contact_ids._name), ('res_id', 'in', self.mailing_list_1.contact_ids.ids)]) - self.assertEqual(len(traces), 3) - - # simulate response to mailing - self.gateway_mail_reply_wrecord(MAIL_TEMPLATE, self.mailing_list_1.contact_ids[0], use_in_reply_to=True) - self.gateway_mail_reply_wrecord(MAIL_TEMPLATE, self.mailing_list_1.contact_ids[1], use_in_reply_to=False) - - mailing_test_utms = self.env['mailing.test.utm'].search([('name', '=', 'Re: %s' % subject)]) - self.assertEqual(len(mailing_test_utms), 2) - for test_utm in mailing_test_utms: - self.assertEqual(test_utm.campaign_id, campaign) - self.assertEqual(test_utm.source_id, source) - self.assertEqual(test_utm.medium_id, medium) diff --git a/addons/test_mass_mailing/tests/test_mailing_test.py b/addons/test_mass_mailing/tests/test_mailing_test.py new file mode 100644 index 00000000000..33c0419af07 --- /dev/null +++ b/addons/test_mass_mailing/tests/test_mailing_test.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.test_mass_mailing.tests.common import TestMassMailCommon +from odoo.tests.common import users +from odoo.tools import mute_logger + + +class TestMailingTest(TestMassMailCommon): + + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_render_mixin') + def test_mailing_test_button(self): + mailing = self.env['mailing.mailing'].create({ + 'name': 'TestButton', + 'subject': 'Subject ${object.name}', + 'preview': 'Preview ${object.name}', + 'state': 'draft', + 'mailing_type': 'mail', + 'body_html': '

Hello ${object.name}

', + 'mailing_model_id': self.env['ir.model']._get('res.partner').id, + }) + mailing_test = self.env['mailing.mailing.test'].create({ + 'email_to': 'test@test.com', + 'mass_mailing_id': mailing.id, + }) + + with self.mock_mail_gateway(): + mailing_test.send_mail_test() + + # Test if bad jinja in the subject raises an error + mailing.write({'subject': 'Subject ${object.name_id.id}'}) + with self.mock_mail_gateway(), self.assertRaises(Exception): + mailing_test.send_mail_test() + + # Test if bad jinja in the body raises an error + mailing.write({ + 'subject': 'Subject ${object.name}', + 'body_html': '

Hello ${object.name_id.id}

', + }) + with self.mock_mail_gateway(), self.assertRaises(Exception): + mailing_test.send_mail_test() + + # Test if bad jinja in the preview raises an error + mailing.write({ + 'body_html': '

Hello ${object.name}

', + 'preview': 'Preview ${object.name_id.id}', + }) + with self.mock_mail_gateway(), self.assertRaises(Exception): + mailing_test.send_mail_test() From b36b74fa570937795c598a9f08086b13ff7773c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 26 Apr 2021 12:38:41 +0000 Subject: [PATCH 2/6] [IMP] test_mass_mailing: add test for archives / deletion Purpose of this commit is to add tests for current behavior of ``keep archives`` field on mailing, used in combination of ``reply-to`` target (either new thread or update existing threads). LINKS Task ID-2117639 COM PR odoo/odoo#40931 --- .../tests/test_mailing_internals.py | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/addons/mass_mailing/tests/test_mailing_internals.py b/addons/mass_mailing/tests/test_mailing_internals.py index bc5408c288b..967420bc8a5 100644 --- a/addons/mass_mailing/tests/test_mailing_internals.py +++ b/addons/mass_mailing/tests/test_mailing_internals.py @@ -213,6 +213,79 @@ class TestMassMailFeatures(MassMailCommon, CronMixinCase): capt.records.ensure_one() self.assertLessEqual(capt.records.call_at, truth) + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_deletion(self): + """ Test deletion in various use case, depending on reply-to """ + # 1- Keep archives and reply-to set to 'answer = new thread' + mailing = self.env['mailing.mailing'].create({ + 'name': 'TestSource', + 'subject': 'TestDeletion', + 'body_html': "
Hello {object.name}
", + 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, + 'contact_list_ids': [(6, 0, self.mailing_list_1.ids)], + 'keep_archives': True, + 'reply_to_mode': 'email', + 'reply_to': self.email_reply_to, + }) + self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) + + with self.mock_mail_gateway(mail_unlink_sent=True): + mailing.action_send_mail() + + self.assertEqual(len(self._mails), 3) + self.assertEqual(len(self._new_mails.exists()), 3) + self.assertEqual(len(self.mailing_list_1.contact_ids.message_ids), 3) + + # 2- Keep archives and reply-to set to 'answer = update thread' + self.mailing_list_1.contact_ids.message_ids.unlink() + mailing = mailing.copy() + mailing.write({ + 'reply_to_mode': 'thread', + }) + self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) + + with self.mock_mail_gateway(mail_unlink_sent=True): + mailing.action_send_mail() + + self.assertEqual(len(self._mails), 3) + self.assertEqual(len(self._new_mails.exists()), 3) + self.assertEqual(len(self.mailing_list_1.contact_ids.message_ids), 3) + + # 3- Remove archives and reply-to set to 'answer = new thread' + self.mailing_list_1.contact_ids.message_ids.unlink() + mailing = mailing.copy() + mailing.write({ + 'keep_archives': False, + 'reply_to_mode': 'email', + 'reply_to': self.email_reply_to, + }) + self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) + + with self.mock_mail_gateway(mail_unlink_sent=True): + mailing.action_send_mail() + + self.assertEqual(len(self._mails), 3) + self.assertEqual(len(self._new_mails.exists()), 0) + self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) + + # 4- Remove archives and reply-to set to 'answer = update thread' + # Imply keeping mail.message for gateway reply) + self.mailing_list_1.contact_ids.message_ids.unlink() + mailing = mailing.copy() + mailing.write({ + 'keep_archives': False, + 'reply_to_mode': 'thread', + }) + self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) + + with self.mock_mail_gateway(mail_unlink_sent=True): + mailing.action_send_mail() + + self.assertEqual(len(self._mails), 3) + self.assertEqual(len(self._new_mails.exists()), 0) + self.assertEqual(len(self.mailing_list_1.contact_ids.message_ids), 3) + @users('user_marketing') @mute_logger('odoo.addons.mail.models.mail_mail') def test_mailing_on_res_partner(self): From 4ef24369c813ec6a6ce997369aa454d9d67a992b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 26 Apr 2021 12:38:49 +0000 Subject: [PATCH 3/6] [IMP] test_mass_mailing: add tests for replies to mailings depending on update mode Purpose of this commit is to add tests related to answers through mail gateway when having reply-to mode of mailing set to either updating existing threads (aka replying on mailed records), either creating new threads (aka using the reply-to alias configuration). LINKS Task ID-2117639 COM PR odoo/odoo#40931 --- addons/mail/tests/common.py | 31 +++++++++-- .../test_mass_mailing/tests/test_mailing.py | 54 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/addons/mail/tests/common.py b/addons/mail/tests/common.py index d8dcf213197..650f273e1ae 100644 --- a/addons/mail/tests/common.py +++ b/addons/mail/tests/common.py @@ -128,7 +128,8 @@ class MockEmail(common.BaseCase): """ Deprecated, remove in 14.4 """ return self.gateway_mail_reply_wrecord(template, record, use_in_reply_to=use_in_reply_to) - def gateway_mail_reply_wrecord(self, template, record, use_in_reply_to=True): + def gateway_mail_reply_wrecord(self, template, record, use_in_reply_to=True, + target_model=None, target_field=None): """ Simulate a reply through the mail gateway. Usage: giving a record, find an email sent to him and use its message-ID to simulate a reply. @@ -148,8 +149,32 @@ class MockEmail(common.BaseCase): subject='Re: %s' % mail_mail.subject, extra=extra, msg_id='<123456.%s.%d@test.example.com>' % (record._name, record.id), - target_model=record._name, - target_field=record._rec_name, + target_model=target_model or record._name, + target_field=target_field or record._rec_name, + ) + + def gateway_mail_reply_wemail(self, template, email_to, use_in_reply_to=True, + target_model=None, target_field=None): + """ Simulate a reply through the mail gateway. Usage: giving a record, + find an email sent to him and use its message-ID to simulate a reply. + + Some noise is added in References just to test some robustness. """ + sent_mail = self._find_sent_mail_wemail(email_to) + + if use_in_reply_to: + extra = 'In-Reply-To:\r\n\t%s\n' % sent_mail['message_id'] + else: + disturbing_other_msg_id = '<123456.654321@another.host.com>' + extra = 'References:\r\n\t%s\n\r%s' % (sent_mail['message_id'], disturbing_other_msg_id) + + return self.format_and_process( + template, + sent_mail['email_to'], + sent_mail['reply_to'], + subject='Re: %s' % sent_mail['subject'], + extra=extra, + target_model=target_model, + target_field=target_field or 'name', ) def from_string(self, text): diff --git a/addons/test_mass_mailing/tests/test_mailing.py b/addons/test_mass_mailing/tests/test_mailing.py index 4179327de94..c5a90927df5 100644 --- a/addons/test_mass_mailing/tests/test_mailing.py +++ b/addons/test_mass_mailing/tests/test_mailing.py @@ -119,6 +119,60 @@ class TestMassMailing(TestMassMailCommon): self.assertMailingStatistics(mailing, expected=5, delivered=4, sent=5, opened=1, clicked=1, bounced=1) self.assertEqual(recipients[1].message_bounce, 1) + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_reply_to_mode_new(self): + mailing = self.env['mailing.mailing'].browse(self.mailing_bl.ids) + recipients = self._create_mailing_test_records(model='mailing.test.blacklist', count=5) + self.assertEqual(len(recipients), 5) + initial_messages = recipients.message_ids + mailing.write({ + 'mailing_domain': [('id', 'in', recipients.ids)], + 'keep_archives': False, + 'reply_to_mode': 'email', + 'reply_to': self.test_alias.display_name, + }) + + with self.mock_mail_gateway(mail_unlink_sent=True): + mailing.action_send_mail() + + answer_rec = self.gateway_mail_reply_wemail(MAIL_TEMPLATE, recipients[0].email_normalized, target_model=self.test_alias.alias_model_id.model) + self.assertTrue(bool(answer_rec)) + self.assertEqual(answer_rec.name, 'Re: %s' % mailing.subject) + self.assertEqual( + answer_rec.message_ids.subject, 'Re: %s' % mailing.subject, + 'Answer should be logged') + self.assertEqual(recipients.message_ids, initial_messages) + + self.assertMailingStatistics(mailing, expected=5, delivered=5, sent=5, opened=1, replied=1) + + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_reply_to_mode_update(self): + mailing = self.env['mailing.mailing'].browse(self.mailing_bl.ids) + recipients = self._create_mailing_test_records(model='mailing.test.blacklist', count=5) + self.assertEqual(len(recipients), 5) + mailing.write({ + 'mailing_domain': [('id', 'in', recipients.ids)], + 'keep_archives': False, + 'reply_to_mode': 'thread', + 'reply_to': self.test_alias.display_name, + }) + + with self.mock_mail_gateway(mail_unlink_sent=True): + mailing.action_send_mail() + + answer_rec = self.gateway_mail_reply_wemail(MAIL_TEMPLATE, recipients[0].email_normalized, target_model=self.test_alias.alias_model_id.model) + self.assertFalse(bool(answer_rec)) + self.assertEqual( + recipients[0].message_ids[1].subject, mailing.subject, + 'Should have keep a log (to enable thread-based answer)') + self.assertEqual( + recipients[0].message_ids[0].subject, 'Re: %s' % mailing.subject, + 'Answer should be logged') + + self.assertMailingStatistics(mailing, expected=5, delivered=5, sent=5, opened=1, replied=1) + @users('user_marketing') @mute_logger('odoo.addons.mail.models.mail_thread') def test_mailing_trace_utm(self): From 59ce7d396930bbb6019249b09b2d9e509cc26bfc Mon Sep 17 00:00:00 2001 From: shreya thakrar Date: Tue, 19 Nov 2019 09:46:03 +0000 Subject: [PATCH 4/6] [IMP] mail, mass_mailing: ease "reply to" fields understanding PURPOSE Right now, `reply_to` field on email template is misleading due to poor explanation. This commit improves the placeholder and tooltip of the fields to make the purpose of the field clearer especially for non technical users. SPECIFICATIONS Update reply-to field placeholder to "Preferred email address when sending via mass mailing options". Update reply-to field helper message to "Preferred email address when sending via mass mailing options.
Only used when the answer is not added into the original discussion."" Update the no_auto_thread field label to "Reply to" in composer and introduce a new radio button replacing the checkbox * The original discussion (thread) * Another email address (new) Rename fields on mail_thread and wizard: ``no_auto_thread`` should be replaced to ``reply_to_force_new`` to ease understanding and be prefixed by reply_to. LINKS Task ID-2117639 COM PR odoo/odoo#40931 ENT PR odoo/enterprise#17941 UPG PR odoo/upgrade#2419 --- addons/mail/__manifest__.py | 2 +- addons/mail/models/mail_template.py | 2 +- addons/mail/views/mail_template_views.xml | 2 +- addons/mail/views/res_partner_views.xml | 2 +- addons/mail/wizard/mail_compose_message.py | 34 +++++++++++++------ .../mail/wizard/mail_compose_message_view.xml | 9 ++--- addons/mass_mailing/models/mailing.py | 2 +- .../wizard/mail_compose_message.py | 24 ++++++------- addons/test_mail/tests/test_mail_composer.py | 6 ++-- 9 files changed, 48 insertions(+), 35 deletions(-) diff --git a/addons/mail/__manifest__.py b/addons/mail/__manifest__.py index af4b10a36ca..326edbfacf0 100644 --- a/addons/mail/__manifest__.py +++ b/addons/mail/__manifest__.py @@ -2,7 +2,7 @@ { 'name': 'Discuss', - 'version': '1.3', + 'version': '1.4', 'category': 'Productivity/Discuss', 'sequence': 145, 'summary': 'Chat, mail gateway and private channels', diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index af9e3b57469..68b642fac90 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -43,7 +43,7 @@ class MailTemplate(models.Model): partner_to = fields.Char('To (Partners)', help="Comma-separated ids of recipient partners (placeholders may be used here)") email_cc = fields.Char('Cc', help="Carbon copy recipients (placeholders may be used here)") - reply_to = fields.Char('Reply-To', help="Preferred response address (placeholders may be used here)") + reply_to = fields.Char('Reply To', help="Email address to which replies will be redirected when sending emails in mass; only used when the reply is not logged in the original discussion thread.") # content body_html = fields.Html('Body', translate=True, sanitize=False) attachment_ids = fields.Many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id', diff --git a/addons/mail/views/mail_template_views.xml b/addons/mail/views/mail_template_views.xml index 14381000377..7626f6fe867 100644 --- a/addons/mail/views/mail_template_views.xml +++ b/addons/mail/views/mail_template_views.xml @@ -59,7 +59,7 @@ + placeholder="Email address to which replies will be redirected when sending emails in mass"/> diff --git a/addons/mail/views/res_partner_views.xml b/addons/mail/views/res_partner_views.xml index da5cc279ede..54aaaab18bb 100644 --- a/addons/mail/views/res_partner_views.xml +++ b/addons/mail/views/res_partner_views.xml @@ -111,7 +111,7 @@ 'default_composition_mode': 'mass_mail', 'default_partner_to': '${object.id or \'\'}', 'default_use_template': False, - 'default_no_auto_thread': True, + 'default_reply_to_force_new': True, }"/> list diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index db33cad58af..4ff8e19e2f3 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -67,10 +67,10 @@ class MailComposer(models.TransientModel): result['model'] = self._context.get('active_model') if 'res_id' in fields and 'res_id' not in result: result['res_id'] = self._context.get('active_id') - if 'no_auto_thread' in fields and 'no_auto_thread' not in result and result.get('model'): + if 'reply_to_mode' in fields and 'reply_to_mode' not in result and result.get('model'): # doesn't support threading if result['model'] not in self.env or not hasattr(self.env[result['model']], 'message_post'): - result['no_auto_thread'] = True + result['reply_to_mode'] = 'new' if 'active_domain' in self._context: # not context.get() because we want to keep global [] domains result['active_domain'] = '%s' % self._context.get('active_domain') @@ -123,10 +123,15 @@ class MailComposer(models.TransientModel): 'mail.activity.type', 'Mail Activity Type', index=True, ondelete='set null') # destination - reply_to = fields.Char('Reply-To', help='Reply email address. Setting the reply_to bypasses the automatic thread creation.') - no_auto_thread = fields.Boolean( - 'No threading for answers', - help='Answers do not go in the original document discussion thread. This has an impact on the generated message-id.') + reply_to = fields.Char('Reply To', help='Reply email address. Setting the reply_to bypasses the automatic thread creation.') + reply_to_force_new = fields.Boolean( + string='Considers answers as new thread', + help='Manage answers as new incoming emails instead of replies going to the same thread.') + reply_to_mode = fields.Selection([ + ('update', 'Log in the original discussion thread'), + ('new', 'Redirect to another email address')], + string='Replies', compute='_compute_reply_to_mode', inverse='_inverse_reply_to_mode', + help="Original Discussion: Answers go in the original document discussion thread. \n Another Email Address: Answers go to the email address mentioned in the tracking message-id instead of original document discussion thread. \n This has an impact on the generated message-id.") is_log = fields.Boolean('Log an Internal Note', help='Whether the message is an internal note (comment mode only)') partner_ids = fields.Many2many( @@ -140,6 +145,15 @@ class MailComposer(models.TransientModel): auto_delete_message = fields.Boolean('Delete Message Copy', help='Do not keep a copy of the email in the document communication history (mass mailing only)') mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing mail server') + @api.depends('reply_to_force_new') + def _compute_reply_to_mode(self): + for composer in self: + composer.reply_to_mode = 'new' if composer.reply_to_force_new else 'update' + + def _inverse_reply_to_mode(self): + for composer in self: + composer.reply_to_force_new = composer.reply_to_mode == 'new' + @api.model def get_record_data(self, values): """ Returns a defaults-like dict with initial values for the composition @@ -275,7 +289,7 @@ class MailComposer(models.TransientModel): rendered_values = self.render_message(res_ids) # compute alias-based reply-to in batch reply_to_value = dict.fromkeys(res_ids, None) - if mass_mail_mode and not self.no_auto_thread: + if mass_mail_mode and not self.reply_to_force_new: records = self.env[self.model].browse(res_ids) reply_to_value = records._notify_get_reply_to(default=self.email_from) @@ -301,7 +315,7 @@ class MailComposer(models.TransientModel): 'author_id': self.author_id.id, 'email_from': self.email_from, 'record_name': self.record_name, - 'no_auto_thread': self.no_auto_thread, + 'no_auto_thread': self.reply_to_force_new, 'mail_server_id': self.mail_server_id.id, 'mail_activity_type_id': self.mail_activity_type_id.id, } @@ -319,11 +333,11 @@ class MailComposer(models.TransientModel): email_dict = rendered_values[res_id] mail_values['partner_ids'] += email_dict.pop('partner_ids', []) mail_values.update(email_dict) - if not self.no_auto_thread: + if not self.reply_to_force_new: mail_values.pop('reply_to') if reply_to_value.get(res_id): mail_values['reply_to'] = reply_to_value[res_id] - if self.no_auto_thread and not mail_values.get('reply_to'): + if self.reply_to_force_new and not mail_values.get('reply_to'): mail_values['reply_to'] = mail_values['email_from'] # mail_mail values: body -> body_html, partner_ids -> recipient_ids mail_values['body_html'] = mail_values.get('body', '') diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml index 95a78247852..d8cac0c74c2 100644 --- a/addons/mail/wizard/mail_compose_message_view.xml +++ b/addons/mail/wizard/mail_compose_message_view.xml @@ -62,10 +62,11 @@ - - + + + diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index c4e3c1e9724..b8dabfe112b 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -631,7 +631,7 @@ class MassMailing(models.Model): 'composition_mode': 'mass_mail', 'mass_mailing_id': mailing.id, 'mailing_list_ids': [(4, l.id) for l in mailing.contact_list_ids], - 'no_auto_thread': mailing.reply_to_mode != 'thread', + 'reply_to_force_new': mailing.reply_to_mode != 'thread', 'template_id': None, 'mail_server_id': mailing.mail_server_id.id, } diff --git a/addons/mass_mailing/wizard/mail_compose_message.py b/addons/mass_mailing/wizard/mail_compose_message.py index 19a345a9e47..256b68398bd 100644 --- a/addons/mass_mailing/wizard/mail_compose_message.py +++ b/addons/mass_mailing/wizard/mail_compose_message.py @@ -25,20 +25,18 @@ class MailComposeMessage(models.TransientModel): self.env['ir.model'].sudo().search([('model', '=', self.model), ('is_mail_thread', '=', True)], limit=1): mass_mailing = self.mass_mailing_id if not mass_mailing: - reply_to_mode = 'email' if self.no_auto_thread else 'thread' - reply_to = self.reply_to if self.no_auto_thread else False mass_mailing = self.env['mailing.mailing'].create({ - 'campaign_id': self.campaign_id.id, - 'name': self.mass_mailing_name, - 'subject': self.subject, - 'state': 'done', - 'reply_to_mode': reply_to_mode, - 'reply_to': reply_to, - 'sent_date': fields.Datetime.now(), - 'body_html': self.body, - 'mailing_model_id': self.env['ir.model']._get(self.model).id, - 'mailing_domain': self.active_domain, - 'attachment_ids': [(6, 0, self.attachment_ids.ids)], + 'campaign_id': self.campaign_id.id, + 'name': self.mass_mailing_name, + 'subject': self.subject, + 'state': 'done', + 'reply_to_mode': self.reply_to_mode, + 'reply_to': self.reply_to if self.reply_to_mode == 'email' else False, + 'sent_date': fields.Datetime.now(), + 'body_html': self.body, + 'mailing_model_id': self.env['ir.model']._get(self.model).id, + 'mailing_domain': self.active_domain, + 'attachment_ids': [(6, 0, self.attachment_ids.ids)], }) # Preprocess res.partners to batch-fetch from db diff --git a/addons/test_mail/tests/test_mail_composer.py b/addons/test_mail/tests/test_mail_composer.py index 6c60ea3d293..17f8e1f5afb 100644 --- a/addons/test_mail/tests/test_mail_composer.py +++ b/addons/test_mail/tests/test_mail_composer.py @@ -110,7 +110,7 @@ class TestComposerForm(TestMailComposer): 'MailComposer: comment mode should have default subject Re: record_name') # record name not displayed currently in view # self.assertEqual(composer_form.record_name, self.test_record.name, 'MailComposer: comment mode should compute record name') - self.assertFalse(composer_form.no_auto_thread) + self.assertFalse(composer_form.reply_to_force_new) self.assertEqual(composer_form.composition_mode, 'comment') self.assertEqual(composer_form.model, self.test_record._name) @@ -172,7 +172,7 @@ class TestComposerForm(TestMailComposer): self.assertFalse(composer_form.subject, 'MailComposer: mass mode should have void default subject if no template') # record name not displayed currently in view # self.assertFalse(composer_form.record_name, 'MailComposer: mass mode should have void record name') - self.assertFalse(composer_form.no_auto_thread) + self.assertFalse(composer_form.reply_to_force_new) self.assertEqual(composer_form.composition_mode, 'mass_mail') self.assertEqual(composer_form.model, self.test_records._name) @@ -186,7 +186,7 @@ class TestComposerForm(TestMailComposer): 'MailComposer: mass mode should have template raw body if template') # record name not displayed currently in view # self.assertFalse(composer_form.record_name, 'MailComposer: mass mode should have void record name') - self.assertFalse(composer_form.no_auto_thread) + self.assertFalse(composer_form.reply_to_force_new) self.assertEqual(composer_form.composition_mode, 'mass_mail') self.assertEqual(composer_form.model, self.test_records._name) From e4cace71152b828635367a90000c8e86fc7205c5 Mon Sep 17 00:00:00 2001 From: shreya thakrar Date: Fri, 29 Nov 2019 09:38:12 +0000 Subject: [PATCH 5/6] [IMP] mail, test_mail, website_(form,sale): rename no_auto_thread field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PURPOSE Rename fields on mail_thread and wizard: ``no_auto_thread`` should be replaced to ``reply_to_force_new`` to ease understanding and be prefixed by reply_to. SPECIFICATIONS For better understanding, this commit renames ``no_auto_thread`` field of ``mail.message`` model to ``reply_to_force_new``, to indicate that if the field is checked (☑) replies should check gateway alias rules instead of updating mailed threads. It is also more coherent with reply_to namespacing used in various mail models (notably new composer fields and ``reply_to_mode`` of mass mailing and mail composer models) LINKS Task ID-2117639 COM PR odoo/odoo#40931 ENT PR odoo/enterprise#17941 UPG PR odoo/upgrade#2419 --- addons/mail/models/mail_message.py | 6 +++--- addons/mail/views/mail_message_views.xml | 2 +- addons/mail/wizard/invite.py | 2 +- addons/mail/wizard/mail_compose_message.py | 2 +- addons/test_mail/tests/test_mail_gateway.py | 4 ++-- addons/test_mail/tests/test_mail_message.py | 4 ++-- addons/website_form/controllers/main.py | 2 -- addons/website_sale/controllers/main.py | 1 - 8 files changed, 10 insertions(+), 13 deletions(-) diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index 64d580dcab4..36ea4ba46cf 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -156,9 +156,9 @@ class Message(models.Model): help='Tracked values are stored in a separate model. This field allow to reconstruct ' 'the tracking and to generate statistics on the model.') # mail gateway - no_auto_thread = fields.Boolean( + reply_to_force_new = fields.Boolean( 'No threading for answers', - help='Answers do not go in the original document discussion thread. This has an impact on the generated message-id.') + help='If true, answers do not go in the original document discussion thread. Instead, it will check for the reply_to in tracking message-id and redirected accordingly. This has an impact on the generated message-id.') message_id = fields.Char('Message-Id', help='Message unique identifier', index=True, readonly=1, copy=False) reply_to = fields.Char('Reply-To', help='Reply email address. Setting the reply_to bypasses the automatic thread creation.') mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing mail server') @@ -1207,7 +1207,7 @@ class Message(models.Model): @api.model def _get_message_id(self, values): - if values.get('no_auto_thread', False) is True: + if values.get('reply_to_force_new', False) is True: message_id = tools.generate_tracking_message_id('reply_to') elif self.is_thread_message(values): message_id = tools.generate_tracking_message_id('%(res_id)s-%(model)s' % values) diff --git a/addons/mail/views/mail_message_views.xml b/addons/mail/views/mail_message_views.xml index 401c4131e2c..57d3df6316b 100644 --- a/addons/mail/views/mail_message_views.xml +++ b/addons/mail/views/mail_message_views.xml @@ -52,7 +52,7 @@ - + diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index ffafa2788be..ef4400441ab 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -67,7 +67,7 @@ class Invite(models.TransientModel): 'reply_to': email_from, 'model': wizard.res_model, 'res_id': wizard.res_id, - 'no_auto_thread': True, + 'reply_to_force_new': True, 'add_sign': True, }) partners_data = [] diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 4ff8e19e2f3..1b0e4437160 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -315,7 +315,7 @@ class MailComposer(models.TransientModel): 'author_id': self.author_id.id, 'email_from': self.email_from, 'record_name': self.record_name, - 'no_auto_thread': self.reply_to_force_new, + 'reply_to_force_new': self.reply_to_force_new, 'mail_server_id': self.mail_server_id.id, 'mail_activity_type_id': self.mail_activity_type_id.id, } diff --git a/addons/test_mail/tests/test_mail_gateway.py b/addons/test_mail/tests/test_mail_gateway.py index 8da6b228b9f..b76e5d9752b 100644 --- a/addons/test_mail/tests/test_mail_gateway.py +++ b/addons/test_mail/tests/test_mail_gateway.py @@ -1043,14 +1043,14 @@ class TestMailgateway(TestMailCommon): first_record = self.env['mail.test.simple'].with_user(self.user_employee).create({'name': 'Replies to Record'}) record_msg = first_record.message_post( subject='Discussion', - no_auto_thread=False, + reply_to_force_new=False, subtype_xmlid='mail.mt_comment', ) self.assertEqual(record_msg.reply_to, formataddr(('%s %s' % (self.user_employee.company_id.name, first_record.name), '%s@%s' % ('catchall.test', 'test.com')))) mail_msg = first_record.message_post( subject='Replies to Record', reply_to='groups@test.com', - no_auto_thread=True, + reply_to_force_new=True, subtype_xmlid='mail.mt_comment', ) self.assertEqual(mail_msg.reply_to, 'groups@test.com') diff --git a/addons/test_mail/tests/test_mail_message.py b/addons/test_mail/tests/test_mail_message.py index 8cf04011b6b..c654d9f58fc 100644 --- a/addons/test_mail/tests/test_mail_message.py +++ b/addons/test_mail/tests/test_mail_message.py @@ -169,11 +169,11 @@ class TestMessageValues(TestMailCommon): self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) - def test_mail_message_values_no_auto_thread(self): + def test_mail_message_values_reply_to_force_new(self): msg = self.Message.create({ 'model': 'mail.test.container', 'res_id': self.alias_record.id, - 'no_auto_thread': True, + 'reply_to_force_new': True, }) self.assertIn('reply_to', msg.message_id.split('@')[0]) self.assertNotIn('mail.test.container', msg.message_id.split('@')[0]) diff --git a/addons/website_form/controllers/main.py b/addons/website_form/controllers/main.py index 3d3bdb87812..5a60a7e60a3 100644 --- a/addons/website_form/controllers/main.py +++ b/addons/website_form/controllers/main.py @@ -223,7 +223,6 @@ class WebsiteForm(http.Controller): 'body': nl2br(custom_content), 'model': model_name, 'message_type': 'comment', - 'no_auto_thread': False, 'res_id': record.id, } mail_id = request.env['mail.message'].with_user(SUPERUSER_ID).create(values) @@ -258,7 +257,6 @@ class WebsiteForm(http.Controller): 'body': _('

Attached files :

'), 'model': model_name, 'message_type': 'comment', - 'no_auto_thread': False, 'res_id': id_record, 'attachment_ids': [(6, 0, orphan_attachment_ids)], 'subtype_id': request.env['ir.model.data'].xmlid_to_res_id('mail.mt_comment'), diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 5c867047313..6e3433e9fa7 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -109,7 +109,6 @@ class WebsiteSaleForm(WebsiteForm): 'body': nl2br(data['custom']), 'model': 'sale.order', 'message_type': 'comment', - 'no_auto_thread': False, 'res_id': order.id, } request.env['mail.message'].with_user(SUPERUSER_ID).create(values) From c8aabac87d8098c4f532f0dc2e7f069df8e33bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 26 Apr 2021 13:40:52 +0000 Subject: [PATCH 6/6] [IMP] mass mailing: update reply_to_mode keys Propagate reply_to radio keys (update and new) to mass mailing in order to have a coherent naming (was thread and email). This naming is also coherent with gateway naming (message_update and message_new). LINKS Task ID-2117639 COM PR odoo/odoo#40931 ENT PR odoo/enterprise#17941 UPG PR odoo/upgrade#2419 --- addons/mass_mailing/__manifest__.py | 2 +- addons/mass_mailing/data/mass_mailing_demo.xml | 2 +- addons/mass_mailing/models/mailing.py | 14 +++++++------- .../mass_mailing/tests/test_mailing_internals.py | 16 ++++++++-------- .../mass_mailing/views/mailing_mailing_views.xml | 6 +++--- .../mass_mailing/wizard/mail_compose_message.py | 4 ++-- .../mass_mailing_crm/data/mass_mailing_demo.xml | 2 +- .../mass_mailing_sale/data/mass_mailing_demo.xml | 2 +- addons/test_mass_mailing/tests/common.py | 2 +- addons/test_mass_mailing/tests/test_mailing.py | 8 ++++---- .../test_mass_mailing/tests/test_performance.py | 4 ++-- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/addons/mass_mailing/__manifest__.py b/addons/mass_mailing/__manifest__.py index 69ae29f29c0..51f1bd6f86d 100644 --- a/addons/mass_mailing/__manifest__.py +++ b/addons/mass_mailing/__manifest__.py @@ -5,7 +5,7 @@ 'name': 'Email Marketing', 'summary': 'Design, send and track emails', 'description': "", - 'version': '2.3', + 'version': '2.4', 'sequence': 60, 'website': 'https://www.odoo.com/page/mailing', 'category': 'Marketing/Email Marketing', diff --git a/addons/mass_mailing/data/mass_mailing_demo.xml b/addons/mass_mailing/data/mass_mailing_demo.xml index 17674fb4136..15e9cc2b790 100644 --- a/addons/mass_mailing/data/mass_mailing_demo.xml +++ b/addons/mass_mailing/data/mass_mailing_demo.xml @@ -83,7 +83,7 @@ - email + new Info <info@yourcompany.example.com>
diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index b8dabfe112b..82abae99248 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -113,7 +113,7 @@ class MassMailing(models.Model): # mailing options mailing_type = fields.Selection([('mail', 'Email')], string="Mailing Type", default="mail", required=True) reply_to_mode = fields.Selection([ - ('thread', 'Recipient Followers'), ('email', 'Specified Email Address')], + ('update', 'Recipient Followers'), ('new', 'Specified Email Address')], string='Reply-To Mode', compute='_compute_reply_to_mode', readonly=False, store=True, help='Thread: replies go to target document. Email: replies are routed to a given email.') @@ -252,16 +252,16 @@ class MassMailing(models.Model): def _compute_reply_to_mode(self): for mailing in self: if mailing.mailing_model_real in ['res.partner', 'mailing.contact']: - mailing.reply_to_mode = 'email' + mailing.reply_to_mode = 'new' else: - mailing.reply_to_mode = 'thread' + mailing.reply_to_mode = 'update' @api.depends('reply_to_mode') def _compute_reply_to(self): for mailing in self: - if mailing.reply_to_mode == 'email' and not mailing.reply_to: + if mailing.reply_to_mode == 'new' and not mailing.reply_to: mailing.reply_to = self.env.user.email_formatted - elif mailing.reply_to_mode == 'thread': + elif mailing.reply_to_mode == 'update': mailing.reply_to = False @api.depends('mailing_model_name', 'contact_list_ids') @@ -631,11 +631,11 @@ class MassMailing(models.Model): 'composition_mode': 'mass_mail', 'mass_mailing_id': mailing.id, 'mailing_list_ids': [(4, l.id) for l in mailing.contact_list_ids], - 'reply_to_force_new': mailing.reply_to_mode != 'thread', + 'reply_to_force_new': mailing.reply_to_mode == 'new', 'template_id': None, 'mail_server_id': mailing.mail_server_id.id, } - if mailing.reply_to_mode == 'email': + if mailing.reply_to_mode == 'new': composer_values['reply_to'] = mailing.reply_to composer = self.env['mail.compose.message'].with_context(active_ids=res_ids).create(composer_values) diff --git a/addons/mass_mailing/tests/test_mailing_internals.py b/addons/mass_mailing/tests/test_mailing_internals.py index 967420bc8a5..361de85c299 100644 --- a/addons/mass_mailing/tests/test_mailing_internals.py +++ b/addons/mass_mailing/tests/test_mailing_internals.py @@ -72,7 +72,7 @@ class TestMassMailValues(MassMailCommon): self.assertEqual(mailing.medium_id, self.env.ref('utm.utm_medium_email')) self.assertEqual(mailing.mailing_model_name, 'res.partner') self.assertEqual(mailing.mailing_model_real, 'res.partner') - self.assertEqual(mailing.reply_to_mode, 'email') + self.assertEqual(mailing.reply_to_mode, 'new') self.assertEqual(mailing.reply_to, self.user_marketing.email_formatted) # default for partner: remove blacklisted self.assertEqual(literal_eval(mailing.mailing_domain), [('is_blacklisted', '=', False)]) @@ -89,7 +89,7 @@ class TestMassMailValues(MassMailCommon): }) self.assertEqual(mailing.mailing_model_name, 'mailing.list') self.assertEqual(mailing.mailing_model_real, 'mailing.contact') - self.assertEqual(mailing.reply_to_mode, 'email') + self.assertEqual(mailing.reply_to_mode, 'new') self.assertEqual(mailing.reply_to, self.email_reply_to) # default for mailing list: depends upon contact_list_ids self.assertEqual(literal_eval(mailing.mailing_domain), []) @@ -104,7 +104,7 @@ class TestMassMailValues(MassMailCommon): }) self.assertEqual(mailing.mailing_model_name, 'mail.channel') self.assertEqual(mailing.mailing_model_real, 'mail.channel') - self.assertEqual(mailing.reply_to_mode, 'thread') + self.assertEqual(mailing.reply_to_mode, 'update') self.assertFalse(mailing.reply_to) @users('user_marketing') @@ -225,7 +225,7 @@ class TestMassMailFeatures(MassMailCommon, CronMixinCase): 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, 'contact_list_ids': [(6, 0, self.mailing_list_1.ids)], 'keep_archives': True, - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'reply_to': self.email_reply_to, }) self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) @@ -241,7 +241,7 @@ class TestMassMailFeatures(MassMailCommon, CronMixinCase): self.mailing_list_1.contact_ids.message_ids.unlink() mailing = mailing.copy() mailing.write({ - 'reply_to_mode': 'thread', + 'reply_to_mode': 'update', }) self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) @@ -257,7 +257,7 @@ class TestMassMailFeatures(MassMailCommon, CronMixinCase): mailing = mailing.copy() mailing.write({ 'keep_archives': False, - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'reply_to': self.email_reply_to, }) self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) @@ -275,7 +275,7 @@ class TestMassMailFeatures(MassMailCommon, CronMixinCase): mailing = mailing.copy() mailing.write({ 'keep_archives': False, - 'reply_to_mode': 'thread', + 'reply_to_mode': 'update', }) self.assertEqual(self.mailing_list_1.contact_ids.message_ids, self.env['mail.message']) @@ -335,7 +335,7 @@ Website3: ${httpurl} External1: Youpie Email: test@odoo.com
""", 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'reply_to': self.email_reply_to, 'contact_list_ids': [(6, 0, self.mailing_list_1.ids)], 'keep_archives': True, diff --git a/addons/mass_mailing/views/mailing_mailing_views.xml b/addons/mass_mailing/views/mailing_mailing_views.xml index 127b8349cd1..1236fbd6431 100644 --- a/addons/mass_mailing/views/mailing_mailing_views.xml +++ b/addons/mass_mailing/views/mailing_mailing_views.xml @@ -241,14 +241,14 @@ }"/>
+ attrs="{'invisible': ['|', ('reply_to_mode', '=', 'update'), ('mailing_model_name', 'in', ['mailing.contact', 'res.partner', 'mailing.list'])],}"> To track replies, this address must belong to this database.
diff --git a/addons/mass_mailing/wizard/mail_compose_message.py b/addons/mass_mailing/wizard/mail_compose_message.py index 256b68398bd..39043268a3f 100644 --- a/addons/mass_mailing/wizard/mail_compose_message.py +++ b/addons/mass_mailing/wizard/mail_compose_message.py @@ -31,7 +31,7 @@ class MailComposeMessage(models.TransientModel): 'subject': self.subject, 'state': 'done', 'reply_to_mode': self.reply_to_mode, - 'reply_to': self.reply_to if self.reply_to_mode == 'email' else False, + 'reply_to': self.reply_to if self.reply_to_mode == 'new' else False, 'sent_date': fields.Datetime.now(), 'body_html': self.body, 'mailing_model_id': self.env['ir.model']._get(self.model).id, @@ -85,7 +85,7 @@ class MailComposeMessage(models.TransientModel): 'mailing_id': mass_mailing.id, 'mailing_trace_ids': [(0, 0, trace_vals)], # email-mode: keep original message for routing - 'notification': mass_mailing.reply_to_mode == 'thread', + 'notification': mass_mailing.reply_to_mode == 'update', 'auto_delete': not mass_mailing.keep_archives, }) return res diff --git a/addons/mass_mailing_crm/data/mass_mailing_demo.xml b/addons/mass_mailing_crm/data/mass_mailing_demo.xml index 41dcaf2d0eb..21817f9bcf9 100644 --- a/addons/mass_mailing_crm/data/mass_mailing_demo.xml +++ b/addons/mass_mailing_crm/data/mass_mailing_demo.xml @@ -11,7 +11,7 @@ [] - email + new ${object.company_id.email}
diff --git a/addons/mass_mailing_sale/data/mass_mailing_demo.xml b/addons/mass_mailing_sale/data/mass_mailing_demo.xml index c1872022fa3..d80d975c1e9 100644 --- a/addons/mass_mailing_sale/data/mass_mailing_demo.xml +++ b/addons/mass_mailing_sale/data/mass_mailing_demo.xml @@ -11,7 +11,7 @@ [] - email + new ${object.company_id.email}
diff --git a/addons/test_mass_mailing/tests/common.py b/addons/test_mass_mailing/tests/common.py index ff368bf59be..2a132a9656b 100644 --- a/addons/test_mass_mailing/tests/common.py +++ b/addons/test_mass_mailing/tests/common.py @@ -39,7 +39,7 @@ class TestMassMailCommon(MassMailCommon, TestMailCommon): """, 'mailing_type': 'mail', 'mailing_model_id': cls.env['ir.model']._get('mailing.test.blacklist').id, - 'reply_to_mode': 'thread', + 'reply_to_mode': 'update', }) @classmethod diff --git a/addons/test_mass_mailing/tests/test_mailing.py b/addons/test_mass_mailing/tests/test_mailing.py index c5a90927df5..7615d858a45 100644 --- a/addons/test_mass_mailing/tests/test_mailing.py +++ b/addons/test_mass_mailing/tests/test_mailing.py @@ -29,7 +29,7 @@ class TestMassMailing(TestMassMailCommon): 'name': 'TestName', 'subject': 'TestSubject', 'body_html': 'Hello ${object.name}', - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'reply_to': '%s@%s' % (self.test_alias.alias_name, self.test_alias.alias_domain), 'keep_archives': True, 'mailing_model_id': self.env['ir.model']._get('res.partner').id, @@ -129,7 +129,7 @@ class TestMassMailing(TestMassMailCommon): mailing.write({ 'mailing_domain': [('id', 'in', recipients.ids)], 'keep_archives': False, - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'reply_to': self.test_alias.display_name, }) @@ -155,7 +155,7 @@ class TestMassMailing(TestMassMailCommon): mailing.write({ 'mailing_domain': [('id', 'in', recipients.ids)], 'keep_archives': False, - 'reply_to_mode': 'thread', + 'reply_to_mode': 'update', 'reply_to': self.test_alias.display_name, }) @@ -191,7 +191,7 @@ class TestMassMailing(TestMassMailCommon): 'name': 'UTMTest', 'subject': subject, 'body_html': '

Hello ${object.name}

', - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'reply_to': '%s@%s' % (self.test_alias.alias_name, self.test_alias.alias_domain), 'keep_archives': True, 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, diff --git a/addons/test_mass_mailing/tests/test_performance.py b/addons/test_mass_mailing/tests/test_performance.py index 127857c4d4f..33ea1885522 100644 --- a/addons/test_mass_mailing/tests/test_performance.py +++ b/addons/test_mass_mailing/tests/test_performance.py @@ -45,7 +45,7 @@ class TestMassMailPerformance(TestMassMailPerformanceBase): 'name': 'Test', 'subject': 'Test', 'body_html': '

Hello quuxUnsubscribe

', - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'mailing_model_id': self.ref('test_mass_mailing.model_mailing_performance'), 'mailing_domain': [('id', 'in', self.mm_recs.ids)], }) @@ -85,7 +85,7 @@ class TestMassMailBlPerformance(TestMassMailPerformanceBase): 'name': 'Test', 'subject': 'Test', 'body_html': '

Hello quuxUnsubscribe

', - 'reply_to_mode': 'email', + 'reply_to_mode': 'new', 'mailing_model_id': self.ref('test_mass_mailing.model_mailing_performance_blacklist'), 'mailing_domain': [('id', 'in', self.mm_recs.ids)], })