From fb1b25802b3b01d7ee9220466de67a1196e45ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Warnon?= Date: Wed, 16 Dec 2020 08:39:45 +0000 Subject: [PATCH] [IMP] mass_mailing[_sms]: send user feedback when testing mass mailings/sms This commit adds user feedback in the form of a message logged on the related document (mailing.mailing) when testing a mailing/sms. Before this change, when sending an email to your own mailbox for testing purpose, or when sending an SMS to your phone, you did not get any interface feedback on whether it worked or not. Now, a logged message will show if it's successful and if not, explain why it failed with a short error message (no IAP credits / misconfigured outgoing mail server / ...). In addition, email and phone inputs are now split on the '\n' character instead of a coma, which allows easier validation of the email addresses. Task-2375526 closes odoo/odoo#63421 Signed-off-by: Thibault Delavallee (tde) --- .../wizard/mailing_mailing_test.py | 47 ++++++++++++++++--- .../wizard/mailing_mailing_test_views.xml | 6 +-- .../wizard/mailing_sms_test.py | 45 ++++++++++++++---- .../wizard/mailing_sms_test_views.xml | 4 +- addons/sms/models/sms_api.py | 20 +++++++- 5 files changed, 100 insertions(+), 22 deletions(-) diff --git a/addons/mass_mailing/wizard/mailing_mailing_test.py b/addons/mass_mailing/wizard/mailing_mailing_test.py index e3c1970afae..595425638a0 100644 --- a/addons/mass_mailing/wizard/mailing_mailing_test.py +++ b/addons/mass_mailing/wizard/mailing_mailing_test.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import fields, models, tools +from odoo import _, fields, models, tools class TestMassMailing(models.TransientModel): _name = 'mailing.mailing.test' _description = 'Sample Mail Wizard' - email_to = fields.Char(string='Recipients', required=True, - help='Comma-separated list of email addresses.', default=lambda self: self.env.user.email_formatted) + email_to = fields.Text(string='Recipients', required=True, + help='Carriage-return-separated list of email addresses.', default=lambda self: self.env.user.email_formatted) mass_mailing_id = fields.Many2one('mailing.mailing', string='Mailing', required=True, ondelete='cascade') def send_mail_test(self): @@ -19,8 +19,16 @@ class TestMassMailing(models.TransientModel): self = self.with_context(ctx) mails_sudo = self.env['mail.mail'].sudo() + valid_emails = [] + invalid_candidates = [] + for candidate in self.email_to.splitlines(): + test_email = tools.email_split(candidate) + if test_email: + valid_emails.append(test_email[0]) + else: + invalid_candidates.append(candidate) + mailing = self.mass_mailing_id - test_emails = tools.email_split(self.email_to) mass_mail_layout = self.env.ref('mass_mailing.mass_mailing_mail_layout') record = self.env[mailing.mailing_model_real].search([], limit=1) @@ -38,20 +46,45 @@ class TestMassMailing(models.TransientModel): body = self.env['mail.render.mixin']._replace_local_links(body) body = tools.html_sanitize(body, sanitize_attributes=True, sanitize_style=True) - for test_mail in test_emails: + for valid_email in valid_emails: mail_values = { 'email_from': mailing.email_from, 'reply_to': mailing.reply_to, - 'email_to': test_mail, + 'email_to': valid_email, 'subject': subject, 'body_html': mass_mail_layout._render({'body': body}, engine='ir.qweb', minimal_qcontext=True), 'notification': True, 'mailing_id': mailing.id, 'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids], - 'auto_delete': True, + 'auto_delete': False, # they are manually deleted after notifying the document 'mail_server_id': mailing.mail_server_id.id, } mail = self.env['mail.mail'].sudo().create(mail_values) mails_sudo |= mail mails_sudo.send() + + notification_messages = [] + if invalid_candidates: + notification_messages.append( + _('Mailing addresses incorrect: %s', ', '.join(invalid_candidates))) + + for mail_sudo in mails_sudo: + if mail_sudo.state == 'sent': + notification_messages.append( + _('Test mailing successfully sent to %s', mail_sudo.email_to)) + elif mail_sudo.state == 'exception': + notification_messages.append( + _('Test mailing could not be sent to %s:
%s', + mail_sudo.email_to, + mail_sudo.failure_reason) + ) + + # manually delete the emails since we passed 'auto_delete: False' + mails_sudo.unlink() + + if notification_messages: + self.mass_mailing_id._message_log(body='' % ''.join( + ['
  • %s
  • ' % notification_message for notification_message in notification_messages] + )) + return True diff --git a/addons/mass_mailing/wizard/mailing_mailing_test_views.xml b/addons/mass_mailing/wizard/mailing_mailing_test_views.xml index 901f5c9105d..6927ac95be6 100644 --- a/addons/mass_mailing/wizard/mailing_mailing_test_views.xml +++ b/addons/mass_mailing/wizard/mailing_mailing_test_views.xml @@ -7,13 +7,13 @@

    - Send a sample email for testing purpose to the address below. + Send a sample mailing for testing purpose to the address below.

    - +
    -
    diff --git a/addons/mass_mailing_sms/wizard/mailing_sms_test.py b/addons/mass_mailing_sms/wizard/mailing_sms_test.py index 1ea9f8718eb..79c4de437c1 100644 --- a/addons/mass_mailing_sms/wizard/mailing_sms_test.py +++ b/addons/mass_mailing_sms/wizard/mailing_sms_test.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, exceptions, fields, models, _ +from odoo import fields, models, _ from odoo.addons.phone_validation.tools import phone_validation @@ -12,28 +12,55 @@ class MassSMSTest(models.TransientModel): def _default_numbers(self): return self.env.user.partner_id.phone_sanitized or "" - numbers = fields.Char(string='Number(s)', required=True, - default=_default_numbers, help='Comma-separated list of phone numbers') + numbers = fields.Text(string='Number(s)', required=True, + default=_default_numbers, help='Carriage-return-separated list of phone numbers') mailing_id = fields.Many2one('mailing.mailing', string='Mailing', required=True, ondelete='cascade') def action_send_sms(self): self.ensure_one() - numbers = [number.strip() for number in self.numbers.split(',')] + + numbers = [number.strip() for number in self.numbers.splitlines()] sanitize_res = phone_validation.phone_sanitize_numbers_w_record(numbers, self.env.user) sanitized_numbers = [info['sanitized'] for info in sanitize_res.values() if info['sanitized']] invalid_numbers = [number for number, info in sanitize_res.items() if info['code']] - if invalid_numbers: - raise exceptions.UserError(_('Following numbers are not correctly encoded: %s, example : "+32 495 85 85 77, +33 545 55 55 55"', repr(invalid_numbers))) - + record = self.env[self.mailing_id.mailing_model_real].search([], limit=1) body = self.mailing_id.body_plaintext if record: # Returns a proper error if there is a syntax error with jinja body = self.env['mail.render.mixin']._render_template(body, self.mailing_id.mailing_model_real, record.ids)[record.id] - self.env['sms.api']._send_sms_batch([{ - 'res_id': 0, + # res_id is used to map the result to the number to log notifications as IAP does not return numbers... + # TODO: clean IAP to make it return a clean dict with numbers / use custom keys / rename res_id to external_id + sent_sms_list = self.env['sms.api']._send_sms_batch([{ + 'res_id': number, 'number': number, 'content': body, } for number in sanitized_numbers]) + + error_messages = {} + if any(sent_sms.get('state') != 'success' for sent_sms in sent_sms_list): + error_messages = self.env['sms.api']._get_sms_api_error_messages() + + notification_messages = [] + if invalid_numbers: + notification_messages.append(_('The following numbers are not correctly encoded: %s', + ', '.join(invalid_numbers))) + + for sent_sms in sent_sms_list: + if sent_sms.get('state') == 'success': + notification_messages.append( + _('Test SMS successfully sent to %s', sent_sms.get('res_id'))) + elif sent_sms.get('state'): + notification_messages.append( + _('Test SMS could not be sent to %s:
    %s', + sent_sms.get('res_id'), + error_messages.get(sent_sms['state'], _("An error occurred."))) + ) + + if notification_messages: + self.mailing_id._message_log(body='
      %s
    ' % ''.join( + ['
  • %s
  • ' % notification_message for notification_message in notification_messages] + )) + return True diff --git a/addons/mass_mailing_sms/wizard/mailing_sms_test_views.xml b/addons/mass_mailing_sms/wizard/mailing_sms_test_views.xml index 09656dd1226..8b8713fe35f 100644 --- a/addons/mass_mailing_sms/wizard/mailing_sms_test_views.xml +++ b/addons/mass_mailing_sms/wizard/mailing_sms_test_views.xml @@ -6,10 +6,10 @@

    - Send a sample SMS for testing purpose to the numbers below (comma-separated list). + Send a sample SMS for testing purpose to the numbers below (carriage-return-separated list).

    - +