Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
3 changed files with 58 additions and 5 deletions
Showing only changes of commit 068951ef1d - Show all commits

View File

@ -10,17 +10,17 @@ import time
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from app import log from app import db, log
from app.comp import moy_ue, moy_sem, inscr_mod from app.comp import moy_ue, moy_sem, inscr_mod
from app.comp.res_compat import NotesTableCompat from app.comp.res_compat import NotesTableCompat
from app.comp.bonus_spo import BonusSport from app.comp.bonus_spo import BonusSport
from app.models import ScoDocSiteConfig from app.models import Formation, FormSemestreInscription, ScoDocSiteConfig
from app.models.moduleimpls import ModuleImpl from app.models.moduleimpls import ModuleImpl
from app.models.but_refcomp import ApcParcours, ApcNiveau from app.models.but_refcomp import ApcParcours, ApcNiveau
from app.models.ues import DispenseUE, UniteEns from app.models.ues import DispenseUE, UniteEns
from app.models.but_validations import ApcValidationAnnee, ApcValidationRCUE from app.models.but_validations import ApcValidationAnnee, ApcValidationRCUE
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc.codes_cursus import UE_SPORT from app.scodoc.codes_cursus import BUT_CODES_ORDERED, UE_SPORT
from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_utils import ModuleType
@ -44,7 +44,8 @@ class ResultatsSemestreBUT(NotesTableCompat):
"""Parcours de chaque étudiant { etudid : parcour_id }""" """Parcours de chaque étudiant { etudid : parcour_id }"""
self.ues_ids_by_parcour: dict[set[int]] = {} self.ues_ids_by_parcour: dict[set[int]] = {}
"""{ parcour_id : set }, ue_id de chaque parcours""" """{ parcour_id : set }, ue_id de chaque parcours"""
self.validations_annee: dict[int, ApcValidationAnnee] = {}
"""chargé par get_validations_annee: jury annuel BUT"""
if not self.load_cached(): if not self.load_cached():
t0 = time.time() t0 = time.time()
self.compute() self.compute()
@ -321,3 +322,42 @@ class ResultatsSemestreBUT(NotesTableCompat):
formsemestre_id=self.formsemestre.id, etudid=etudid formsemestre_id=self.formsemestre.id, etudid=etudid
).count() ).count()
) )
def get_validations_annee(self) -> dict[int, ApcValidationAnnee]:
"""Les validations des étudiants de ce semestre
pour l'année BUT d'une formation compatible avec celle de ce semestre.
Attention:
1) la validation ne provient pas nécessairement de ce semestre
(redoublants, pair/impair, extérieurs).
2) l'étudiant a pu démissionner ou défaillir.
3) S'il y a plusieurs validations pour le même étudiant, prend la "meilleure".
Mémorise le résultat (dans l'instance, pas en cache: TODO voir au profiler)
"""
if self.validations_annee:
return self.validations_annee
annee_but = (self.formsemestre.semestre_id + 1) // 2
validations = (
ApcValidationAnnee.query.filter_by(ordre=annee_but)
.join(Formation)
.filter_by(formation_code=self.formsemestre.formation.formation_code)
.join(
FormSemestreInscription,
db.and_(
FormSemestreInscription.etudid == ApcValidationAnnee.etudid,
FormSemestreInscription.formsemestre_id == self.formsemestre.id,
),
)
)
validation_by_etud = {}
for validation in validations:
if validation.etudid in validation_by_etud:
# keep the "best"
if BUT_CODES_ORDERED.get(validation.code, 0) > BUT_CODES_ORDERED.get(
validation_by_etud[validation.etudid].code, 0
):
validation_by_etud[validation.etudid] = validation
else:
validation_by_etud[validation.etudid] = validation
self.validations_annee = validation_by_etud
return self.validations_annee

View File

@ -251,6 +251,7 @@ def formsemestre_recapcomplet(
<div><tt>~</tt></div><div>valeur manquante</div> <div><tt>~</tt></div><div>valeur manquante</div>
<div><tt>=</tt></div><div>UE dispensée</div> <div><tt>=</tt></div><div>UE dispensée</div>
<div><tt>nan</tt></div><div>valeur non disponible</div> <div><tt>nan</tt></div><div>valeur non disponible</div>
<div>📍</div><div>code jury non enregistré</div>
</div> </div>
</div> </div>
""" """

View File

@ -81,11 +81,14 @@ class TableJury(TableRecap):
def add_jury(self): def add_jury(self):
"""Ajoute la colonne code jury et le lien. """Ajoute la colonne code jury et le lien.
Le code jury est celui du semestre: cette colonne n'est montrée - Le code jury est celui du semestre: cette colonne n'est montrée
que pour les formations classiques, ce code n'est pas utilisé en BUT. que pour les formations classiques, ce code n'est pas utilisé en BUT.
- En BUT, on donne la décision de jury annuelle.
""" """
res = self.res res = self.res
autorisations = res.get_autorisations_inscription() autorisations = res.get_autorisations_inscription()
if res.is_apc:
validations_annee = res.get_validations_annee()
for row in self.rows: for row in self.rows:
etud = row.etud etud = row.etud
if not res.is_apc: if not res.is_apc:
@ -115,6 +118,15 @@ class TableJury(TableRecap):
group="jury_code_sem", group="jury_code_sem",
classes=["recorded_code"], classes=["recorded_code"],
) )
if res.is_apc: # BUT
validation_annee = validations_annee.get(etud.id, None)
row.add_cell(
"decision_annuelle",
"Année",
validation_annee.code if validation_annee else "",
group="jury_code_sem",
classes=["recorded_code"],
)
# Lien saisie ou visu jury # Lien saisie ou visu jury
a_saisir = (not res.validations) or (not res.validations.has_decision(etud)) a_saisir = (not res.validations) or (not res.validations.has_decision(etud))
row.add_cell( row.add_cell(