Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][FIX] mail_composer_cc_bcc: fix duplicate key value error "unique_mail_message_id_res_partner_id_if_set" #1493

Open
wants to merge 4 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion mail_composer_cc_bcc/models/mail_mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,12 @@ def _send( # noqa: max-complexity: 4
{"state": "sent", "message_id": res, "failure_reason": False}
)
_logger.info(
"Mail with ID %r and Message-Id %r successfully sent",
"Mail with ID %r and Message-Id %r "
"from %r to (redacted) %r successfully sent",
mail.id,
mail.message_id,
tools.email_normalize(msg["from"]),
tools.mail.email_anonymize(tools.email_normalize(msg["to"])),
)
# /!\ can't use mail.state here, as mail.refresh() will cause an error
# see revid:[email protected] in 6.1
Expand Down
38 changes: 28 additions & 10 deletions mail_composer_cc_bcc/models/mail_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ class MailThread(models.AbstractModel):
def _message_create(self, values_list):
context = self.env.context
res = super()._message_create(values_list)
partners_cc = context.get("partner_cc_ids", None)
if partners_cc:
res.recipient_cc_ids = partners_cc
partners_bcc = context.get("partner_bcc_ids", None)
if partners_bcc:
res.recipient_bcc_ids = partners_bcc
for message in res:
if message.message_type == "notification":
continue
partners_cc = context.get("partner_cc_ids", None)
if partners_cc:
message.recipient_cc_ids = partners_cc
partners_bcc = context.get("partner_bcc_ids", None)
if partners_bcc:
message.recipient_bcc_ids = partners_bcc
return res

def _notify_by_email_get_base_mail_values(self, message, additional_values=None):
Expand All @@ -26,10 +29,11 @@ def _notify_by_email_get_base_mail_values(self, message, additional_values=None)
can be sent to those addresses.
"""
context = self.env.context

res = super()._notify_by_email_get_base_mail_values(
message, additional_values=additional_values
)
if context.get("skip_adding_cc_bcc", False):
return res
partners_cc = context.get("partner_cc_ids", None)
if partners_cc:
res["email_cc"] = format_emails(partners_cc)
Expand All @@ -48,7 +52,8 @@ def _notify_get_recipients(self, message, msg_vals, **kwargs):
rdata = super()._notify_get_recipients(message, msg_vals, **kwargs)
context = self.env.context
is_from_composer = context.get("is_from_composer", False)
if not is_from_composer:
skip_adding_cc_bcc = context.get("skip_adding_cc_bcc", False)
if not is_from_composer or skip_adding_cc_bcc:
return rdata
for pdata in rdata:
pdata["type"] = "customer"
Expand All @@ -62,9 +67,13 @@ def _notify_get_recipients(self, message, msg_vals, **kwargs):
recipients_cc_bcc = MailFollowers._get_recipient_data(
None, message_type, subtype_id, partners_cc_bcc.ids
)
partners_already_marked_as_recipient = [r.get("id", False) for r in rdata]
for _, value in recipients_cc_bcc.items():
for _, data in value.items():
if not data.get("id"):
if (
not data.get("id")
or data.get("id") in partners_already_marked_as_recipient
):
continue
if not data.get(
"notif"
Expand Down Expand Up @@ -92,6 +101,9 @@ def _notify_by_email_get_final_mail_values(
recipient_ids, base_mail_values, additional_values=additional_values
)
context = self.env.context
skip_adding_cc_bcc = context.get("skip_adding_cc_bcc", False)
if skip_adding_cc_bcc:
return res
r_ids = list(recipient_ids)
partners_cc = context.get("partner_cc_ids", None)
if partners_cc:
Expand All @@ -110,7 +122,8 @@ def _notify_get_recipients_classify(
recipient_data, model_name, msg_vals=msg_vals
)
is_from_composer = self.env.context.get("is_from_composer", False)
if not is_from_composer:
skip_adding_cc_bcc = self.env.context.get("skip_adding_cc_bcc", False)
if not is_from_composer or skip_adding_cc_bcc:
return res
ids = []
customer_data = None
Expand All @@ -126,3 +139,8 @@ def _notify_get_recipients_classify(
else:
customer_data["recipients"] += ids
return [customer_data]

def _notify_thread(self, message, msg_vals=False, **kwargs):
if message.message_type == "notification":
self = self.with_context(skip_adding_cc_bcc=True)
return super(MailThread, self)._notify_thread(message, msg_vals, **kwargs)
75 changes: 67 additions & 8 deletions mail_composer_cc_bcc/tests/test_mail_cc_bcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

import hashlib
import inspect
from unittest.mock import patch

from odoo import tools
from odoo.tests import Form

from odoo.addons.mail.models.mail_mail import MailMail as upstream
from odoo.addons.mail.models.mail_thread import MailThread
from odoo.addons.mail.tests.test_mail_composer import TestMailComposer

VALID_HASHES = [
Expand All @@ -16,6 +18,7 @@
"5d1ab352416f5074e131f35f20098d5b",
"46172c91183f2cb50b22a6b3b5e3869b",
"8f26c4084cc7fc300e64d19ccdc944fe",
"db6cc0d3513a0c85bd716e4cb0a4d09c",
]


Expand Down Expand Up @@ -96,12 +99,12 @@ def test_template_cc_bcc(self):
# Company default values
env.company.default_partner_cc_ids = self.partner_cc3
env.company.default_partner_bcc_ids = self.partner_cc2
# Product template values
tmpl_model = env["ir.model"].search([("model", "=", "product.template")])
# Partner template values
tmpl_model = env["ir.model"].search([("model", "=", "res.partner")])
partner_cc = self.partner_cc
partner_bcc = self.partner_bcc
vals = {
"name": "Product Template: Re: [E-COM11] Cabinet with Doors",
"name": "Test Template",
"model_id": tmpl_model.id,
"subject": "Re: [E-COM11] Cabinet with Doors",
"body_html": """<p style="margin:0px 0 12px 0;box-sizing:border-box;">
Expand All @@ -113,18 +116,18 @@ def test_template_cc_bcc(self):
(partner_bcc.name or "False", partner_bcc.email or "False")
),
}
prod_tmpl = env["mail.template"].create(vals)
partner_tmpl = env["mail.template"].create(vals)
# Open mail composer form and check for default values from company
form = self.open_mail_composer_form()
composer = form.save()
self.assertEqual(composer.partner_cc_ids, self.partner_cc3)
self.assertEqual(composer.partner_bcc_ids, self.partner_cc2)
# Change email template and check for values from it
form.template_id = prod_tmpl
form.template_id = partner_tmpl
composer = form.save()
# Beside existing Cc and Bcc, add template's ones
form = Form(composer)
form.template_id = prod_tmpl
form.template_id = partner_tmpl
composer = form.save()
expecting = self.partner_cc3 + self.partner_cc
self.assertEqual(composer.partner_cc_ids, expecting)
Expand All @@ -138,8 +141,8 @@ def test_template_cc_bcc(self):
form = Form(composer)
form.template_id = env["mail.template"]
form.save()
self.assertFalse(form.template_id)
form.template_id = prod_tmpl
self.assertFalse(form.template_id) # no template
form.template_id = partner_tmpl
composer = form.save()
expecting = self.partner_cc3 + self.partner_cc
self.assertEqual(composer.partner_cc_ids, expecting)
Expand Down Expand Up @@ -186,3 +189,59 @@ def test_mail_without_cc_bcc(self):
if subject == mail.get("subject"):
sent_mails += 1
self.assertEqual(sent_mails, 1)

def test_tracking_mail_without_cc_bcc(self):
Partner = self.env["res.partner"]
p1 = Partner.create(
{"name": "Customer1", "email": "[email protected]"}
).with_context(mail_notrack=False)
self.cr.precommit.clear()
p2 = Partner.create({"name": "Customer2", "email": "[email protected]"})

original_message_post = MailThread.message_post

def patched_message_post(self, **kwargs):
self = self.with_context(
mail_post_autofollow=self.env.context.get("mail_post_autofollow", True),
)
# to trigger tracking email
p1.write({"email": "[email protected]"})
return original_message_post(self, **kwargs)

ctx = {
"default_partner_ids": p1.ids,
"default_model": Partner._name,
"default_res_id": p1.id,
"mail_notify_force_send": True,
}
form = Form(self.env["mail.compose.message"].with_context(**ctx))
form.body = "<p>Hello</p>"
composer = form.save()
composer.partner_bcc_ids = p2.ids
with self.mock_mail_gateway(), self.mock_mail_app(), patch(
"odoo.addons.mail.models.mail_thread.MailThread.message_post",
new=patched_message_post,
):
composer._action_send_mail()
self.flush_tracking()
self.assertEqual(
len(self._new_msgs),
2,
)
self.assertEqual(
self.ref("mail.mt_note"),
self._new_msgs[1].subtype_id.id,
"Expected a tracking message",
)

# Main email should include cc/bcc
main_message = self._new_msgs.filtered(lambda x: x.message_type == "comment")
self.assertEqual(len(main_message.notified_partner_ids), 2)
self.assertEqual(len(main_message.notification_ids), 2)
main_mail = main_message.mail_ids
self.assertEqual(len(main_mail.recipient_ids), 2)

# tracking email should not include cc/bcc
tracking_message = self._new_msgs.filtered(lambda x: x.message_type == "note")
tracking_field_mail = tracking_message.mail_ids
self.assertFalse(tracking_field_mail.email_bcc)
Loading