forked from ScoDoc/DocScoDoc
207 lines
7.6 KiB
Python
207 lines
7.6 KiB
Python
##############################################################################
|
|
# ScoDoc
|
|
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
|
# See LICENSE
|
|
##############################################################################
|
|
|
|
"""Cursus en BUT
|
|
|
|
Classe raccordant avec ScoDoc 7:
|
|
ScoDoc 7 utilisait sco_cursus_dut.SituationEtudCursus
|
|
|
|
Ce module définit une classe SituationEtudCursusBUT
|
|
avec la même interface.
|
|
|
|
"""
|
|
import collections
|
|
from typing import Union
|
|
|
|
from flask import g, url_for
|
|
|
|
from app import db
|
|
from app import log
|
|
from app.comp.res_but import ResultatsSemestreBUT
|
|
from app.comp.res_compat import NotesTableCompat
|
|
|
|
from app.comp import res_sem
|
|
from app.models import formsemestre
|
|
|
|
from app.models.but_refcomp import (
|
|
ApcAnneeParcours,
|
|
ApcCompetence,
|
|
ApcNiveau,
|
|
ApcParcours,
|
|
ApcParcoursNiveauCompetence,
|
|
)
|
|
from app.models import Scolog, ScolarAutorisationInscription
|
|
from app.models.but_validations import (
|
|
ApcValidationAnnee,
|
|
ApcValidationRCUE,
|
|
RegroupementCoherentUE,
|
|
)
|
|
from app.models.etudiants import Identite
|
|
from app.models.formations import Formation
|
|
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
|
from app.models.ues import UniteEns
|
|
from app.models.validations import ScolarFormSemestreValidation
|
|
from app.scodoc import codes_cursus as sco_codes
|
|
from app.scodoc.codes_cursus import RED, UE_STANDARD
|
|
from app.scodoc import sco_utils as scu
|
|
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
|
|
|
|
from app.scodoc import sco_cursus_dut
|
|
|
|
|
|
class SituationEtudCursusBUT(sco_cursus_dut.SituationEtudCursusClassic):
|
|
"""Pour compat ScoDoc 7: à revoir pour le BUT"""
|
|
|
|
def __init__(self, etud: dict, formsemestre_id: int, res: ResultatsSemestreBUT):
|
|
super().__init__(etud, formsemestre_id, res)
|
|
# Ajustements pour le BUT
|
|
self.can_compensate_with_prev = False # jamais de compensation à la mode DUT
|
|
|
|
def check_compensation_dut(self, semc: dict, ntc: NotesTableCompat):
|
|
"Jamais de compensation façon DUT"
|
|
return False
|
|
|
|
def parcours_validated(self):
|
|
"True si le parcours est validé"
|
|
return False # XXX TODO
|
|
|
|
|
|
class EtudCursusBUT:
|
|
"""L'état de l'étudiant dans son cursus BUT
|
|
Liste des niveaux validés/à valider
|
|
"""
|
|
|
|
def __init__(self, etud: Identite, formation: Formation):
|
|
"""formation indique la spécialité préparée"""
|
|
# Vérifie que l'étudiant est bien inscrit à un sem. de cette formation
|
|
if formation.id not in (
|
|
ins.formsemestre.formation.id for ins in etud.formsemestre_inscriptions
|
|
):
|
|
raise ScoValueError(
|
|
f"{etud.nomprenom} non inscrit dans {formation.titre} v{formation.version}"
|
|
)
|
|
if not formation.referentiel_competence:
|
|
raise ScoNoReferentielCompetences(formation=formation)
|
|
#
|
|
self.etud = etud
|
|
self.formation = formation
|
|
self.inscriptions = sorted(
|
|
[
|
|
ins
|
|
for ins in etud.formsemestre_inscriptions
|
|
if ins.formsemestre.formation.referentiel_competence
|
|
and (
|
|
ins.formsemestre.formation.referentiel_competence.id
|
|
== formation.referentiel_competence.id
|
|
)
|
|
],
|
|
key=lambda s: (s.formsemestre.semestre_id, s.formsemestre.date_debut),
|
|
)
|
|
"Liste des inscriptions aux sem. de la formation, triées par indice et chronologie"
|
|
self.parcour: ApcParcours = self.inscriptions[-1].parcour
|
|
"Le parcours à valider: celui du DERNIER semestre suivi (peut être None)"
|
|
self.niveaux_by_annee = {}
|
|
"{ annee : liste des niveaux à valider }"
|
|
self.niveaux: dict[int, ApcNiveau] = {}
|
|
"cache les niveaux"
|
|
for annee in (1, 2, 3):
|
|
niveaux_d = formation.referentiel_competence.get_niveaux_by_parcours(
|
|
annee, self.parcour
|
|
)[1]
|
|
# groupe les niveaux de tronc commun et ceux spécifiques au parcour
|
|
self.niveaux_by_annee[annee] = niveaux_d["TC"] + (
|
|
niveaux_d[self.parcour.id] if self.parcour else []
|
|
)
|
|
self.niveaux.update(
|
|
{niveau.id: niveau for niveau in self.niveaux_by_annee[annee]}
|
|
)
|
|
# Probablement inutile:
|
|
# # Cherche les validations de jury enregistrées pour chaque niveau
|
|
# self.validations_by_niveau = collections.defaultdict(lambda: [])
|
|
# " { niveau_id : [ ApcValidationRCUE ] }"
|
|
# for validation_rcue in ApcValidationRCUE.query.filter_by(etud=etud):
|
|
# self.validations_by_niveau[validation_rcue.niveau().id].append(
|
|
# validation_rcue
|
|
# )
|
|
# self.validation_by_niveau = {
|
|
# niveau_id: sorted(
|
|
# validations, key=lambda v: sco_codes.BUT_CODES_ORDERED[v.code]
|
|
# )[0]
|
|
# for niveau_id, validations in self.validations_by_niveau.items()
|
|
# }
|
|
# "{ niveau_id : meilleure validation pour ce niveau }"
|
|
|
|
self.validation_par_competence_et_annee = {}
|
|
"""{ competence_id : { 'BUT1' : validation_rcue (la "meilleure"), ... } }"""
|
|
for validation_rcue in ApcValidationRCUE.query.filter_by(etud=etud):
|
|
niveau = validation_rcue.niveau()
|
|
if not niveau.competence.id in self.validation_par_competence_et_annee:
|
|
self.validation_par_competence_et_annee[niveau.competence.id] = {}
|
|
previous_validation = self.validation_par_competence_et_annee.get(
|
|
niveau.competence.id
|
|
).get(validation_rcue.annee())
|
|
# prend la "meilleure" validation
|
|
if (not previous_validation) or (
|
|
sco_codes.BUT_CODES_ORDERED[validation_rcue.code]
|
|
> sco_codes.BUT_CODES_ORDERED[previous_validation["code"]]
|
|
):
|
|
self.validation_par_competence_et_annee[niveau.competence.id][
|
|
niveau.annee
|
|
] = validation_rcue
|
|
|
|
self.competences = {
|
|
competence.id: competence
|
|
for competence in (
|
|
self.parcour.query_competences()
|
|
if self.parcour
|
|
else self.formation.referentiel_competence.get_competences_tronc_commun()
|
|
)
|
|
}
|
|
"cache { competence_id : competence }"
|
|
|
|
def to_dict(self):
|
|
"""
|
|
{
|
|
competence_id : {
|
|
annee : meilleure_validation
|
|
}
|
|
}
|
|
"""
|
|
return {
|
|
competence.id: {
|
|
annee: self.validation_par_competence_et_annee.get(
|
|
competence.id, {}
|
|
).get(annee)
|
|
for annee in ("BUT1", "BUT2", "BUT3")
|
|
}
|
|
for competence in self.competences.values()
|
|
}
|
|
|
|
# XXX TODO OPTIMISATION ACCESS TABLE JURY
|
|
def to_dict_codes(self) -> dict[int, dict[str, int]]:
|
|
"""
|
|
{
|
|
competence_id : {
|
|
annee : { validation}
|
|
}
|
|
}
|
|
où validation est un petit dict avec niveau_id, etc.
|
|
"""
|
|
d = {}
|
|
for competence in self.competences.values():
|
|
d[competence.id] = {}
|
|
for annee in ("BUT1", "BUT2", "BUT3"):
|
|
validation_rcue: ApcValidationRCUE = (
|
|
self.validation_par_competence_et_annee.get(competence.id, {}).get(
|
|
annee
|
|
)
|
|
)
|
|
|
|
d[competence.id][annee] = (
|
|
validation_rcue.to_dict_codes() if validation_rcue else None
|
|
)
|
|
return d
|