forked from ScoDoc/ScoDoc
Prépare modernisation de NT
This commit is contained in:
parent
9eb2c2462b
commit
dce7dc42cb
@ -4,7 +4,6 @@
|
|||||||
# See LICENSE
|
# See LICENSE
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from collections import defaultdict
|
|
||||||
import datetime
|
import datetime
|
||||||
from flask import url_for, g
|
from flask import url_for, g
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -15,62 +14,24 @@ from app import db
|
|||||||
from app.comp import moy_ue, moy_sem, inscr_mod
|
from app.comp import moy_ue, moy_sem, inscr_mod
|
||||||
from app.models import ModuleImpl
|
from app.models import ModuleImpl
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_cache import ResultatsSemestreBUTCache
|
|
||||||
from app.scodoc import sco_bulletins_json
|
from app.scodoc import sco_bulletins_json
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc.sco_utils import jsnan, fmt_note
|
from app.scodoc.sco_utils import jsnan, fmt_note
|
||||||
|
from app.comp.res_sem import ResultatsSemestre, NotesTableCompat
|
||||||
|
|
||||||
|
|
||||||
class ResultatsSemestreBUT:
|
class ResultatsSemestreBUT(NotesTableCompat):
|
||||||
"""Structure légère pour stocker les résultats du semestre et
|
"""Résultats BUT: organisation des calculs"""
|
||||||
générer les bulletins.
|
|
||||||
__init__ : charge depuis le cache ou calcule
|
|
||||||
"""
|
|
||||||
|
|
||||||
_cached_attrs = (
|
_cached_attrs = NotesTableCompat._cached_attrs + ()
|
||||||
"sem_cube",
|
|
||||||
"modimpl_inscr_df",
|
|
||||||
"modimpl_coefs_df",
|
|
||||||
"etud_moy_ue",
|
|
||||||
"modimpls_evals_poids",
|
|
||||||
"modimpls_evals_notes",
|
|
||||||
"etud_moy_gen",
|
|
||||||
"etud_moy_gen_ranks",
|
|
||||||
"modimpls_evaluations_complete",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, formsemestre):
|
def __init__(self, formsemestre):
|
||||||
self.formsemestre = formsemestre
|
super().__init__(formsemestre)
|
||||||
self.ues = formsemestre.query_ues().all()
|
|
||||||
self.modimpls = formsemestre.modimpls.all()
|
|
||||||
self.etuds = self.formsemestre.get_inscrits(include_dem=False)
|
|
||||||
self.etud_index = {e.id: idx for idx, e in enumerate(self.etuds)}
|
|
||||||
self.saes = [
|
|
||||||
m for m in self.modimpls if m.module.module_type == scu.ModuleType.SAE
|
|
||||||
]
|
|
||||||
self.ressources = [
|
|
||||||
m for m in self.modimpls if m.module.module_type == scu.ModuleType.RESSOURCE
|
|
||||||
]
|
|
||||||
if not self.load_cached():
|
if not self.load_cached():
|
||||||
self.compute()
|
self.compute()
|
||||||
self.store()
|
self.store()
|
||||||
|
|
||||||
def load_cached(self) -> bool:
|
|
||||||
"Load cached dataframes, returns False si pas en cache"
|
|
||||||
data = ResultatsSemestreBUTCache.get(self.formsemestre.id)
|
|
||||||
if not data:
|
|
||||||
return False
|
|
||||||
for attr in self._cached_attrs:
|
|
||||||
setattr(self, attr, data[attr])
|
|
||||||
return True
|
|
||||||
|
|
||||||
def store(self):
|
|
||||||
"Cache our dataframes"
|
|
||||||
ResultatsSemestreBUTCache.set(
|
|
||||||
self.formsemestre.id,
|
|
||||||
{attr: getattr(self, attr) for attr in self._cached_attrs},
|
|
||||||
)
|
|
||||||
|
|
||||||
def compute(self):
|
def compute(self):
|
||||||
"Charge les notes et inscriptions et calcule toutes les moyennes"
|
"Charge les notes et inscriptions et calcule toutes les moyennes"
|
||||||
(
|
(
|
||||||
@ -100,6 +61,13 @@ class ResultatsSemestreBUT:
|
|||||||
)
|
)
|
||||||
self.etud_moy_gen_ranks = moy_sem.comp_ranks_series(self.etud_moy_gen)
|
self.etud_moy_gen_ranks = moy_sem.comp_ranks_series(self.etud_moy_gen)
|
||||||
|
|
||||||
|
|
||||||
|
class BulletinBUT(ResultatsSemestreBUT):
|
||||||
|
"""Génération du bulletin BUT.
|
||||||
|
Cette classe génère des dictionnaires avec toutes les informations
|
||||||
|
du bulletin, qui sont immédiatement traduisibles en JSON.
|
||||||
|
"""
|
||||||
|
|
||||||
def etud_ue_mod_results(self, etud, ue, modimpls) -> dict:
|
def etud_ue_mod_results(self, etud, ue, modimpls) -> dict:
|
||||||
"dict synthèse résultats dans l'UE pour les modules indiqués"
|
"dict synthèse résultats dans l'UE pour les modules indiqués"
|
||||||
d = {}
|
d = {}
|
||||||
@ -233,7 +201,7 @@ class ResultatsSemestreBUT:
|
|||||||
},
|
},
|
||||||
"formsemestre_id": formsemestre.id,
|
"formsemestre_id": formsemestre.id,
|
||||||
"etat_inscription": etat_inscription,
|
"etat_inscription": etat_inscription,
|
||||||
"options": bulletin_option_affichage(formsemestre),
|
"options": sco_preferences.bulletin_option_affichage(formsemestre.id),
|
||||||
}
|
}
|
||||||
semestre_infos = {
|
semestre_infos = {
|
||||||
"etapes": [str(x.etape_apo) for x in formsemestre.etapes if x.etape_apo],
|
"etapes": [str(x.etape_apo) for x in formsemestre.etapes if x.etape_apo],
|
||||||
@ -298,125 +266,3 @@ class ResultatsSemestreBUT:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
def bulletin_option_affichage(formsemestre):
|
|
||||||
"dict avec les options d'affichages (préférences) pour ce semestre"
|
|
||||||
prefs = sco_preferences.SemPreferences(formsemestre.id)
|
|
||||||
fields = (
|
|
||||||
"bul_show_abs",
|
|
||||||
"bul_show_abs_modules",
|
|
||||||
"bul_show_ects",
|
|
||||||
"bul_show_codemodules",
|
|
||||||
"bul_show_matieres",
|
|
||||||
"bul_show_rangs",
|
|
||||||
"bul_show_ue_rangs",
|
|
||||||
"bul_show_mod_rangs",
|
|
||||||
"bul_show_moypromo",
|
|
||||||
"bul_show_minmax",
|
|
||||||
"bul_show_minmax_mod",
|
|
||||||
"bul_show_minmax_eval",
|
|
||||||
"bul_show_coef",
|
|
||||||
"bul_show_ue_cap_details",
|
|
||||||
"bul_show_ue_cap_current",
|
|
||||||
"bul_show_temporary",
|
|
||||||
"bul_temporary_txt",
|
|
||||||
"bul_show_uevalid",
|
|
||||||
"bul_show_date_inscr",
|
|
||||||
)
|
|
||||||
# on enlève le "bul_" de la clé:
|
|
||||||
return {field[4:]: prefs[field] for field in fields}
|
|
||||||
|
|
||||||
|
|
||||||
# Pour raccorder le code des anciens bulletins qui attendent une NoteTable
|
|
||||||
class APCNotesTableCompat:
|
|
||||||
"""Implementation partielle de NotesTable pour les formations APC
|
|
||||||
Accès aux notes et rangs.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, formsemestre):
|
|
||||||
self.results = ResultatsSemestreBUT(formsemestre)
|
|
||||||
nb_etuds = len(self.results.etuds)
|
|
||||||
self.rangs = self.results.etud_moy_gen_ranks
|
|
||||||
self.moy_min = self.results.etud_moy_gen.min()
|
|
||||||
self.moy_max = self.results.etud_moy_gen.max()
|
|
||||||
self.moy_moy = self.results.etud_moy_gen.mean()
|
|
||||||
self.bonus = defaultdict(lambda: 0.0) # XXX
|
|
||||||
self.ue_rangs = {
|
|
||||||
u.id: (defaultdict(lambda: 0.0), nb_etuds) for u in self.results.ues
|
|
||||||
}
|
|
||||||
self.mod_rangs = {
|
|
||||||
m.id: (defaultdict(lambda: 0), nb_etuds) for m in self.results.modimpls
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_ues(self):
|
|
||||||
ues = []
|
|
||||||
for ue in self.results.ues:
|
|
||||||
d = ue.to_dict()
|
|
||||||
d.update(
|
|
||||||
{
|
|
||||||
"max": self.results.etud_moy_ue[ue.id].max(),
|
|
||||||
"min": self.results.etud_moy_ue[ue.id].min(),
|
|
||||||
"moy": self.results.etud_moy_ue[ue.id].mean(),
|
|
||||||
"nb_moy": len(self.results.etud_moy_ue),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
ues.append(d)
|
|
||||||
return ues
|
|
||||||
|
|
||||||
def get_modimpls(self):
|
|
||||||
return [m.to_dict() for m in self.results.modimpls]
|
|
||||||
|
|
||||||
def get_etud_moy_gen(self, etudid):
|
|
||||||
return self.results.etud_moy_gen[etudid]
|
|
||||||
|
|
||||||
def get_moduleimpls_attente(self):
|
|
||||||
return [] # XXX TODO
|
|
||||||
|
|
||||||
def get_etud_rang(self, etudid):
|
|
||||||
return self.rangs[etudid]
|
|
||||||
|
|
||||||
def get_etud_rang_group(self, etudid, group_id):
|
|
||||||
return (None, 0) # XXX unimplemented TODO
|
|
||||||
|
|
||||||
def get_etud_ue_status(self, etudid, ue_id):
|
|
||||||
return {
|
|
||||||
"cur_moy_ue": self.results.etud_moy_ue[ue_id][etudid],
|
|
||||||
"is_capitalized": False, # XXX TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_etud_mod_moy(self, moduleimpl_id, etudid):
|
|
||||||
mod_idx = self.results.modimpl_coefs_df.columns.get_loc(moduleimpl_id)
|
|
||||||
etud_idx = self.results.etud_index[etudid]
|
|
||||||
# moyenne sur les UE:
|
|
||||||
self.results.sem_cube[etud_idx, mod_idx].mean()
|
|
||||||
|
|
||||||
def get_mod_stats(self, moduleimpl_id):
|
|
||||||
return {
|
|
||||||
"moy": "-",
|
|
||||||
"max": "-",
|
|
||||||
"min": "-",
|
|
||||||
"nb_notes": "-",
|
|
||||||
"nb_missing": "-",
|
|
||||||
"nb_valid_evals": "-",
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_evals_in_mod(self, moduleimpl_id):
|
|
||||||
mi = ModuleImpl.query.get(moduleimpl_id)
|
|
||||||
evals_results = []
|
|
||||||
for e in mi.evaluations:
|
|
||||||
d = e.to_dict()
|
|
||||||
d["heure_debut"] = e.heure_debut # datetime.time
|
|
||||||
d["heure_fin"] = e.heure_fin
|
|
||||||
d["jour"] = e.jour # datetime
|
|
||||||
d["notes"] = {
|
|
||||||
etud.id: {
|
|
||||||
"etudid": etud.id,
|
|
||||||
"value": self.results.modimpls_evals_notes[e.moduleimpl_id][e.id][
|
|
||||||
etud.id
|
|
||||||
],
|
|
||||||
}
|
|
||||||
for etud in self.results.etuds
|
|
||||||
}
|
|
||||||
evals_results.append(d)
|
|
||||||
return evals_results
|
|
||||||
|
@ -314,13 +314,3 @@ def bulletin_but_xml_compat(
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
|
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
formsemestre_id=718
|
|
||||||
etudid=12496
|
|
||||||
from app.but.bulletin_but import *
|
|
||||||
mapp.set_sco_dept("RT")
|
|
||||||
sem = FormSemestre.query.get(formsemestre_id)
|
|
||||||
r = ResultatsSemestreBUT(sem)
|
|
||||||
"""
|
|
||||||
|
216
app/comp/res_sem.py
Normal file
216
app/comp/res_sem.py
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
##############################################################################
|
||||||
|
# ScoDoc
|
||||||
|
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||||
|
# See LICENSE
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
from functools import cached_property
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
from app.scodoc.sco_cache import ResultatsSemestreCache
|
||||||
|
from app.scodoc.sco_codes_parcours import UE_SPORT
|
||||||
|
|
||||||
|
# Il faut bien distinguer
|
||||||
|
# - ce qui est caché de façon persistente (via redis):
|
||||||
|
# ce sont les attributs listés dans `_cached_attrs`
|
||||||
|
# le stockage et l'invalidation sont gérés dans sco_cache.py
|
||||||
|
#
|
||||||
|
# - les valeurs cachées durant le temps d'une requête
|
||||||
|
# (durée de vie de l'instance de ResultatsSemestre)
|
||||||
|
# qui sont notamment les attributs décorés par `@cached_property``
|
||||||
|
#
|
||||||
|
class ResultatsSemestre:
|
||||||
|
_cached_attrs = (
|
||||||
|
"sem_cube",
|
||||||
|
"modimpl_inscr_df",
|
||||||
|
"modimpl_coefs_df",
|
||||||
|
"etud_moy_ue",
|
||||||
|
"modimpls_evals_poids",
|
||||||
|
"modimpls_evals_notes",
|
||||||
|
"etud_moy_gen",
|
||||||
|
"etud_moy_gen_ranks",
|
||||||
|
"modimpls_evaluations_complete",
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, formsemestre):
|
||||||
|
self.formsemestre = formsemestre
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
def load_cached(self) -> bool:
|
||||||
|
"Load cached dataframes, returns False si pas en cache"
|
||||||
|
data = ResultatsSemestreCache.get(self.formsemestre.id)
|
||||||
|
if not data:
|
||||||
|
return False
|
||||||
|
for attr in self._cached_attrs:
|
||||||
|
setattr(self, attr, data[attr])
|
||||||
|
return True
|
||||||
|
|
||||||
|
def store(self):
|
||||||
|
"Cache our data"
|
||||||
|
"Cache our dataframes"
|
||||||
|
ResultatsSemestreCache.set(
|
||||||
|
self.formsemestre.id,
|
||||||
|
{attr: getattr(self, attr) for attr in self._cached_attrs},
|
||||||
|
)
|
||||||
|
|
||||||
|
def compute(self):
|
||||||
|
"Charge les notes et inscriptions et calcule toutes les moyennes"
|
||||||
|
# voir ce qui est chargé / calculé ici et dans les sous-classes
|
||||||
|
TODO
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def etuds(self):
|
||||||
|
"Liste des inscrits au semestre, sans les démissionnaires"
|
||||||
|
# nb: si les liste des inscrits change, ResultatsSemestre devient invalide
|
||||||
|
return self.formsemestre.get_inscrits(include_dem=False)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def etud_index(self):
|
||||||
|
"dict { etudid : indice dans les inscrits }"
|
||||||
|
return {e.id: idx for idx, e in enumerate(self.etuds)}
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def ues(self):
|
||||||
|
"Liste des UE du semestre"
|
||||||
|
return self.formsemestre.query_ues().all()
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def modimpls(self):
|
||||||
|
"Liste des modimpls du semestre (triée par numéro de module)"
|
||||||
|
modimpls = self.formsemestre.modimpls.all()
|
||||||
|
modimpls.sort(key=lambda m: m.module.numero)
|
||||||
|
return modimpls
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def ressources(self):
|
||||||
|
"Liste des ressources du semestre, triées par numéro de module"
|
||||||
|
return [
|
||||||
|
m for m in self.modimpls if m.module.module_type == scu.ModuleType.RESSOURCE
|
||||||
|
]
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def saes(self):
|
||||||
|
"Liste des SAÉs du semestre, triées par numéro de module"
|
||||||
|
return [m for m in self.modimpls if m.module.module_type == scu.ModuleType.SAE]
|
||||||
|
|
||||||
|
|
||||||
|
class StatsMoyenne:
|
||||||
|
"""Une moyenne d'un ensemble étudiants sur quelque chose
|
||||||
|
(moyenne générale d'un semestre, d'un module, d'un groupe...)
|
||||||
|
et les statistiques associées: min, max, moy, effectif
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, vals):
|
||||||
|
"""Calcul les statistiques.
|
||||||
|
Les valeurs NAN ou non numériques sont toujours enlevées.
|
||||||
|
"""
|
||||||
|
self.moy = np.nanmean(vals)
|
||||||
|
self.min = np.nanmin(vals)
|
||||||
|
self.max = np.nanmax(vals)
|
||||||
|
self.size = len(vals)
|
||||||
|
self.nb_vals = self.size - np.count_nonzero(np.isnan(vals))
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
"min": self.min,
|
||||||
|
"max": self.max,
|
||||||
|
"moy": self.moy,
|
||||||
|
"size": self.size,
|
||||||
|
"nb_vals": self.nb_vals,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Pour raccorder le code des anciens codes qui attendent une NoteTable
|
||||||
|
class NotesTableCompat(ResultatsSemestre):
|
||||||
|
"""Implementation partielle de NotesTable WIP TODO
|
||||||
|
Accès aux notes et rangs.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_cached_attrs = ResultatsSemestre._cached_attrs + ()
|
||||||
|
|
||||||
|
def __init__(self, formsemestre):
|
||||||
|
super().__init__(formsemestre)
|
||||||
|
nb_etuds = len(self.etuds)
|
||||||
|
self.bonus = defaultdict(lambda: 0.0) # XXX TODO
|
||||||
|
self.ue_rangs = {u.id: (defaultdict(lambda: 0.0), nb_etuds) for u in self.ues}
|
||||||
|
self.mod_rangs = {
|
||||||
|
m.id: (defaultdict(lambda: 0), nb_etuds) for m in self.modimpls
|
||||||
|
}
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def stats_moy_gen(self):
|
||||||
|
"""Stats (moy/min/max) sur la moyenne générale"""
|
||||||
|
return StatsMoyenne(self.etud_moy_gen)
|
||||||
|
|
||||||
|
def get_ues_stat_dict(self, filter_sport=False): # was get_ues()
|
||||||
|
"""Liste des UEs, ordonnée par numero.
|
||||||
|
Si filter_sport, retire les UE de type SPORT.
|
||||||
|
Résultat: liste de dicts { champs UE U stats moyenne UE }
|
||||||
|
"""
|
||||||
|
ues = []
|
||||||
|
for ue in self.ues:
|
||||||
|
if filter_sport and ue.type == UE_SPORT:
|
||||||
|
continue
|
||||||
|
d = ue.to_dict()
|
||||||
|
d.update(StatsMoyenne(self.etud_moy_ue[ue.id]).to_dict())
|
||||||
|
ues.append(d)
|
||||||
|
return ues
|
||||||
|
|
||||||
|
def get_modimpls(self):
|
||||||
|
return [m.to_dict() for m in self.results.modimpls]
|
||||||
|
|
||||||
|
def get_etud_moy_gen(self, etudid):
|
||||||
|
return self.results.etud_moy_gen[etudid]
|
||||||
|
|
||||||
|
def get_moduleimpls_attente(self):
|
||||||
|
return [] # XXX TODO
|
||||||
|
|
||||||
|
def get_etud_rang(self, etudid):
|
||||||
|
return self.etud_moy_gen_ranks[etudid]
|
||||||
|
|
||||||
|
def get_etud_rang_group(self, etudid, group_id):
|
||||||
|
return (None, 0) # XXX unimplemented TODO
|
||||||
|
|
||||||
|
def get_etud_ue_status(self, etudid, ue_id):
|
||||||
|
return {
|
||||||
|
"cur_moy_ue": self.results.etud_moy_ue[ue_id][etudid],
|
||||||
|
"is_capitalized": False, # XXX TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_etud_mod_moy(self, moduleimpl_id, etudid):
|
||||||
|
mod_idx = self.results.modimpl_coefs_df.columns.get_loc(moduleimpl_id)
|
||||||
|
etud_idx = self.results.etud_index[etudid]
|
||||||
|
# moyenne sur les UE:
|
||||||
|
self.results.sem_cube[etud_idx, mod_idx].mean()
|
||||||
|
|
||||||
|
def get_mod_stats(self, moduleimpl_id):
|
||||||
|
return {
|
||||||
|
"moy": "-",
|
||||||
|
"max": "-",
|
||||||
|
"min": "-",
|
||||||
|
"nb_notes": "-",
|
||||||
|
"nb_missing": "-",
|
||||||
|
"nb_valid_evals": "-",
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_evals_in_mod(self, moduleimpl_id):
|
||||||
|
mi = ModuleImpl.query.get(moduleimpl_id)
|
||||||
|
evals_results = []
|
||||||
|
for e in mi.evaluations:
|
||||||
|
d = e.to_dict()
|
||||||
|
d["heure_debut"] = e.heure_debut # datetime.time
|
||||||
|
d["heure_fin"] = e.heure_fin
|
||||||
|
d["jour"] = e.jour # datetime
|
||||||
|
d["notes"] = {
|
||||||
|
etud.id: {
|
||||||
|
"etudid": etud.id,
|
||||||
|
"value": self.results.modimpls_evals_notes[e.moduleimpl_id][e.id][
|
||||||
|
etud.id
|
||||||
|
],
|
||||||
|
}
|
||||||
|
for etud in self.results.etuds
|
||||||
|
}
|
||||||
|
evals_results.append(d)
|
||||||
|
return evals_results
|
@ -84,7 +84,11 @@ class FormSemestre(db.Model):
|
|||||||
etapes = db.relationship(
|
etapes = db.relationship(
|
||||||
"FormSemestreEtape", cascade="all,delete", backref="formsemestre"
|
"FormSemestreEtape", cascade="all,delete", backref="formsemestre"
|
||||||
)
|
)
|
||||||
modimpls = db.relationship("ModuleImpl", backref="formsemestre", lazy="dynamic")
|
modimpls = db.relationship(
|
||||||
|
"ModuleImpl",
|
||||||
|
backref="formsemestre",
|
||||||
|
lazy="dynamic",
|
||||||
|
)
|
||||||
etuds = db.relationship(
|
etuds = db.relationship(
|
||||||
"Identite",
|
"Identite",
|
||||||
secondary="notes_formsemestre_inscription",
|
secondary="notes_formsemestre_inscription",
|
||||||
|
@ -68,7 +68,7 @@ class TableTag(object):
|
|||||||
self.taglist = []
|
self.taglist = []
|
||||||
|
|
||||||
self.resultats = {}
|
self.resultats = {}
|
||||||
self.rangs = {}
|
self.etud_moy_gen_ranks = {}
|
||||||
self.statistiques = {}
|
self.statistiques = {}
|
||||||
|
|
||||||
# *****************************************************************************************************************
|
# *****************************************************************************************************************
|
||||||
@ -117,15 +117,15 @@ class TableTag(object):
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------------------------------------
|
||||||
def get_moy_from_stats(self, tag):
|
def get_moy_from_stats(self, tag):
|
||||||
""" Renvoie la moyenne des notes calculées pour d'un tag donné"""
|
"""Renvoie la moyenne des notes calculées pour d'un tag donné"""
|
||||||
return self.statistiques[tag][0] if tag in self.statistiques else None
|
return self.statistiques[tag][0] if tag in self.statistiques else None
|
||||||
|
|
||||||
def get_min_from_stats(self, tag):
|
def get_min_from_stats(self, tag):
|
||||||
""" Renvoie la plus basse des notes calculées pour d'un tag donné"""
|
"""Renvoie la plus basse des notes calculées pour d'un tag donné"""
|
||||||
return self.statistiques[tag][1] if tag in self.statistiques else None
|
return self.statistiques[tag][1] if tag in self.statistiques else None
|
||||||
|
|
||||||
def get_max_from_stats(self, tag):
|
def get_max_from_stats(self, tag):
|
||||||
""" Renvoie la plus haute des notes calculées pour d'un tag donné"""
|
"""Renvoie la plus haute des notes calculées pour d'un tag donné"""
|
||||||
return self.statistiques[tag][2] if tag in self.statistiques else None
|
return self.statistiques[tag][2] if tag in self.statistiques else None
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------------------------------------
|
||||||
@ -236,7 +236,7 @@ class TableTag(object):
|
|||||||
return moystr
|
return moystr
|
||||||
|
|
||||||
def str_res_d_un_etudiant(self, etudid, delim=";"):
|
def str_res_d_un_etudiant(self, etudid, delim=";"):
|
||||||
"""Renvoie sur une ligne les résultats d'un étudiant à tous les tags (par ordre alphabétique). """
|
"""Renvoie sur une ligne les résultats d'un étudiant à tous les tags (par ordre alphabétique)."""
|
||||||
return delim.join(
|
return delim.join(
|
||||||
[self.str_resTag_d_un_etudiant(tag, etudid) for tag in self.get_all_tags()]
|
[self.str_resTag_d_un_etudiant(tag, etudid) for tag in self.get_all_tags()]
|
||||||
)
|
)
|
||||||
@ -256,7 +256,7 @@ class TableTag(object):
|
|||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
def str_tagtable(self, delim=";", decimal_sep=","):
|
def str_tagtable(self, delim=";", decimal_sep=","):
|
||||||
"""Renvoie une chaine de caractère listant toutes les moyennes, les rangs des étudiants pour tous les tags. """
|
"""Renvoie une chaine de caractère listant toutes les moyennes, les rangs des étudiants pour tous les tags."""
|
||||||
entete = ["etudid", "nom", "prenom"]
|
entete = ["etudid", "nom", "prenom"]
|
||||||
for tag in self.get_all_tags():
|
for tag in self.get_all_tags():
|
||||||
entete += [titre + "_" + tag for titre in ["note", "rang", "nb_inscrit"]]
|
entete += [titre + "_" + tag for titre in ["note", "rang", "nb_inscrit"]]
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
"""Calculs sur les notes et cache des resultats
|
"""Calculs sur les notes et cache des résultats
|
||||||
|
|
||||||
|
Ancien code ScoDoc 7 en cours de rénovation
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
@ -102,7 +104,7 @@ def comp_ranks(T):
|
|||||||
|
|
||||||
def get_sem_ues_modimpls(formsemestre_id, modimpls=None):
|
def get_sem_ues_modimpls(formsemestre_id, modimpls=None):
|
||||||
"""Get liste des UE du semestre (à partir des moduleimpls)
|
"""Get liste des UE du semestre (à partir des moduleimpls)
|
||||||
(utilisé quand on ne peut pas construire nt et faire nt.get_ues())
|
(utilisé quand on ne peut pas construire nt et faire nt.get_ues_stat_dict())
|
||||||
"""
|
"""
|
||||||
if modimpls is None:
|
if modimpls is None:
|
||||||
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
@ -316,7 +318,7 @@ class NotesTable:
|
|||||||
self.moy_min = self.moy_max = "NA"
|
self.moy_min = self.moy_max = "NA"
|
||||||
|
|
||||||
# calcul rangs (/ moyenne generale)
|
# calcul rangs (/ moyenne generale)
|
||||||
self.rangs = comp_ranks(T)
|
self.etud_moy_gen_ranks = comp_ranks(T)
|
||||||
|
|
||||||
self.rangs_groupes = (
|
self.rangs_groupes = (
|
||||||
{}
|
{}
|
||||||
@ -417,43 +419,14 @@ class NotesTable:
|
|||||||
else:
|
else:
|
||||||
return ' <font color="red">(%s)</font> ' % etat
|
return ' <font color="red">(%s)</font> ' % etat
|
||||||
|
|
||||||
def get_ues(self, filter_sport=False, filter_non_inscrit=False, etudid=None):
|
def get_ues_stat_dict(self, filter_sport=False): # was get_ues()
|
||||||
"""liste des ue, ordonnée par numero.
|
"""Liste des UEs, ordonnée par numero.
|
||||||
Si filter_non_inscrit, retire les UE dans lesquelles l'etudiant n'est
|
|
||||||
inscrit à aucun module.
|
|
||||||
Si filter_sport, retire les UE de type SPORT
|
Si filter_sport, retire les UE de type SPORT
|
||||||
"""
|
"""
|
||||||
if not filter_sport and not filter_non_inscrit:
|
if not filter_sport:
|
||||||
return self._ues
|
return self._ues
|
||||||
|
|
||||||
if filter_sport:
|
|
||||||
ues_src = [ue for ue in self._ues if ue["type"] != UE_SPORT]
|
|
||||||
else:
|
else:
|
||||||
ues_src = self._ues
|
return [ue for ue in self._ues if ue["type"] != UE_SPORT]
|
||||||
if not filter_non_inscrit:
|
|
||||||
return ues_src
|
|
||||||
ues = []
|
|
||||||
for ue in ues_src:
|
|
||||||
if self.get_etud_ue_status(etudid, ue["ue_id"])["is_capitalized"]:
|
|
||||||
# garde toujours les UE capitalisees
|
|
||||||
has_note = True
|
|
||||||
else:
|
|
||||||
has_note = False
|
|
||||||
# verifie que l'etud. est inscrit a au moins un module de l'UE
|
|
||||||
# (en fait verifie qu'il a une note)
|
|
||||||
modimpls = self.get_modimpls(ue["ue_id"])
|
|
||||||
|
|
||||||
for modi in modimpls:
|
|
||||||
moy = self.get_etud_mod_moy(modi["moduleimpl_id"], etudid)
|
|
||||||
try:
|
|
||||||
float(moy)
|
|
||||||
has_note = True
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if has_note:
|
|
||||||
ues.append(ue)
|
|
||||||
return ues
|
|
||||||
|
|
||||||
def get_modimpls(self, ue_id=None):
|
def get_modimpls(self, ue_id=None):
|
||||||
"liste des modules pour une UE (ou toutes si ue_id==None), triés par matières."
|
"liste des modules pour une UE (ou toutes si ue_id==None), triés par matières."
|
||||||
@ -522,7 +495,7 @@ class NotesTable:
|
|||||||
|
|
||||||
Les moyennes d'UE ne tiennent pas compte des capitalisations.
|
Les moyennes d'UE ne tiennent pas compte des capitalisations.
|
||||||
"""
|
"""
|
||||||
ues = self.get_ues()
|
ues = self.get_ues_stat_dict()
|
||||||
sum_moy = 0 # la somme des moyennes générales valides
|
sum_moy = 0 # la somme des moyennes générales valides
|
||||||
nb_moy = 0 # le nombre de moyennes générales valides
|
nb_moy = 0 # le nombre de moyennes générales valides
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
@ -561,9 +534,9 @@ class NotesTable:
|
|||||||
i = 0
|
i = 0
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
i += 1
|
i += 1
|
||||||
ue["nb_moy"] = len(ue["_notes"])
|
ue["nb_vals"] = len(ue["_notes"])
|
||||||
if ue["nb_moy"] > 0:
|
if ue["nb_vals"] > 0:
|
||||||
ue["moy"] = sum(ue["_notes"]) / ue["nb_moy"]
|
ue["moy"] = sum(ue["_notes"]) / ue["nb_vals"]
|
||||||
ue["max"] = max(ue["_notes"])
|
ue["max"] = max(ue["_notes"])
|
||||||
ue["min"] = min(ue["_notes"])
|
ue["min"] = min(ue["_notes"])
|
||||||
else:
|
else:
|
||||||
@ -767,7 +740,7 @@ class NotesTable:
|
|||||||
sem_ects_pot_fond = 0.0
|
sem_ects_pot_fond = 0.0
|
||||||
sem_ects_pot_pro = 0.0
|
sem_ects_pot_pro = 0.0
|
||||||
|
|
||||||
for ue in self.get_ues():
|
for ue in self.get_ues_stat_dict():
|
||||||
# - On calcule la moyenne d'UE courante:
|
# - On calcule la moyenne d'UE courante:
|
||||||
if not block_computation:
|
if not block_computation:
|
||||||
mu = self.comp_etud_moy_ue(etudid, ue_id=ue["ue_id"], cnx=cnx)
|
mu = self.comp_etud_moy_ue(etudid, ue_id=ue["ue_id"], cnx=cnx)
|
||||||
@ -981,7 +954,7 @@ class NotesTable:
|
|||||||
return self.T
|
return self.T
|
||||||
|
|
||||||
def get_etud_rang(self, etudid) -> str:
|
def get_etud_rang(self, etudid) -> str:
|
||||||
return self.rangs.get(etudid, "999")
|
return self.etud_moy_gen_ranks.get(etudid, "999")
|
||||||
|
|
||||||
def get_etud_rang_group(self, etudid, group_id):
|
def get_etud_rang_group(self, etudid, group_id):
|
||||||
"""Returns rank of etud in this group and number of etuds in group.
|
"""Returns rank of etud in this group and number of etuds in group.
|
||||||
@ -1347,7 +1320,7 @@ class NotesTable:
|
|||||||
|
|
||||||
# Rappel des épisodes précédents: T est une liste de liste
|
# Rappel des épisodes précédents: T est une liste de liste
|
||||||
# Colonnes: 0 moy_gen, moy_ue1, ..., moy_ue_n, moy_mod1, ..., moy_mod_n, etudid
|
# Colonnes: 0 moy_gen, moy_ue1, ..., moy_ue_n, moy_mod1, ..., moy_mod_n, etudid
|
||||||
ues = self.get_ues() # incluant le(s) UE de sport
|
ues = self.get_ues_stat_dict() # incluant le(s) UE de sport
|
||||||
for t in self.T:
|
for t in self.T:
|
||||||
etudid = t[-1]
|
etudid = t[-1]
|
||||||
if etudid in results.etud_moy_gen: # evite les démissionnaires
|
if etudid in results.etud_moy_gen: # evite les démissionnaires
|
||||||
@ -1358,4 +1331,4 @@ class NotesTable:
|
|||||||
# re-trie selon la nouvelle moyenne générale:
|
# re-trie selon la nouvelle moyenne générale:
|
||||||
self.T.sort(key=self._row_key)
|
self.T.sort(key=self._row_key)
|
||||||
# Remplace aussi le rang:
|
# Remplace aussi le rang:
|
||||||
self.rangs = results.etud_moy_gen_ranks
|
self.etud_moy_gen_ranks = results.etud_moy_gen_ranks
|
||||||
|
@ -118,7 +118,7 @@ def doSignaleAbsence(
|
|||||||
mod = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
mod = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
formsemestre_id = mod["formsemestre_id"]
|
formsemestre_id = mod["formsemestre_id"]
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
||||||
ues = nt.get_ues(etudid=etudid)
|
ues = nt.get_ues_stat_dict()
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
modimpls = nt.get_modimpls(ue_id=ue["ue_id"])
|
modimpls = nt.get_modimpls(ue_id=ue["ue_id"])
|
||||||
for modimpl in modimpls:
|
for modimpl in modimpls:
|
||||||
@ -175,7 +175,7 @@ def SignaleAbsenceEtud(): # etudid implied
|
|||||||
"abs_require_module", formsemestre_id
|
"abs_require_module", formsemestre_id
|
||||||
)
|
)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
||||||
ues = nt.get_ues(etudid=etudid)
|
ues = nt.get_ues_stat_dict()
|
||||||
if require_module:
|
if require_module:
|
||||||
menu_module = """
|
menu_module = """
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
@ -437,7 +437,7 @@ class ApoEtud(dict):
|
|||||||
|
|
||||||
# Elements UE
|
# Elements UE
|
||||||
decisions_ue = nt.get_etud_decision_ues(etudid)
|
decisions_ue = nt.get_etud_decision_ues(etudid)
|
||||||
for ue in nt.get_ues():
|
for ue in nt.get_ues_stat_dict():
|
||||||
if code in ue["code_apogee"].split(","):
|
if code in ue["code_apogee"].split(","):
|
||||||
if self.export_res_ues:
|
if self.export_res_ues:
|
||||||
if decisions_ue and ue["ue_id"] in decisions_ue:
|
if decisions_ue and ue["ue_id"] in decisions_ue:
|
||||||
@ -973,7 +973,7 @@ class ApoData(object):
|
|||||||
continue
|
continue
|
||||||
# associé à une UE:
|
# associé à une UE:
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
||||||
for ue in nt.get_ues():
|
for ue in nt.get_ues_stat_dict():
|
||||||
if code in ue["code_apogee"].split(","):
|
if code in ue["code_apogee"].split(","):
|
||||||
s.add(code)
|
s.add(code)
|
||||||
continue
|
continue
|
||||||
|
@ -218,10 +218,10 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
|||||||
] # deprecated / keep it for backward compat in templates
|
] # deprecated / keep it for backward compat in templates
|
||||||
|
|
||||||
# --- Notes
|
# --- Notes
|
||||||
ues = nt.get_ues()
|
ues = nt.get_ues_stat_dict()
|
||||||
modimpls = nt.get_modimpls()
|
modimpls = nt.get_modimpls()
|
||||||
moy_gen = nt.get_etud_moy_gen(etudid)
|
moy_gen = nt.get_etud_moy_gen(etudid)
|
||||||
I["nb_inscrits"] = len(nt.rangs)
|
I["nb_inscrits"] = len(nt.etud_moy_gen_ranks)
|
||||||
I["moy_gen"] = scu.fmt_note(moy_gen)
|
I["moy_gen"] = scu.fmt_note(moy_gen)
|
||||||
I["moy_min"] = scu.fmt_note(nt.moy_min)
|
I["moy_min"] = scu.fmt_note(nt.moy_min)
|
||||||
I["moy_max"] = scu.fmt_note(nt.moy_max)
|
I["moy_max"] = scu.fmt_note(nt.moy_max)
|
||||||
@ -265,7 +265,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
|||||||
I["rang_gr"] = rang_gr
|
I["rang_gr"] = rang_gr
|
||||||
I["gr_name"] = gr_name
|
I["gr_name"] = gr_name
|
||||||
I["ninscrits_gr"] = ninscrits_gr
|
I["ninscrits_gr"] = ninscrits_gr
|
||||||
I["nbetuds"] = len(nt.rangs)
|
I["nbetuds"] = len(nt.etud_moy_gen_ranks)
|
||||||
I["nb_demissions"] = nt.nb_demissions
|
I["nb_demissions"] = nt.nb_demissions
|
||||||
I["nb_defaillants"] = nt.nb_defaillants
|
I["nb_defaillants"] = nt.nb_defaillants
|
||||||
if prefs["bul_show_rangs"]:
|
if prefs["bul_show_rangs"]:
|
||||||
|
@ -153,9 +153,9 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
pid = partition["partition_id"]
|
pid = partition["partition_id"]
|
||||||
partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid)
|
partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid)
|
||||||
|
|
||||||
ues = nt.get_ues()
|
ues = nt.get_ues_stat_dict()
|
||||||
modimpls = nt.get_modimpls()
|
modimpls = nt.get_modimpls()
|
||||||
nbetuds = len(nt.rangs)
|
nbetuds = len(nt.etud_moy_gen_ranks)
|
||||||
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||||
if (
|
if (
|
||||||
nt.get_moduleimpls_attente()
|
nt.get_moduleimpls_attente()
|
||||||
|
@ -151,9 +151,9 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid)
|
partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid)
|
||||||
|
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > toutes notes
|
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > toutes notes
|
||||||
ues = nt.get_ues()
|
ues = nt.get_ues_stat_dict()
|
||||||
modimpls = nt.get_modimpls()
|
modimpls = nt.get_modimpls()
|
||||||
nbetuds = len(nt.rangs)
|
nbetuds = len(nt.etud_moy_gen_ranks)
|
||||||
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||||
if (
|
if (
|
||||||
nt.get_moduleimpls_attente()
|
nt.get_moduleimpls_attente()
|
||||||
|
@ -155,14 +155,14 @@ class EvaluationCache(ScoDocCache):
|
|||||||
cls.delete_many(evaluation_ids)
|
cls.delete_many(evaluation_ids)
|
||||||
|
|
||||||
|
|
||||||
class ResultatsSemestreBUTCache(ScoDocCache):
|
class ResultatsSemestreCache(ScoDocCache):
|
||||||
"""Cache pour les résultats ResultatsSemestreBUT.
|
"""Cache pour les résultats ResultatsSemestre.
|
||||||
Clé: formsemestre_id
|
Clé: formsemestre_id
|
||||||
Valeur: { un paquet de dataframes }
|
Valeur: { un paquet de dataframes }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
prefix = "RBUT"
|
prefix = "RSEM"
|
||||||
timeout = 1 * 60 # ttl 1 minutes (en phase de mise au point)
|
timeout = 60 * 60 # ttl 1 heure (en phase de mise au point)
|
||||||
|
|
||||||
|
|
||||||
class AbsSemEtudCache(ScoDocCache):
|
class AbsSemEtudCache(ScoDocCache):
|
||||||
@ -299,7 +299,7 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa
|
|||||||
SemInscriptionsCache.delete_many(formsemestre_ids)
|
SemInscriptionsCache.delete_many(formsemestre_ids)
|
||||||
|
|
||||||
SemBulletinsPDFCache.invalidate_sems(formsemestre_ids)
|
SemBulletinsPDFCache.invalidate_sems(formsemestre_ids)
|
||||||
ResultatsSemestreBUTCache.delete_many(formsemestre_ids)
|
ResultatsSemestreCache.delete_many(formsemestre_ids)
|
||||||
|
|
||||||
|
|
||||||
class DefferedSemCacheManager:
|
class DefferedSemCacheManager:
|
||||||
|
@ -51,6 +51,7 @@ from app.scodoc import sco_formsemestre_edit
|
|||||||
from app.scodoc import sco_formsemestre_inscriptions
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
from app.scodoc import sco_formsemestre_status
|
from app.scodoc import sco_formsemestre_status
|
||||||
from app.scodoc import sco_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
|
from app.scodoc.sco_parcours_dut import etud_est_inscrit_ue
|
||||||
from app.scodoc import sco_photos
|
from app.scodoc import sco_photos
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_pvjury
|
from app.scodoc import sco_pvjury
|
||||||
@ -543,7 +544,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
|
|
||||||
nt = sco_cache.NotesTableCache.get(
|
nt = sco_cache.NotesTableCache.get(
|
||||||
sem["formsemestre_id"]
|
sem["formsemestre_id"]
|
||||||
) # > get_ues, get_etud_moy_gen, get_etud_ue_status
|
) # > get_ues_stat_dict, get_etud_moy_gen, get_etud_ue_status
|
||||||
if is_cur:
|
if is_cur:
|
||||||
type_sem = "*" # now unused
|
type_sem = "*" # now unused
|
||||||
class_sem = "sem_courant"
|
class_sem = "sem_courant"
|
||||||
@ -582,8 +583,17 @@ def formsemestre_recap_parcours_table(
|
|||||||
else:
|
else:
|
||||||
H.append('<td colspan="%d"><em>en cours</em></td>')
|
H.append('<td colspan="%d"><em>en cours</em></td>')
|
||||||
H.append('<td class="rcp_nonass">%s</td>' % ass) # abs
|
H.append('<td class="rcp_nonass">%s</td>' % ass) # abs
|
||||||
# acronymes UEs
|
# acronymes UEs auxquelles l'étudiant est inscrit:
|
||||||
ues = nt.get_ues(filter_sport=True, filter_non_inscrit=True, etudid=etudid)
|
# XXX il est probable que l'on doive ici ajouter les
|
||||||
|
# XXX UE capitalisées
|
||||||
|
ues = nt.get_ues_stat_dict(filter_sport=True)
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
ues = [
|
||||||
|
ue
|
||||||
|
for ue in ues
|
||||||
|
if etud_est_inscrit_ue(cnx, etudid, sem["formsemestre_id"], ue["ue_id"])
|
||||||
|
]
|
||||||
|
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
H.append('<td class="ue_acro"><span>%s</span></td>' % ue["acronyme"])
|
H.append('<td class="ue_acro"><span>%s</span></td>' % ue["acronyme"])
|
||||||
if len(ues) < Se.nb_max_ue:
|
if len(ues) < Se.nb_max_ue:
|
||||||
|
@ -479,11 +479,13 @@ def get_etuds_with_capitalized_ue(formsemestre_id):
|
|||||||
returns { ue_id : [ { infos } ] }
|
returns { ue_id : [ { infos } ] }
|
||||||
"""
|
"""
|
||||||
UECaps = scu.DictDefault(defaultvalue=[])
|
UECaps = scu.DictDefault(defaultvalue=[])
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_ues, get_etud_ue_status
|
nt = sco_cache.NotesTableCache.get(
|
||||||
|
formsemestre_id
|
||||||
|
) # > get_ues_stat_dict, get_etud_ue_status
|
||||||
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
||||||
args={"formsemestre_id": formsemestre_id}
|
args={"formsemestre_id": formsemestre_id}
|
||||||
)
|
)
|
||||||
ues = nt.get_ues()
|
ues = nt.get_ues_stat_dict()
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
for etud in inscrits:
|
for etud in inscrits:
|
||||||
status = nt.get_etud_ue_status(etud["etudid"], ue["ue_id"])
|
status = nt.get_etud_ue_status(etud["etudid"], ue["ue_id"])
|
||||||
|
@ -109,7 +109,7 @@ def SituationEtudParcours(etud, formsemestre_id):
|
|||||||
"""renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)"""
|
"""renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)"""
|
||||||
nt = sco_cache.NotesTableCache.get(
|
nt = sco_cache.NotesTableCache.get(
|
||||||
formsemestre_id
|
formsemestre_id
|
||||||
) # > get_etud_decision_sem, get_etud_moy_gen, get_ues, get_etud_ue_status, etud_check_conditions_ues
|
) # > get_etud_decision_sem, get_etud_moy_gen, get_ues_stat_dict, get_etud_ue_status, etud_check_conditions_ues
|
||||||
parcours = nt.parcours
|
parcours = nt.parcours
|
||||||
#
|
#
|
||||||
if parcours.ECTS_ONLY:
|
if parcours.ECTS_ONLY:
|
||||||
@ -330,8 +330,10 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
ue_acros = {} # acronyme ue : 1
|
ue_acros = {} # acronyme ue : 1
|
||||||
nb_max_ue = 0
|
nb_max_ue = 0
|
||||||
for sem in sems:
|
for sem in sems:
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"]) # > get_ues
|
nt = sco_cache.NotesTableCache.get(
|
||||||
ues = nt.get_ues(filter_sport=True)
|
sem["formsemestre_id"]
|
||||||
|
) # > get_ues_stat_dict
|
||||||
|
ues = nt.get_ues_stat_dict(filter_sport=True)
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
ue_acros[ue["acronyme"]] = 1
|
ue_acros[ue["acronyme"]] = 1
|
||||||
nb_ue = len(ues)
|
nb_ue = len(ues)
|
||||||
@ -419,9 +421,7 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
self.moy_gen >= (self.parcours.BARRE_MOY - scu.NOTES_TOLERANCE)
|
self.moy_gen >= (self.parcours.BARRE_MOY - scu.NOTES_TOLERANCE)
|
||||||
)
|
)
|
||||||
# conserve etat UEs
|
# conserve etat UEs
|
||||||
ue_ids = [
|
ue_ids = [x["ue_id"] for x in self.nt.get_ues_stat_dict(filter_sport=True)]
|
||||||
x["ue_id"] for x in self.nt.get_ues(etudid=self.etudid, filter_sport=True)
|
|
||||||
]
|
|
||||||
self.ues_status = {} # ue_id : status
|
self.ues_status = {} # ue_id : status
|
||||||
for ue_id in ue_ids:
|
for ue_id in ue_ids:
|
||||||
self.ues_status[ue_id] = self.nt.get_etud_ue_status(self.etudid, ue_id)
|
self.ues_status[ue_id] = self.nt.get_etud_ue_status(self.etudid, ue_id)
|
||||||
@ -903,8 +903,10 @@ def formsemestre_validate_ues(formsemestre_id, etudid, code_etat_sem, assiduite)
|
|||||||
"""
|
"""
|
||||||
valid_semestre = CODES_SEM_VALIDES.get(code_etat_sem, False)
|
valid_semestre = CODES_SEM_VALIDES.get(code_etat_sem, False)
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_ues, get_etud_ue_status
|
nt = sco_cache.NotesTableCache.get(
|
||||||
ue_ids = [x["ue_id"] for x in nt.get_ues(etudid=etudid, filter_sport=True)]
|
formsemestre_id
|
||||||
|
) # > get_ues_stat_dict, get_etud_ue_status
|
||||||
|
ue_ids = [x["ue_id"] for x in nt.get_ues_stat_dict(filter_sport=True)]
|
||||||
for ue_id in ue_ids:
|
for ue_id in ue_ids:
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
if not assiduite:
|
if not assiduite:
|
||||||
@ -1000,7 +1002,7 @@ def formsemestre_has_decisions(formsemestre_id):
|
|||||||
|
|
||||||
|
|
||||||
def etud_est_inscrit_ue(cnx, etudid, formsemestre_id, ue_id):
|
def etud_est_inscrit_ue(cnx, etudid, formsemestre_id, ue_id):
|
||||||
"""Vrai si l'étudiant est inscrit a au moins un module de cette UE dans ce semestre"""
|
"""Vrai si l'étudiant est inscrit à au moins un module de cette UE dans ce semestre"""
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"""SELECT mi.*
|
"""SELECT mi.*
|
||||||
|
@ -61,7 +61,7 @@ def etud_get_poursuite_info(sem, etud):
|
|||||||
nt = sco_cache.NotesTableCache.get(s["formsemestre_id"])
|
nt = sco_cache.NotesTableCache.get(s["formsemestre_id"])
|
||||||
dec = nt.get_etud_decision_sem(etudid)
|
dec = nt.get_etud_decision_sem(etudid)
|
||||||
# Moyennes et rangs des UE
|
# Moyennes et rangs des UE
|
||||||
ues = nt.get_ues(filter_sport=True)
|
ues = nt.get_ues_stat_dict(filter_sport=True)
|
||||||
moy_ues = [
|
moy_ues = [
|
||||||
(
|
(
|
||||||
ue["acronyme"],
|
ue["acronyme"],
|
||||||
|
@ -2266,3 +2266,31 @@ def doc_preferences():
|
|||||||
)
|
)
|
||||||
|
|
||||||
return "\n".join([" | ".join(x) for x in L])
|
return "\n".join([" | ".join(x) for x in L])
|
||||||
|
|
||||||
|
|
||||||
|
def bulletin_option_affichage(formsemestre_id: int) -> dict:
|
||||||
|
"dict avec les options d'affichages (préférences) pour ce semestre"
|
||||||
|
prefs = SemPreferences(formsemestre_id)
|
||||||
|
fields = (
|
||||||
|
"bul_show_abs",
|
||||||
|
"bul_show_abs_modules",
|
||||||
|
"bul_show_ects",
|
||||||
|
"bul_show_codemodules",
|
||||||
|
"bul_show_matieres",
|
||||||
|
"bul_show_rangs",
|
||||||
|
"bul_show_ue_rangs",
|
||||||
|
"bul_show_mod_rangs",
|
||||||
|
"bul_show_moypromo",
|
||||||
|
"bul_show_minmax",
|
||||||
|
"bul_show_minmax_mod",
|
||||||
|
"bul_show_minmax_eval",
|
||||||
|
"bul_show_coef",
|
||||||
|
"bul_show_ue_cap_details",
|
||||||
|
"bul_show_ue_cap_current",
|
||||||
|
"bul_show_temporary",
|
||||||
|
"bul_temporary_txt",
|
||||||
|
"bul_show_uevalid",
|
||||||
|
"bul_show_date_inscr",
|
||||||
|
)
|
||||||
|
# on enlève le "bul_" de la clé:
|
||||||
|
return {field[4:]: prefs[field] for field in fields}
|
||||||
|
@ -52,7 +52,7 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
"Feuille excel pour preparation des jurys"
|
"Feuille excel pour preparation des jurys"
|
||||||
nt = sco_cache.NotesTableCache.get(
|
nt = sco_cache.NotesTableCache.get(
|
||||||
formsemestre_id
|
formsemestre_id
|
||||||
) # > get_etudids, get_etud_moy_gen, get_ues, get_etud_ue_status, get_etud_decision_sem, identdict,
|
) # > get_etudids, get_etud_moy_gen, get_ues_stat_dict, get_etud_ue_status, get_etud_decision_sem, identdict,
|
||||||
etudids = nt.get_etudids(sorted=True) # tri par moy gen
|
etudids = nt.get_etudids(sorted=True) # tri par moy gen
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
@ -85,8 +85,8 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
if Se.prev:
|
if Se.prev:
|
||||||
ntp = sco_cache.NotesTableCache.get(
|
ntp = sco_cache.NotesTableCache.get(
|
||||||
Se.prev["formsemestre_id"]
|
Se.prev["formsemestre_id"]
|
||||||
) # > get_ues, get_etud_ue_status, get_etud_moy_gen, get_etud_decision_sem
|
) # > get_ues_stat_dict, get_etud_ue_status, get_etud_moy_gen, get_etud_decision_sem
|
||||||
for ue in ntp.get_ues(filter_sport=True):
|
for ue in ntp.get_ues_stat_dict(filter_sport=True):
|
||||||
ue_status = ntp.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = ntp.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
ue_code_s = (
|
ue_code_s = (
|
||||||
ue["ue_code"] + "_%s" % ntp.sem["semestre_id"]
|
ue["ue_code"] + "_%s" % ntp.sem["semestre_id"]
|
||||||
@ -102,7 +102,7 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
prev_code[etudid] += "+" # indique qu'il a servi a compenser
|
prev_code[etudid] += "+" # indique qu'il a servi a compenser
|
||||||
|
|
||||||
moy[etudid] = nt.get_etud_moy_gen(etudid)
|
moy[etudid] = nt.get_etud_moy_gen(etudid)
|
||||||
for ue in nt.get_ues(filter_sport=True):
|
for ue in nt.get_ues_stat_dict(filter_sport=True):
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
ue_code_s = ue["ue_code"] + "_%s" % nt.sem["semestre_id"]
|
ue_code_s = ue["ue_code"] + "_%s" % nt.sem["semestre_id"]
|
||||||
moy_ue[ue_code_s][etudid] = ue_status["moy"]
|
moy_ue[ue_code_s][etudid] = ue_status["moy"]
|
||||||
@ -310,9 +310,9 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
ws.append_blank_row()
|
ws.append_blank_row()
|
||||||
ws.append_single_cell_row("Titre des UE")
|
ws.append_single_cell_row("Titre des UE")
|
||||||
if prev_moy:
|
if prev_moy:
|
||||||
for ue in ntp.get_ues(filter_sport=True):
|
for ue in ntp.get_ues_stat_dict(filter_sport=True):
|
||||||
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
||||||
for ue in nt.get_ues(filter_sport=True):
|
for ue in nt.get_ues_stat_dict(filter_sport=True):
|
||||||
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
ws.append_row(ws.make_row(["", "", "", ue["acronyme"], ue["titre"]]))
|
||||||
#
|
#
|
||||||
ws.append_blank_row()
|
ws.append_blank_row()
|
||||||
|
@ -161,7 +161,7 @@ def _comp_ects_by_ue_code_and_type(nt, decision_ues):
|
|||||||
|
|
||||||
def _comp_ects_capitalises_by_ue_code(nt, etudid):
|
def _comp_ects_capitalises_by_ue_code(nt, etudid):
|
||||||
"""Calcul somme des ECTS des UE capitalisees"""
|
"""Calcul somme des ECTS des UE capitalisees"""
|
||||||
ues = nt.get_ues()
|
ues = nt.get_ues_stat_dict()
|
||||||
ects_by_ue_code = {}
|
ects_by_ue_code = {}
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
|
@ -304,9 +304,9 @@ def make_formsemestre_recapcomplet(
|
|||||||
)[0]
|
)[0]
|
||||||
nt = sco_cache.NotesTableCache.get(
|
nt = sco_cache.NotesTableCache.get(
|
||||||
formsemestre_id
|
formsemestre_id
|
||||||
) # > get_modimpls, get_ues, get_table_moyennes_triees, get_etud_decision_sem, get_etud_etat, get_etud_rang, get_nom_short, get_mod_stats, nt.moy_moy, get_etud_decision_sem,
|
) # > get_modimpls, get_ues_stat_dict, get_table_moyennes_triees, get_etud_decision_sem, get_etud_etat, get_etud_rang, get_nom_short, get_mod_stats, nt.moy_moy, get_etud_decision_sem,
|
||||||
modimpls = nt.get_modimpls()
|
modimpls = nt.get_modimpls()
|
||||||
ues = nt.get_ues() # incluant le(s) UE de sport
|
ues = nt.get_ues_stat_dict() # incluant le(s) UE de sport
|
||||||
#
|
#
|
||||||
if formsemestre.formation.is_apc():
|
if formsemestre.formation.is_apc():
|
||||||
nt.apc_recompute_moyennes()
|
nt.apc_recompute_moyennes()
|
||||||
@ -964,7 +964,7 @@ def _formsemestre_recapcomplet_json(
|
|||||||
etudid = t[-1]
|
etudid = t[-1]
|
||||||
if is_apc:
|
if is_apc:
|
||||||
etud = Identite.query.get(etudid)
|
etud = Identite.query.get(etudid)
|
||||||
r = bulletin_but.ResultatsSemestreBUT(formsemestre)
|
r = bulletin_but.BulletinBUT(formsemestre)
|
||||||
bul = r.bulletin_etud(etud, formsemestre)
|
bul = r.bulletin_etud(etud, formsemestre)
|
||||||
else:
|
else:
|
||||||
bul = sco_bulletins_json.formsemestre_bulletinetud_published_dict(
|
bul = sco_bulletins_json.formsemestre_bulletinetud_published_dict(
|
||||||
|
@ -429,19 +429,10 @@ def SignaleAbsenceGrHebdo(
|
|||||||
]
|
]
|
||||||
#
|
#
|
||||||
modimpls_list = []
|
modimpls_list = []
|
||||||
# Initialize with first student
|
ues = nt.get_ues_stat_dict()
|
||||||
ues = nt.get_ues(etudid=etuds[0]["etudid"])
|
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
modimpls_list += nt.get_modimpls(ue_id=ue["ue_id"])
|
modimpls_list += nt.get_modimpls(ue_id=ue["ue_id"])
|
||||||
|
|
||||||
# Add modules other students are subscribed to
|
|
||||||
for etud in etuds[1:]:
|
|
||||||
modimpls_etud = []
|
|
||||||
ues = nt.get_ues(etudid=etud["etudid"])
|
|
||||||
for ue in ues:
|
|
||||||
modimpls_etud += nt.get_modimpls(ue_id=ue["ue_id"])
|
|
||||||
modimpls_list += [m for m in modimpls_etud if m not in modimpls_list]
|
|
||||||
|
|
||||||
menu_module = ""
|
menu_module = ""
|
||||||
for modimpl in modimpls_list:
|
for modimpl in modimpls_list:
|
||||||
if modimpl["moduleimpl_id"] == moduleimpl_id:
|
if modimpl["moduleimpl_id"] == moduleimpl_id:
|
||||||
@ -606,19 +597,10 @@ def SignaleAbsenceGrSemestre(
|
|||||||
#
|
#
|
||||||
if etuds:
|
if etuds:
|
||||||
modimpls_list = []
|
modimpls_list = []
|
||||||
# Initialize with first student
|
ues = nt.get_ues_stat_dict()
|
||||||
ues = nt.get_ues(etudid=etuds[0]["etudid"])
|
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
modimpls_list += nt.get_modimpls(ue_id=ue["ue_id"])
|
modimpls_list += nt.get_modimpls(ue_id=ue["ue_id"])
|
||||||
|
|
||||||
# Add modules other students are subscribed to
|
|
||||||
for etud in etuds[1:]:
|
|
||||||
modimpls_etud = []
|
|
||||||
ues = nt.get_ues(etudid=etud["etudid"])
|
|
||||||
for ue in ues:
|
|
||||||
modimpls_etud += nt.get_modimpls(ue_id=ue["ue_id"])
|
|
||||||
modimpls_list += [m for m in modimpls_etud if m not in modimpls_list]
|
|
||||||
|
|
||||||
menu_module = ""
|
menu_module = ""
|
||||||
for modimpl in modimpls_list:
|
for modimpl in modimpls_list:
|
||||||
if modimpl["moduleimpl_id"] == moduleimpl_id:
|
if modimpl["moduleimpl_id"] == moduleimpl_id:
|
||||||
@ -750,8 +732,8 @@ def _gen_form_saisie_groupe(
|
|||||||
if etud["cursem"]:
|
if etud["cursem"]:
|
||||||
nt = sco_cache.NotesTableCache.get(
|
nt = sco_cache.NotesTableCache.get(
|
||||||
etud["cursem"]["formsemestre_id"]
|
etud["cursem"]["formsemestre_id"]
|
||||||
) # > get_ues, get_etud_ue_status
|
) # > get_ues_stat_dict, get_etud_ue_status
|
||||||
for ue in nt.get_ues():
|
for ue in nt.get_ues_stat_dict():
|
||||||
status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
if status["is_capitalized"]:
|
if status["is_capitalized"]:
|
||||||
cap.append(ue["acronyme"])
|
cap.append(ue["acronyme"])
|
||||||
|
@ -296,7 +296,7 @@ def formsemestre_bulletinetud(
|
|||||||
code_nip=str(code_nip)
|
code_nip=str(code_nip)
|
||||||
).first_or_404()
|
).first_or_404()
|
||||||
if format == "json":
|
if format == "json":
|
||||||
r = bulletin_but.ResultatsSemestreBUT(formsemestre)
|
r = bulletin_but.BulletinBUT(formsemestre)
|
||||||
return jsonify(r.bulletin_etud(etud, formsemestre))
|
return jsonify(r.bulletin_etud(etud, formsemestre))
|
||||||
elif format == "html":
|
elif format == "html":
|
||||||
return render_template(
|
return render_template(
|
||||||
|
Loading…
Reference in New Issue
Block a user