forked from ScoDoc/ScoDoc
BUT: Calcul des UEs à valider par parcour. WIP: tets unitaire écrit mais ne passe pas (manque assoc UE à plusieurs parcours)
This commit is contained in:
parent
cf778eba85
commit
4f9638582a
@ -16,6 +16,7 @@ from app.comp.res_compat import NotesTableCompat
|
||||
from app.comp.bonus_spo import BonusSport
|
||||
from app.models import ScoDocSiteConfig
|
||||
from app.models.moduleimpls import ModuleImpl
|
||||
from app.models.but_refcomp import ApcParcours, ApcNiveau
|
||||
from app.models.ues import DispenseUE, UniteEns
|
||||
from app.models.but_validations import ApcValidationAnnee, ApcValidationRCUE
|
||||
from app.scodoc import sco_preferences
|
||||
@ -41,6 +42,8 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
||||
"""ndarray (etuds x modimpl x ue)"""
|
||||
self.etuds_parcour_id = None
|
||||
"""Parcours de chaque étudiant { etudid : parcour_id }"""
|
||||
self.ues_ids_by_parcour: dict[set[int]] = {}
|
||||
"""{ parcour_id : set }, ue_id de chaque parcours"""
|
||||
|
||||
if not self.load_cached():
|
||||
t0 = time.time()
|
||||
@ -259,10 +262,43 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
||||
def etud_ues_ids(self, etudid: int) -> list[int]:
|
||||
"""Liste des id d'UE auxquelles l'étudiant est inscrit (sans bonus).
|
||||
(surchargée ici pour prendre en compte les parcours)
|
||||
Ne prend pas en compte les éventuelles DispenseUE (pour le moment ?)
|
||||
"""
|
||||
s = self.ues_inscr_parcours_df.loc[etudid]
|
||||
return s.index[s.notna()]
|
||||
|
||||
def etud_parcours_ues_ids(self, etudid: int) -> set[int]:
|
||||
"""Ensemble les id des UEs que l'étudiant doit valider dans ce semestre compte tenu
|
||||
du parcours dans lequel il est inscrit.
|
||||
Se base sur le parcours dans ce semestre, et le référentiel de compétences.
|
||||
Note: il n'est pas nécessairement inscrit à toutes ces UEs.
|
||||
Ensemble vide si pas de référentiel.
|
||||
|
||||
La requête est longue, les ue_ids par parcour sont donc cachés.
|
||||
"""
|
||||
parcour_id = self.etuds_parcour_id[etudid]
|
||||
if parcour_id in self.ues_ids_by_parcour: # cache
|
||||
return self.ues_ids_by_parcour[parcour_id]
|
||||
# Hors cache:
|
||||
ref_comp = self.formsemestre.formation.referentiel_competence
|
||||
if ref_comp is None:
|
||||
return set()
|
||||
parcour: ApcParcours = ApcParcours.query.get(parcour_id)
|
||||
annee = (self.formsemestre.semestre_id + 1) // 2
|
||||
niveaux = ApcNiveau.niveaux_annee_de_parcours(parcour, annee, ref_comp)
|
||||
# Les UEs du formsemestre associées à ces niveaux:
|
||||
ues_parcour = self.formsemestre.formation.query_ues_parcour(parcour)
|
||||
ues_ids = set()
|
||||
for niveau in niveaux:
|
||||
ue = ues_parcour.filter_by(niveau_competence=niveau).first()
|
||||
if ue:
|
||||
ues_ids.add(ue.id)
|
||||
|
||||
# memoize
|
||||
self.ues_ids_by_parcour[parcour_id] = ues_ids
|
||||
|
||||
return ues_ids
|
||||
|
||||
def etud_has_decision(self, etudid):
|
||||
"""True s'il y a une décision de jury pour cet étudiant émanant de ce formsemestre.
|
||||
prend aussi en compte les autorisations de passage.
|
||||
|
@ -125,6 +125,13 @@ class ResultatsSemestre(ResultatsCache):
|
||||
# car tous les étudiants sont inscrits à toutes les UE
|
||||
return [ue.id for ue in self.ues if ue.type != UE_SPORT]
|
||||
|
||||
def etud_parcours_ues_ids(self, etudid: int) -> set[int]:
|
||||
"""Ensemble des UEs que l'étudiant "doit" valider.
|
||||
En formations classiques, c'est la même chose (en set) que etud_ues_ids.
|
||||
Surchargée en BUT pour donner les UEs du parcours de l'étudiant.
|
||||
"""
|
||||
return {ue.id for ue in self.ues if ue.type != UE_SPORT}
|
||||
|
||||
def etud_ues(self, etudid: int) -> Generator[UniteEns]:
|
||||
"""Liste des UE auxquelles l'étudiant est inscrit
|
||||
(sans bonus, en BUT prend en compte le parcours de l'étudiant)."""
|
||||
|
@ -214,7 +214,6 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
||||
"""
|
||||
parcours_info = {}
|
||||
for parcour in self.parcours:
|
||||
print(f"# Parcours {parcour.code}")
|
||||
descr_parcour = {}
|
||||
parcours_info[parcour.id] = descr_parcour
|
||||
for annee in (1, 2, 3):
|
||||
|
@ -676,7 +676,7 @@ class RowRecap(tb.Row):
|
||||
# Les moyennes des modules (ou ressources et SAÉs) dans cette UE
|
||||
self.add_ue_modimpls_cols(ue, ue_status["is_capitalized"])
|
||||
|
||||
self.nb_ues_etud_parcours = len(res.etud_ues_ids(etud.id))
|
||||
self.nb_ues_etud_parcours = len(res.etud_parcours_ues_ids(etud.id))
|
||||
ue_valid_txt = (
|
||||
ue_valid_txt_html
|
||||
) = f"{self.nb_ues_validables}/{self.nb_ues_etud_parcours}"
|
||||
|
@ -79,15 +79,44 @@ Formation:
|
||||
# S5 Parcours BAT + TP
|
||||
'UE5.1': # Parcours BAT seulement
|
||||
annee: BUT3
|
||||
parcours: BAT # + RAPEB, BEC
|
||||
competence: "Solutions Bâtiment"
|
||||
'UE5.2': # Parcours TP seulement
|
||||
annee: BUT3
|
||||
parcours: TP # + BEC
|
||||
competence: "Solutions TP"
|
||||
'UE5.3':
|
||||
annee: BUT3
|
||||
parcours: RAPEB # + BEC
|
||||
competence: "Dimensionner"
|
||||
'UE5.4':
|
||||
annee: BUT3
|
||||
parcours: BAT # + TP
|
||||
competence: Organiser
|
||||
'UE5.5':
|
||||
annee: BUT3
|
||||
parcours: BAT # + TP
|
||||
competence: Piloter
|
||||
# S6 Parcours BAT + TP
|
||||
'UE6.1': # Parcours BAT seulement
|
||||
annee: BUT3
|
||||
parcours: BAT # + RAPEB, BEC
|
||||
competence: "Solutions Bâtiment"
|
||||
'UE6.2': # Parcours TP seulement
|
||||
annee: BUT3
|
||||
parcours: TP # + BEC
|
||||
competence: "Solutions TP"
|
||||
'UE6.3':
|
||||
annee: BUT3
|
||||
parcours: RAPEB # + BEC
|
||||
competence: "Dimensionner"
|
||||
'UE6.4':
|
||||
annee: BUT3
|
||||
parcours: BAT # + TP
|
||||
competence: Organiser
|
||||
'UE6.5':
|
||||
annee: BUT3
|
||||
parcours: BAT # + TP
|
||||
competence: Piloter
|
||||
|
||||
modules_parcours:
|
||||
@ -157,7 +186,7 @@ Etudiants:
|
||||
|
||||
S5:
|
||||
parcours: BAT
|
||||
dispense_ues: ['UE5.2']
|
||||
dispense_ues: ['UE5.2', 'UE5.3']
|
||||
notes_modules:
|
||||
"R5.01": 15 # toutes UE
|
||||
"SAÉ 5.BAT.01": 10 # UE5.1
|
||||
@ -188,7 +217,7 @@ Etudiants:
|
||||
|
||||
S5:
|
||||
parcours: TP
|
||||
dispense_ues: ['UE5.1']
|
||||
dispense_ues: ['UE5.1', 'UE5.3']
|
||||
notes_modules:
|
||||
"R5.01": 15 # toutes UE
|
||||
"SAÉ 5.BAT.01": 10 # UE5.1
|
||||
|
@ -24,7 +24,7 @@ from tests.unit import yaml_setup, yaml_setup_but
|
||||
|
||||
import app
|
||||
from app.but.jury_but_validation_auto import formsemestre_validation_auto_but
|
||||
from app.models import FormSemestre
|
||||
from app.models import Formation, FormSemestre
|
||||
from config import TestConfig
|
||||
|
||||
DEPT = TestConfig.DEPT_TEST
|
||||
@ -124,3 +124,23 @@ def test_but_jury_GCCD_CY(test_client):
|
||||
formsemestres = FormSemestre.query.order_by(
|
||||
FormSemestre.date_debut, FormSemestre.semestre_id
|
||||
).all()
|
||||
|
||||
formation: Formation = formsemestres[0].formation
|
||||
# Vérifie les UEs du parcours BAT
|
||||
parcour_BAT = formation.referentiel_competence.parcours.filter_by(
|
||||
code="BAT"
|
||||
).first()
|
||||
assert parcour_BAT
|
||||
# check le nombre d'UE dans chaque semestre BUT:
|
||||
assert [
|
||||
len(formation.query_ues_parcour(parcour_BAT).filter_by(semestre_idx=i).all())
|
||||
for i in range(1, 7)
|
||||
] == [5, 5, 5, 5, 3, 3]
|
||||
# Vérifie les UEs du parcours TP
|
||||
parcour_TP = formation.referentiel_competence.parcours.filter_by(code="TP").first()
|
||||
assert parcour_TP
|
||||
# check le nombre d'UE dans chaque semestre BUT:
|
||||
assert [
|
||||
len(formation.query_ues_parcour(parcour_TP).filter_by(semestre_idx=i).all())
|
||||
for i in range(1, 7)
|
||||
] == [5, 5, 5, 5, 3, 3]
|
||||
|
Loading…
Reference in New Issue
Block a user