"""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 (ma–vr), 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 occurrences(blok): wd = blok.tijdslot.dag basis = lesdagen.get(wd, 0) weg = 0 for u in blok.uitzonderingen.all(): if u.vervalt and sj.start_datum <= u.datum <= sj.eind_datum 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, })