[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:
committed by
Thibault Delavallée
parent
4ef24369c8
commit
59ce7d3969
@@ -2,7 +2,7 @@
|
||||
|
||||
{
|
||||
'name': 'Discuss',
|
||||
'version': '1.3',
|
||||
'version': '1.4',
|
||||
'category': 'Productivity/Discuss',
|
||||
'sequence': 145,
|
||||
'summary': 'Chat, mail gateway and private channels',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user