roosterwijs/backend/modules/uren/views.py

150 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Urenoverzicht: berekent lesuren per groep/vak en per leerling.
Roosterblokken zijn wekelijks: per schooljaar telt een blok zo vaak mee als er
lesdagen op die weekdag zijn (vrije dagen/vakanties/studiedagen tellen niet mee),
minus de keren dat het blok via een uitzondering vervalt.
"""
from datetime import timedelta
from rest_framework.decorators import api_view
from rest_framework.response import Response
from core.models import KalenderDag, Persoon, Roosterblok, Rol, Schooljaar, Subgroep, Tijdslot
def _duur_uren(ts):
s, e = ts.start_tijd, ts.eind_tijd
return ((e.hour * 60 + e.minute) - (s.hour * 60 + s.minute)) / 60.0
@api_view(["GET"])
def urenoverzicht(request):
sjid = request.query_params.get("schooljaar")
if not sjid:
return Response({"detail": "Geef een schooljaar op."}, status=400)
try:
sj = Schooljaar.objects.get(pk=sjid)
except Schooljaar.DoesNotExist:
return Response({"detail": "Schooljaar niet gevonden."}, status=404)
# Lesdagen per weekdag (mavr), vrije dagen uitgezonderd.
vrije = set(KalenderDag.objects.filter(schooljaar=sj).values_list("datum", flat=True))
lesdagen = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
d = sj.start_datum
while d <= sj.eind_datum:
wd = d.weekday()
if wd <= 4 and d not in vrije:
lesdagen[wd] += 1
d += timedelta(days=1)
blokken = list(
Roosterblok.objects.filter(schooljaar=sj)
.select_related("tijdslot", "activiteit", "groep", "subgroep", "leerling", "leerling__groep")
.prefetch_related("uitzonderingen")
)
subgroepen = {s.id: s for s in Subgroep.objects.prefetch_related("leden").all()}
sub_leden = {sid: set(s.leden.values_list("id", flat=True)) for sid, s in subgroepen.items()}
leerlingen = list(Persoon.objects.filter(rol=Rol.LEERLING).select_related("groep"))
def _tel_weekdag(van, tot, wd):
n = 0
d = van
while d <= tot:
if d.weekday() == wd and d not in vrije:
n += 1
d += timedelta(days=1)
return n
def occurrences(blok):
wd = blok.tijdslot.dag
# Geldigheidsperiode binnen het schooljaar clampen.
van = max(blok.geldig_van or sj.start_datum, sj.start_datum)
tot = min(blok.geldig_tot or sj.eind_datum, sj.eind_datum)
if van > tot:
return 0
if blok.geldig_van is None and blok.geldig_tot is None:
basis = lesdagen.get(wd, 0)
else:
basis = _tel_weekdag(van, tot, wd)
weg = 0
for u in blok.uitzonderingen.all():
if u.vervalt and van <= u.datum <= tot and u.datum.weekday() == wd and u.datum not in vrije:
weg += 1
return max(basis - weg, 0)
def groep_van_blok(b):
if b.groep_id:
return b.groep
if b.subgroep_id:
s = subgroepen.get(b.subgroep_id)
return s.groep if s else None
if b.leerling_id:
return b.leerling.groep
return None
blok_uren = {}
groep_map = {}
for b in blokken:
u = _duur_uren(b.tijdslot) * occurrences(b)
blok_uren[b.id] = u
g = groep_van_blok(b)
if g:
gm = groep_map.setdefault(g.id, {"naam": g.naam, "vakken": {}})
gm["vakken"][b.activiteit.naam] = gm["vakken"].get(b.activiteit.naam, 0) + u
per_groep = []
for gm in groep_map.values():
vakken = [{"vak": k, "uren": round(v, 1)} for k, v in sorted(gm["vakken"].items())]
per_groep.append({
"groep": gm["naam"],
"totaal": round(sum(x["uren"] for x in vakken), 1),
"vakken": vakken,
})
per_groep.sort(key=lambda x: x["groep"])
# Stage-uren (module optioneel).
stages = []
alle_ts = []
try:
from modules.stage.models import Stage
alle_ts = list(Tijdslot.objects.all())
stages = list(Stage.objects.filter(actief=True))
except Exception:
pass
per_leerling = []
for l in leerlingen:
vakken = {}
for b in blokken:
hoort = (
(b.groep_id and l.groep_id == b.groep_id)
or (b.subgroep_id and l.id in sub_leden.get(b.subgroep_id, set()))
or (b.leerling_id == l.id)
)
if hoort:
vakken[b.activiteit.naam] = vakken.get(b.activiteit.naam, 0) + blok_uren[b.id]
stage_uren = 0
for st in stages:
if st.leerling_id != l.id:
continue
for ts in alle_ts:
if st.dekt_tijdslot(ts):
stage_uren += _duur_uren(ts) * lesdagen.get(ts.dag, 0)
vak_list = [{"vak": k, "uren": round(v, 1)} for k, v in sorted(vakken.items())]
totaal = sum(x["uren"] for x in vak_list) + stage_uren
if vak_list or stage_uren:
per_leerling.append({
"leerling": l.volledige_naam,
"groep": l.groep.naam if l.groep else None,
"vakken": vak_list,
"stage_uren": round(stage_uren, 1),
"totaal": round(totaal, 1),
})
per_leerling.sort(key=lambda x: x["leerling"])
return Response({
"schooljaar": sj.naam,
"lesdagen": lesdagen,
"per_groep": per_groep,
"per_leerling": per_leerling,
})