From 73c4a4965b5cc480b0b66007ab46bb7a6fe7f450 Mon Sep 17 00:00:00 2001 From: BryanSomko <101172034+BryanSomko@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:13:10 +0200 Subject: [PATCH 1/4] [FIX] mail_composer_cc_bcc: fix duplicate key value violates unique constraint "unique_mail_message_id_res_partner_id_if_set" when adding the same user to CC field that is already set as a follower --- mail_composer_cc_bcc/models/mail_thread.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mail_composer_cc_bcc/models/mail_thread.py b/mail_composer_cc_bcc/models/mail_thread.py index 43bf5dd564..964987ac52 100644 --- a/mail_composer_cc_bcc/models/mail_thread.py +++ b/mail_composer_cc_bcc/models/mail_thread.py @@ -62,9 +62,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" From b925ef74d55883f727768b367fa7d1bc98a0b751 Mon Sep 17 00:00:00 2001 From: trisdoan Date: Mon, 21 Oct 2024 11:49:50 +0700 Subject: [PATCH 2/4] [FIX] mail_composer_cc_bcc: replace product.template with res.part in tests --- mail_composer_cc_bcc/tests/test_mail_cc_bcc.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py b/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py index fb0751cc03..06a9951586 100644 --- a/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py +++ b/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py @@ -96,12 +96,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": """

@@ -113,18 +113,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) @@ -138,8 +138,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) From 20bc9924b89d4a1b9572d12f7149cf41e27f297d Mon Sep 17 00:00:00 2001 From: trisdoan Date: Tue, 22 Oct 2024 09:56:46 +0700 Subject: [PATCH 3/4] [FIX] mail_composer_cc_bcc:send RFQ by email --- mail_composer_cc_bcc/models/mail_thread.py | 32 +++++++--- .../tests/test_mail_cc_bcc.py | 58 +++++++++++++++++++ 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/mail_composer_cc_bcc/models/mail_thread.py b/mail_composer_cc_bcc/models/mail_thread.py index 964987ac52..9bf15a7264 100644 --- a/mail_composer_cc_bcc/models/mail_thread.py +++ b/mail_composer_cc_bcc/models/mail_thread.py @@ -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): @@ -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) @@ -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" @@ -96,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: @@ -114,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 @@ -130,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) diff --git a/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py b/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py index 06a9951586..d86abb5fc6 100644 --- a/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py +++ b/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py @@ -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 = [ @@ -186,3 +188,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": "test1@test.example.com"} + ).with_context(mail_notrack=False) + self.cr.precommit.clear() + p2 = Partner.create({"name": "Customer2", "email": "test2@test.example.com"}) + + 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": "test@test.example.com"}) + 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 = "

Hello

" + 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) From 15f7086c376bd7d6062f137205900e98fa164870 Mon Sep 17 00:00:00 2001 From: trisdoan Date: Tue, 14 Jan 2025 12:24:32 +0700 Subject: [PATCH 4/4] [UPD] mail_composer_cc_bcc: adapt changes to upstream --- mail_composer_cc_bcc/models/mail_mail.py | 5 ++++- mail_composer_cc_bcc/tests/test_mail_cc_bcc.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mail_composer_cc_bcc/models/mail_mail.py b/mail_composer_cc_bcc/models/mail_mail.py index 29ab4d6e3f..7d6c7b426b 100644 --- a/mail_composer_cc_bcc/models/mail_mail.py +++ b/mail_composer_cc_bcc/models/mail_mail.py @@ -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:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1 diff --git a/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py b/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py index d86abb5fc6..662908eaa5 100644 --- a/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py +++ b/mail_composer_cc_bcc/tests/test_mail_cc_bcc.py @@ -18,6 +18,7 @@ "5d1ab352416f5074e131f35f20098d5b", "46172c91183f2cb50b22a6b3b5e3869b", "8f26c4084cc7fc300e64d19ccdc944fe", + "db6cc0d3513a0c85bd716e4cb0a4d09c", ]