avoid overlapping shift registrations for helpers
This commit is contained in:
parent
7e4ff4366b
commit
8a194f3fc7
|
@ -97,6 +97,40 @@ class Helper(models.Model):
|
||||||
token.send()
|
token.send()
|
||||||
return token
|
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
|
# current or next shift
|
||||||
def important_shift(self):
|
def important_shift(self):
|
||||||
ret = (
|
ret = (
|
||||||
|
|
|
@ -13,7 +13,11 @@
|
||||||
<div class="notification">Diese Schicht wurde gelöscht.</div>
|
<div class="notification">Diese Schicht wurde gelöscht.</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not can_register and not is_registered %}
|
{% if not can_register and not is_registered %}
|
||||||
|
{% if has_overlap %}
|
||||||
|
<div class="notification is-warning">Du hast bereits eine überlappende Schicht zu dieser Zeit: <a href="{% url 'shift' overlapping_shift.id %}">{{ overlapping_shift.room.name }} ({{ overlapping_shift.start_at }})</a></div>
|
||||||
|
{% else %}
|
||||||
<div class="notification">Diese Schicht ist bereits besetzt.</div>
|
<div class="notification">Diese Schicht ist bereits besetzt.</div>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -211,6 +211,13 @@ def shift(request, shiftid):
|
||||||
context["can_register"] = False
|
context["can_register"] = False
|
||||||
if reg[0].can_cancel():
|
if reg[0].can_cancel():
|
||||||
context["can_cancel"] = True
|
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 request.method == "POST":
|
||||||
if EmptyForm(request.POST).is_valid():
|
if EmptyForm(request.POST).is_valid():
|
||||||
|
@ -236,6 +243,14 @@ def shift(request, shiftid):
|
||||||
)
|
)
|
||||||
return redirect("index")
|
return redirect("index")
|
||||||
if context["can_register"]:
|
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 = ShiftRegistration(helper=helper, shift=shift)
|
||||||
s.save()
|
s.save()
|
||||||
messages.add_message(
|
messages.add_message(
|
||||||
|
|
Loading…
Reference in New Issue