From b8c7eddb3493e881a3e2c3d41bd0166ff93e4ef9 Mon Sep 17 00:00:00 2001 From: "Andrea Grazioso (agr-odoo)" Date: Fri, 30 Aug 2019 09:43:01 +0000 Subject: [PATCH] [FIX] calendar: invitation for deleted event (recurring) From calendar create a recursive event and add some guests. Delete one event of the chain. Invitations (Mail) will be created for the deleted event, and should not be the case because the event has been deleted. This happens because the recursive event is really just a record in the database representing all the generated events. When the user want to delete an event in the chain, a new event, copy of the "parent" event has to be registered and subsequently disabled. In the process of creating the event the mail is sent as side effect. Note that the code to prevent this was partially there because a context flag "dont_notify" is sent by the unlink in Calendar.Meeting but was ignored from the mail subsystem. opw-2039576 closes odoo/odoo#36270 Signed-off-by: Nans Lefebvre (len) --- addons/calendar/models/calendar.py | 6 ++- addons/calendar/tests/test_calendar.py | 58 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index 5cc3e8faa2d..b02fed1bcf4 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -1065,11 +1065,13 @@ class Meeting(models.Model): meeting_attendees |= attendee meeting_partners |= partner - if meeting_attendees: + if meeting_attendees and not self._context.get('detaching'): to_notify = meeting_attendees.filtered(lambda a: a.email != current_user.email) to_notify._send_mail_to_attendees('calendar.calendar_template_meeting_invitation') + if meeting_attendees: meeting.write({'attendee_ids': [(4, meeting_attendee.id) for meeting_attendee in meeting_attendees]}) + if meeting_partners: meeting.message_subscribe(partner_ids=meeting_partners.ids) @@ -1417,7 +1419,7 @@ class Meeting(models.Model): # do not copy the id if data.get('id'): del data['id'] - return meeting_origin.copy(default=data) + return meeting_origin.with_context(detaching=True).copy(default=data) @api.multi def action_detach_recurring_event(self): diff --git a/addons/calendar/tests/test_calendar.py b/addons/calendar/tests/test_calendar.py index 9b8fd31897f..b47868bbcb6 100644 --- a/addons/calendar/tests/test_calendar.py +++ b/addons/calendar/tests/test_calendar.py @@ -7,6 +7,7 @@ from datetime import datetime, timedelta, time from odoo import fields from odoo.tests.common import TransactionCase import pytz +import re class TestCalendar(TransactionCase): @@ -384,3 +385,60 @@ class TestCalendar(TransactionCase): }) self.assertEqual(str(activity_id.date_deadline), '2018-10-16') + + def test_event_creation_mail(self): + """ + Check that mail are sent to the attendees on event creation + Check that mail are sent to the added attendees on event edit + Check that mail are NOT sent to the attendees when detaching a recurring event + """ + + def _test_one_mail_per_attendee(self, m, partners): + # check that every attendee receive a (single) mail for the event + for partner in partners: + mail = self.env['mail.mail'].search([ + ('recipient_ids', 'in', partner.id), + ('subject', 'like', m.name), + ]) + self.assertEqual(len(mail), 1) + + partners = [ + self.env['res.partner'].create({'name':'testuser0','email': u'bob@example.com'}), + self.env['res.partner'].create({'name':'testuser1','email': u'alice@example.com'}), + ] + partner_ids = [(6, False, [p.id for p in partners]),] + now = fields.Datetime.now() + m = self.CalendarEvent.create({ + 'name': "mailTest1", + 'allday': False, + 'rrule': u'FREQ=DAILY;INTERVAL=1;COUNT=5', + 'duration': 0.5, + 'partner_ids': partner_ids, + 'start': fields.Datetime.to_string(now + timedelta(days=10)), + 'stop': fields.Datetime.to_string(now + timedelta(days=15)), + }) + + # every partner should have 1 mail sent + _test_one_mail_per_attendee(self, m, partners) + + # adding more partners to the event + partners.extend([ + self.env['res.partner'].create({'name':'testuser2','email': u'marc@example.com'}), + self.env['res.partner'].create({'name':'testuser3','email': u'carl@example.com'}), + self.env['res.partner'].create({'name':'testuser4','email': u'alain@example.com'}), + ]) + partner_ids = [(6, False, [p.id for p in partners]),] + m.write({'partner_ids': partner_ids}) + + # more email should be sent + _test_one_mail_per_attendee(self, m, partners) + + # calculate virtualid to detach one event + virtid = str(m.id) + '-' + ''.join(re.split('[\D]', fields.Datetime.to_string(now + timedelta(days=12)))) + + # detaching a virtual event in the chain + self.env['calendar.event'].browse(virtid).detach_recurring_event(values={'active':False}) + + # since the detach actually create an event in the backend + # we check that no mail notifications are sent to the attendees + _test_one_mail_per_attendee(self, m, partners)