19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:28 +01:00
parent 20ddc1b4a3
commit c0efcc53f5
1162 changed files with 125577 additions and 105287 deletions

View file

@ -1,29 +1,28 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from dateutil.relativedelta import relativedelta
from unittest.mock import patch
from odoo.addons.google_calendar.utils.google_event import GoogleEvent
from odoo.addons.google_calendar.utils.google_calendar import GoogleCalendarService
from odoo.addons.google_account.models.google_service import GoogleService
from odoo.addons.google_calendar.models.res_users import User
from odoo.addons.google_calendar.models.res_users import ResUsers
from odoo.addons.google_calendar.tests.test_sync_common import TestSyncGoogle, patch_api
from odoo.tests.common import users, warmup
from odoo.tests import tagged
from odoo import tools
@tagged('odoo2google', 'is_query_count')
@patch.object(User, '_get_google_calendar_token', lambda user: 'dummy-token')
@tagged('odoo2google', 'calendar_performance', 'is_query_count')
@patch.object(ResUsers, '_get_google_calendar_token', lambda user: 'dummy-token')
class TestSyncOdoo2Google(TestSyncGoogle):
def setUp(self):
super().setUp()
self.env.user.partner_id.tz = "Europe/Brussels"
self.google_service = GoogleCalendarService(self.env['google.service'])
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env.user.partner_id.tz = "Europe/Brussels"
cls.google_service = GoogleCalendarService(cls.env['google.service'])
# Make sure this test will work for the next 30 years
self.env['ir.config_parameter'].set_param('google_calendar.sync.range_days', 10000)
cls.env['ir.config_parameter'].set_param('google_calendar.sync.range_days', 10000)
@patch_api
def test_event_creation(self):
@ -51,7 +50,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
'summary': 'Event',
'description': tools.html_sanitize(description),
'description': event.description,
'location': '',
'visibility': 'private',
'guestsCanModify': True,
@ -77,7 +76,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
})
partner_model = self.env.ref('base.model_res_partner')
partner = self.env['res.partner'].search([], limit=1)
with self.assertQueryCount(__system__=616):
with self.assertQueryCount(__system__=526):
events = self.env['calendar.event'].create([{
'name': "Event %s" % (i),
'start': datetime(2020, 1, 15, 8, 0),
@ -92,10 +91,9 @@ class TestSyncOdoo2Google(TestSyncGoogle):
events._sync_odoo2google(self.google_service)
with self.assertQueryCount(__system__=130):
with self.assertQueryCount(__system__=24):
events.unlink()
@patch_api
@users('__system__')
@warmup
@ -108,8 +106,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'duration': 18,
})
partner_model = self.env.ref('base.model_res_partner')
partner = self.env['res.partner'].search([], limit=1)
with self.assertQueryCount(__system__=72):
with self.assertQueryCount(__system__=105):
event = self.env['calendar.event'].create({
'name': "Event",
'start': datetime(2020, 1, 15, 8, 0),
@ -126,7 +123,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'res_id': partner.id,
})
with self.assertQueryCount(__system__=35):
with self.assertQueryCount(__system__=29):
event.unlink()
def test_event_without_user(self):
@ -164,7 +161,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
'summary': 'Event',
'description': '',
'description': event.description,
'location': '',
'visibility': 'private',
'guestsCanModify': True,
@ -193,7 +190,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'summary': 'Event',
'description': '',
'location': '',
'visibility': 'public',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': 'odoobot@example.com', 'self': True},
@ -255,7 +251,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'summary': 'Event',
'description': '',
'location': '',
'visibility': 'public',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': 'odoobot@example.com', 'self': True},
@ -291,7 +286,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'summary': 'Event',
'description': '',
'location': '',
'visibility': 'public',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': 'odoobot@example.com', 'self': True},
@ -345,7 +339,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'attendees': [{'email': 'odoobot@example.com', 'responseStatus': 'accepted'}],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.recurrence_id.id}},
'reminders': {'overrides': [], 'useDefault': False},
'visibility': 'public',
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=1;BYDAY=WE'],
'transparency': 'opaque',
}, timeout=3)
@ -390,9 +383,8 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
'summary': 'Event',
'description': '',
'description': event.description,
'location': '',
'visibility': 'public',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': 'jean-luc@opoo.com', 'self': True},
@ -436,7 +428,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=WE'],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: new_recurrence.id}},
'reminders': {'overrides': [], 'useDefault': False},
'visibility': 'public',
'transparency': 'opaque',
}, timeout=3)
@ -559,14 +550,13 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'start': {'date': str(event.start_date), 'dateTime': None},
'end': {'date': str(event.stop_date + relativedelta(days=1)), 'dateTime': None},
'summary': 'Event with attendees',
'description': '',
'description': event.description,
'location': '',
'guestsCanModify': True,
'organizer': {'email': 'odoobot@example.com', 'self': True},
'attendees': [{'email': 'jean-luc@opoo.com', 'responseStatus': 'declined'}],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
'reminders': {'overrides': [], 'useDefault': False},
'visibility': 'public',
'transparency': 'opaque',
})
@ -605,39 +595,9 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'recurrence': ['RRULE:FREQ=WEEKLY;WKST=SU;COUNT=2;BYDAY=WE'],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: new_recurrence.id}},
'reminders': {'overrides': [], 'useDefault': False},
'visibility': 'public',
'transparency': 'opaque',
}, timeout=3)
@patch.object(GoogleService, '_do_request')
def test_send_update_do_request(self, mock_do_request):
self.env.cr.postcommit.clear()
event = self.env['calendar.event'].create({
'name': "Event",
'allday': True,
'start': datetime(2020, 1, 15),
'stop': datetime(2020, 1, 15),
'need_sync': False,
})
event.with_context(send_updates=True)._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertGoogleEventSendUpdates('all')
@patch.object(GoogleService, '_do_request')
def test_not_send_update_do_request(self, mock_do_request):
event = self.env['calendar.event'].create({
'name': "Event",
'allday': True,
'start': datetime(2020, 1, 15),
'stop': datetime(2020, 1, 15),
'need_sync': False,
})
event.with_context(send_updates=False)._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertGoogleEventSendUpdates('none')
@patch_api
def test_recurrence_delete_single_events(self):
"""
@ -678,7 +638,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'attendees': [{'email': 'odoobot@example.com', 'responseStatus': 'accepted'}],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event_1.id}},
'reminders': {'overrides': [], 'useDefault': False},
'visibility': 'public',
'status': 'cancelled',
'transparency': 'opaque',
}, timeout=3)
@ -691,6 +650,92 @@ class TestSyncOdoo2Google(TestSyncGoogle):
self.assertFalse(event_2.active)
self.assertFalse(recurrence.active)
@patch_api
def test_create_event_with_sync_config_paused(self):
"""
Creates an event with the synchronization paused, its field 'need_sync'
must be True for later synchronizing it with Google Calendar.
"""
# Set synchronization as active and unpause the synchronization.
self.env.user.google_synchronization_stopped = False
self.env.user.sudo().pause_google_synchronization()
# Create record and call synchronization method.
record = self.env['calendar.event'].create({
'name': "Event",
'start': datetime(2023, 6, 29, 8, 0),
'stop': datetime(2023, 6, 29, 18, 0),
'need_sync': True
})
record._sync_odoo2google(self.google_service)
# Assert that synchronization is paused, insert wasn't called and record is waiting to be synced.
self.assertFalse(self.env.user.google_synchronization_stopped)
self.assertEqual(self.env.user._get_google_sync_status(), "sync_paused")
self.assertTrue(record.need_sync, "Sync variable must be true for updating event when sync re-activates")
self.assertGoogleEventNotInserted()
@patch_api
def test_update_synced_event_with_sync_config_paused(self):
"""
Updates a synced event with synchronization paused, event must be modified and have its
field 'need_sync' as True for later synchronizing it with Google Calendar.
"""
# Set synchronization as active and unpause it.
self.env.user.google_synchronization_stopped = False
self.env.user.sudo().unpause_google_synchronization()
# Setup synced record in Calendar.
record = self.env['calendar.event'].create({
'google_id': 'aaaaaaaaa',
'name': "Event",
'start': datetime(2023, 6, 29, 8, 0),
'stop': datetime(2023, 6, 29, 18, 0),
'need_sync': False
})
# Pause synchronization and update synced event. It will only update it locally.
self.env.user.sudo().pause_google_synchronization()
record.write({'name': "Updated Event"})
record._sync_odoo2google(self.google_service)
# Assert that synchronization is paused, patch wasn't called and record is waiting to be synced.
self.assertFalse(self.env.user.google_synchronization_stopped)
self.assertEqual(self.env.user._get_google_sync_status(), "sync_paused")
self.assertEqual(record.name, "Updated Event", "Assert that event name was updated in Odoo Calendar")
self.assertTrue(record.need_sync, "Sync variable must be true for updating event when sync re-activates")
self.assertGoogleEventNotPatched()
@patch_api
def test_delete_synced_event_with_sync_config_paused(self):
"""
Deletes a synced event with synchronization paused, event must be archived in Odoo and
have its field 'need_sync' as True for later synchronizing it with Google Calendar.
"""
# Set synchronization as active and then pause synchronization.
self.env.user.google_synchronization_stopped = False
self.env.user.sudo().unpause_google_synchronization()
# Setup synced record in Calendar.
record = self.env['calendar.event'].create({
'google_id': 'aaaaaaaaa',
'name': "Event",
'start': datetime(2023, 6, 29, 8, 0),
'stop': datetime(2023, 6, 29, 18, 0),
'need_sync': False
})
# Pause synchronization and delete synced event.
self.env.user.sudo().pause_google_synchronization()
record.unlink()
# Assert that synchronization is paused, delete wasn't called and record was archived in Odoo.
self.assertFalse(self.env.user.google_synchronization_stopped)
self.assertEqual(self.env.user._get_google_sync_status(), "sync_paused")
self.assertFalse(record.active, "Event must be archived in Odoo after unlinking it")
self.assertTrue(record.need_sync, "Sync variable must be true for updating event in Google when sync re-activates")
self.assertGoogleEventNotDeleted()
@patch_api
def test_videocall_location_on_location_set(self):
partner = self.env['res.partner'].create({'name': 'Jean-Luc', 'email': 'jean-luc@opoo.com'})
@ -703,7 +748,7 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'location' : 'Event Location'
})
event._sync_odoo2google(self.google_service)
self.assertGoogleEventHasNoConferenceData()
self.assertGoogleEventInserted({'conferenceData': False})
@patch_api
def test_event_available_privacy(self):
@ -723,7 +768,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'summary': 'Event',
'description': '',
'location': '',
'visibility': 'public',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': 'odoobot@example.com', 'self': True},
@ -750,7 +794,6 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'summary': 'Event',
'description': '',
'location': '',
'visibility': 'public',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': 'odoobot@example.com', 'self': True},
@ -759,6 +802,55 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'transparency': 'opaque',
})
@patch_api
@patch.object(ResUsers, '_sync_request')
def test_event_sync_after_pause_period(self, mock_sync_request):
""" Ensure that an event created during the paused synchronization period gets synchronized after resuming it. """
# Pause the synchronization and creates the local event.
self.organizer_user.google_synchronization_stopped = False
self.organizer_user.sudo().pause_google_synchronization()
record = self.env['calendar.event'].with_user(self.organizer_user).create({
'name': "Event",
'start': datetime(2023, 1, 15, 8, 0),
'stop': datetime(2023, 1, 15, 18, 0),
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)]
})
# Define mock return values for the '_sync_request' method.
mock_sync_request.return_value = {
'events': GoogleEvent([]),
'default_reminders': (),
'full_sync': False,
}
# With the synchronization paused, manually call the synchronization to simulate the page refresh.
self.organizer_user.sudo()._sync_google_calendar(self.google_service)
self.assertFalse(self.organizer_user.google_synchronization_stopped, "Synchronization should not be stopped, only paused.")
self.assertEqual(self.organizer_user._get_google_sync_status(), "sync_paused", "Synchronization must be paused since it wasn't resumed yet.")
self.assertTrue(record.need_sync, "Record must have its 'need_sync' variable as true for it to be synchronized when the synchronization is resumed.")
self.assertGoogleEventNotInserted()
# Unpause the synchronization and call the calendar synchronization. Ensure the event was inserted in Google side.
self.organizer_user.sudo().unpause_google_synchronization()
self.organizer_user.with_user(self.organizer_user).sudo()._sync_google_calendar(self.google_service)
self.assertGoogleEventInserted({
'id': False,
'start': {'dateTime': '2023-01-15T08:00:00+00:00', 'date': None},
'end': {'dateTime': '2023-01-15T18:00:00+00:00', 'date': None},
'summary': 'Event',
'description': record.description,
'location': '',
'guestsCanModify': True,
'transparency': 'opaque',
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': self.organizer_user.email, 'self': True},
'attendees': [
{'email': self.attendee_user.email, 'responseStatus': 'needsAction'},
{'email': self.organizer_user.email, 'responseStatus': 'accepted'}
],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: record.id}},
})
@patch_api
def test_allday_duplicated_first_event_in_recurrence(self):
""" Ensure that when creating recurrence with 'all day' events the first event won't get duplicated in Google. """
@ -788,9 +880,8 @@ class TestSyncOdoo2Google(TestSyncGoogle):
'start': {'date': '2024-01-17', 'dateTime': None},
'end': {'date': '2024-01-18', 'dateTime': None},
'summary': 'All Day Recurrent Event',
'description': '',
'description': event.description,
'location': '',
'visibility': 'public',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': self.organizer_user.email, 'self': True},
@ -801,118 +892,227 @@ class TestSyncOdoo2Google(TestSyncGoogle):
}, timeout=3)
@patch_api
def test_partner_type_change(self):
"""Test syncing an event with a private address attendee using
a user without access to private addresses.
@patch.object(ResUsers, '_sync_request')
def test_skip_google_sync_for_non_synchronized_users_new_events(self, mock_sync_request):
"""
user = self.env['res.users'].create({
'name': 'user1',
'login': 'user1',
'email': 'user1@odoo.com',
})
private_partner = self.env['res.partner'].create({
'name': 'Private Contact',
'email': 'private_email@example.com',
'type': 'private',
})
event = self.env['calendar.event'].create({
'name': "Private Event",
'user_id': user.id,
'start': datetime(2020, 1, 13, 16, 55),
'stop': datetime(2020, 1, 13, 19, 55),
'partner_ids': [(4, private_partner.id)],
'privacy': 'private',
Skip the synchro of new events by attendees when the organizer is not synchronized with Google.
Otherwise, the event ownership will be lost to the attendee and it could generate duplicates in
Odoo, as well cause problems in the future the synchronization of that event for the original owner.
"""
with self.mock_datetime_and_now("2023-01-10"):
# Stop the synchronization for the organizer and leave the attendee synchronized.
# Then, create an event with the organizer and attendee. Assert that it was not inserted.
self.organizer_user.google_synchronization_stopped = True
self.attendee_user.google_synchronization_stopped = False
record = self.env['calendar.event'].with_user(self.organizer_user).create({
'name': "Event",
'start': datetime(2023, 1, 15, 8, 0),
'stop': datetime(2023, 1, 15, 18, 0),
'need_sync': True,
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)]
})
self.assertGoogleEventNotInserted()
# Define mock return values for the '_sync_request' method.
mock_sync_request.return_value = {
'events': GoogleEvent([]),
'default_reminders': (),
'full_sync': False,
}
# Synchronize the attendee, and ensure that the event was not inserted after it.
self.attendee_user.with_user(self.attendee_user).sudo()._sync_google_calendar(self.google_service)
self.assertGoogleAPINotCalled()
# Now, we synchronize the organizer and make sure the event got inserted by him.
self.organizer_user.with_user(self.organizer_user).restart_google_synchronization()
self.organizer_user.with_user(self.organizer_user).sudo()._sync_google_calendar(self.google_service)
self.assertGoogleEventInserted({
'id': False,
'start': {'dateTime': '2023-01-15T08:00:00+00:00', 'date': None},
'end': {'dateTime': '2023-01-15T18:00:00+00:00', 'date': None},
'summary': 'Event',
'description': ('<div><strong>Organized by</strong><br>'
'organizer_user (base.group_user)<br><a href="mailto:o.o@example.com">o.o@example.com</a><br><br>'
'<strong>Contact Details</strong><br>'
'attendee_user (base.group_user)<br><a href="mailto:a.a@example.com">a.a@example.com</a></div>'),
'location': '',
'guestsCanModify': True,
'transparency': 'opaque',
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': self.organizer_user.email, 'self': True},
'attendees': [
{'email': self.attendee_user.email, 'responseStatus': 'needsAction'},
{'email': self.organizer_user.email, 'responseStatus': 'accepted'}
],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: record.id}},
})
@patch_api
def test_event_duplication_allday_google_calendar(self):
event = self.env['calendar.event'].with_user(self.organizer_user).create({
'name': "Event",
'allday': True,
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)],
'start': datetime(2020, 1, 15),
'stop': datetime(2020, 1, 15),
'need_sync': False,
})
event = event.with_user(user)
event.env.invalidate_all()
event._sync_odoo2google(self.google_service)
event_response_data = {
'id': False,
'start': {'date': '2020-01-15', 'dateTime': None},
'end': {'date': '2020-01-16', 'dateTime': None},
'summary': 'Event',
'description': event.description,
'location': '',
'guestsCanModify': True,
'organizer': {'email': self.organizer_user.email, 'self': True},
'attendees': [
{'email': self.attendee_user.email, 'responseStatus': 'needsAction'},
{'email': self.organizer_user.email, 'responseStatus': 'accepted'}
],
'reminders': {'overrides': [], 'useDefault': False},
'transparency': 'opaque',
}
self.assertGoogleEventInsertedMultiTime({
**event_response_data,
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
})
event2 = event.copy()
event2._sync_odoo2google(self.google_service)
event_response_data['description'] = event2.description
self.assertGoogleEventInsertedMultiTime({
**event_response_data,
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event2.id}},
})
def test_event_over_send_updates(self):
"""Test that events that are over don't sent updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
past_event = self.env['calendar.event'].create({
'name': "Event",
'start': datetime(2020, 1, 15, 8, 0),
'stop': datetime(2020, 1, 15, 9, 0),
'need_sync': False,
})
past_event._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertTrue(past_event._is_event_over(), "Event should be considered over")
self.assertGoogleEventSendUpdates('none')
def test_event_not_over_send_updates(self):
"""Test that events that are not over send updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
future_date = datetime(2023, 1, 20, 8, 0) # Fixed date instead of datetime.now()
future_event = self.env['calendar.event'].create({
'name': "Future Event",
'start': future_date,
'stop': future_date + relativedelta(hours=1),
'need_sync': False,
})
# Sync the event and verify send_updates is set to 'all'
future_event._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertFalse(future_event._is_event_over(), "Future event should not be considered over")
self.assertGoogleEventSendUpdates('all')
def test_recurrence_over_send_updates(self):
"""Test that recurrences that are over don't send updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
past_event = self.env['calendar.event'].create({
'name': "Past Recurring Event",
'start': datetime(2020, 1, 15, 8, 0),
'stop': datetime(2020, 1, 15, 9, 0),
'need_sync': False,
})
past_recurrence = self.env['calendar.recurrence'].create({
'rrule': 'FREQ=WEEKLY;COUNT=2;BYDAY=WE',
'base_event_id': past_event.id,
'need_sync': False,
})
past_recurrence._apply_recurrence()
# Sync the recurrence and verify send_updates is set to 'none'
past_recurrence._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertTrue(past_recurrence._is_event_over(), "Past recurrence should be considered over")
self.assertGoogleEventSendUpdates('none')
def test_recurrence_not_over_send_updates(self):
"""Test that recurrences that are not over send updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
future_date = datetime(2023, 1, 20, 8, 0)
future_event = self.env['calendar.event'].create({
'name': "Future Recurring Event",
'start': future_date,
'stop': future_date + relativedelta(hours=1),
'need_sync': False,
})
future_recurrence = self.env['calendar.recurrence'].create(
{
'rrule': 'FREQ=WEEKLY;COUNT=2;BYDAY=WE',
'base_event_id': future_event.id,
'need_sync': False,
}
)
future_recurrence._apply_recurrence()
# Sync the recurrence and verify send_updates is set to 'all'
future_recurrence._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertFalse(future_recurrence._is_event_over(), "Future recurrence should not be considered over")
self.assertGoogleEventSendUpdates('all')
@patch_api
def test_eliminate_remote_meet_link_when_removed_locally(self):
partner = self.env['res.partner'].create({'name': 'Name', 'email': 'email@emailprovider.com'})
google_id = 'nicegoogleid'
event = self.env['calendar.event'].create({
'google_id': google_id,
'name': "Awesome event",
'start': datetime(2020, 1, 15, 8, 0),
'stop': datetime(2020, 1, 15, 18, 0),
'partner_ids': [(4, partner.id)],
'need_sync': False,
})
event.write({'videocall_location': False})
event._sync_odoo2google(self.google_service)
self.assertGoogleEventPatched(google_id, {'conferenceData': None}, timeout=3)
@patch_api
def test_event_creation_for_different_user(self):
"""
Test event is synchronized for organizer with active google synchronization if it is
created by a user with google synchronization stopped.
"""
self.attendee_user.google_synchronization_stopped = True
self.organizer_user.google_calendar_token = 'dummy-token'
event = self.env['calendar.event'].with_user(self.attendee_user).create({
'name': "Event",
'start': datetime(2020, 1, 15, 8, 0),
'stop': datetime(2020, 1, 15, 18, 0),
'user_id': self.organizer_user.id,
'partner_ids': [(4, self.organizer_user.partner_id.id), (4, self.attendee_user.partner_id.id)],
})
event._sync_odoo2google(self.google_service)
self.assertGoogleEventInserted({
'id': False,
'start': {'dateTime': '2020-01-13T16:55:00+00:00', 'date': None},
'end': {'dateTime': '2020-01-13T19:55:00+00:00', 'date': None},
'summary': 'Private Event',
'description': '',
'location': '',
'visibility': 'private',
'guestsCanModify': True,
'reminders': {'overrides': [], 'useDefault': False},
'organizer': {'email': 'user1@odoo.com', 'self': True},
'attendees': [{'email': 'private_email@example.com', 'responseStatus': 'needsAction'}],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
'transparency': 'opaque',
})
@patch_api
def test_update_allday_to_timed_event(self):
""" Ensure that updating in Odoo all-day events to timed events is reflected in Google. """
# Create an 'all-day' event synchronized with Google.
self.organizer_user.stop_google_synchronization()
event = self.env['calendar.event'].with_user(self.organizer_user).create({
'name': "AllDay",
'google_id': 'allDayEv',
'user_id': self.organizer_user.id,
'start': datetime(2024, 1, 17),
'stop': datetime(2024, 1, 17),
'allday': True,
'need_sync': False,
'recurrency': True,
'recurrence_id': False,
})
# In Odoo, update the event from 'all-day' to timed event.
# Ensure that it got successfully patched in Google side.
self.organizer_user.restart_google_synchronization()
event.with_user(self.organizer_user.id).write({"allday": False})
self.assertGoogleEventPatched(event.google_id, {
'id': event.google_id,
'start': {'date': None, 'dateTime': '2024-01-17T00:00:00+00:00'},
'end': {'date': None, 'dateTime': '2024-01-17T00:00:00+00:00'},
'summary': 'AllDay',
'description': '',
'start': {'dateTime': '2020-01-15T08:00:00+00:00', 'date': None},
'end': {'dateTime': '2020-01-15T18:00:00+00:00', 'date': None},
'summary': 'Event',
'location': '',
'guestsCanModify': True,
'organizer': {'email': 'o.o@example.com', 'self': True},
'attendees': [{'email': 'o.o@example.com', 'responseStatus': 'accepted'}],
'organizer': {'email': 'o.o@example.com', 'self': False},
'attendees': [{'email': 'a.a@example.com', 'responseStatus': 'accepted'}, {'email': 'o.o@example.com', 'responseStatus': 'needsAction'}],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
'reminders': {'overrides': [], 'useDefault': False},
'visibility': 'public',
'transparency': 'opaque',
}, timeout=3)
@patch_api
def test_update_timed_to_allday_event(self):
""" Ensure that updating in Odoo timed events to all-day events is reflected in Google. """
# Create a timed event synchronized with Google.
self.organizer_user.stop_google_synchronization()
event = self.env['calendar.event'].with_user(self.organizer_user).create({
'name': "TimedEvent",
'google_id': 'timedEvId',
'user_id': self.organizer_user.id,
'start': datetime(2024, 1, 17, 10, 00),
'stop': datetime(2024, 1, 17, 11, 00),
'allday': False,
'need_sync': False,
'recurrency': True,
'recurrence_id': False,
})
# In Odoo, update the event from timed to 'all-day'.
# Ensure that it got successfully patched in Google side.
self.organizer_user.restart_google_synchronization()
event.with_user(self.organizer_user.id).write({"allday": True})
self.assertGoogleEventPatched(event.google_id, {
'id': event.google_id,
'start': {'date': '2024-01-17', 'dateTime': None},
'end': {'date': '2024-01-18', 'dateTime': None},
'summary': 'TimedEvent',
'description': '',
'location': '',
'guestsCanModify': True,
'organizer': {'email': 'o.o@example.com', 'self': True},
'attendees': [{'email': 'o.o@example.com', 'responseStatus': 'accepted'}],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}},
'reminders': {'overrides': [], 'useDefault': False},
'visibility': 'public',
'transparency': 'opaque',
}, timeout=3)