diff --git a/shiftregister/app/models.py b/shiftregister/app/models.py
index 20f57a5..34bb420 100644
--- a/shiftregister/app/models.py
+++ b/shiftregister/app/models.py
@@ -97,6 +97,40 @@ class Helper(models.Model):
token.send()
return token
+ def has_overlapping_shift(self, shift):
+ new_shift_end = shift.start_at + shift.duration
+
+ return (
+ ShiftRegistration.objects.annotate(
+ shift_end=ExpressionWrapper(
+ F("shift__start_at") + F("shift__duration"),
+ output_field=models.DateTimeField(),
+ )
+ )
+ .filter(
+ helper=self,
+ shift__deleted=False,
+ state__in=[
+ ShiftRegistration.RegState.REGISTERED,
+ ShiftRegistration.RegState.CHECKED_IN,
+ ],
+ )
+ .filter(
+ # Case 1: Start time falls between new shift's start and end
+ Q(
+ shift__start_at__gte=shift.start_at,
+ shift__start_at__lt=new_shift_end,
+ )
+ |
+ # Case 2: End time falls between new shift's start and end
+ Q(shift_end__gt=shift.start_at, shift_end__lte=new_shift_end)
+ |
+ # Case 3: Completely encompasses the new shift
+ Q(shift__start_at__lte=shift.start_at, shift_end__gte=new_shift_end)
+ )
+ .first()
+ )
+
# current or next shift
def important_shift(self):
ret = (
diff --git a/shiftregister/app/templates/shift.html b/shiftregister/app/templates/shift.html
index f97ad15..9904c73 100644
--- a/shiftregister/app/templates/shift.html
+++ b/shiftregister/app/templates/shift.html
@@ -13,7 +13,11 @@
Diese Schicht wurde gelöscht.
{% endif %}
{% if not can_register and not is_registered %}
+ {% if has_overlap %}
+ Diese Schicht ist bereits besetzt.
+ {% endif %}
{% endif %}
diff --git a/shiftregister/app/views.py b/shiftregister/app/views.py
index 9f268d0..fd94fbb 100644
--- a/shiftregister/app/views.py
+++ b/shiftregister/app/views.py
@@ -211,6 +211,13 @@ def shift(request, shiftid):
context["can_register"] = False
if reg[0].can_cancel():
context["can_cancel"] = True
+ elif context["can_register"]:
+ # Check for overlapping shifts
+ overlapping_reg = helper.has_overlapping_shift(shift)
+ if overlapping_reg:
+ context["can_register"] = False
+ context["has_overlap"] = True
+ context["overlapping_shift"] = overlapping_reg.shift
if request.method == "POST":
if EmptyForm(request.POST).is_valid():
@@ -236,6 +243,14 @@ def shift(request, shiftid):
)
return redirect("index")
if context["can_register"]:
+ overlapping_reg = helper.has_overlapping_shift(shift)
+ if overlapping_reg:
+ messages.add_message(
+ request,
+ messages.ERROR,
+ "Du hast bereits eine überlappende Schicht zu dieser Zeit.",
+ )
+ return redirect("shift", shiftid=shift.pk)
s = ShiftRegistration(helper=helper, shift=shift)
s.save()
messages.add_message(