main #1
|
@ -25,6 +25,7 @@ class FallbackAssignmentInline(admin.TabularInline):
|
|||
model = FallbackAssignment
|
||||
ordering = ("shift__start_at",)
|
||||
readonly_fields = ("shift",)
|
||||
fk_name = "team_member"
|
||||
|
||||
|
||||
@admin.register(TeamMember)
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 5.0.4 on 2025-05-14 11:39
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("fallback", "0008_alter_teammember_comment"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="fallbackassignment",
|
||||
name="traded_to",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="received_trades",
|
||||
to="fallback.teammember",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -21,18 +21,19 @@ class TeamMember(models.Model):
|
|||
id = models.IntegerField(default=generate_id, editable=False, primary_key=True)
|
||||
name = models.CharField(max_length=100)
|
||||
comment = models.CharField(max_length=100, blank=True, default="")
|
||||
fallback_shifts = models.ManyToManyField(Shift, through="FallbackAssignment")
|
||||
fallback_shifts = models.ManyToManyField(
|
||||
Shift, through="FallbackAssignment", through_fields=("team_member", "shift")
|
||||
)
|
||||
|
||||
def url(self):
|
||||
return "https://helfen.kntkt.de" + reverse(
|
||||
"my_fallback_shifts",
|
||||
kwargs={
|
||||
"team_member_id": urlsafe_b64encode(
|
||||
self.id.to_bytes(3, byteorder="big")
|
||||
).decode("utf-8")
|
||||
},
|
||||
kwargs={"team_member_id": self.url_id()},
|
||||
)
|
||||
|
||||
def url_id(self):
|
||||
return urlsafe_b64encode(self.id.to_bytes(3, byteorder="big")).decode("utf-8")
|
||||
|
||||
def assign_random_shifts(self):
|
||||
needs_fallback = Q(deleted=False, calendar__needs_fallback=True)
|
||||
|
||||
|
@ -199,6 +200,15 @@ class FallbackAssignment(models.Model):
|
|||
shift = models.ForeignKey(Shift, on_delete=models.CASCADE)
|
||||
team_member = models.ForeignKey(TeamMember, on_delete=models.CASCADE)
|
||||
was_full = models.BooleanField(default=False)
|
||||
traded_to = models.ForeignKey(
|
||||
TeamMember,
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="received_trades",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
if self.traded_to:
|
||||
return f"{self.shift} {self.team_member.name} -> {self.traded_to.name}"
|
||||
return f"{self.shift} {self.team_member.name}"
|
||||
|
|
|
@ -9,6 +9,22 @@
|
|||
<div class="content">
|
||||
<a href="{% url 'pages:view' 'team_faq' %}">Häufig gestellte Fragen zu Teamschichten</a>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<h4 class="subtitle">Schicht übernehmen</h4>
|
||||
<form method="POST">
|
||||
{% csrf_token %}
|
||||
<div class="field has-addons">
|
||||
<div class="control">
|
||||
<input class="input" type="number" name="assignment_id" placeholder="Assignment ID" required>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button type="submit" name="take_shift" class="button is-info">Übernehmen/Entfernen</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if assignments %}
|
||||
{% if is_draw %}
|
||||
<pre class="mb-5 select_all">Hallo {{ team_member.name }}, hier deine Teamschichten für das Festival:
|
||||
|
@ -26,6 +42,7 @@ Diese Schichtzuteilung wurde maschinell erstellt und ist auch ohne Unterschrift
|
|||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tausch-ID</th>
|
||||
<th>Wann</th>
|
||||
<th>Wie lange</th>
|
||||
<th>Wo</th>
|
||||
|
@ -38,13 +55,19 @@ Diese Schichtzuteilung wurde maschinell erstellt und ist auch ohne Unterschrift
|
|||
{% for assignment in assignments %}
|
||||
{% with assignment.shift as shift %}
|
||||
<tr{% if shift.registration_count == shift.required_helpers|default:shift.room.required_helpers or assignment.was_full %} class="has-text-grey" style="text-decoration: line-through;"{% endif %}>
|
||||
<td>{{ assignment.id }} {% if assignment.traded_to %}*{% endif %}</td>
|
||||
<td>{{ shift.start_at }}</td>
|
||||
<td>{{ shift.duration|duration }}</td>
|
||||
<td>{{ shift.room.name }} </td>
|
||||
<td>{{ shift.registration_count }}/{{ shift.required_helpers|default:shift.room.required_helpers }}</td>
|
||||
<td>
|
||||
{% for assignment in shift.fallbackassignment_set.all %}
|
||||
{{ assignment.team_member.name }}{% if not forloop.last %}, {% endif %}
|
||||
{% for fa in shift.fallbackassignment_set.all %}
|
||||
{% if fa.traded_to %}
|
||||
{{ fa.traded_to.name }}
|
||||
{% else %}
|
||||
{{ fa.team_member.name }}
|
||||
{% endif %}
|
||||
{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
|
@ -61,7 +84,7 @@ Diese Schichtzuteilung wurde maschinell erstellt und ist auch ohne Unterschrift
|
|||
{% if user.is_authenticated %}
|
||||
<form method="POST">
|
||||
{% csrf_token %}
|
||||
<button class="button is-success" type="submit">Schichten zulosen</button>
|
||||
<button class="button is-success" type="submit" name="draw_shifts">Schichten zulosen</button>
|
||||
</form>
|
||||
{% else %}
|
||||
Noch keine Schichten zugewiesen, bitte wende dich an den Infopoint.
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
from base64 import urlsafe_b64decode
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import Count
|
||||
from django.db.models import Count, Q
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
|
||||
from shiftregister.fallback.models import TeamMember
|
||||
from shiftregister.fallback.models import FallbackAssignment, TeamMember
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
@ -22,15 +24,44 @@ def my_fallback_shifts(request, team_member_id):
|
|||
|
||||
is_draw = False
|
||||
if request.method == "POST":
|
||||
team_member.assign_random_shifts()
|
||||
is_draw = True
|
||||
if "draw_shifts" in request.POST:
|
||||
team_member.assign_random_shifts()
|
||||
is_draw = True
|
||||
elif "take_shift" in request.POST:
|
||||
assignment_id = request.POST.get("assignment_id")
|
||||
try:
|
||||
assignment = FallbackAssignment.objects.get(pk=assignment_id)
|
||||
if assignment.team_member == team_member:
|
||||
assignment.traded_to = None
|
||||
messages.success(request, f"Schicht erfolgreich zurückgenommen")
|
||||
elif assignment.traded_to == team_member:
|
||||
assignment.traded_to = None
|
||||
messages.success(request, f"Schicht erfolgreich zurückgegeben")
|
||||
else:
|
||||
assignment.traded_to = team_member
|
||||
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:
|
||||
messages.error(request, "Ungültige Schicht-ID")
|
||||
|
||||
assignments = (
|
||||
FallbackAssignment.objects.filter(
|
||||
Q(team_member=team_member, traded_to__isnull=True)
|
||||
| Q(traded_to=team_member)
|
||||
)
|
||||
.prefetch_related("shift", "traded_to", "team_member")
|
||||
.order_by("shift__start_at")
|
||||
)
|
||||
|
||||
context = {
|
||||
"team_member": team_member,
|
||||
"assignments": team_member.fallbackassignment_set.order_by(
|
||||
"shift__start_at"
|
||||
).all(),
|
||||
# "shifts": team_member.fallback_shifts.order_by("start_at").all(),
|
||||
"assignments": assignments,
|
||||
"is_draw": is_draw,
|
||||
}
|
||||
return render(request, "my_fallback_shifts.html", context)
|
||||
|
|
|
@ -18,7 +18,18 @@
|
|||
<tr>
|
||||
<td>{{ shift.room.name }}</td>
|
||||
<td>{{ shift.start_at }}</td>
|
||||
<td>{% for fa in shift.fallbackassignment_set.all %}{% if not fa.was_full %}{{ fa.team_member.name }}{% if not forloop.last %}, {% endif %}{% endif %}{% endfor %}</td>
|
||||
<td>
|
||||
{% for fa in shift.fallbackassignment_set.all %}
|
||||
{% if not fa.was_full %}
|
||||
{% if fa.traded_to %}
|
||||
{{ fa.traded_to.name }} ({{ fa.id }})
|
||||
{% else %}
|
||||
{{ fa.team_member.name }} ({{ fa.id }})
|
||||
{% endif %}
|
||||
{% if not forloop.last %}, {% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
|
|
|
@ -59,7 +59,11 @@
|
|||
{% for fallback in shift.event.fallbackassignment_set.all %}
|
||||
<div class="column is-one-quarter">
|
||||
<div class="box{% if fallback.was_full %} has-text-grey" style="text-decoration: line-through;{% endif %}">
|
||||
{{ fallback.team_member.name }}
|
||||
{% if fallback.traded_to %}
|
||||
{{ fallback.traded_to.name }}
|
||||
{% else %}
|
||||
{{ fallback.team_member.name }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
Loading…
Reference in New Issue