Skip to content
Snippets Groups Projects
Commit 0afb82c7 authored by Hangzhi Yu's avatar Hangzhi Yu
Browse files

Generalize overlap handling mechanism in separate class method

parent 9d7a2750
No related branches found
No related tags found
1 merge request!66Resolve "Add mechanism to clear all absences of person in given time span"
Pipeline #194887 passed
......@@ -144,6 +144,94 @@ class Absence(FreeBusy):
"""Return the title of the calendar event."""
return ""
@classmethod
def clear_or_extend_absences_in_timespan(
cls,
person: Person,
datetime_start: datetime,
datetime_end: datetime,
reason: AbsenceReason | None = None,
) -> list:
extended_absence = None
modified_absences = []
events_within = cls.get_objects(
None,
{"person": person.pk},
start=datetime_start,
end=datetime_end,
)
for event_within in events_within:
event_within_datetime_start = (
event_within.datetime_start
if event_within.datetime_start
else datetime.combine(event_within.date_start, time.min)
)
event_within_datetime_end = (
event_within.datetime_end
if event_within.datetime_end
else datetime.combine(event_within.date_end, time.max)
)
# If overlapping absence has the same reason, just extend it
if reason is not None and event_within.reason == reason:
event_within.datetime_start = min(datetime_start, event_within_datetime_start)
event_within.datetime_end = max(datetime_end, event_within_datetime_end)
event_within.save(skip_overlap_handling=True)
extended_absence = event_within
modified_absences.append(event_within)
else:
if (
datetime_start > event_within_datetime_start
and datetime_end < event_within_datetime_end
):
# Cut existing event in two parts
# First, cut end date of existing one
event_within.datetime_end = datetime_start
event_within.save(skip_overlap_handling=True)
modified_absences.append(event_within)
# Then, create new event based on existing one filling up the remaining time
end_filler_event = event_within
end_filler_event.pk = None
end_filler_event.id = None
end_filler_event.calendarevent_ptr_id = None
end_filler_event.freebusy_ptr_id = None
end_filler_event._state.adding = True
end_filler_event.datetime_start = datetime_end
end_filler_event.datetime_end = event_within_datetime_end
end_filler_event.save(skip_overlap_handling=True)
modified_absences.append(end_filler_event)
elif (
datetime_start <= event_within_datetime_start
and datetime_end >= event_within_datetime_end
):
# Delete existing event
if event_within in modified_absences:
modified_absences.remove(event_within)
event_within.delete()
elif (
datetime_start > event_within_datetime_start
and datetime_start < event_within_datetime_end
and datetime_end >= event_within_datetime_end
):
# Cut end of existing event
event_within.datetime_end = datetime_start
event_within.save(skip_overlap_handling=True)
modified_absences.append(event_within)
elif (
datetime_start <= event_within_datetime_start
and datetime_end < event_within_datetime_end
and datetime_end > event_within_datetime_start
):
# Cut start of existing event
event_within.datetime_start = datetime_end
event_within.save(skip_overlap_handling=True)
modified_absences.append(event_within)
return modified_absences, extended_absence
def __str__(self):
return f"{self.person} ({self.datetime_start} - {self.datetime_end})"
......@@ -164,84 +252,10 @@ class Absence(FreeBusy):
else datetime.combine(self.date_end, time.max)
).astimezone(self.timezone)
events_within = Absence.get_objects(
None,
{"person": self.person.pk},
start=new_datetime_start,
end=new_datetime_end,
modified_absences, extended_absence = self.clear_or_extend_absences_in_timespan(
self.person, new_datetime_start, new_datetime_end, self.reason
)
for event_within in events_within:
event_within_datetime_start = (
event_within.datetime_start
if event_within.datetime_start
else datetime.combine(event_within.date_start, time.min)
)
event_within_datetime_end = (
event_within.datetime_end
if event_within.datetime_end
else datetime.combine(event_within.date_end, time.max)
)
# If overlapping absence has the same reason, just extend it
if event_within.reason == self.reason:
event_within.datetime_start = min(
new_datetime_start, event_within_datetime_start
)
event_within.datetime_end = max(new_datetime_end, event_within_datetime_end)
event_within.save(skip_overlap_handling=True)
extended_absence = event_within
modified_absences.append(event_within)
else:
if (
new_datetime_start > event_within_datetime_start
and new_datetime_end < event_within_datetime_end
):
# Cut existing event in two parts
# First, cut end date of existing one
event_within.datetime_end = new_datetime_start
event_within.save(skip_overlap_handling=True)
modified_absences.append(event_within)
# Then, create new event based on existing one filling up the remaining time
end_filler_event = event_within
end_filler_event.pk = None
end_filler_event.id = None
end_filler_event.calendarevent_ptr_id = None
end_filler_event.freebusy_ptr_id = None
end_filler_event._state.adding = True
end_filler_event.datetime_start = new_datetime_end
end_filler_event.datetime_end = event_within_datetime_end
end_filler_event.save(skip_overlap_handling=True)
modified_absences.append(end_filler_event)
elif (
new_datetime_start <= event_within_datetime_start
and new_datetime_end >= event_within_datetime_end
):
# Delete existing event
if event_within in modified_absences:
modified_absences.remove(event_within)
event_within.delete()
elif (
new_datetime_start > event_within_datetime_start
and new_datetime_start < event_within_datetime_end
and new_datetime_end >= event_within_datetime_end
):
# Cut end of existing event
event_within.datetime_end = new_datetime_start
event_within.save(skip_overlap_handling=True)
modified_absences.append(event_within)
elif (
new_datetime_start <= event_within_datetime_start
and new_datetime_end < event_within_datetime_end
and new_datetime_end > event_within_datetime_start
):
# Cut start of existing event
event_within.datetime_start = new_datetime_end
event_within.save(skip_overlap_handling=True)
modified_absences.append(event_within)
modified_absences.append(self)
modified_absences.append(self)
if extended_absence is not None:
self._extended_absence = extended_absence
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment