roosterwijs/backend/modules/vervanging/views.py
bes-r c845588e5e
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
Add roles modules audit logging and CI
2026-07-04 23:01:06 +02:00

86 lines
3.4 KiB
Python

from datetime import timedelta
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from core.audit import audit_log
from core.models import Afwezigheid, BlokUitzondering, Persoon, Roosterblok
from core.permissions import StaffDataPermission, module_permission_class
VervangingModuleEnabled = module_permission_class("vervanging")
def _datums(start, eind, weekdag):
dag = start
while dag <= eind:
if dag.weekday() == weekdag:
yield dag
dag += timedelta(days=1)
def _beschikbare_medewerkers(blok):
bezet = Persoon.objects.filter(begeleider_roosterblokken__tijdslot=blok.tijdslot).values("id")
qs = Persoon.objects.exclude(rol="leerling").filter(actief=True).exclude(id__in=bezet)
return qs.exclude(id__in=blok.begeleiders.values("id")).distinct()
@api_view(["GET"])
@permission_classes([StaffDataPermission, VervangingModuleEnabled])
def suggesties(request):
afw_id = request.query_params.get("afwezigheid")
try:
afw = Afwezigheid.objects.select_related("persoon").get(pk=afw_id)
except Afwezigheid.DoesNotExist:
return Response({"detail": "Afwezigheid niet gevonden."}, status=404)
blokken = (
Roosterblok.objects
.filter(begeleiders=afw.persoon, sjabloon=False)
.select_related("tijdslot", "activiteit", "groep", "subgroep", "leerling")
.prefetch_related("begeleiders")
)
resultaat = []
for blok in blokken:
datums = list(_datums(afw.start_datum, afw.eind_datum, blok.tijdslot.dag))
if not datums:
continue
kandidaten = _beschikbare_medewerkers(blok)[:8]
resultaat.append({
"roosterblok": blok.id,
"activiteit": blok.activiteit.naam,
"tijdslot": str(blok.tijdslot),
"doel": blok.groep.naam if blok.groep_id else blok.subgroep.naam if blok.subgroep_id else blok.leerling.volledige_naam,
"datums": datums,
"kandidaten": [
{"id": p.id, "naam": p.volledige_naam, "rol": p.get_rol_display()}
for p in kandidaten
],
})
return Response({
"afwezigheid": afw.id,
"persoon": afw.persoon.volledige_naam,
"suggesties": resultaat,
})
@api_view(["POST"])
@permission_classes([StaffDataPermission, VervangingModuleEnabled])
def toepassen(request):
blok_id = request.data.get("roosterblok")
datum = request.data.get("datum")
vervanger_id = request.data.get("vervanger")
if not (blok_id and datum and vervanger_id):
return Response({"detail": "roosterblok, datum en vervanger zijn verplicht."}, status=400)
if not StaffDataPermission().has_permission(request, type("View", (), {"write_roles": ("roostermaker", "directie")})()):
return Response({"detail": "Je hebt geen rechten om vervangingen toe te passen."}, status=403)
obj, _ = BlokUitzondering.objects.update_or_create(
roosterblok_id=blok_id,
datum=datum,
defaults={
"vervalt": False,
"vervanger_id": vervanger_id,
"opmerking": request.data.get("opmerking", "Vervanging"),
},
)
audit_log(request, "replacement_apply", f"BlokUitzondering:{obj.pk}", {"roosterblok": blok_id, "datum": datum})
return Response({"id": obj.id, "roosterblok": obj.roosterblok_id, "datum": obj.datum, "vervanger": obj.vervanger_id})