From 4c76247a889cde3f9708d12e2f38de0c2c74cc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 13 Dec 2019 16:09:19 +0000 Subject: [PATCH 1/4] [FIX] test_mass_mailing: fix wrong model id given to test Due to some default values / model strange computation a wrong model was not considered as an invalid mailing. Let us fix tests so that models are correct. LINKS Task ID 2088577 PR #41877 Enterprise PR odoo/enterprise#7278 --- addons/test_mass_mailing/tests/test_mass_mailing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/test_mass_mailing/tests/test_mass_mailing.py b/addons/test_mass_mailing/tests/test_mass_mailing.py index 430438e76a0..47d372f986a 100644 --- a/addons/test_mass_mailing/tests/test_mass_mailing.py +++ b/addons/test_mass_mailing/tests/test_mass_mailing.py @@ -135,7 +135,7 @@ class TestAccessRights(TransactionCase): self.mass_mailing = mass_mailing.create({ 'name': 'One', 'subject': 'One', - 'mailing_model_id': self.env['ir.model']._get(mass_mailing_contacts).id, + 'mailing_model_id': self.env['ir.model']._get('mailing.contact').id, 'body_html': 'This is mass mail marketing demo'}) self.mass_mailing.contact_list_ids = [mailing_list_1.id] self.mass_mailing.action_put_in_queue() @@ -191,7 +191,7 @@ class TestAccessRights(TransactionCase): self.mass_mailing = mass_mailing.create({ 'name': 'One', 'subject': 'One', - 'mailing_model_id': self.env['ir.model']._get(mass_mailing_contacts).id, + 'mailing_model_id': self.env['ir.model']._get('mailing.contact').id, 'body_html': 'This is mass mail marketing demo'}) self.mass_mailing.contact_list_ids = [mailing_list_1.id, mailing_list_2.id] self.mass_mailing.action_put_in_queue() @@ -241,7 +241,7 @@ class TestAccessRights(TransactionCase): self.mass_mailing = mass_mailing.create({ 'name': 'One', 'subject': 'One', - 'mailing_model_id': self.env['ir.model']._get(mass_mailing_contacts).id, + 'mailing_model_id': self.env['ir.model']._get('mailing.contact').id, 'body_html': 'This is mass mail marketing demo'}) self.mass_mailing.contact_list_ids = [mailing_list_1.id] self.mass_mailing.action_put_in_queue() From ffe1d4047da181f97fafe2a69f64e6f283fbeb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Voet?= Date: Fri, 13 Dec 2019 11:48:36 +0000 Subject: [PATCH 2/4] [REF] mass_mailing: move from onchange / default to stored editable computed fields PURPOSE Try to move from onchange / default_get to stored editable computed fields. Normally behavior should be the same (computed or set by user), with support in create / write + onchange without additional code. SPECIFICATIONS Update classic fields with onchange to stored editable computed fields. It means their value will come either from manual user input, either computed based on triggers. Purpose is to remove all onchange and default_get when possible. Clean fields definition inconsistencies, like default / required on computed fields. Indeed computed fields should always have a value, maybe coming from user input. They should not have default / required that are attributes for classic fields. LINKS Task ID 2088577 PR #41877 Enterprise PR odoo/enterprise#7278 --- addons/mass_mailing/models/mailing.py | 124 ++++++++++-------- .../views/mailing_mailing_views.xml | 2 +- .../models/mailing_mailing.py | 11 +- .../models/mailing_mailing.py | 38 ++---- 4 files changed, 92 insertions(+), 83 deletions(-) diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index 999b3f824b0..50146c79a66 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -40,7 +40,7 @@ class MassMailing(models.Model): A mass mailing is an occurence of sending emails. """ _name = 'mailing.mailing' _description = 'Mass Mailing' - _inherit = [ 'mail.thread', 'mail.activity.mixin', 'mail.render.mixin'] + _inherit = ['mail.thread', 'mail.activity.mixin', 'mail.render.mixin'] # number of periods for tracking mail_mail statistics _period_number = 6 _order = 'sent_date DESC' @@ -56,16 +56,6 @@ class MassMailing(models.Model): except ValueError: return False - @api.model - def default_get(self, fields): - res = super(MassMailing, self).default_get(fields) - if 'reply_to_mode' in fields and not 'reply_to_mode' in res and res.get('mailing_model_real'): - if res['mailing_model_real'] in ['res.partner', 'mailing.contact']: - res['reply_to_mode'] = 'email' - else: - res['reply_to_mode'] = 'thread' - return res - active = fields.Boolean(default=True, tracking=True) subject = fields.Char('Subject', help='Subject of emails to send', required=True, translate=True) email_from = fields.Char(string='Send From', required=True, @@ -81,7 +71,10 @@ class MassMailing(models.Model): campaign_id = fields.Many2one('utm.campaign', string='UTM Campaign') source_id = fields.Many2one('utm.source', string='Source', required=True, ondelete='cascade', help="This is the link source, e.g. Search Engine, another domain, or name of email list") - medium_id = fields.Many2one('utm.medium', string='Medium', help="Delivery method: Email") + medium_id = fields.Many2one( + 'utm.medium', string='Medium', + compute='_compute_medium_id', readonly=False, store=True, + help="UTM Medium: delivery method (email, sms, ...)") clicks_ratio = fields.Integer(compute="_compute_clicks_ratio", string="Number of Clicks") state = fields.Selection([('draft', 'Draft'), ('in_queue', 'In Queue'), ('sending', 'Sending'), ('done', 'Sent')], string='Status', required=True, tracking=True, copy=False, default='draft', group_expand='_group_expand_states') @@ -89,21 +82,30 @@ class MassMailing(models.Model): user_id = fields.Many2one('res.users', string='Responsible', tracking=True, default=lambda self: self.env.user) # 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')], string='Reply-To Mode', required=True) - reply_to = fields.Char(string='Reply To', help='Preferred Reply-To Address', - default=lambda self: self.env.user.email_formatted) + reply_to_mode = fields.Selection([ + ('thread', 'Recipient Followers'), ('email', '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.') + reply_to = fields.Char( + string='Reply To', compute='_compute_reply_to', readonly=False, store=True, + help='Preferred Reply-To Address') # recipients - mailing_model_real = fields.Char(compute='_compute_model', string='Recipients Real Model', default='mailing.contact', required=True) - mailing_model_id = fields.Many2one('ir.model', string='Recipients Model', domain=[('model', 'in', MASS_MAILING_BUSINESS_MODELS)], + mailing_model_real = fields.Char(string='Recipients Real Model', compute='_compute_model') + mailing_model_id = fields.Many2one( + 'ir.model', string='Recipients Model', ondelete='cascade', required=True, + domain=[('model', 'in', MASS_MAILING_BUSINESS_MODELS)], default=lambda self: self.env.ref('mass_mailing.model_mailing_list').id) - mailing_model_name = fields.Char(related='mailing_model_id.model', string='Recipients Model Name', readonly=True, related_sudo=True) - mailing_domain = fields.Char(string='Domain', default=[]) + mailing_model_name = fields.Char( + string='Recipients Model Name', related='mailing_model_id.model', + readonly=True, related_sudo=True) + mailing_domain = fields.Char( + string='Domain', compute='_compute_mailing_domain', + readonly=False, store=True) mail_server_id = fields.Many2one('ir.mail_server', string='Mail Server', default=_get_default_mail_server_id, help="Use a specific mail server in priority. Otherwise Odoo relies on the first outgoing mail server available (based on their sequencing) as it does for normal mails.") - contact_list_ids = fields.Many2many('mailing.list', 'mail_mass_mailing_list_rel', - string='Mailing Lists') + contact_list_ids = fields.Many2many('mailing.list', 'mail_mass_mailing_list_rel', string='Mailing Lists') contact_ab_pc = fields.Integer(string='A/B Testing percentage', help='Percentage of the contacts that will be mailed. Recipients will be taken randomly.', default=100) unique_ab_testing = fields.Boolean(string='Allow A/B Testing', default=False, @@ -128,7 +130,7 @@ class MassMailing(models.Model): replied_ratio = fields.Integer(compute="_compute_statistics", string='Replied Ratio') bounced_ratio = fields.Integer(compute="_compute_statistics", string='Bounced Ratio') next_departure = fields.Datetime(compute="_compute_next_departure", string='Scheduled date') - + def _compute_total(self): for mass_mailing in self: mass_mailing.total = len(mass_mailing.sudo()._get_recipients()) @@ -147,11 +149,6 @@ class MassMailing(models.Model): for mass_mailing in self: mass_mailing.clicks_ratio = mapped_data.get(mass_mailing.id, 0) - @api.depends('mailing_model_id') - def _compute_model(self): - for record in self: - record.mailing_model_real = (record.mailing_model_name != 'mailing.list') and record.mailing_model_name or 'mailing.contact' - def _compute_statistics(self): """ Compute statistics of the mass mailing """ self.env.cr.execute(""" @@ -197,30 +194,53 @@ class MassMailing(models.Model): else: mass_mailing.next_departure = cron_time - @api.onchange('mailing_model_name', 'contact_list_ids') - def _onchange_model_and_list(self): - mailing_domain = literal_eval(self.mailing_domain) if self.mailing_domain else [] - if self.mailing_model_name: - if mailing_domain: - try: - self.env[self.mailing_model_name].search(mailing_domain, limit=1) - except: - mailing_domain = [] - if not mailing_domain: - if self.mailing_model_name == 'mailing.list' and self.contact_list_ids: - mailing_domain = [('list_ids', 'in', self.contact_list_ids.ids)] - elif 'is_blacklisted' in self.env[self.mailing_model_name]._fields and not self.mailing_domain: - mailing_domain = [('is_blacklisted', '=', False)] - elif 'opt_out' in self.env[self.mailing_model_name]._fields and not self.mailing_domain: - mailing_domain = [('opt_out', '=', False)] - else: - mailing_domain = [] - self.mailing_domain = repr(mailing_domain) + @api.depends('mailing_type') + def _compute_medium_id(self): + for mailing in self: + if mailing.mailing_type == 'mail' and not mailing.medium_id: + mailing.medium_id = self.env.ref('utm.utm_medium_email').id - @api.onchange('mailing_type') - def _onchange_mailing_type(self): - if self.mailing_type == 'mail' and not self.medium_id: - self.medium_id = self.env.ref('utm.utm_medium_email').id + @api.depends('mailing_model_id') + def _compute_model(self): + for record in self: + record.mailing_model_real = (record.mailing_model_name != 'mailing.list') and record.mailing_model_name or 'mailing.contact' + + @api.depends('mailing_model_real') + 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' + else: + mailing.reply_to_mode = 'thread' + + @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: + mailing.reply_to = self.env.user.email_formatted + elif mailing.reply_to_mode == 'thread': + mailing.reply_to = False + + @api.depends('mailing_model_name', 'contact_list_ids') + def _compute_mailing_domain(self): + for mailing in self: + mailing_domain = literal_eval(mailing.mailing_domain) if mailing.mailing_domain else [] + if mailing.mailing_model_name: + if mailing_domain: + try: + self.env[mailing.mailing_model_name].search(mailing_domain, limit=1) + except: + mailing_domain = [] + if not mailing_domain: + if mailing.mailing_model_name == 'mailing.list' and mailing.contact_list_ids: + mailing_domain = [('list_ids', 'in', mailing.contact_list_ids.ids)] + elif 'is_blacklisted' in self.env[mailing.mailing_model_name]._fields and not mailing.mailing_domain: + mailing_domain = [('is_blacklisted', '=', False)] + elif 'opt_out' in self.env[mailing.mailing_model_name]._fields and not mailing.mailing_domain: + mailing_domain = [('opt_out', '=', False)] + else: + mailing_domain = [] + mailing.mailing_domain = repr(mailing_domain) # ------------------------------------------------------ # ORM @@ -232,8 +252,6 @@ class MassMailing(models.Model): values['name'] = "%s %s" % (values['subject'], datetime.strftime(fields.datetime.now(), tools.DEFAULT_SERVER_DATETIME_FORMAT)) if values.get('body_html'): values['body_html'] = self._convert_inline_images_to_urls(values['body_html']) - if 'medium_id' not in values and values.get('mailing_type', 'mail') == 'mail': - values['medium_id'] = self.env.ref('utm.utm_medium_email').id return super(MassMailing, self).create(values) def write(self, values): diff --git a/addons/mass_mailing/views/mailing_mailing_views.xml b/addons/mass_mailing/views/mailing_mailing_views.xml index 53f60fcbbb6..414248e5034 100644 --- a/addons/mass_mailing/views/mailing_mailing_views.xml +++ b/addons/mass_mailing/views/mailing_mailing_views.xml @@ -144,7 +144,7 @@
-
diff --git a/addons/mass_mailing_event/models/mailing_mailing.py b/addons/mass_mailing_event/models/mailing_mailing.py index cf70517af1c..ac454e5877d 100644 --- a/addons/mass_mailing_event/models/mailing_mailing.py +++ b/addons/mass_mailing_event/models/mailing_mailing.py @@ -4,10 +4,11 @@ from odoo import models, api class MassMailingCampaign(models.Model): _inherit = "mailing.mailing" - @api.onchange('mailing_model_real', 'contact_list_ids') - def _onchange_model_and_list(self): + @api.depends('mailing_model_real', 'contact_list_ids') + def _compute_mailing_domain(self): # TDE FIXME: whuuut ? - result = super(MassMailingCampaign, self)._onchange_model_and_list() - if self.mailing_model_name == 'event.registration' and self.mailing_domain == '[]': - self.mailing_domain = self.env.context.get('default_mailing_domain', '[]') + result = super(MassMailingCampaign, self)._compute_mailing_domain() + for mailing in self: + if mailing.mailing_model_name == 'event.registration' and mailing.mailing_domain == '[]': + mailing.mailing_domain = self.env.context.get('default_mailing_domain', '[]') return result diff --git a/addons/mass_mailing_sms/models/mailing_mailing.py b/addons/mass_mailing_sms/models/mailing_mailing.py index 1738e03dc78..2f51dd7eeca 100644 --- a/addons/mass_mailing_sms/models/mailing_mailing.py +++ b/addons/mass_mailing_sms/models/mailing_mailing.py @@ -22,7 +22,7 @@ class Mailing(models.Model): # mailing options mailing_type = fields.Selection(selection_add=[('sms', 'SMS')]) # sms options - body_plaintext = fields.Text('SMS Body') + body_plaintext = fields.Text('SMS Body', compute='_compute_body_plaintext', store=True, readonly=False) sms_template_id = fields.Many2one('sms.template', string='SMS Template', ondelete='set null') sms_has_insufficient_credit = fields.Boolean( 'Insufficient IAP credits', compute='_compute_sms_has_insufficient_credit', @@ -32,17 +32,20 @@ class Mailing(models.Model): # opt_out_link sms_allow_unsubscribe = fields.Boolean('Include opt-out link', default=False) - @api.onchange('mailing_type') - def _onchange_mailing_type(self): - if self.mailing_type == 'sms' and (not self.medium_id or self.medium_id == self.env.ref('utm.utm_medium_email')): - self.medium_id = self.env.ref('mass_mailing_sms.utm_medium_sms').id - elif self.mailing_type == 'mail' and (not self.medium_id or self.medium_id == self.env.ref('mass_mailing_sms.utm_medium_sms')): - self.medium_id = self.env.ref('utm.utm_medium_email').id + @api.depends('mailing_type') + def _compute_medium_id(self): + super(Mailing, self)._compute_medium_id() + for mailing in self: + if mailing.mailing_type == 'sms' and (not mailing.medium_id or mailing.medium_id == self.env.ref('utm.utm_medium_email')): + mailing.medium_id = self.env.ref('mass_mailing_sms.utm_medium_sms').id + elif mailing.mailing_type == 'mail' and (not mailing.medium_id or mailing.medium_id == self.env.ref('mass_mailing_sms.utm_medium_sms')): + mailing.medium_id = self.env.ref('utm.utm_medium_email').id - @api.onchange('sms_template_id', 'mailing_type') - def _onchange_sms_template_id(self): - if self.mailing_type == 'sms' and self.sms_template_id: - self.body_plaintext = self.sms_template_id.body + @api.depends('sms_template_id', 'mailing_type') + def _compute_body_plaintext(self): + for mailing in self: + if mailing.mailing_type == 'sms' and mailing.sms_template_id: + mailing.body_plaintext = mailing.sms_template_id.body @api.depends('mailing_trace_ids.failure_type') def _compute_sms_has_insufficient_credit(self): @@ -54,19 +57,6 @@ class Mailing(models.Model): for mailing in self: mailing.sms_has_insufficient_credit = mailing in mailing_ids - # -------------------------------------------------- - # CRUD - # -------------------------------------------------- - - @api.model - def create(self, values): - if values.get('mailing_type') == 'sms': - if not values.get('medium_id'): - values['medium_id'] = self.env.ref('mass_mailing_sms.utm_medium_sms').id - if values.get('sms_template_id') and not values.get('body_plaintext'): - values['body_plaintext'] = self.env['sms.template'].browse(values['sms_template_id']).body - return super(Mailing, self).create(values) - # -------------------------------------------------- # BUSINESS / VIEWS ACTIONS # -------------------------------------------------- From 110decad006c89c6462308245a4f295c5bf570f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 16 Dec 2019 12:51:49 +0000 Subject: [PATCH 3/4] [REF] mass_mailing(_sms): force domain reset when changing model / type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit we rewrite the compute on mailing domain to simply reset it once the mailing domain is changed. Indeed trying to keep a previous domain based on try / except has no meaning from functional point of view. If model changes then domain should change as it is a business record, not just a technical domain to try to apply. LINKS Task ID 2088577 PR #41877 Enterprise PR odoo/enterprise#7278 Co-Authored-By: Thibault Delavallée Co-Authored-By: Aurélien Warnon --- addons/mass_mailing/models/mailing.py | 44 +++++++++---------- addons/mass_mailing_event/models/__init__.py | 1 - addons/mass_mailing_event/models/event.py | 6 +-- .../models/mailing_mailing.py | 14 ------ .../mass_mailing_event_track/models/event.py | 2 +- .../models/slide_channel.py | 2 +- .../models/mailing_mailing.py | 12 +++++ 7 files changed, 37 insertions(+), 44 deletions(-) delete mode 100644 addons/mass_mailing_event/models/mailing_mailing.py diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index 50146c79a66..ee16a00b1d9 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -224,23 +224,10 @@ class MassMailing(models.Model): @api.depends('mailing_model_name', 'contact_list_ids') def _compute_mailing_domain(self): for mailing in self: - mailing_domain = literal_eval(mailing.mailing_domain) if mailing.mailing_domain else [] - if mailing.mailing_model_name: - if mailing_domain: - try: - self.env[mailing.mailing_model_name].search(mailing_domain, limit=1) - except: - mailing_domain = [] - if not mailing_domain: - if mailing.mailing_model_name == 'mailing.list' and mailing.contact_list_ids: - mailing_domain = [('list_ids', 'in', mailing.contact_list_ids.ids)] - elif 'is_blacklisted' in self.env[mailing.mailing_model_name]._fields and not mailing.mailing_domain: - mailing_domain = [('is_blacklisted', '=', False)] - elif 'opt_out' in self.env[mailing.mailing_model_name]._fields and not mailing.mailing_domain: - mailing_domain = [('opt_out', '=', False)] + if not mailing.mailing_model_name: + mailing.mailing_domain = '' else: - mailing_domain = [] - mailing.mailing_domain = repr(mailing_domain) + mailing.mailing_domain = repr(mailing._get_default_mailing_domain()) # ------------------------------------------------------ # ORM @@ -492,16 +479,17 @@ class MassMailing(models.Model): } def _get_recipients(self): - if self.mailing_domain: - domain = safe_eval(self.mailing_domain) - res_ids = self.env[self.mailing_model_real].search(domain).ids - else: + try: + mailing_domain = literal_eval(self.mailing_domain) + except: res_ids = [] - domain = [('id', 'in', res_ids)] + mailing_domain = [('id', 'in', res_ids)] + else: + res_ids = self.env[self.mailing_model_real].search(mailing_domain).ids # randomly choose a fragment if self.contact_ab_pc < 100: - contact_nbr = self.env[self.mailing_model_real].search_count(domain) + contact_nbr = self.env[self.mailing_model_real].search_count(mailing_domain) topick = int(contact_nbr / 100.0 * self.contact_ab_pc) if self.campaign_id and self.unique_ab_testing: already_mailed = self.campaign_id._get_mailing_recipients()[self.campaign_id.id] @@ -592,6 +580,18 @@ class MassMailing(models.Model): # TOOLS # ------------------------------------------------------ + def _get_default_mailing_domain(self): + mailing_domain = [] + if self.mailing_model_name == 'mailing.list' and self.contact_list_ids: + mailing_domain = [('list_ids', 'in', self.contact_list_ids.ids)] + + if self.mailing_type == 'mail' and 'is_blacklisted' in self.env[self.mailing_model_name]._fields: + mailing_domain = expression.AND([[('is_blacklisted', '=', False)], mailing_domain]) + if self.mailing_type == 'mail' and 'opt_out' in self.env[self.mailing_model_name]._fields: + mailing_domain = expression.AND([[('opt_out', '=', False)], mailing_domain]) + + return mailing_domain + def _unsubscribe_token(self, res_id, email): """Generate a secure hash for this mailing list and parameters. diff --git a/addons/mass_mailing_event/models/__init__.py b/addons/mass_mailing_event/models/__init__.py index 87f0737c96a..80862024115 100644 --- a/addons/mass_mailing_event/models/__init__.py +++ b/addons/mass_mailing_event/models/__init__.py @@ -2,4 +2,3 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import event -from . import mailing_mailing diff --git a/addons/mass_mailing_event/models/event.py b/addons/mass_mailing_event/models/event.py index e0443acc7d3..88def04d85f 100644 --- a/addons/mass_mailing_event/models/event.py +++ b/addons/mass_mailing_event/models/event.py @@ -8,10 +8,6 @@ class Event(models.Model): _inherit = "event.event" def action_mass_mailing_attendees(self): - if len(self) == 1: - domain = "[('event_id', '=', {})]".format(self.id) - else: - domain = "[('event_id', 'in', {})]".format(self.ids) mass_mailing_action = dict( name='Mass Mail Attendees', type='ir.actions.act_window', @@ -20,7 +16,7 @@ class Event(models.Model): target='current', context=dict( default_mailing_model_id=self.env.ref('event.model_event_registration').id, - default_mailing_domain=domain, + default_mailing_domain=repr([('event_id', 'in', self.ids)]) ), ) return mass_mailing_action diff --git a/addons/mass_mailing_event/models/mailing_mailing.py b/addons/mass_mailing_event/models/mailing_mailing.py deleted file mode 100644 index ac454e5877d..00000000000 --- a/addons/mass_mailing_event/models/mailing_mailing.py +++ /dev/null @@ -1,14 +0,0 @@ -from odoo import models, api - - -class MassMailingCampaign(models.Model): - _inherit = "mailing.mailing" - - @api.depends('mailing_model_real', 'contact_list_ids') - def _compute_mailing_domain(self): - # TDE FIXME: whuuut ? - result = super(MassMailingCampaign, self)._compute_mailing_domain() - for mailing in self: - if mailing.mailing_model_name == 'event.registration' and mailing.mailing_domain == '[]': - mailing.mailing_domain = self.env.context.get('default_mailing_domain', '[]') - return result diff --git a/addons/mass_mailing_event_track/models/event.py b/addons/mass_mailing_event_track/models/event.py index c3395986fbd..c6210c728aa 100644 --- a/addons/mass_mailing_event_track/models/event.py +++ b/addons/mass_mailing_event_track/models/event.py @@ -16,7 +16,7 @@ class Event(models.Model): target='current', context=dict( default_mailing_model_id=self.env.ref('website_event_track.model_event_track').id, - default_mailing_domain="[('event_id', 'in', %s), ('stage_id.is_cancel', '!=', True)]" % self.ids, + default_mailing_domain=repr([('event_id', 'in', self.ids), ('stage_id.is_cancel', '!=', True)]), ), ) return mass_mailing_action diff --git a/addons/mass_mailing_slides/models/slide_channel.py b/addons/mass_mailing_slides/models/slide_channel.py index 7822dc8113d..1c781c02da3 100644 --- a/addons/mass_mailing_slides/models/slide_channel.py +++ b/addons/mass_mailing_slides/models/slide_channel.py @@ -8,7 +8,7 @@ class Course(models.Model): _inherit = "slide.channel" def action_mass_mailing_attendees(self): - domain = [('slide_channel_ids', 'in', self.ids)] + domain = repr([('slide_channel_ids', 'in', self.ids)]) mass_mailing_action = dict( name=_('Mass Mail Course Members'), type='ir.actions.act_window', diff --git a/addons/mass_mailing_sms/models/mailing_mailing.py b/addons/mass_mailing_sms/models/mailing_mailing.py index 2f51dd7eeca..d8064da6c0e 100644 --- a/addons/mass_mailing_sms/models/mailing_mailing.py +++ b/addons/mass_mailing_sms/models/mailing_mailing.py @@ -5,6 +5,7 @@ import logging from odoo import api, fields, models, _ from odoo.exceptions import UserError +from odoo.osv import expression _logger = logging.getLogger(__name__) @@ -209,3 +210,14 @@ class Mailing(models.Model): composer._action_send_sms() mailing.write({'state': 'done', 'sent_date': fields.Datetime.now()}) return True + + # -------------------------------------------------- + # TOOLS + # -------------------------------------------------- + + def _get_default_mailing_domain(self): + mailing_domain = super(Mailing, self)._get_default_mailing_domain() + if self.mailing_type == 'sms' and 'phone_blacklisted' in self.env[self.mailing_model_name]._fields: + mailing_domain = expression.AND([mailing_domain, [('phone_blacklisted', '=', False)]]) + + return mailing_domain From f807b636faa889bbca1c2bcdbe6af7c4818fff7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 16 Dec 2019 12:51:47 +0000 Subject: [PATCH 4/4] [IMP] mass_mailing: add some tests related to fields computation LINKS Task ID 2088577 PR #41877 Enterprise PR odoo/enterprise#7278 --- addons/mass_mailing/tests/__init__.py | 2 + addons/mass_mailing/tests/common.py | 37 ++++++++++ .../tests/test_mailing_internals.py | 73 +++++++++++++++++++ addons/mass_mailing_sms/tests/__init__.py | 1 + .../tests/test_mailing_internals.py | 61 ++++++++++++++++ 5 files changed, 174 insertions(+) create mode 100644 addons/mass_mailing/tests/common.py create mode 100644 addons/mass_mailing/tests/test_mailing_internals.py create mode 100644 addons/mass_mailing_sms/tests/test_mailing_internals.py diff --git a/addons/mass_mailing/tests/__init__.py b/addons/mass_mailing/tests/__init__.py index 36745d1525a..4d3ec554b79 100644 --- a/addons/mass_mailing/tests/__init__.py +++ b/addons/mass_mailing/tests/__init__.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import common +from . import test_mailing_internals from . import test_mass_mailing_list_merge from . import test_mass_mailing_shortener diff --git a/addons/mass_mailing/tests/common.py b/addons/mass_mailing/tests/common.py new file mode 100644 index 00000000000..3eb93ea226f --- /dev/null +++ b/addons/mass_mailing/tests/common.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.mail.tests.common import MailCase, mail_new_test_user +from odoo.tests.common import SavepointCase + + +class TestMassMailCommon(SavepointCase, MailCase): + + @classmethod + def setUpClass(cls): + super(TestMassMailCommon, cls).setUpClass() + + cls.user_marketing = mail_new_test_user( + cls.env, login='user_marketing', + groups='base.group_user,base.group_partner_manager,mass_mailing.group_mass_mailing_user', + name='Martial Marketing', signature='--\nMartial') + + cls.mailing_list_1 = cls.env['mailing.list'].create({ + 'name': 'List1', + 'contact_ids': [ + (0, 0, {'name': 'Déboulonneur', 'email': 'fleurus@example.com'}), + (0, 0, {'name': 'Gorramts', 'email': 'gorramts@example.com'}), + (0, 0, {'name': 'Ybrant', 'email': 'ybrant@example.com'}), + ] + }) + cls.mailing_list_2 = cls.env['mailing.list'].create({ + 'name': 'List2', + 'contact_ids': [ + (0, 0, {'name': 'Gilberte', 'email': 'gilberte@example.com'}), + (0, 0, {'name': 'Gilberte En Mieux', 'email': 'gilberte@example.com'}), + (0, 0, {'name': 'Norbert', 'email': 'norbert@example.com'}), + (0, 0, {'name': 'Ybrant', 'email': 'ybrant@example.com'}), + ] + }) + + cls.email_reply_to = 'MyCompany SomehowAlias ' diff --git a/addons/mass_mailing/tests/test_mailing_internals.py b/addons/mass_mailing/tests/test_mailing_internals.py new file mode 100644 index 00000000000..8f25119063d --- /dev/null +++ b/addons/mass_mailing/tests/test_mailing_internals.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from ast import literal_eval + +from odoo.addons.mass_mailing.tests.common import TestMassMailCommon +from odoo.tests.common import users +from odoo.tools import mute_logger + + +class TestMassMailValues(TestMassMailCommon): + + @users('user_marketing') + def test_mailing_computed_fields(self): + # Create on res.partner, with default values for computed fields + mailing = self.env['mailing.mailing'].create({ + 'name': 'TestMailing', + 'subject': 'Test', + 'mailing_type': 'mail', + 'body_html': '

Hello ${object.name}

', + 'mailing_model_id': self.env['ir.model']._get('res.partner').id, + }) + self.assertEqual(mailing.user_id, self.user_marketing) + 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, self.user_marketing.email_formatted) + # default for partner: remove blacklisted + self.assertEqual(literal_eval(mailing.mailing_domain), [('is_blacklisted', '=', False)]) + # update domain + mailing.write({ + 'mailing_domain': [('email', 'ilike', 'test.example.com')] + }) + self.assertEqual(literal_eval(mailing.mailing_domain), [('email', 'ilike', 'test.example.com')]) + + # reset mailing model -> reset domain; set reply_to -> keep it + mailing.write({ + 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, + 'reply_to': self.email_reply_to, + }) + 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, self.email_reply_to) + # default for mailing list: depends upon contact_list_ids + self.assertEqual(literal_eval(mailing.mailing_domain), []) + mailing.write({ + 'contact_list_ids': [(4, self.mailing_list_1.id), (4, self.mailing_list_2.id)] + }) + self.assertEqual(literal_eval(mailing.mailing_domain), [('list_ids', 'in', (self.mailing_list_1 | self.mailing_list_2).ids)]) + + # reset mailing model -> reset domain and reply to mode + mailing.write({ + 'mailing_model_id': self.env['ir.model']._get('mail.channel').id, + }) + self.assertEqual(mailing.mailing_model_name, 'mail.channel') + self.assertEqual(mailing.mailing_model_real, 'mail.channel') + self.assertEqual(mailing.reply_to_mode, 'thread') + self.assertFalse(mailing.reply_to) + + @users('user_marketing') + def test_mailing_computed_fields_default(self): + mailing = self.env['mailing.mailing'].with_context( + default_mailing_domain=repr([('email', 'ilike', 'test.example.com')]) + ).create({ + 'name': 'TestMailing', + 'subject': 'Test', + 'mailing_type': 'mail', + 'body_html': '

Hello ${object.name}

', + 'mailing_model_id': self.env['ir.model']._get('res.partner').id, + }) + self.assertEqual(literal_eval(mailing.mailing_domain), [('email', 'ilike', 'test.example.com')]) diff --git a/addons/mass_mailing_sms/tests/__init__.py b/addons/mass_mailing_sms/tests/__init__.py index 511e649c9e2..56c4c9c54f6 100644 --- a/addons/mass_mailing_sms/tests/__init__.py +++ b/addons/mass_mailing_sms/tests/__init__.py @@ -2,3 +2,4 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import common +from . import test_mailing_internals diff --git a/addons/mass_mailing_sms/tests/test_mailing_internals.py b/addons/mass_mailing_sms/tests/test_mailing_internals.py new file mode 100644 index 00000000000..049c41fae32 --- /dev/null +++ b/addons/mass_mailing_sms/tests/test_mailing_internals.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from ast import literal_eval + +from odoo.addons.mass_mailing.tests.common import TestMassMailCommon +from odoo.tests.common import users +from odoo.tools import mute_logger + + +class TestMassMailValues(TestMassMailCommon): + + @classmethod + def setUpClass(cls): + super(TestMassMailValues, cls).setUpClass() + + cls.sms_template_partner = cls.env['sms.template'].create({ + 'name': 'Test Template', + 'model_id': cls.env['ir.model']._get('res.partner').id, + 'body': 'Dear ${object.display_name} this is an SMS.' + }) + + @users('user_marketing') + def test_mailing_computed_fields(self): + # Create on res.partner, with default values for computed fields + mailing = self.env['mailing.mailing'].create({ + 'name': 'TestMailing', + 'subject': 'Test', + 'mailing_type': 'sms', + 'body_plaintext': 'Coucou hibou', + 'mailing_model_id': self.env['ir.model']._get('res.partner').id, + }) + self.assertEqual(mailing.user_id, self.user_marketing) + self.assertEqual(mailing.body_plaintext, 'Coucou hibou') + self.assertEqual(mailing.medium_id, self.env.ref('mass_mailing_sms.utm_medium_sms')) + self.assertEqual(mailing.mailing_model_name, 'res.partner') + self.assertEqual(mailing.mailing_model_real, 'res.partner') + # default for partner: remove blacklisted + self.assertEqual(literal_eval(mailing.mailing_domain), [('phone_blacklisted', '=', False)]) + # update template -> update body + mailing.write({'sms_template_id': self.sms_template_partner.id}) + self.assertEqual(mailing.body_plaintext, self.sms_template_partner.body) + # update domain + mailing.write({ + 'mailing_domain': [('email', 'ilike', 'test.example.com')] + }) + self.assertEqual(literal_eval(mailing.mailing_domain), [('email', 'ilike', 'test.example.com')]) + + # reset mailing model -> reset domain; set reply_to -> keep it + mailing.write({ + 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, + 'reply_to': self.email_reply_to, + }) + self.assertEqual(mailing.mailing_model_name, 'mailing.list') + self.assertEqual(mailing.mailing_model_real, 'mailing.contact') + # default for mailing list: depends upon contact_list_ids + self.assertEqual(literal_eval(mailing.mailing_domain), []) + mailing.write({ + 'contact_list_ids': [(4, self.mailing_list_1.id), (4, self.mailing_list_2.id)] + }) + self.assertEqual(literal_eval(mailing.mailing_domain), [('list_ids', 'in', (self.mailing_list_1 | self.mailing_list_2).ids)])