[IMP] mass_mailing_custom_unsubscribe: black, isort, prettier

This commit is contained in:
Carlos Roca 2020-08-24 10:36:19 +02:00 committed by Ernesto Tejeda
parent 9cdbc02cfc
commit 844c382fe7
9 changed files with 258 additions and 225 deletions

View File

@ -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,
}

View File

@ -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),

View File

@ -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)

View File

@ -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()

View File

@ -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?'",
)

View File

@ -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.")

View File

@ -2,4 +2,5 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_ui
# from . import test_unsubscription

View File

@ -1,9 +1,10 @@
# Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# 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))

View File

@ -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,
}
)