Skip to content
Snippets Groups Projects
Commit 636ae38b authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Merge branch '39-add-mechanism-to-clear-all-absences-of-person-in-given-time-span' into 'master'

Resolve "Add mechanism to clear all absences of person in given time span"

Closes #39

See merge request !66
parents 9d7a2750 0afb82c7
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 #194930 canceled
......@@ -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