# Copyright 2023 Camptocamp # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import hashlib import inspect from odoo import tools from odoo.tests import Form, tagged from odoo.tests.common import TransactionCase from odoo.addons.mail.tests.common import MailCase from odoo.addons.mail.tests.test_mail_composer import TestMailComposerForm from odoo.addons.mail.wizard.mail_compose_message import ( MailComposer as MailComposer_upstream, ) VALID_HASHES = { "mail.composer:_compute_partner_ids": ["813ef112e3948fe625b9a89428f2518d"], } class TestMailCcBcc(TestMailComposerForm): @classmethod def setUpClass(cls): super().setUpClass() env = cls.env cls.partner = env.ref("base.res_partner_address_31") cls.partner_cc = env.ref("base.partner_demo") cls.partner_cc2 = env.ref("base.partner_demo_portal") cls.partner_cc3 = env.ref("base.res_partner_main1") cls.partner_bcc = env.ref("base.res_partner_main2") def open_mail_composer_form(self): # Use form to populate data test_record = self.test_record.with_env(self.env) ctx = { "default_partner_ids": test_record.ids, "default_model": test_record._name, "default_res_ids": test_record.ids, # to ensure consistent test results even when mail_post_defer is installed "mail_notify_force_send": True, } form = Form(self.env["mail.compose.message"].with_context(**ctx)) form.body = "

Hello

" return form def test_MailComposer_upstream_file_hash(self): """Test that copied upstream function hasn't received fixes""" _compute_partner_ids = inspect.getsource( MailComposer_upstream._compute_partner_ids ).encode() func_hash = hashlib.md5(_compute_partner_ids).hexdigest() self.assertIn(func_hash, VALID_HASHES.get("mail.composer:_compute_partner_ids")) def test_email_cc_bcc(self): self.test_record.email = "test@example.com" form = self.open_mail_composer_form() composer = form.save() # Use object to update Many2many fields (form can't do like this) composer.partner_cc_ids = self.partner_cc composer.partner_cc_ids |= self.partner_cc2 composer.partner_cc_ids |= self.partner_cc3 composer.partner_bcc_ids = self.partner_bcc with self.mock_mail_gateway(): composer._action_send_mail() self.assertEqual(len(self._mails), 5) # Verify recipients of mail.message message = self.test_record.message_ids[0] # only keep 1 email to avoid clutting db # but actually send 1 mail per recipients self.assertEqual(len(message.mail_ids), 1) self.assertEqual(len(message.recipient_cc_ids), 3) self.assertEqual(len(message.recipient_bcc_ids), 1) # Verify notification for_message = [ ("mail_message_id", "=", message.id), ("notification_type", "=", "email"), ] notif = self.env["mail.notification"].search(for_message) self.assertEqual(len(notif), 5) # Verify data of mail.mail mail = message.mail_ids expecting = ", ".join( [ '"Marc Demo" ', '"Joel Willis" ', '"Chester Reed" ', ] ) self.assertEqual(mail.email_cc, expecting) expecting = '"Dwayne Newman" ' self.assertEqual(mail.email_bcc, expecting) def test_template_cc_bcc(self): env = self.env # Company default values env.company.default_partner_cc_ids = self.partner_cc3 env.company.default_partner_bcc_ids = self.partner_cc2 # 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", "model_id": tmpl_model.id, "subject": "Re: [E-COM11] Cabinet with Doors", "body_html": """

Test Template

""", "email_cc": tools.formataddr( (partner_cc.name or "False", partner_cc.email or "False") ), "email_bcc": tools.formataddr( (partner_bcc.name or "False", partner_bcc.email or "False") ), } 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 = partner_tmpl composer = form.save() # Beside existing Cc and Bcc, add template's ones form = Form(composer) form.template_id = partner_tmpl composer = form.save() expecting = self.partner_cc3 + self.partner_cc self.assertEqual(composer.partner_cc_ids, expecting) expecting = self.partner_cc2 + self.partner_bcc self.assertEqual(composer.partner_bcc_ids, expecting) # But not add Marc Demo from cc field to partner_ids field self.assertEqual(len(composer.partner_ids), 1) self.assertEqual(composer.partner_ids.display_name, "Test") # Selecting the template again doesn't add as the partners already # in the list form = Form(composer) form.template_id = env["mail.template"] form.save() 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) expecting = self.partner_cc2 + self.partner_bcc self.assertEqual(composer.partner_bcc_ids, expecting) def set_company(self): company = self.env.company # Company default values company.default_partner_cc_ids = self.partner_cc3 company.default_partner_bcc_ids = self.partner_cc2 def test_recipient_ids_and_cc_bcc(self): self.set_company() form = self.open_mail_composer_form() composer = form.save() composer.partner_ids = self.partner + self.partner_cc with self.mock_mail_gateway(): composer._action_send_mail() message = self.test_record.message_ids[0] self.assertEqual(len(message.mail_ids), 1) # Only 4 partners notified self.assertEqual(len(message.notified_partner_ids), 4) self.assertEqual(len(message.notification_ids), 4) def test_mail_without_cc_bcc(self): self.set_company() form = self.open_mail_composer_form() subject = "Testing without cc/bcc single mail" form.subject = subject composer = form.save() composer.partner_cc_ids = None composer.partner_bcc_ids = None composer.partner_ids = self.partner + self.partner_cc # 2 emails are sent ctx = {"mail_notify_force_send": True} ctx.update(composer.env.context) composer = composer.with_context(**ctx) with self.mock_mail_gateway(): composer._action_send_mail() sent_mails = 0 for mail in self._mails: if subject == mail.get("subject"): sent_mails += 1 self.assertEqual(sent_mails, 2, "There should be 2 mails sent") @tagged("-at_install", "post_install") class TestMailComposerCcBccWithTracking(TransactionCase, MailCase): @classmethod def setUpClass(cls): super().setUpClass() cls.partner = cls.env.ref("base.res_partner_address_31") cls.partner_cc = cls.env.ref("base.partner_demo") cls.partner_bcc = cls.env.ref("base.res_partner_main2") cls.admin_user = cls.env.ref("base.user_admin") if "purchase.order" in cls.env: cls.new_po = ( cls.env["purchase.order"] .create( { "partner_id": cls.partner.id, } ) .with_context(mail_notrack=False) ) def test_tracking_mail_without_cc_bcc(self): if "purchase.order" in self.env: self.cr.precommit.clear() # create a PO # user subscribe to tracking status of PO self.new_po.message_subscribe( partner_ids=self.admin_user.partner_id.ids, subtype_ids=( ( self.env.ref("purchase.mt_rfq_sent") | self.env.ref("purchase.mt_rfq_confirmed") ).ids ), ) composer_ctx = self.new_po.action_rfq_send() # send RFQ with cc/bcc form = Form( self.env["mail.compose.message"].with_context(**composer_ctx["context"]) ) composer = form.save() composer.partner_ids = self.partner composer.partner_cc_ids = self.partner_cc composer.partner_bcc_ids = self.partner_bcc with self.mock_mail_gateway(), self.mock_mail_app(): composer._action_send_mail() self.flush_tracking() self.assertEqual( len(self._new_msgs), 2, "Expected a tracking message and a RFQ message", ) self.assertEqual( self.ref("purchase.mt_rfq_sent"), self._new_msgs[1].subtype_id.id, "Expected a tracking message", ) # RFQ email should include cc/bcc rfq_message = self._new_msgs.filtered(lambda x: x.message_type == "comment") self.assertEqual(len(rfq_message.notified_partner_ids), 3) self.assertEqual(len(rfq_message.notification_ids), 3) rfq_mail = rfq_message.mail_ids self.assertEqual(len(rfq_mail.recipient_ids), 3) # tracking email should not include cc/bcc tracking_message = self._new_msgs.filtered( lambda x: x.message_type == "notification" ) tracking_field_mail = tracking_message.mail_ids self.assertEqual(len(tracking_field_mail.recipient_ids), 1) self.assertEqual( tracking_field_mail.recipient_ids, self.admin_user.partner_id )