add PINs for shift trades
continuous-integration/drone/push Build is passing Details

This commit is contained in:
xAndy 2025-05-14 14:17:08 +02:00
parent f55b653ccd
commit 6e45b1543b
5 changed files with 86 additions and 25 deletions

View File

@ -30,7 +30,7 @@ class FallbackAssignmentInline(admin.TabularInline):
@admin.register(TeamMember) @admin.register(TeamMember)
class TeamMemberAdmin(admin.ModelAdmin): class TeamMemberAdmin(admin.ModelAdmin):
fields = ("id", "name", "comment", "url") fields = ("id", "name", "comment", "url", "pin")
readonly_fields = ("id", "url") readonly_fields = ("id", "url")
list_display = ("name", "comment", "shift_count") list_display = ("name", "comment", "shift_count")
ordering = ("name",) ordering = ("name",)

View File

@ -0,0 +1,22 @@
# Generated by Django 5.0.4 on 2025-05-14 11:55
from django.db import migrations, models
import shiftregister.fallback.models
class Migration(migrations.Migration):
dependencies = [
("fallback", "0009_fallbackassignment_traded_to"),
]
operations = [
migrations.AddField(
model_name="teammember",
name="pin",
field=models.IntegerField(
default=shiftregister.fallback.models.generate_pin
),
),
]

View File

@ -2,7 +2,7 @@ import math
import secrets import secrets
from base64 import urlsafe_b64encode from base64 import urlsafe_b64encode
from datetime import datetime, time from datetime import datetime, time
from random import random from random import randint, random
import sentry_sdk import sentry_sdk
from django.db.models import Count, Exists, ExpressionWrapper, Max, OuterRef, Sum from django.db.models import Count, Exists, ExpressionWrapper, Max, OuterRef, Sum
@ -17,10 +17,15 @@ def generate_id():
return int.from_bytes(secrets.token_bytes(3), byteorder="big") return int.from_bytes(secrets.token_bytes(3), byteorder="big")
def generate_pin():
return randint(1000, 9999)
class TeamMember(models.Model): class TeamMember(models.Model):
id = models.IntegerField(default=generate_id, editable=False, primary_key=True) id = models.IntegerField(default=generate_id, editable=False, primary_key=True)
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
comment = models.CharField(max_length=100, blank=True, default="") comment = models.CharField(max_length=100, blank=True, default="")
pin = models.IntegerField(default=generate_pin)
fallback_shifts = models.ManyToManyField( fallback_shifts = models.ManyToManyField(
Shift, through="FallbackAssignment", through_fields=("team_member", "shift") Shift, through="FallbackAssignment", through_fields=("team_member", "shift")
) )

View File

@ -16,12 +16,24 @@
{% csrf_token %} {% csrf_token %}
<div class="field has-addons"> <div class="field has-addons">
<div class="control"> <div class="control">
<input class="input" type="number" name="assignment_id" placeholder="Assignment ID" required> {{ trade_form.assignment_id }}
</div>
<div class="control">
{{ trade_form.pin }}
</div> </div>
<div class="control"> <div class="control">
<button type="submit" name="take_shift" class="button is-info">Übernehmen/Entfernen</button> <button type="submit" name="take_shift" class="button is-info">Übernehmen/Entfernen</button>
</div> </div>
</div> </div>
{% if form.errors %}
<div class="field">
{% for field in trade_form %}
{% for error in field.errors %}
<p class="help is-danger">{{ error }}</p>
{% endfor %}
{% endfor %}
</div>
{% endif %}
</form> </form>
</div> </div>
@ -31,6 +43,8 @@
{{ team_member.url }} {{ team_member.url }}
Deine PIN um Schichten zu übernehmen ist {{ team_member.pin }}
Deine Schichten werden in den nächsten Tagen weniger werden, wenn wir alle Schichten unter mehr Teammitgliedern verteilen. Deine Schichten werden in den nächsten Tagen weniger werden, wenn wir alle Schichten unter mehr Teammitgliedern verteilen.
Du kannst unter dem Link immer nachschauen, welche Schichten du noch hast und welche schon von Helfis belegt sind. Du kannst unter dem Link immer nachschauen, welche Schichten du noch hast und welche schon von Helfis belegt sind.
Bei Schichten mit mehreren Personen, bei denen nicht alle von Helfis belegt sind, koordiniere dich bitte mit den anderen Teammitgliedern, wer von euch die Schicht übernimmt. Bei Schichten mit mehreren Personen, bei denen nicht alle von Helfis belegt sind, koordiniere dich bitte mit den anderen Teammitgliedern, wer von euch die Schicht übernimmt.

View File

@ -1,5 +1,6 @@
from base64 import urlsafe_b64decode from base64 import urlsafe_b64decode
from django import forms
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db.models import Count, Q from django.db.models import Count, Q
@ -9,7 +10,14 @@ from django.urls import reverse
from shiftregister.fallback.models import FallbackAssignment, TeamMember from shiftregister.fallback.models import FallbackAssignment, TeamMember
# Create your views here.
class TradeForm(forms.Form):
assignment_id = forms.IntegerField(
widget=forms.NumberInput(attrs={"class": "input", "placeholder": "Schicht-ID"})
)
pin = forms.IntegerField(
widget=forms.NumberInput(attrs={"class": "input", "placeholder": "Deine PIN"})
)
def my_fallback_shifts(request, team_member_id): def my_fallback_shifts(request, team_member_id):
@ -23,32 +31,43 @@ def my_fallback_shifts(request, team_member_id):
team_member = get_object_or_404(TeamMember, pk=team_member_id) team_member = get_object_or_404(TeamMember, pk=team_member_id)
is_draw = False is_draw = False
trade_form = TradeForm(
request.POST
if request.method == "POST" and "take_shift" in request.POST
else None
)
if request.method == "POST": if request.method == "POST":
if "draw_shifts" in request.POST: if "draw_shifts" in request.POST:
team_member.assign_random_shifts() team_member.assign_random_shifts()
is_draw = True is_draw = True
elif "take_shift" in request.POST: elif "take_shift" in request.POST and trade_form.is_valid():
assignment_id = request.POST.get("assignment_id") assignment_id = trade_form.cleaned_data["assignment_id"]
try: pin = trade_form.cleaned_data["pin"]
assignment = FallbackAssignment.objects.get(pk=assignment_id)
if assignment.team_member == team_member: if pin != team_member.pin:
assignment.traded_to = None messages.error(request, "Ungültige PIN")
messages.success(request, f"Schicht erfolgreich zurückgenommen") else:
elif assignment.traded_to == team_member: try:
assignment.traded_to = None assignment = FallbackAssignment.objects.get(pk=assignment_id)
messages.success(request, f"Schicht erfolgreich zurückgegeben") if assignment.team_member == team_member:
else: assignment.traded_to = None
assignment.traded_to = team_member messages.success(request, f"Schicht erfolgreich zurückgenommen")
messages.success(request, f"Schicht erfolgreich übernommen") elif assignment.traded_to == team_member:
assignment.save() assignment.traded_to = None
return redirect( messages.success(request, f"Schicht erfolgreich zurückgegeben")
reverse( else:
"my_fallback_shifts", assignment.traded_to = team_member
kwargs={"team_member_id": team_member.url_id()}, messages.success(request, f"Schicht erfolgreich übernommen")
assignment.save()
return redirect(
reverse(
"my_fallback_shifts",
kwargs={"team_member_id": team_member.url_id()},
)
) )
) except FallbackAssignment.DoesNotExist:
except FallbackAssignment.DoesNotExist: messages.error(request, "Ungültige Schicht-ID")
messages.error(request, "Ungültige Schicht-ID")
assignments = ( assignments = (
FallbackAssignment.objects.filter( FallbackAssignment.objects.filter(
@ -63,6 +82,7 @@ def my_fallback_shifts(request, team_member_id):
"team_member": team_member, "team_member": team_member,
"assignments": assignments, "assignments": assignments,
"is_draw": is_draw, "is_draw": is_draw,
"trade_form": trade_form,
} }
return render(request, "my_fallback_shifts.html", context) return render(request, "my_fallback_shifts.html", context)