ScoDoc/app/but/validations_view.py

141 lines
5.3 KiB
Python
Raw Permalink Normal View History

##############################################################################
# ScoDoc
2023-12-31 23:04:06 +01:00
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""Jury édition manuelle des décisions RCUE antérieures
"""
from flask import render_template
from app import db, log
from app.but import cursus_but
from app.models import (
ApcCompetence,
ApcNiveau,
ApcReferentielCompetences,
# ApcValidationAnnee, # TODO
ApcValidationRCUE,
Formation,
FormSemestre,
Identite,
# ScolarAutorisationInscription,
ScolarFormSemestreValidation,
UniteEns,
)
from app.models.ues import UEParcours
from app.scodoc import codes_cursus
2024-09-04 21:01:03 +02:00
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
from app.views import ScoData
def validation_rcues(etud: Identite, formsemestre: FormSemestre, edit: bool = False):
"""Page de saisie des décisions de RCUEs "antérieures"
On peut l'utiliser pour saisir la validation de n'importe quel RCUE
d'une année antérieure et de la formation du formsemestre indiqué.
"""
formation: Formation = formsemestre.formation
refcomp = formation.referentiel_competence
if refcomp is None:
raise ScoNoReferentielCompetences(formation=formation)
2024-09-04 21:01:03 +02:00
if etud.id not in formsemestre.etuds_inscriptions:
raise ScoValueError(
f"Etudiant {etud.nom_prenom()} non inscrit à {formsemestre.titre_mois()}"
)
parcour = formsemestre.etuds_inscriptions[etud.id].parcour
# Si non inscrit à un parcours, prend toutes les compétences
competences_parcour, ects_parcours = cursus_but.parcour_formation_competences(
parcour, formation
)
ue_validation_by_niveau = get_ue_validation_by_niveau(refcomp, etud)
rcue_validation_by_niveau = get_rcue_validation_by_niveau(
refcomp, etud, None if parcour is None else parcour.id
)
ects_acquis = sum((v.ects() for v in ue_validation_by_niveau.values()))
return render_template(
"but/validation_rcues.j2",
competences_parcour=competences_parcour,
edit=edit,
ects_acquis=ects_acquis,
ects_parcours=ects_parcours,
formation=formation,
parcour=parcour,
rcue_validation_by_niveau=rcue_validation_by_niveau,
rcue_codes=sorted(codes_cursus.CODES_JURY_RCUE),
sco=ScoData(formsemestre=formsemestre, etud=etud),
title=f"{formation.acronyme} - Niveaux et UEs",
ue_validation_by_niveau=ue_validation_by_niveau,
)
def get_ue_validation_by_niveau(
refcomp: ApcReferentielCompetences, etud: Identite
) -> dict[tuple[int, str], ScolarFormSemestreValidation]:
"""Les validations d'UEs de cet étudiant liées à ce référentiel de compétences
dans le parcours suivi par l'étudiant (celui de son semestre le plus récent
dans un semestre de ce référentiel).
Pour chaque niveau / pair ou impair, choisi la "meilleure" validation.
"""
parcour = cursus_but.get_etud_parcours(etud, refcomp.id)
validations = (
cursus_but.but_validations_ues_parcours(etud, parcour.id)
if parcour is not None
else cursus_but.but_validations_ues(etud, refcomp.id)
)
# La meilleure validation pour chaque UE
ue_validation_by_niveau = {} # { (niveau_id, pair|impair) : validation }
for validation in validations:
if validation.ue.niveau_competence is None:
log(
f"""validation_rcues: ignore validation d'UE {
validation.ue.id} pas de niveau de competence"""
)
continue
2024-09-23 14:28:32 +02:00
semestre_idx = validation.ue.guess_semestre_idx()
key = (
validation.ue.niveau_competence.id,
2024-09-23 14:28:32 +02:00
"impair" if semestre_idx % 2 else "pair",
)
existing = ue_validation_by_niveau.get(key, None)
if (not existing) or (
codes_cursus.BUT_CODES_ORDER[existing.code]
< codes_cursus.BUT_CODES_ORDER[validation.code]
):
ue_validation_by_niveau[key] = validation
return ue_validation_by_niveau
def get_rcue_validation_by_niveau(
refcomp: ApcReferentielCompetences, etud: Identite, parcour_id: int | None
) -> dict[int, ApcValidationRCUE]:
"""Les validations d'UEs de cet étudiant liées à ce référentiel de compétences.
Si parcour_id n'est pas None, restreint aux niveaux de ce parcours
et du tronc commun.
Pour chaque niveau / pair ou impair, choisi la "meilleure" validation.
"""
validations: list[ApcValidationRCUE] = (
ApcValidationRCUE.query.filter_by(etudid=etud.id)
.join(UniteEns, UniteEns.id == ApcValidationRCUE.ue2_id)
.join(ApcNiveau, UniteEns.niveau_competence_id == ApcNiveau.id)
.join(ApcCompetence)
.filter_by(referentiel_id=refcomp.id)
.filter(
db.or_(
UniteEns.id.in_(
UEParcours.query.with_entities(UEParcours.ue_id).filter(
UEParcours.parcours_id == parcour_id
)
),
~UniteEns.id.in_(UEParcours.query.with_entities(UEParcours.ue_id)),
)
)
.all()
)
return {
validation.ue2.niveau_competence.id: validation for validation in validations
}