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

Cut existing absences on absence creation to avoid overlaps

parent a29a3544
No related branches found
No related tags found
1 merge request!52Resolve "Only allow one absence at any point of time"
Pipeline #193951 passed
from datetime import datetime, time
from django.db import models
from django.db.models import Q, QuerySet
from django.http import HttpRequest
......@@ -145,6 +147,81 @@ class Absence(FreeBusy):
def __str__(self):
return f"{self.person} ({self.datetime_start} - {self.datetime_end})"
def save(self, *args, skip_overlap_handling=False, **kwargs):
if not skip_overlap_handling:
events_within = Absence.get_objects(
None,
{"person": self.person.pk},
start=self.datetime_start or self.date_start,
end=self.datetime_end or self.date_end,
)
# Convert dates of new event to datetimes in case dates are used
new_datetime_start = (
self.datetime_start
if self.datetime_start
else datetime.combine(self.date_start, time())
).astimezone(self.timezone)
new_datetime_end = (
self.datetime_end
if self.datetime_end
else datetime.combine(self.date_end, datetime.max.time())
).astimezone(self.timezone)
for event_within in events_within:
event_within_datetime_start = (
Absence.value_start_datetime(event_within)
if event_within.datetime_start
else datetime.combine(Absence.value_start_datetime(event_within), time())
)
event_within_datetime_end = (
Absence.value_end_datetime(event_within)
if event_within.datetime_end
else datetime.combine(
Absence.value_end_datetime(event_within), datetime.max.time()
)
)
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)
# Then, create new event filling up the remaining time span
end_filler_event = event_within
end_filler_event.pk = None
end_filler_event.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)
elif (
new_datetime_start <= event_within_datetime_start
and new_datetime_end >= event_within_datetime_end
):
# Delete existing event
event_within.delete()
elif (
new_datetime_start > event_within_datetime_start
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)
elif (
new_datetime_start <= event_within_datetime_start
and new_datetime_end < event_within_datetime_end
):
# Cut start of existing event
event_within.datetime_start = new_datetime_end
event_within.save(skip_overlap_handling=True)
super().save(*args, **kwargs)
class Meta:
verbose_name = _("Absence")
verbose_name_plural = _("Absences")
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