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 %} +
Du hast bereits eine überlappende Schicht zu dieser Zeit: {{ overlapping_shift.room.name }} ({{ overlapping_shift.start_at }})
+ {% else %}
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(