From 8b7f1c892b6185e89254a3b414dbf46d246df7aa Mon Sep 17 00:00:00 2001 From: Leonardo Pavan Rocha Date: Mon, 14 Aug 2023 18:04:36 +0200 Subject: [PATCH] [FIX] google_calendar: sync setting needs action status to accepted event When an event is created by user A and user B is invited, user A automatically accepts the event. If both users are using google sync and user B accepts the invitation from the google interface, the status of the events are set to needAction for user A. This occurs because the odoo values will always write the time related fields, even when those did not change. This causes the status to be changed to needAction because we assume the time of the event has changed and user A needs to verify it. This commit fixes this by only setting time values when they were really changed and by switching the logic that triggers the reset of the status. As most times a default alarm is generated by google, we should not treat it as condition for updating the time and, therefore, potentially updating the status of the attendee. task-3464054 closes odoo/odoo#137471 Signed-off-by: Arnaud Joset (arj) Signed-off-by: Leonardo Pavan Rocha --- addons/calendar/models/calendar_event.py | 4 +- addons/google_calendar/models/calendar.py | 9 ++-- .../tests/test_sync_google2odoo.py | 44 ++++++++++++++++++- addons/google_calendar/utils/google_event.py | 6 +++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/addons/calendar/models/calendar_event.py b/addons/calendar/models/calendar_event.py index 3eaa4f25303..66f2199ec52 100644 --- a/addons/calendar/models/calendar_event.py +++ b/addons/calendar/models/calendar_event.py @@ -617,9 +617,11 @@ class Meeting(models.Model): self.videocall_channel_id.add_members(new_partner_ids) time_fields = self.env['calendar.event']._get_time_fields() - if any([values.get(key) for key in time_fields]) or 'alarm_ids' in values: + if any([values.get(key) for key in time_fields]): update_alarms = True update_time = True + if 'alarm_ids' in values: + update_alarms = True if (not recurrence_update_setting or recurrence_update_setting == 'self_only' and len(self) == 1) and 'follow_recurrence' not in values: if any({field: values.get(field) for field in time_fields if field in values}): diff --git a/addons/google_calendar/models/calendar.py b/addons/google_calendar/models/calendar.py index 66ec475c789..a835aa06ca2 100644 --- a/addons/google_calendar/models/calendar.py +++ b/addons/google_calendar/models/calendar.py @@ -171,8 +171,10 @@ class Meeting(models.Model): if stop < start: stop = parse(google_event.end.get('date')) values['allday'] = True - values['start'] = start - values['stop'] = stop + if related_event['start'] != start: + values['start'] = start + if related_event['stop'] != stop: + values['stop'] = stop return values @api.model @@ -189,7 +191,8 @@ class Meeting(models.Model): emails = [a.get('email') for a in google_attendees] existing_attendees = self.env['calendar.attendee'] if google_event.exists(self.env): - existing_attendees = self.browse(google_event.odoo_id(self.env)).attendee_ids + event = google_event.get_odoo_event(self.env) + existing_attendees = event.attendee_ids attendees_by_emails = {tools.email_normalize(a.email): a for a in existing_attendees} partners = self._get_sync_partner(emails) for attendee in zip(emails, partners, google_attendees): diff --git a/addons/google_calendar/tests/test_sync_google2odoo.py b/addons/google_calendar/tests/test_sync_google2odoo.py index 0d02cdc0129..caff6f75b48 100644 --- a/addons/google_calendar/tests/test_sync_google2odoo.py +++ b/addons/google_calendar/tests/test_sync_google2odoo.py @@ -1146,8 +1146,8 @@ class TestSyncGoogle2Odoo(TestSyncGoogle): }]) self.sync(gevent) # User attendee removed but gevent owner might be added after synch. - mails = sorted(set(event.attendee_ids.mapped('email'))) - self.assertEqual(mails, ['odoobot@example.com']) + mails = event.attendee_ids.mapped('email') + self.assertFalse(mails) self.assertGoogleAPINotCalled() @@ -1741,3 +1741,43 @@ class TestSyncGoogle2Odoo(TestSyncGoogle): self.assertTrue(guest_user.google_synchronization_stopped) guest_user.sudo().restart_google_synchronization() self.assertFalse(guest_user.google_synchronization_stopped) + + @patch_api + def test_attendee_status_is_not_updated_when_syncing_and_time_data_is_not_changed(self): + recurrence_id = "aaaaaaaa" + organizer = new_test_user(self.env, login="organizer") + other_user = new_test_user(self.env, login='calendar_user') + base_event = self.env['calendar.event'].with_user(organizer).create({ + 'name': 'coucou', + 'start': datetime(2020, 1, 6, 9, 0), + 'stop': datetime(2020, 1, 6, 10, 0), + 'need_sync': False, + 'partner_ids': [Command.set([organizer.partner_id.id, other_user.partner_id.id])] + }) + recurrence = self.env['calendar.recurrence'].with_user(organizer).create({ + 'google_id': recurrence_id, + 'rrule': 'FREQ=DAILY;INTERVAL=1;COUNT=3', + 'need_sync': False, + 'base_event_id': base_event.id, + }) + recurrence._apply_recurrence() + + self.assertTrue(all(len(event.attendee_ids) == 2 for event in recurrence.calendar_event_ids), 'should have 2 attendees in all recurring events') + organizer_state = recurrence.calendar_event_ids.sorted('start')[0].attendee_ids.filtered(lambda attendee: attendee.partner_id.email == organizer.partner_id.email).state + self.assertEqual(organizer_state, 'accepted', 'organizer should have accepted') + values = [{ + 'summary': 'coucou', + 'id': recurrence_id, + 'recurrence': ['RRULE:FREQ=DAILY;INTERVAL=1;COUNT=3'], + 'start': {'dateTime': '2020-01-06T10:00:00+01:00'}, + 'end': {'dateTime': '2020-01-06T11:00:00+01:00'}, + 'reminders': {'useDefault': True}, + 'organizer': {'email': organizer.partner_id.email}, + 'attendees': [{'email': organizer.partner_id.email, 'responseStatus': 'accepted'}, {'email': other_user.partner_id.email, 'responseStatus': 'accepted'}], + 'updated': self.now, + }] + self.env['calendar.recurrence'].with_user(other_user)._sync_google2odoo(GoogleEvent(values)) + events = recurrence.calendar_event_ids.sorted('start') + self.assertEqual(len(events), 3, "it should have created a recurrence with 3 events") + self.assertEqual(events[0].attendee_ids[0].state, 'accepted', 'after google sync, organizer should have accepted status still') + self.assertGoogleAPINotCalled() diff --git a/addons/google_calendar/utils/google_event.py b/addons/google_calendar/utils/google_event.py index 441388d22aa..4a006868072 100644 --- a/addons/google_calendar/utils/google_event.py +++ b/addons/google_calendar/utils/google_event.py @@ -230,3 +230,9 @@ class GoogleEvent(abc.Set): def is_available(self): return self.transparency == 'transparent' + + def get_odoo_event(self, env): + if self._get_model(env)._name == 'calendar.event': + return env['calendar.event'].browse(self.odoo_id(self.env)) + else: + return env['calendar.recurrence'].browse(self.odoo_id(self.env)).base_event_id