diff --git a/partner_event/models/event_registration.py b/partner_event/models/event_registration.py index 905d6d2e8..50ab2e82a 100644 --- a/partner_event/models/event_registration.py +++ b/partner_event/models/event_registration.py @@ -101,6 +101,31 @@ def write(self, vals): self._update_attendee_partner_id(vals) return super().write(vals) + def _message_get_default_recipients(self, with_cc=False, all_tos=False): + """Prefer the attendee partner over the generic heuristics. + + The generic heuristics pick ``partner_id``, which is the person that + made the booking, or fall back to the registration email; mails + composed from a registration are meant for the attendee. Only that + recipient is swapped, so any other partner contributed by another + module stays in the list. ``email_to`` is dropped because it can only + hold the registration email when no partner was picked, which is the + same recipient the attendee partner now stands for. ``email_cc`` stays + as ``super()`` computed it (it already honors ``with_cc``), and + ``all_tos`` is deprecated in 19.0 and only forwarded. + """ + res = super()._message_get_default_recipients(with_cc=with_cc, all_tos=all_tos) + for record in self.filtered("attendee_partner_id"): + values = res[record.id] + attendee_id = record.attendee_partner_id.id + others = [ + partner_id + for partner_id in values["partner_ids"] + if partner_id not in (record.partner_id.id, attendee_id) + ] + values.update(partner_ids=[attendee_id] + others, email_to="") + return res + def partner_data_update(self, data): reg_data = {k: v for k, v in data.items() if k in ["name", "email", "phone"]} if reg_data: diff --git a/partner_event/tests/test_event_registration.py b/partner_event/tests/test_event_registration.py index 1b5e00250..8bb733fa2 100644 --- a/partner_event/tests/test_event_registration.py +++ b/partner_event/tests/test_event_registration.py @@ -7,6 +7,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from datetime import datetime, timedelta +from unittest.mock import patch from psycopg2 import IntegrityError @@ -188,3 +189,90 @@ def test_write_without_email_preserves_attendee_partner(self): self.assertTrue(existing_attendee) reg.write({"name": "Updated Name"}) self.assertEqual(reg.attendee_partner_id, existing_attendee) + + def test_message_get_default_recipients(self): + recipients = self.registration_02._message_get_default_recipients() + self.assertEqual( + recipients[self.registration_02.id]["partner_ids"], + self.registration_02.attendee_partner_id.ids, + ) + self.assertFalse(recipients[self.registration_02.id]["email_to"]) + # Without an attendee partner the generic heuristics still apply + event = self.env["event.event"].create( + { + "name": "Test event no partner", + "date_begin": fields.Datetime.now(), + "date_end": fields.Datetime.now(), + } + ) + registration = ( + self.env["event.registration"] + .with_context(registration_force_draft=True) + .create( + { + "email": "no.partner@test.com", + "name": "No Partner", + "event_id": event.id, + } + ) + ) + self.assertFalse(registration.attendee_partner_id) + recipient = registration._message_get_default_recipients()[registration.id] + self.assertFalse(recipient["partner_ids"]) + # mail may format the address ('"No Partner" '); + # the mailbox is what matters + self.assertIn("no.partner@test.com", recipient["email_to"]) + + def test_message_get_default_recipients_keeps_extra_partners(self): + """Only the booking partner is swapped for the attendee one. + + Another module may contribute extra default recipients through + ``_message_add_default_recipients``, and they have to survive the + swap. ``email`` is forced to empty because ``event.registration`` sets + ``_mail_defaults_to_email``: with an address on the registration the + generic heuristics return it instead of any partner, and there would + be no extra recipient to preserve. + """ + partner_model = self.env["res.partner"] + booking_partner = partner_model.create( + {"name": "Booking Partner", "email": "booking@test.com"} + ) + attendee_partner = partner_model.create( + {"name": "Attendee Partner", "email": "attendee@test.com"} + ) + extra_partner = partner_model.create( + {"name": "Extra Partner", "email": "extra@test.com"} + ) + registration = ( + self.env["event.registration"] + .with_context(registration_force_draft=True) + .create( + { + "event_id": self.event_0.id, + "name": "Test Registration 03", + "email": False, + "partner_id": booking_partner.id, + "attendee_partner_id": attendee_partner.id, + } + ) + ) + registration_cls = type(registration) + add_default_recipients = registration_cls._message_add_default_recipients + + def _message_add_default_recipients(self): + found = add_default_recipients(self) + for values in found.values(): + values["partners"] |= extra_partner + return found + + with patch.object( + registration_cls, + "_message_add_default_recipients", + _message_add_default_recipients, + ): + recipients = registration._message_get_default_recipients() + partner_ids = recipients[registration.id]["partner_ids"] + self.assertNotIn(booking_partner.id, partner_ids) + self.assertEqual( + sorted(partner_ids), sorted(attendee_partner.ids + extra_partner.ids) + )