caldav_sync: further fixes for organizer issues
This commit is contained in:
parent
3ebadcb969
commit
4b19f8262e
2 changed files with 44 additions and 14 deletions
|
|
@ -611,7 +611,8 @@ class CalendarEvent(models.Model):
|
|||
owned = (
|
||||
existing_instance and existing_instance.partner_id == user.partner_id
|
||||
)
|
||||
values = self._get_values_from_ical_component(component, user)
|
||||
# Pass for_creation=True only when creating a new event
|
||||
values = self._get_values_from_ical_component(component, user, for_creation=not existing_instance)
|
||||
recurrency_vals = self._get_recurrency_values_from_ical_event(component)
|
||||
if not existing_instance:
|
||||
# If we're creating an instance and it doesn't follow the recurrence,
|
||||
|
|
@ -647,7 +648,7 @@ class CalendarEvent(models.Model):
|
|||
return synced_events
|
||||
|
||||
@api.model
|
||||
def _get_existing_instance(self, uid, recurrence_id: datetime) -> CalendarEvent:
|
||||
def _get_existing_instance(self, uid, recurrence_id: Optional[datetime]) -> CalendarEvent:
|
||||
"""Find the Odoo calendar.event record matching uid and,
|
||||
if set, recurrence_id.
|
||||
"""
|
||||
|
|
@ -686,7 +687,7 @@ class CalendarEvent(models.Model):
|
|||
|
||||
return instance or self.env["calendar.event"].search(
|
||||
[
|
||||
("caldav_uid", "=", "uid"),
|
||||
("caldav_uid", "=", uid),
|
||||
("recurrence_id", "=", False),
|
||||
]
|
||||
)
|
||||
|
|
@ -841,14 +842,15 @@ class CalendarEvent(models.Model):
|
|||
|
||||
@api.model
|
||||
def _get_values_from_ical_component(
|
||||
self, component: icalendar.cal.Component, user: User
|
||||
self, component: icalendar.cal.Component, user: User, for_creation: bool = False
|
||||
) -> Dict:
|
||||
"""Get the dictionary representing calendar.event field values from
|
||||
an iCalendar event.
|
||||
|
||||
:param component: The iCalendar component from which to extract
|
||||
values.
|
||||
:param component: The iCalendar component from which to extract values.
|
||||
:param user: The res.users record the event will belong to.
|
||||
:param for_creation: Whether these values are for creating a new event (True)
|
||||
or updating an existing one (False).
|
||||
:return: The dictionary of values to construct a calendar.event."""
|
||||
start = component.get("dtstart") and component.decoded("dtstart")
|
||||
if isinstance(start, datetime):
|
||||
|
|
@ -856,11 +858,11 @@ class CalendarEvent(models.Model):
|
|||
end = component.get("dtend") and component.decoded("dtend")
|
||||
if isinstance(end, datetime):
|
||||
end = end.astimezone(utc).replace(tzinfo=None)
|
||||
organizer_partner = self._get_organizer_partner(component)
|
||||
# Get the Odoo user ID associated with the organizer partner
|
||||
# If no Odoo user is associated, set to False (external)
|
||||
organizer = organizer_partner.user_ids[0].id if organizer_partner.user_ids else False
|
||||
|
||||
# Get attendees regardless of creation/update
|
||||
attendee_ids = self._get_attendee_partners(component, user.partner_id.email)
|
||||
|
||||
# Basic values that apply to both creation and updates
|
||||
values = {
|
||||
"name": str(component.get("summary")),
|
||||
"start": start,
|
||||
|
|
@ -872,10 +874,25 @@ class CalendarEvent(models.Model):
|
|||
"videocall_location": self._extract_component_text(component, "conference"),
|
||||
"caldav_uid": str(component.get("uid")),
|
||||
"partner_ids": [(6, 0, attendee_ids.ids)],
|
||||
"partner_id": organizer_partner.id if organizer_partner else user.partner_id.id,
|
||||
"user_id": organizer,
|
||||
|
||||
}
|
||||
|
||||
# Only set user_id and partner_id during creation
|
||||
if for_creation:
|
||||
organizer_partner = self._get_organizer_partner(component)
|
||||
if organizer_partner:
|
||||
# Get the Odoo user ID associated with the organizer partner
|
||||
organizer = organizer_partner.user_ids[0].id if organizer_partner.user_ids else False
|
||||
values.update({
|
||||
"partner_id": organizer_partner.id,
|
||||
"user_id": organizer,
|
||||
})
|
||||
else:
|
||||
# For new events without an organizer, use the current user
|
||||
values.update({
|
||||
"partner_id": user.partner_id.id,
|
||||
"user_id": user.id,
|
||||
})
|
||||
|
||||
return values
|
||||
|
||||
@api.model
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from collections.abc import Iterable
|
||||
from odoo.tests import TransactionCase
|
||||
from odoo.tests import TransactionCase, tagged
|
||||
from odoo import Command
|
||||
from unittest.mock import patch, MagicMock, DEFAULT
|
||||
import icalendar
|
||||
|
|
@ -85,6 +85,7 @@ def _patch_caldav_with_events_from_ics(ics_paths, user, last_modified=None):
|
|||
yield
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestCalendarEvent(TransactionCase, CaldavTestCommon):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
|
@ -127,17 +128,29 @@ class TestCalendarEvent(TransactionCase, CaldavTestCommon):
|
|||
ics_path = _get_ics_path("basic.ics")
|
||||
with _patch_caldav_with_events_from_ics(ics_path, user):
|
||||
self.env["calendar.event"].poll_caldav_server()
|
||||
|
||||
# Verify the event was created correctly
|
||||
event = self.env["calendar.event"].search([("user_id", "=", user.id)])
|
||||
self.assertEqual(event.name, "Test")
|
||||
orig_start = event.start
|
||||
orig_stop = event.stop
|
||||
|
||||
# Now update the event with the updated ICS data
|
||||
ics_path = _get_ics_path("basic_updated.ics")
|
||||
with _patch_caldav_with_events_from_ics(
|
||||
ics_path,
|
||||
user,
|
||||
last_modified=(datetime.now(UTC)),
|
||||
):
|
||||
# Clear any caches to ensure fresh data
|
||||
self.env["calendar.event"].invalidate_model()
|
||||
self.env["calendar.event"].poll_caldav_server()
|
||||
|
||||
# Refresh the event from the database to get updated values
|
||||
event.invalidate_recordset()
|
||||
event = self.env["calendar.event"].search([("user_id", "=", user.id)])
|
||||
|
||||
# Verify the event was updated correctly
|
||||
self.assertEqual(event.name, "Test Updated")
|
||||
# This next one is just lazy avoiding the HTML stripping
|
||||
self.assertIn("Some note ...", event.description)
|
||||
|
|
|
|||
Loading…
Reference in a new issue