From 59ce7d396930bbb6019249b09b2d9e509cc26bfc Mon Sep 17 00:00:00 2001 From: shreya thakrar Date: Tue, 19 Nov 2019 09:46:03 +0000 Subject: [PATCH] [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)