diff --git a/engine/apps/schedules/ical_events/adapter/amixr_recurring_ical_events_adapter.py b/engine/apps/schedules/ical_events/adapter/amixr_recurring_ical_events_adapter.py index f1d74cff..b5729313 100644 --- a/engine/apps/schedules/ical_events/adapter/amixr_recurring_ical_events_adapter.py +++ b/engine/apps/schedules/ical_events/adapter/amixr_recurring_ical_events_adapter.py @@ -2,22 +2,12 @@ from collections import defaultdict from datetime import datetime from typing import List -from django.apps import apps from django.utils import timezone from icalendar import Calendar, Event from recurring_ical_events import UnfoldableCalendar, compare_greater, is_event, time_span_contains_event -from apps.schedules.constants import ( - ICAL_DATETIME_END, - ICAL_DATETIME_STAMP, - ICAL_DATETIME_START, - ICAL_RRULE, - ICAL_UID, - ICAL_UNTIL, - RE_EVENT_UID_V1, - RE_EVENT_UID_V2, -) from apps.schedules.ical_events.proxy.ical_proxy import IcalService +from apps.schedules.ical_utils import get_start_and_end_with_respect_to_event_type EXTRA_LOOKUP_DAYS = 16 @@ -105,17 +95,7 @@ class AmixrRecurringIcalEventsAdapter(IcalService): ) def filter_extra_days(event): - CustomOnCallShift = apps.get_model("schedules", "CustomOnCallShift") - match = RE_EVENT_UID_V2.match(event[ICAL_UID]) or RE_EVENT_UID_V1.match(event[ICAL_UID]) - # use different calculation rule for events from custom shifts generated at web - if match and int(match.groups()[-1]) == CustomOnCallShift.SOURCE_WEB: - event_start = max(event[ICAL_DATETIME_START].dt, event[ICAL_DATETIME_STAMP].dt) - event_end = event[ICAL_DATETIME_END].dt - if event.get(ICAL_RRULE, {}).get(ICAL_UNTIL): - event_end = min(event[ICAL_RRULE][ICAL_UNTIL][0], event[ICAL_DATETIME_END].dt) - else: - event_start = event[ICAL_DATETIME_START].dt - event_end = event[ICAL_DATETIME_END].dt + event_start, event_end = get_start_and_end_with_respect_to_event_type(event) return time_span_contains_event(start_date, end_date, event_start, event_end) return list(filter(filter_extra_days, events)) diff --git a/engine/apps/schedules/ical_utils.py b/engine/apps/schedules/ical_utils.py index e44fa9ae..49206b8b 100644 --- a/engine/apps/schedules/ical_utils.py +++ b/engine/apps/schedules/ical_utils.py @@ -165,7 +165,6 @@ def list_of_oncall_shifts_from_ical( def get_shifts_dict(calendar, calendar_type, schedule, datetime_start, datetime_end, date, with_empty_shifts=False): - OnCallScheduleWeb = apps.get_model("schedules", "OnCallScheduleWeb") events = ical_events.get_events_from_ical_between(calendar, datetime_start, datetime_end) result_datetime = [] result_date = [] @@ -177,14 +176,7 @@ def get_shifts_dict(calendar, calendar_type, schedule, datetime_start, datetime_ # Define on-call shift out of ical event that has the actual user if len(users) > 0 or with_empty_shifts: if type(event[ICAL_DATETIME_START].dt) == datetime.date: - if isinstance(schedule, OnCallScheduleWeb): - start = max(event[ICAL_DATETIME_START].dt, event[ICAL_DATETIME_STAMP].dt.date()) - end = event[ICAL_DATETIME_END].dt - if event.get(ICAL_RRULE, {}).get(ICAL_UNTIL): - end = min(event[ICAL_DATETIME_END].dt, event[ICAL_RRULE][ICAL_UNTIL][0].date()) - else: - start = event[ICAL_DATETIME_START].dt - end = event[ICAL_DATETIME_END].dt + start, end = get_start_and_end_with_respect_to_event_type(event, full_day_event=True) if start <= date < end: result_date.append( { @@ -199,22 +191,11 @@ def get_shifts_dict(calendar, calendar_type, schedule, datetime_start, datetime_ } ) else: - if isinstance(schedule, OnCallScheduleWeb): - start = max( - event[ICAL_DATETIME_START].dt.astimezone(pytz.UTC), - event[ICAL_DATETIME_STAMP].dt.astimezone(pytz.UTC), - ) - end = event[ICAL_DATETIME_END].dt.astimezone(pytz.UTC) - if event.get(ICAL_RRULE, {}).get(ICAL_UNTIL): - end = min(event[ICAL_DATETIME_END].dt.astimezone(pytz.UTC), event[ICAL_RRULE][ICAL_UNTIL][0]) - else: - start = event[ICAL_DATETIME_START].dt.astimezone(pytz.UTC) - end = event[ICAL_DATETIME_END].dt.astimezone(pytz.UTC) - + start, end = get_start_and_end_with_respect_to_event_type(event) result_datetime.append( { - "start": start, - "end": end, + "start": start.astimezone(pytz.UTC), + "end": end.astimezone(pytz.UTC), "users": users, "missing_users": missing_users, "priority": priority, @@ -762,3 +743,28 @@ def convert_windows_timezone_to_iana(tz_name): logger.debug("Converting the timezone from Windows to IANA. '{}' -> '{}'".format(tz_name, result)) return result + + +def get_start_and_end_with_respect_to_event_type(event, full_day_event=False): + """ + Calculate start and end datetime (or dates for full_day_event) + """ + CustomOnCallShift = apps.get_model("schedules", "CustomOnCallShift") + + start = event[ICAL_DATETIME_START].dt + end = event[ICAL_DATETIME_END].dt + + match = RE_EVENT_UID_V2.match(event[ICAL_UID]) or RE_EVENT_UID_V1.match(event[ICAL_UID]) + # use different calculation rule for events from custom shifts generated at web + if match and int(match.groups()[-1]) == CustomOnCallShift.SOURCE_WEB: + rotation_start = event[ICAL_DATETIME_STAMP] + until = event.get(ICAL_RRULE, {}).get(ICAL_UNTIL) + + if full_day_event: + rotation_start = rotation_start.date() + until = until.date() if until else None + + start = max(start, rotation_start) + end = min(end, until) if until else end + + return start, end