diff --git a/mass_mailing_custom_unsubscribe/__manifest__.py b/mass_mailing_custom_unsubscribe/__manifest__.py index 7ecae46..f723c5c 100644 --- a/mass_mailing_custom_unsubscribe/__manifest__.py +++ b/mass_mailing_custom_unsubscribe/__manifest__.py @@ -3,32 +3,25 @@ # Copyright 2020 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Customizable unsubscription process on mass mailing emails', - 'summary': 'Know and track (un)subscription reasons, GDPR compliant', - 'category': 'Marketing', - 'version': '12.0.1.0.2', - 'depends': [ - 'mass_mailing', + "name": "Customizable unsubscription process on mass mailing emails", + "summary": "Know and track (un)subscription reasons, GDPR compliant", + "category": "Marketing", + "version": "12.0.1.0.2", + "depends": ["mass_mailing"], + "data": [ + "security/ir.model.access.csv", + "data/mail_unsubscription_reason.xml", + "templates/general_reason_form.xml", + "templates/mass_mailing_contact_reason.xml", + "views/assets.xml", + "views/mail_unsubscription_reason_view.xml", + "views/mail_mass_mailing_list_view.xml", + "views/mail_unsubscription_view.xml", ], - 'data': [ - 'security/ir.model.access.csv', - 'data/mail_unsubscription_reason.xml', - 'templates/general_reason_form.xml', - 'templates/mass_mailing_contact_reason.xml', - 'views/assets.xml', - 'views/mail_unsubscription_reason_view.xml', - 'views/mail_mass_mailing_list_view.xml', - 'views/mail_unsubscription_view.xml', - ], - 'demo': [ - 'demo/assets.xml', - ], - 'images': [ - 'images/form.png', - ], - 'author': 'Tecnativa,' - 'Odoo Community Association (OCA)', - 'website': 'https://github.com/OCA/social', - 'license': 'AGPL-3', - 'installable': True, + "demo": ["demo/assets.xml"], + "images": ["images/form.png"], + "author": "Tecnativa," "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/social", + "license": "AGPL-3", + "installable": True, } diff --git a/mass_mailing_custom_unsubscribe/controllers/main.py b/mass_mailing_custom_unsubscribe/controllers/main.py index 37c2ab7..0db8084 100644 --- a/mass_mailing_custom_unsubscribe/controllers/main.py +++ b/mass_mailing_custom_unsubscribe/controllers/main.py @@ -6,6 +6,7 @@ import logging from odoo.http import request, route + from odoo.addons.mass_mailing.controllers.main import MassMailController _logger = logging.getLogger(__name__) @@ -35,14 +36,15 @@ class CustomUnsubscribe(MassMailController): "reasons": reasons, "res_id": res_id, "token": token, - }) + }, + ) @route() def mailing(self, mailing_id, email=None, res_id=None, token="", **post): """Ask/save unsubscription reason.""" _logger.debug( - "Called `mailing()` with: %r", - (mailing_id, email, res_id, token, post)) + "Called `mailing()` with: %r", (mailing_id, email, res_id, token, post) + ) reasons = request.env["mail.unsubscription.reason"].search([]) res_id = res_id and int(res_id) try: @@ -55,67 +57,89 @@ class CustomUnsubscribe(MassMailController): # Unsubscribe, saving reason and details by context details = post.get("details", False) self._add_extra_context(mailing_id, res_id, reason_id, details) - mailing_obj = request.env['mail.mass_mailing'] + mailing_obj = request.env["mail.mass_mailing"] mass_mailing = mailing_obj.sudo().browse(mailing_id) model = mass_mailing.mailing_model_real - if ("opt_out" in request.env[model]._fields and - model != "mail.mass_mailing.contact"): + if ( + "opt_out" in request.env[model]._fields + and model != "mail.mass_mailing.contact" + ): mass_mailing.update_opt_out_other(email, [res_id], True) - result = request.render("mass_mailing.page_unsubscribed", { - "email": email, - "mailing_id": mailing_id, - "res_id": res_id, - "show_blacklist_button": request.env[ - "ir.config_parameter" - ].sudo().get_param( - "mass_mailing.show_blacklist_buttons" - ), - }) + result = request.render( + "mass_mailing.page_unsubscribed", + { + "email": email, + "mailing_id": mailing_id, + "res_id": res_id, + "show_blacklist_button": request.env["ir.config_parameter"] + .sudo() + .get_param("mass_mailing.show_blacklist_buttons"), + }, + ) result.qcontext.update({"reasons": reasons}) else: # You could get a DetailsRequiredError here, but only if HTML5 # validation fails, which should not happen in modern browsers - result = super().mailing( - mailing_id, email, res_id, token=token, **post) + result = super().mailing(mailing_id, email, res_id, token=token, **post) if model == "mail.mass_mailing.contact": # update list_ids taking into account # not_cross_unsubscriptable field - result.qcontext.update({ - "reasons": reasons, - "list_ids": result.qcontext["list_ids"].filtered( - lambda mailing_list: - not mailing_list.not_cross_unsubscriptable or - mailing_list in mass_mailing.contact_list_ids - ) - }) + result.qcontext.update( + { + "reasons": reasons, + "list_ids": result.qcontext["list_ids"].filtered( + lambda m_list: not m_list.not_cross_unsubscriptable + or m_list in mass_mailing.contact_list_ids + ), + } + ) return result @route() - def unsubscribe(self, mailing_id, opt_in_ids, opt_out_ids, email, res_id, - token, reason_id=None, details=None): + def unsubscribe( + self, + mailing_id, + opt_in_ids, + opt_out_ids, + email, + res_id, + token, + reason_id=None, + details=None, + ): """Store unsubscription reasons when unsubscribing from RPC.""" # Update request context self._add_extra_context(mailing_id, res_id, reason_id, details) _logger.debug( "Called `unsubscribe()` with: %r", - (mailing_id, opt_in_ids, opt_out_ids, email, res_id, token, - reason_id, details)) + ( + mailing_id, + opt_in_ids, + opt_out_ids, + email, + res_id, + token, + reason_id, + details, + ), + ) return super().unsubscribe( - mailing_id, opt_in_ids, opt_out_ids, email, res_id, token) + mailing_id, opt_in_ids, opt_out_ids, email, res_id, token + ) @route() - def blacklist_add(self, mailing_id, res_id, email, token, reason_id=None, - details=None): + def blacklist_add( + self, mailing_id, res_id, email, token, reason_id=None, details=None + ): self._add_extra_context(mailing_id, res_id, reason_id, details) - return super().blacklist_add( - mailing_id, res_id, email, token) + return super().blacklist_add(mailing_id, res_id, email, token) @route() - def blacklist_remove(self, mailing_id, res_id, email, token, - reason_id=None, details=None): + def blacklist_remove( + self, mailing_id, res_id, email, token, reason_id=None, details=None + ): self._add_extra_context(mailing_id, res_id, reason_id, details) - return super().blacklist_remove( - mailing_id, res_id, email, token) + return super().blacklist_remove(mailing_id, res_id, email, token) def _add_extra_context(self, mailing_id, res_id, reason_id, details): environ = request.httprequest.headers.environ @@ -123,11 +147,8 @@ class CustomUnsubscribe(MassMailController): # redefinition of _add and _remove methods of the mail.blacklist class extra_context = { "default_metadata": "\n".join( - "%s: %s" % (val, environ.get(val)) for val in ( - "REMOTE_ADDR", - "HTTP_USER_AGENT", - "HTTP_ACCEPT_LANGUAGE", - ) + "{}: {}".format(val, environ.get(val)) + for val in ("REMOTE_ADDR", "HTTP_USER_AGENT", "HTTP_ACCEPT_LANGUAGE") ), "mailing_id": mailing_id, "unsubscription_res_id": int(res_id), diff --git a/mass_mailing_custom_unsubscribe/models/mail_blacklist.py b/mass_mailing_custom_unsubscribe/models/mail_blacklist.py index 40fdd90..29746e7 100644 --- a/mass_mailing_custom_unsubscribe/models/mail_blacklist.py +++ b/mass_mailing_custom_unsubscribe/models/mail_blacklist.py @@ -5,34 +5,36 @@ from odoo import models class MailBlackList(models.Model): - _inherit = 'mail.blacklist' + _inherit = "mail.blacklist" def _add(self, email): - mailing_id = self.env.context.get('mailing_id') - res_id = self.env.context.get('unsubscription_res_id') + mailing_id = self.env.context.get("mailing_id") + res_id = self.env.context.get("unsubscription_res_id") if mailing_id and res_id: - mailing = self.env['mail.mass_mailing'].browse(mailing_id, - self._prefetch) + mailing = self.env["mail.mass_mailing"].browse(mailing_id, self._prefetch) model_name = mailing.mailing_model_real - self.env["mail.unsubscription"].create({ - "email": email, - "mass_mailing_id": mailing_id, - "unsubscriber_id": "%s,%d" % (model_name, res_id), - "action": "blacklist_add", - }) + self.env["mail.unsubscription"].create( + { + "email": email, + "mass_mailing_id": mailing_id, + "unsubscriber_id": "%s,%d" % (model_name, res_id), + "action": "blacklist_add", + } + ) return super()._add(email) def _remove(self, email): - mailing_id = self.env.context.get('mailing_id') - res_id = self.env.context.get('unsubscription_res_id') + mailing_id = self.env.context.get("mailing_id") + res_id = self.env.context.get("unsubscription_res_id") if mailing_id and res_id: - mailing = self.env['mail.mass_mailing'].browse(mailing_id, - self._prefetch) + mailing = self.env["mail.mass_mailing"].browse(mailing_id, self._prefetch) model_name = mailing.mailing_model_real - self.env["mail.unsubscription"].create({ - "email": email, - "mass_mailing_id": mailing_id, - "unsubscriber_id": "%s,%d" % (model_name, res_id), - "action": "blacklist_rm", - }) + self.env["mail.unsubscription"].create( + { + "email": email, + "mass_mailing_id": mailing_id, + "unsubscriber_id": "%s,%d" % (model_name, res_id), + "action": "blacklist_rm", + } + ) return super()._remove(email) diff --git a/mass_mailing_custom_unsubscribe/models/mail_mass_mailing.py b/mass_mailing_custom_unsubscribe/models/mail_mass_mailing.py index 0fd71a2..20d6e48 100644 --- a/mass_mailing_custom_unsubscribe/models/mail_mass_mailing.py +++ b/mass_mailing_custom_unsubscribe/models/mail_mass_mailing.py @@ -2,9 +2,10 @@ # Copyright 2020 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from itertools import groupby + from odoo import models, tools from odoo.tools.safe_eval import safe_eval -from itertools import groupby class MailMassMailing(models.Model): @@ -14,61 +15,65 @@ class MailMassMailing(models.Model): """Save unsubscription reason when opting out from mailing.""" self.ensure_one() action = "unsubscription" if value else "subscription" - subscription_model = self.env['mail.mass_mailing.list_contact_rel'] - opt_out_records = subscription_model.search([ - ('contact_id.email', '=ilike', email), - ('list_id', 'in', list_ids), - ('opt_out', '!=', value), - ]) - model_name = 'mail.mass_mailing.contact' - for contact, subscriptions in groupby(opt_out_records, - lambda r: r.contact_id): + subscription_model = self.env["mail.mass_mailing.list_contact_rel"] + opt_out_records = subscription_model.search( + [ + ("contact_id.email", "=ilike", email), + ("list_id", "in", list_ids), + ("opt_out", "!=", value), + ] + ) + model_name = "mail.mass_mailing.contact" + for contact, subscriptions in groupby(opt_out_records, lambda r: r.contact_id): mailing_list_ids = [r.list_id.id for r in subscriptions] # reason_id and details are expected from the context - self.env["mail.unsubscription"].create({ - "email": email, - "mass_mailing_id": self.id, - "unsubscriber_id": "%s,%d" % (model_name, contact.id), - 'mailing_list_ids': [(6, False, mailing_list_ids)], - "action": action, - }) + self.env["mail.unsubscription"].create( + { + "email": email, + "mass_mailing_id": self.id, + "unsubscriber_id": "%s,%d" % (model_name, contact.id), + "mailing_list_ids": [(6, False, mailing_list_ids)], + "action": action, + } + ) return super().update_opt_out(email, list_ids, value) def update_opt_out_other(self, email, res_ids, value): """Method for changing unsubscription for models with opt_out field.""" - model = self.env[self.mailing_model_real].with_context( - active_test=False) + model = self.env[self.mailing_model_real].with_context(active_test=False) action = "unsubscription" if value else "subscription" - if 'opt_out' in model._fields: - email_fname = 'email_from' - if 'email' in model._fields: - email_fname = 'email' - records = model.search([ - ('id', 'in', res_ids), (email_fname, 'ilike', email)]) - records.write({'opt_out': value}) + if "opt_out" in model._fields: + email_fname = "email_from" + if "email" in model._fields: + email_fname = "email" + records = model.search( + [("id", "in", res_ids), (email_fname, "ilike", email)] + ) + records.write({"opt_out": value}) for res_id in res_ids: - self.env["mail.unsubscription"].create({ - "email": email, - "mass_mailing_id": self.id, - "unsubscriber_id": "%s,%d" % ( - self.mailing_model_real, res_id), - "action": action, - }) + self.env["mail.unsubscription"].create( + { + "email": email, + "mass_mailing_id": self.id, + "unsubscriber_id": "%s,%d" % (self.mailing_model_real, res_id), + "action": action, + } + ) def _get_opt_out_list(self): """Handle models with opt_out field for excluding them.""" self.ensure_one() - model = self.env[self.mailing_model_real].with_context( - active_test=False) - if (self.mailing_model_real != "mail.mass_mailing.contact" and - 'opt_out' in model._fields): - email_fname = 'email_from' - if 'email' in model._fields: - email_fname = 'email' + model = self.env[self.mailing_model_real].with_context(active_test=False) + if ( + self.mailing_model_real != "mail.mass_mailing.contact" + and "opt_out" in model._fields + ): + email_fname = "email_from" + if "email" in model._fields: + email_fname = "email" domain = safe_eval(self.mailing_domain) - domain = [('opt_out', '=', True)] + domain + domain = [("opt_out", "=", True)] + domain recs = self.env[self.mailing_model_real].search(domain) - normalized_email = ( - tools.email_split(c[email_fname]) for c in recs) - return set(e[0].lower() for e in normalized_email if e) + normalized_email = (tools.email_split(c[email_fname]) for c in recs) + return {e[0].lower() for e in normalized_email if e} return super()._get_opt_out_list() diff --git a/mass_mailing_custom_unsubscribe/models/mail_mass_mailing_list.py b/mass_mailing_custom_unsubscribe/models/mail_mass_mailing_list.py index f4539f1..f1088e6 100644 --- a/mass_mailing_custom_unsubscribe/models/mail_mass_mailing_list.py +++ b/mass_mailing_custom_unsubscribe/models/mail_mass_mailing_list.py @@ -10,5 +10,6 @@ class MailMassMailing(models.Model): not_cross_unsubscriptable = fields.Boolean( string="Not cross unsubscriptable", help="If you mark this field, this list won't be shown when " - "unsubscribing from other mailing list, in the section: " - "'Is there any other mailing list you want to leave?'") + "unsubscribing from other mailing list, in the section: " + "'Is there any other mailing list you want to leave?'", + ) diff --git a/mass_mailing_custom_unsubscribe/models/mail_unsubscription.py b/mass_mailing_custom_unsubscribe/models/mail_unsubscription.py index a3d1038..1a46d63 100644 --- a/mass_mailing_custom_unsubscribe/models/mail_unsubscription.py +++ b/mass_mailing_custom_unsubscribe/models/mail_unsubscription.py @@ -2,8 +2,9 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import _, api, fields, models -from odoo.addons.mass_mailing.models.mass_mailing import \ - MASS_MAILING_BUSINESS_MODELS + +from odoo.addons.mass_mailing.models.mass_mailing import MASS_MAILING_BUSINESS_MODELS + from .. import exceptions @@ -14,11 +15,8 @@ class MailUnsubscription(models.Model): _rec_name = "date" _order = "date DESC" - date = fields.Datetime( - default=lambda self: self._default_date(), - required=True) - email = fields.Char( - required=True) + date = fields.Datetime(default=lambda self: self._default_date(), required=True) + email = fields.Char(required=True) action = fields.Selection( selection=[ ("subscription", "Subscription"), @@ -34,11 +32,13 @@ class MailUnsubscription(models.Model): "mail.mass_mailing", "Mass mailing", required=True, - help="Mass mailing from which he was unsubscribed.") + help="Mass mailing from which he was unsubscribed.", + ) unsubscriber_id = fields.Reference( lambda self: self._selection_unsubscriber_id(), "(Un)subscriber", - help="Who was subscribed or unsubscribed.") + help="Who was subscribed or unsubscribed.", + ) mailing_list_ids = fields.Many2many( comodel_name="mail.mass_mailing.list", string="Mailing lists", @@ -48,21 +48,19 @@ class MailUnsubscription(models.Model): "mail.unsubscription.reason", "Reason", ondelete="restrict", - help="Why the unsubscription was made.") - details = fields.Text( - help="More details on why the unsubscription was made.") - details_required = fields.Boolean( - related="reason_id.details_required") + help="Why the unsubscription was made.", + ) + details = fields.Text(help="More details on why the unsubscription was made.") + details_required = fields.Boolean(related="reason_id.details_required") metadata = fields.Text( - readonly=True, - help="HTTP request metadata used when creating this record.", + readonly=True, help="HTTP request metadata used when creating this record." ) def map_mailing_list_models(self, models): model_mapped = [] for model in models: - if model == 'mail.mass_mailing.list': - model_mapped.append(('mail.mass_mailing.contact', model)) + if model == "mail.mass_mailing.list": + model_mapped.append(("mail.mass_mailing.contact", model)) else: model_mapped.append((model, model)) return model_mapped @@ -74,8 +72,11 @@ class MailUnsubscription(models.Model): @api.model def _selection_unsubscriber_id(self): """Models that can be linked to a ``mail.mass_mailing``.""" - model = self.env['ir.model'].search( - [('model', 'in', MASS_MAILING_BUSINESS_MODELS)]).mapped('model') + model = ( + self.env["ir.model"] + .search([("model", "in", MASS_MAILING_BUSINESS_MODELS)]) + .mapped("model") + ) return self.map_mailing_list_models(model) @api.multi @@ -86,7 +87,8 @@ class MailUnsubscription(models.Model): unsubscription_states = {"unsubscription", "blacklist_add"} if one.action in unsubscription_states and not one.reason_id: raise exceptions.ReasonRequiredError( - _("Please indicate why are you unsubscribing.")) + _("Please indicate why are you unsubscribing.") + ) @api.multi @api.constrains("details", "reason_id") @@ -95,7 +97,8 @@ class MailUnsubscription(models.Model): for one in self: if not one.details and one.details_required: raise exceptions.DetailsRequiredError( - _("Please provide details on why you are unsubscribing.")) + _("Please provide details on why you are unsubscribing.") + ) @api.model def create(self, vals): @@ -110,12 +113,8 @@ class MailUnsubscriptionReason(models.Model): _description = "Mail unsubscription reason" _order = "sequence, name" - name = fields.Char( - index=True, - translate=True, - required=True) + name = fields.Char(index=True, translate=True, required=True) details_required = fields.Boolean( - help="Check to ask for more details when this reason is selected.") - sequence = fields.Integer( - index=True, - help="Position of the reason in the list.") + help="Check to ask for more details when this reason is selected." + ) + sequence = fields.Integer(index=True, help="Position of the reason in the list.") diff --git a/mass_mailing_custom_unsubscribe/tests/__init__.py b/mass_mailing_custom_unsubscribe/tests/__init__.py index 25c1497..b42af8c 100644 --- a/mass_mailing_custom_unsubscribe/tests/__init__.py +++ b/mass_mailing_custom_unsubscribe/tests/__init__.py @@ -2,4 +2,5 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import test_ui + # from . import test_unsubscription diff --git a/mass_mailing_custom_unsubscribe/tests/test_ui.py b/mass_mailing_custom_unsubscribe/tests/test_ui.py index 981b190..7d9960d 100644 --- a/mass_mailing_custom_unsubscribe/tests/test_ui.py +++ b/mass_mailing_custom_unsubscribe/tests/test_ui.py @@ -1,9 +1,10 @@ # Copyright 2016 Jairo Llopis # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import mock -from odoo.tests.common import HttpCase from werkzeug import urls +from odoo.tests.common import HttpCase + class UICase(HttpCase): _tour_run = "odoo.__DEBUG__.services['web_tour.tour'].run('%s')" @@ -11,7 +12,7 @@ class UICase(HttpCase): def extract_url(self, mail, *args, **kwargs): url = mail._get_unsubscribe_url(self.email) - self.assertTrue(urls.url_parse(url).decode_query().get('token')) + self.assertTrue(urls.url_parse(url).decode_query().get("token")) self.assertTrue(url.startswith(self.domain)) self.url = url.replace(self.domain, "", 1) return True @@ -26,24 +27,27 @@ class UICase(HttpCase): side_effect=self.extract_url, ) - self.domain = self.env["ir.config_parameter"].get_param('web.base.url') + self.domain = self.env["ir.config_parameter"].get_param("web.base.url") List = self.lists = self.env["mail.mass_mailing.list"] for n in range(4): self.lists += List.create({"name": "test list %d" % n}) - self.contact = self.env["mail.mass_mailing.contact"].create({ - "name": "test contact", - "email": self.email, - "list_ids": [(6, False, self.lists.ids)], - }) - self.mailing = self.env["mail.mass_mailing"].create({ - "name": "test mailing %d" % n, - "mailing_model_id": self.env.ref( - 'mass_mailing.model_mail_mass_mailing_list').id, - "contact_list_ids": [ - (6, 0, [self.lists[0].id, self.lists[3].id]) - ], - "reply_to_mode": "thread", - }) + self.contact = self.env["mail.mass_mailing.contact"].create( + { + "name": "test contact", + "email": self.email, + "list_ids": [(6, False, self.lists.ids)], + } + ) + self.mailing = self.env["mail.mass_mailing"].create( + { + "name": "test mailing %d" % n, + "mailing_model_id": self.env.ref( + "mass_mailing.model_mail_mass_mailing_list" + ).id, + "contact_list_ids": [(6, 0, [self.lists[0].id, self.lists[3].id])], + "reply_to_mode": "thread", + } + ) self.mailing._onchange_model_and_list() # HACK https://github.com/odoo/odoo/pull/14429 self.mailing.body_html = """ @@ -76,7 +80,8 @@ class UICase(HttpCase): url_path=self.url, code=self._tour_run % tour, ready=self._tour_ready % tour, - login='demo') + login="demo", + ) # Check results from running tour self.assertFalse(self.lists[0].subscription_contact_ids.opt_out) @@ -92,32 +97,31 @@ class UICase(HttpCase): # first unsubscription reason = "mass_mailing_custom_unsubscribe.reason_other" unsubscription_1 = self.env["mail.unsubscription"].search( - common_domain + [ + common_domain + + [ ("action", "=", "unsubscription"), - ("details", "=", "I want to unsubscribe because I want. " - "Period."), + ("details", "=", "I want to unsubscribe because I want. " "Period."), ("reason_id", "=", self.env.ref(reason).id), ] ) # second unsubscription reason = "mass_mailing_custom_unsubscribe.reason_not_interested" unsubscription_2 = self.env["mail.unsubscription"].search( - common_domain + [ + common_domain + + [ ("action", "=", "unsubscription"), ("reason_id", "=", self.env.ref(reason).id), ] ) # re-subscription from self.lists[3] unsubscription_3 = self.env["mail.unsubscription"].search( - common_domain + [ - ("action", "=", "subscription"), - ] + common_domain + [("action", "=", "subscription")] ) # unsubscriptions above are all unsubscriptions saved during the # tour and they are all the existing unsubscriptions self.assertEqual( unsubscription_1 | unsubscription_2 | unsubscription_3, - self.env["mail.unsubscription"].search([]) + self.env["mail.unsubscription"].search([]), ) self.assertEqual(3, len(self.env["mail.unsubscription"].search([]))) @@ -125,13 +129,12 @@ class UICase(HttpCase): """Test a partner that wants to unsubscribe.""" # Change mailing to be sent to partner partner_id = self.env["res.partner"].name_create( - "Demo Partner <%s>" % self.email)[0] - self.mailing.mailing_model_id = self.env.ref( - "base.model_res_partner") - self.mailing.mailing_domain = repr([ - ('is_blacklisted', '=', False), - ('id', '=', partner_id), - ]) + "Demo Partner <%s>" % self.email + )[0] + self.mailing.mailing_model_id = self.env.ref("base.model_res_partner") + self.mailing.mailing_domain = repr( + [("is_blacklisted", "=", False), ("id", "=", partner_id)] + ) # Extract the unsubscription link from the message body with self.mail_postprocess_patch: self.mailing.send_mail() @@ -141,18 +144,21 @@ class UICase(HttpCase): url_path=self.url, code=self._tour_run % tour, ready=self._tour_ready % tour, - login='demo') + login="demo", + ) # Check results from running tour partner = self.env["res.partner"].browse(partner_id) self.assertTrue(partner.is_blacklisted) reason_xid = "mass_mailing_custom_unsubscribe.reason_not_interested" - unsubscriptions = self.env["mail.unsubscription"].search([ - ("action", "=", 'blacklist_add'), - ("mass_mailing_id", "=", self.mailing.id), - ("email", "=", self.email), - ("unsubscriber_id", "=", "res.partner,%d" % partner_id), - ("details", "=", False), - ("reason_id", "=", self.env.ref(reason_xid).id), - ]) + unsubscriptions = self.env["mail.unsubscription"].search( + [ + ("action", "=", "blacklist_add"), + ("mass_mailing_id", "=", self.mailing.id), + ("email", "=", self.email), + ("unsubscriber_id", "=", "res.partner,%d" % partner_id), + ("details", "=", False), + ("reason_id", "=", self.env.ref(reason_xid).id), + ] + ) self.assertEqual(1, len(unsubscriptions)) diff --git a/mass_mailing_custom_unsubscribe/tests/test_unsubscription.py b/mass_mailing_custom_unsubscribe/tests/test_unsubscription.py index 660e7ab..de8d2b9 100644 --- a/mass_mailing_custom_unsubscribe/tests/test_unsubscription.py +++ b/mass_mailing_custom_unsubscribe/tests/test_unsubscription.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo.tests.common import SavepointCase + from .. import exceptions @@ -9,22 +10,26 @@ class UnsubscriptionCase(SavepointCase): def test_details_required(self): """Cannot create unsubscription without details when required.""" with self.assertRaises(exceptions.DetailsRequiredError): - self.env["mail.unsubscription"].create({ - "email": "axelor@yourcompany.example.com", - "mass_mailing_id": self.env.ref("mass_mailing.mass_mail_1").id, - "unsubscriber_id": - "res.partner,%d" % self.env.ref("base.res_partner_2").id, - "reason_id": - self.env.ref( - "mass_mailing_custom_unsubscribe.reason_other").id, - }) + self.env["mail.unsubscription"].create( + { + "email": "axelor@yourcompany.example.com", + "mass_mailing_id": self.env.ref("mass_mailing.mass_mail_1").id, + "unsubscriber_id": "res.partner,%d" + % self.env.ref("base.res_partner_2").id, + "reason_id": self.env.ref( + "mass_mailing_custom_unsubscribe.reason_other" + ).id, + } + ) def test_reason_required(self): """Cannot create unsubscription without reason when required.""" with self.assertRaises(exceptions.ReasonRequiredError): - self.env["mail.unsubscription"].create({ - "email": "axelor@yourcompany.example.com", - "mass_mailing_id": self.env.ref("mass_mailing.mass_mail_1").id, - "unsubscriber_id": - "res.partner,%d" % self.env.ref("base.res_partner_2").id, - }) + self.env["mail.unsubscription"].create( + { + "email": "axelor@yourcompany.example.com", + "mass_mailing_id": self.env.ref("mass_mailing.mass_mail_1").id, + "unsubscriber_id": "res.partner,%d" + % self.env.ref("base.res_partner_2").id, + } + )