Add shift-specific 'required_helpers' field
This commit is contained in:
parent
7a08080604
commit
8437882b14
|
@ -16,7 +16,9 @@ class ShiftAdmin(admin.ModelAdmin):
|
||||||
# object.helpers.count()
|
# object.helpers.count()
|
||||||
|
|
||||||
def free_slots(self, object):
|
def free_slots(self, object):
|
||||||
return object.room.required_helpers - object.shiftregistration_set.count()
|
return (
|
||||||
|
object.required_helpers or object.room.required_helpers
|
||||||
|
) - object.shiftregistration_set.count()
|
||||||
|
|
||||||
|
|
||||||
def send_login(modeladmin, request, queryset):
|
def send_login(modeladmin, request, queryset):
|
||||||
|
@ -24,7 +26,7 @@ def send_login(modeladmin, request, queryset):
|
||||||
helper.send_confirmation()
|
helper.send_confirmation()
|
||||||
|
|
||||||
|
|
||||||
class RegistationInline(admin.TabularInline):
|
class RegistrationInline(admin.TabularInline):
|
||||||
model = ShiftRegistration
|
model = ShiftRegistration
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ class HelperAdmin(admin.ModelAdmin):
|
||||||
readonly_fields = ("phone",)
|
readonly_fields = ("phone",)
|
||||||
fields = ("name", "phone", "number_validated")
|
fields = ("name", "phone", "number_validated")
|
||||||
list_display = ("name",)
|
list_display = ("name",)
|
||||||
inlines = (RegistationInline,)
|
inlines = (RegistrationInline,)
|
||||||
actions = (send_login,)
|
actions = (send_login,)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.0.4 on 2022-05-10 13:03
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("app", "0003_logintoken_send_count"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="shift",
|
||||||
|
name="required_helpers",
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
|
@ -22,8 +22,10 @@ class Shift(models.Model):
|
||||||
room = models.ForeignKey(Room, on_delete=models.RESTRICT)
|
room = models.ForeignKey(Room, on_delete=models.RESTRICT)
|
||||||
start_at = models.DateTimeField()
|
start_at = models.DateTimeField()
|
||||||
duration = models.DurationField()
|
duration = models.DurationField()
|
||||||
|
required_helpers = models.IntegerField(
|
||||||
|
default=0, help_text="When this is set to zero, the room value is used instead."
|
||||||
|
)
|
||||||
deleted = models.BooleanField(default=False)
|
deleted = models.BooleanField(default=False)
|
||||||
# todo: add helper amount override field
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.room.name}: {self.start_at}"
|
return f"{self.room.name}: {self.start_at}"
|
||||||
|
@ -82,7 +84,7 @@ class ShiftRegistration(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
def send_reminder(self):
|
def send_reminder(self):
|
||||||
text = f"Deine Kontakt-Schicht begint um {self.shift.start_at.strftime('%H:%M')}, bitte komme eine halbe Stunde vorher an den Infopoint."
|
text = f"Deine kontakt-Schicht beginnt um {self.shift.start_at.strftime('%H:%M')}, bitte komm eine halbe Stunde vorher an den Infopoint."
|
||||||
msg = Message(to=self.helper, text=text)
|
msg = Message(to=self.helper, text=text)
|
||||||
msg.save()
|
msg.save()
|
||||||
self.reminder_sent = True
|
self.reminder_sent = True
|
||||||
|
|
|
@ -35,11 +35,14 @@ def index(request):
|
||||||
if imp_shift and imp_shift.is_running():
|
if imp_shift and imp_shift.is_running():
|
||||||
context["current_shift"] = imp_shift
|
context["current_shift"] = imp_shift
|
||||||
|
|
||||||
|
help_wanted = Q(required_helpers__gt=F("reg_count")) | Q(required_helpers=0) & Q(
|
||||||
|
room__required_helpers__gt=F("reg_count")
|
||||||
|
)
|
||||||
free_shifts = (
|
free_shifts = (
|
||||||
Shift.objects.annotate(reg_count=Count("shiftregistration"))
|
Shift.objects.annotate(reg_count=Count("shiftregistration"))
|
||||||
.filter(
|
.filter(
|
||||||
|
help_wanted,
|
||||||
start_at__gt=timezone.now(),
|
start_at__gt=timezone.now(),
|
||||||
room__required_helpers__gt=F("reg_count"),
|
|
||||||
deleted=False,
|
deleted=False,
|
||||||
)
|
)
|
||||||
.order_by("start_at")
|
.order_by("start_at")
|
||||||
|
@ -49,8 +52,8 @@ def index(request):
|
||||||
free_shifts = (
|
free_shifts = (
|
||||||
Shift.objects.annotate(reg_count=Count("shiftregistration"))
|
Shift.objects.annotate(reg_count=Count("shiftregistration"))
|
||||||
.filter(
|
.filter(
|
||||||
|
help_wanted,
|
||||||
start_at__gt=timezone.now(),
|
start_at__gt=timezone.now(),
|
||||||
room__required_helpers__gt=F("reg_count"),
|
|
||||||
deleted=False,
|
deleted=False,
|
||||||
)
|
)
|
||||||
.filter(~Q(shiftregistration__helper=request.helper))
|
.filter(~Q(shiftregistration__helper=request.helper))
|
||||||
|
@ -161,7 +164,11 @@ def shift(request, shiftid):
|
||||||
|
|
||||||
# this currently ignores date/time
|
# this currently ignores date/time
|
||||||
request.session["last_seen_shift"] = shiftid
|
request.session["last_seen_shift"] = shiftid
|
||||||
if shift.room.required_helpers > shift.shiftregistration_set.count():
|
if (
|
||||||
|
shift.required_helpers > shift.shiftregistration_set.count()
|
||||||
|
or shift.required_helpers == 0
|
||||||
|
and shift.room.required_helpers > shift.shiftregistration_set.count()
|
||||||
|
):
|
||||||
context["can_register"] = True
|
context["can_register"] = True
|
||||||
|
|
||||||
if helper:
|
if helper:
|
||||||
|
|
|
@ -25,11 +25,26 @@ def import_calendar(calendar):
|
||||||
events = {}
|
events = {}
|
||||||
for event in cal.walk("vevent"):
|
for event in cal.walk("vevent"):
|
||||||
uid = event.decoded("uid").decode()
|
uid = event.decoded("uid").decode()
|
||||||
room = (
|
summary = event.decoded("summary").decode()
|
||||||
event.decoded("location", None) or event.decoded("summary")
|
|
||||||
).decode()
|
|
||||||
start = event.decoded("dtstart").astimezone(timezone.utc)
|
start = event.decoded("dtstart").astimezone(timezone.utc)
|
||||||
end = event.decoded("dtend").astimezone(timezone.utc)
|
end = event.decoded("dtend").astimezone(timezone.utc)
|
||||||
|
location = event.decoded("location", None)
|
||||||
|
if location is not None:
|
||||||
|
location = location.decode()
|
||||||
|
|
||||||
|
if location:
|
||||||
|
room = location
|
||||||
|
try:
|
||||||
|
required_helpers = int(summary)
|
||||||
|
except ValueError:
|
||||||
|
required_helpers = 0
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
room, required_helpers = tuple(summary.split())
|
||||||
|
required_helpers = int(required_helpers)
|
||||||
|
except ValueError:
|
||||||
|
room = summary
|
||||||
|
required_helpers = 0
|
||||||
|
|
||||||
if not uid or not room:
|
if not uid or not room:
|
||||||
return False
|
return False
|
||||||
|
@ -40,6 +55,7 @@ def import_calendar(calendar):
|
||||||
{
|
{
|
||||||
"start_at": start,
|
"start_at": start,
|
||||||
"duration": end - start,
|
"duration": end - start,
|
||||||
|
"required_helpers": required_helpers,
|
||||||
"uuid": uid,
|
"uuid": uid,
|
||||||
"calendar": calendar,
|
"calendar": calendar,
|
||||||
},
|
},
|
||||||
|
@ -52,7 +68,7 @@ def import_calendar(calendar):
|
||||||
if r == None:
|
if r == None:
|
||||||
rooms[room] = Room(
|
rooms[room] = Room(
|
||||||
name=room, required_helpers=0
|
name=room, required_helpers=0
|
||||||
) # required_helpers=0 ensures a shift in a new room is not displayed until the correct number of required helpers is set
|
) # required_helpers=0 ensures a shift in a new room is not displayed unless the correct number of required helpers is set or the shift itself specifies it
|
||||||
rooms[room].save()
|
rooms[room].save()
|
||||||
|
|
||||||
for e in Event.objects.filter(calendar=calendar, uuid__in=events):
|
for e in Event.objects.filter(calendar=calendar, uuid__in=events):
|
||||||
|
@ -62,6 +78,7 @@ def import_calendar(calendar):
|
||||||
e.room = rooms[room]
|
e.room = rooms[room]
|
||||||
e.start_at = event["start_at"]
|
e.start_at = event["start_at"]
|
||||||
e.duration = event["duration"]
|
e.duration = event["duration"]
|
||||||
|
e.required_helpers = event["required_helpers"]
|
||||||
e.save()
|
e.save()
|
||||||
|
|
||||||
events[uuid] = (room, e)
|
events[uuid] = (room, e)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<strong>Ort:</strong> {{ shift.room.name }}<br>
|
<strong>Ort:</strong> {{ shift.room.name }}<br>
|
||||||
<strong>Beginn:</strong> {{ shift.start_at }}<br>
|
<strong>Beginn:</strong> {{ shift.start_at }}<br>
|
||||||
<strong>Dauer:</strong> {{ shift.duration }}<br>
|
<strong>Dauer:</strong> {{ shift.duration }}<br>
|
||||||
<strong>Belegung:</strong> {{ shift.shiftregistration_set.count }}/{{ shift.room.required_helpers }}
|
<strong>Belegung:</strong> {{ shift.shiftregistration_set.count }}/{{ shift.required_helpers|default:shift.room.required_helpers }}
|
||||||
</div>
|
</div>
|
||||||
<div class="is-flex is-justify-content-end">
|
<div class="is-flex is-justify-content-end">
|
||||||
<a class="button is-info is-small" href="{% url 'team:shift' shift.id %}">Details</a>
|
<a class="button is-info is-small" href="{% url 'team:shift' shift.id %}">Details</a>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{% block title %}Schichtdetails{% endblock %}
|
{% block title %}Schichtdetails{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h3 class="title is-spaced">{% if shift.deleted %}(gelöscht) {% endif %}{{ shift.room.name }} {{ shift.start_at }} ({{ shift.shiftregistration_set.count }}/{{ shift.room.required_helpers }})</h3>
|
<h3 class="title is-spaced">{% if shift.deleted %}(gelöscht) {% endif %}{{ shift.room.name }} {{ shift.start_at }} ({{ shift.shiftregistration_set.count }}/{{ shift.required_helpers|default:shift.room.required_helpers }})</h3>
|
||||||
{% if shift.shiftregistration_set.all %}
|
{% if shift.shiftregistration_set.all %}
|
||||||
<h5 class="subtitle">Helfer*innen</h5>
|
<h5 class="subtitle">Helfer*innen</h5>
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
|
|
|
@ -25,13 +25,13 @@ def shift_overview(request):
|
||||||
output_field=DateTimeField(),
|
output_field=DateTimeField(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.filter(start_at__lte=timezone.now(), end_at__gte=timezone.now())
|
.filter(start_at__lte=timezone.now(), end_at__gte=timezone.now(), deleted=False)
|
||||||
.order_by("start_at")
|
.order_by("start_at")
|
||||||
]
|
]
|
||||||
|
|
||||||
# probably can do some distinct/group by stuff but not sure how tih django queries
|
# probably can do some distinct/group by stuff but not sure how tih django queries
|
||||||
context["next_shifts"] = [
|
context["next_shifts"] = [
|
||||||
Shift.objects.filter(room=room, start_at__gt=timezone.now())
|
Shift.objects.filter(room=room, start_at__gt=timezone.now(), deleted=False)
|
||||||
.order_by("start_at")
|
.order_by("start_at")
|
||||||
.first()
|
.first()
|
||||||
for room in Room.objects.all()
|
for room in Room.objects.all()
|
||||||
|
@ -97,6 +97,10 @@ class FreeShiftList(ShiftList):
|
||||||
title = "Freie Schichten"
|
title = "Freie Schichten"
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
help_wanted = Q(required_helpers__gt=F("reg_count")) | Q(
|
||||||
|
required_helpers=0
|
||||||
|
) & Q(room__required_helpers__gt=F("reg_count"))
|
||||||
return Shift.objects.annotate(reg_count=Count("shiftregistration")).filter(
|
return Shift.objects.annotate(reg_count=Count("shiftregistration")).filter(
|
||||||
start_at__gt=timezone.now(), room__required_helpers__gt=F("reg_count")
|
help_wanted,
|
||||||
|
start_at__gt=timezone.now(),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue