[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. <br> 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
This commit is contained in:
shreya thakrar
2021-04-26 13:53:20 +00:00
committed by Thibault Delavallée
parent 4ef24369c8
commit 59ce7d3969
9 changed files with 48 additions and 35 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
{
'name': 'Discuss',
'version': '1.3',
'version': '1.4',
'category': 'Productivity/Discuss',
'sequence': 145,
'summary': 'Chat, mail gateway and private channels',
+1 -1
View File
@@ -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',
+1 -1
View File
@@ -59,7 +59,7 @@
<field name="email_cc" attrs="{'invisible': [('use_default_to', '=', True)]}"
placeholder="Comma-separated carbon copy recipients addresses"/>
<field name="reply_to"
placeholder="Preferred reply address"/>
placeholder="Email address to which replies will be redirected when sending emails in mass"/>
<field name="scheduled_date" string="Scheduled Send Date"/>
</group>
</page>
+1 -1
View File
@@ -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,
}"/>
<field name="binding_model_id" ref="base.model_res_partner"/>
<field name="binding_view_types">list</field>
+24 -10
View File
@@ -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', '')
@@ -62,10 +62,11 @@
<field name="notify"
attrs="{'invisible':[('composition_mode', '!=', 'mass_post')]}"/>
<!-- mass mailing -->
<field name="no_auto_thread" attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
<field name="reply_to" placeholder="Email address to redirect replies..."
attrs="{'invisible':['|', ('no_auto_thread', '=', False), ('composition_mode', '!=', 'mass_mail')],
'required':[('no_auto_thread', '=', True), ('composition_mode', '=', 'mass_mail')]}"/>
<field name="reply_to_force_new" invisible="1"/>
<field name="reply_to_mode" attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}" widget="radio"/>
<field name="reply_to" placeholder="Email address to which replies will be redirected"
attrs="{'invisible':['|', ('reply_to_mode', '=', 'update'), ('composition_mode', '!=', 'mass_mail')],
'required':[('reply_to_mode', '!=', 'update'), ('composition_mode', '=', 'mass_mail')]}"/>
</group>
<field name="body" options="{'style-inline': true}"/>
<group col="4">
+1 -1
View File
@@ -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,
}
@@ -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
+3 -3
View File
@@ -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)