forked from ScoDoc/ScoDoc
Merge branch 'dev92' of https://scodoc.org/git/ScoDoc/ScoDoc into entreprises
This commit is contained in:
commit
15f313fedd
@ -20,10 +20,10 @@ Flask, SQLAlchemy, au lien de Python2/Zope dans les versions précédentes).
|
|||||||
|
|
||||||
### État actuel (26 jan 22)
|
### État actuel (26 jan 22)
|
||||||
|
|
||||||
- 9.1 (master) reproduit l'ensemble des fonctions de ScoDoc 7 (donc pas de BUT), sauf:
|
- 9.1.5x (master) reproduit l'ensemble des fonctions de ScoDoc 7 (donc pas de BUT), sauf:
|
||||||
- ancien module "Entreprises" (obsolète) et ajoute la gestion du BUT.
|
- ancien module "Entreprises" (obsolète) et ajoute la gestion du BUT.
|
||||||
|
|
||||||
- 9.2 (branche refactor_nt) est la version de développement.
|
- 9.2 (branche dev92) est la version de développement.
|
||||||
|
|
||||||
|
|
||||||
### Lignes de commandes
|
### Lignes de commandes
|
||||||
|
@ -76,7 +76,9 @@ class User(UserMixin, db.Model):
|
|||||||
"Departement",
|
"Departement",
|
||||||
foreign_keys=[Departement.acronym],
|
foreign_keys=[Departement.acronym],
|
||||||
primaryjoin=(dept == Departement.acronym),
|
primaryjoin=(dept == Departement.acronym),
|
||||||
lazy="dynamic",
|
lazy="select",
|
||||||
|
passive_deletes="all",
|
||||||
|
uselist=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
@ -236,7 +238,7 @@ class User(UserMixin, db.Model):
|
|||||||
def get_dept_id(self) -> int:
|
def get_dept_id(self) -> int:
|
||||||
"returns user's department id, or None"
|
"returns user's department id, or None"
|
||||||
if self.dept:
|
if self.dept:
|
||||||
return self._departement.first().id
|
return self._departement.id
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Permissions management:
|
# Permissions management:
|
||||||
|
@ -9,14 +9,15 @@
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from flask import url_for, g
|
from flask import url_for, g
|
||||||
from app.models.formsemestre import FormSemestre
|
|
||||||
|
|
||||||
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
|
from app.models import FormSemestre, Identite
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc import sco_bulletins_json
|
from app.scodoc import sco_bulletins_json
|
||||||
|
from app.scodoc import sco_bulletins_pdf
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc.sco_codes_parcours import UE_SPORT
|
from app.scodoc.sco_codes_parcours import UE_SPORT
|
||||||
from app.scodoc.sco_utils import fmt_note
|
from app.scodoc.sco_utils import fmt_note
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
|
||||||
|
|
||||||
|
|
||||||
class BulletinBUT:
|
class BulletinBUT:
|
||||||
@ -28,6 +29,7 @@ class BulletinBUT:
|
|||||||
def __init__(self, formsemestre: FormSemestre):
|
def __init__(self, formsemestre: FormSemestre):
|
||||||
""" """
|
""" """
|
||||||
self.res = ResultatsSemestreBUT(formsemestre)
|
self.res = ResultatsSemestreBUT(formsemestre)
|
||||||
|
self.prefs = sco_preferences.SemPreferences(formsemestre.id)
|
||||||
|
|
||||||
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"
|
||||||
@ -84,7 +86,7 @@ class BulletinBUT:
|
|||||||
"saes": self.etud_ue_mod_results(etud, ue, res.saes),
|
"saes": self.etud_ue_mod_results(etud, ue, res.saes),
|
||||||
}
|
}
|
||||||
if ue.type != UE_SPORT:
|
if ue.type != UE_SPORT:
|
||||||
if sco_preferences.get_preference("bul_show_ue_rangs", res.formsemestre.id):
|
if self.prefs["bul_show_ue_rangs"]:
|
||||||
rangs, effectif = res.ue_rangs[ue.id]
|
rangs, effectif = res.ue_rangs[ue.id]
|
||||||
rang = rangs[etud.id]
|
rang = rangs[etud.id]
|
||||||
else:
|
else:
|
||||||
@ -155,9 +157,7 @@ class BulletinBUT:
|
|||||||
if e.visibulletin
|
if e.visibulletin
|
||||||
and (
|
and (
|
||||||
modimpl_results.evaluations_etat[e.id].is_complete
|
modimpl_results.evaluations_etat[e.id].is_complete
|
||||||
or sco_preferences.get_preference(
|
or self.prefs["bul_show_all_evals"]
|
||||||
"bul_show_all_evals", res.formsemestre.id
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@ -216,9 +216,11 @@ class BulletinBUT:
|
|||||||
else:
|
else:
|
||||||
return f"Bonus de {fmt_note(bonus_vect.iloc[0])}"
|
return f"Bonus de {fmt_note(bonus_vect.iloc[0])}"
|
||||||
|
|
||||||
def bulletin_etud(self, etud, formsemestre, force_publishing=False) -> dict:
|
def bulletin_etud(
|
||||||
"""Le bulletin de l'étudiant dans ce semestre.
|
self, etud: Identite, formsemestre, force_publishing=False
|
||||||
Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai
|
) -> dict:
|
||||||
|
"""Le bulletin de l'étudiant dans ce semestre: dict pour la version JSON / HTML.
|
||||||
|
- Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai
|
||||||
(bulletins non publiés).
|
(bulletins non publiés).
|
||||||
"""
|
"""
|
||||||
res = self.res
|
res = self.res
|
||||||
@ -239,7 +241,9 @@ class BulletinBUT:
|
|||||||
},
|
},
|
||||||
"formsemestre_id": formsemestre.id,
|
"formsemestre_id": formsemestre.id,
|
||||||
"etat_inscription": etat_inscription,
|
"etat_inscription": etat_inscription,
|
||||||
"options": sco_preferences.bulletin_option_affichage(formsemestre.id),
|
"options": sco_preferences.bulletin_option_affichage(
|
||||||
|
formsemestre.id, self.prefs
|
||||||
|
),
|
||||||
}
|
}
|
||||||
if not published:
|
if not published:
|
||||||
return d
|
return d
|
||||||
@ -254,7 +258,7 @@ class BulletinBUT:
|
|||||||
"inscription": "", # inutilisé mais nécessaire pour le js de Seb.
|
"inscription": "", # inutilisé mais nécessaire pour le js de Seb.
|
||||||
"groupes": [], # XXX TODO
|
"groupes": [], # XXX TODO
|
||||||
"absences": {
|
"absences": {
|
||||||
"injustifie": nbabsjust,
|
"injustifie": nbabs - nbabsjust,
|
||||||
"total": nbabs,
|
"total": nbabs,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -312,3 +316,12 @@ class BulletinBUT:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def bulletin_etud_complet(self, etud) -> dict:
|
||||||
|
"""Bulletin dict complet avec toutes les infos pour les bulletins pdf"""
|
||||||
|
d = self.bulletin_etud(force_publishing=True)
|
||||||
|
d["filigranne"] = sco_bulletins_pdf.get_filigranne(
|
||||||
|
self.res.get_etud_etat(etud.id), self.prefs
|
||||||
|
)
|
||||||
|
# XXX TODO A COMPLETER
|
||||||
|
raise NotImplementedError()
|
||||||
|
@ -145,7 +145,7 @@ def bulletin_but_xml_compat(
|
|||||||
doc.append(Element("note_max", value="20")) # notes toujours sur 20
|
doc.append(Element("note_max", value="20")) # notes toujours sur 20
|
||||||
doc.append(Element("bonus_sport_culture", value=str(bonus)))
|
doc.append(Element("bonus_sport_culture", value=str(bonus)))
|
||||||
# Liste les UE / modules /evals
|
# Liste les UE / modules /evals
|
||||||
for ue in results.ues:
|
for ue in results.ues: # avec bonus
|
||||||
rang_ue = 0 # XXX TODO rang de l'étudiant dans cette UE
|
rang_ue = 0 # XXX TODO rang de l'étudiant dans cette UE
|
||||||
nb_inscrits_ue = (
|
nb_inscrits_ue = (
|
||||||
nb_inscrits # approx: compliqué de définir le "nb d'inscrit à une UE"
|
nb_inscrits # approx: compliqué de définir le "nb d'inscrit à une UE"
|
||||||
@ -161,25 +161,31 @@ def bulletin_but_xml_compat(
|
|||||||
doc.append(x_ue)
|
doc.append(x_ue)
|
||||||
if ue.type != sco_codes_parcours.UE_SPORT:
|
if ue.type != sco_codes_parcours.UE_SPORT:
|
||||||
v = results.etud_moy_ue[ue.id][etud.id]
|
v = results.etud_moy_ue[ue.id][etud.id]
|
||||||
|
vmin = results.etud_moy_ue[ue.id].min()
|
||||||
|
vmax = results.etud_moy_ue[ue.id].max()
|
||||||
else:
|
else:
|
||||||
v = 0 # XXX TODO valeur bonus sport pour cet étudiant
|
v = results.bonus or 0.0
|
||||||
|
vmin = vmax = 0.0
|
||||||
x_ue.append(
|
x_ue.append(
|
||||||
Element(
|
Element(
|
||||||
"note",
|
"note",
|
||||||
value=scu.fmt_note(v),
|
value=scu.fmt_note(v),
|
||||||
min=scu.fmt_note(results.etud_moy_ue[ue.id].min()),
|
min=scu.fmt_note(vmin),
|
||||||
max=scu.fmt_note(results.etud_moy_ue[ue.id].max()),
|
max=scu.fmt_note(vmax),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0)))
|
x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0)))
|
||||||
x_ue.append(Element("rang", value=str(rang_ue)))
|
x_ue.append(Element("rang", value=str(rang_ue)))
|
||||||
x_ue.append(Element("effectif", value=str(nb_inscrits_ue)))
|
x_ue.append(Element("effectif", value=str(nb_inscrits_ue)))
|
||||||
# Liste les modules rattachés à cette UE
|
# Liste les modules rattachés à cette UE
|
||||||
for modimpl in results.modimpls:
|
for modimpl in results.formsemestre.modimpls:
|
||||||
# Liste ici uniquement les modules rattachés à cette UE
|
# Liste ici uniquement les modules rattachés à cette UE
|
||||||
if modimpl.module.ue.id == ue.id:
|
if modimpl.module.ue.id == ue.id:
|
||||||
# mod_moy = scu.fmt_note(results.etud_moy_ue[ue.id][etud.id])
|
# mod_moy = scu.fmt_note(results.etud_moy_ue[ue.id][etud.id])
|
||||||
|
try:
|
||||||
coef = results.modimpl_coefs_df[modimpl.id][ue.id]
|
coef = results.modimpl_coefs_df[modimpl.id][ue.id]
|
||||||
|
except KeyError:
|
||||||
|
coef = 0.0
|
||||||
x_mod = Element(
|
x_mod = Element(
|
||||||
"module",
|
"module",
|
||||||
id=str(modimpl.id),
|
id=str(modimpl.id),
|
||||||
@ -214,6 +220,7 @@ def bulletin_but_xml_compat(
|
|||||||
note_max_origin=str(e.note_max),
|
note_max_origin=str(e.note_max),
|
||||||
)
|
)
|
||||||
x_mod.append(x_eval)
|
x_mod.append(x_eval)
|
||||||
|
try:
|
||||||
x_eval.append(
|
x_eval.append(
|
||||||
Element(
|
Element(
|
||||||
"note",
|
"note",
|
||||||
@ -225,6 +232,11 @@ def bulletin_but_xml_compat(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
except KeyError:
|
||||||
|
x_eval.append(
|
||||||
|
Element("note", value="", note_max="")
|
||||||
|
)
|
||||||
|
|
||||||
# XXX TODO: Evaluations incomplètes ou futures: XXX
|
# XXX TODO: Evaluations incomplètes ou futures: XXX
|
||||||
# XXX TODO UE capitalisee (listee seulement si meilleure que l'UE courante)
|
# XXX TODO UE capitalisee (listee seulement si meilleure que l'UE courante)
|
||||||
|
|
||||||
|
@ -19,10 +19,12 @@ class FormationRefCompForm(FlaskForm):
|
|||||||
|
|
||||||
|
|
||||||
class RefCompLoadForm(FlaskForm):
|
class RefCompLoadForm(FlaskForm):
|
||||||
|
referentiel_standard = SelectField(
|
||||||
|
"Choisir un référentiel de compétences officiel BUT"
|
||||||
|
)
|
||||||
upload = FileField(
|
upload = FileField(
|
||||||
label="Sélectionner un fichier XML Orébut",
|
label="Ou bien sélectionner un fichier XML au format Orébut",
|
||||||
validators=[
|
validators=[
|
||||||
FileRequired(),
|
|
||||||
FileAllowed(
|
FileAllowed(
|
||||||
[
|
[
|
||||||
"xml",
|
"xml",
|
||||||
@ -33,3 +35,13 @@ class RefCompLoadForm(FlaskForm):
|
|||||||
)
|
)
|
||||||
submit = SubmitField("Valider")
|
submit = SubmitField("Valider")
|
||||||
cancel = SubmitField("Annuler")
|
cancel = SubmitField("Annuler")
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
if not super().validate():
|
||||||
|
return False
|
||||||
|
if (self.referentiel_standard.data == "0") == (not self.upload.data):
|
||||||
|
self.referentiel_standard.errors.append(
|
||||||
|
"Choisir soit un référentiel, soit un fichier xml"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
from typing import TextIO
|
from typing import TextIO
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
|
|
||||||
from app.models.but_refcomp import (
|
from app.models.but_refcomp import (
|
||||||
@ -19,7 +21,7 @@ from app.models.but_refcomp import (
|
|||||||
ApcAnneeParcours,
|
ApcAnneeParcours,
|
||||||
ApcParcoursNiveauCompetence,
|
ApcParcoursNiveauCompetence,
|
||||||
)
|
)
|
||||||
from app.scodoc.sco_exceptions import ScoFormatError
|
from app.scodoc.sco_exceptions import ScoFormatError, ScoValueError
|
||||||
|
|
||||||
|
|
||||||
def orebut_import_refcomp(xml_data: str, dept_id: int, orig_filename=None):
|
def orebut_import_refcomp(xml_data: str, dept_id: int, orig_filename=None):
|
||||||
@ -27,6 +29,16 @@ def orebut_import_refcomp(xml_data: str, dept_id: int, orig_filename=None):
|
|||||||
peut lever TypeError ou ScoFormatError
|
peut lever TypeError ou ScoFormatError
|
||||||
Résultat: instance de ApcReferentielCompetences
|
Résultat: instance de ApcReferentielCompetences
|
||||||
"""
|
"""
|
||||||
|
# Vérifie que le même fichier n'a pas déjà été chargé:
|
||||||
|
if ApcReferentielCompetences.query.filter_by(
|
||||||
|
scodoc_orig_filename=orig_filename, dept_id=dept_id
|
||||||
|
).count():
|
||||||
|
raise ScoValueError(
|
||||||
|
f"""Un référentiel a déjà été chargé d'un fichier de même nom.
|
||||||
|
({orig_filename})
|
||||||
|
Supprimez-le ou changer le nom du fichier."""
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
root = ElementTree.XML(xml_data)
|
root = ElementTree.XML(xml_data)
|
||||||
except ElementTree.ParseError as exc:
|
except ElementTree.ParseError as exc:
|
||||||
@ -42,7 +54,16 @@ def orebut_import_refcomp(xml_data: str, dept_id: int, orig_filename=None):
|
|||||||
if not competences:
|
if not competences:
|
||||||
raise ScoFormatError("élément 'competences' manquant")
|
raise ScoFormatError("élément 'competences' manquant")
|
||||||
for competence in competences.findall("competence"):
|
for competence in competences.findall("competence"):
|
||||||
|
try:
|
||||||
c = ApcCompetence(**ApcCompetence.attr_from_xml(competence.attrib))
|
c = ApcCompetence(**ApcCompetence.attr_from_xml(competence.attrib))
|
||||||
|
db.session.flush()
|
||||||
|
except sqlalchemy.exc.IntegrityError:
|
||||||
|
# ne devrait plus se produire car pas d'unicité de l'id: donc inutile
|
||||||
|
db.session.rollback()
|
||||||
|
raise ScoValueError(
|
||||||
|
f"""Un référentiel a déjà été chargé avec les mêmes compétences ! ({competence.attrib["id"]})
|
||||||
|
"""
|
||||||
|
)
|
||||||
ref.competences.append(c)
|
ref.competences.append(c)
|
||||||
# --- SITUATIONS
|
# --- SITUATIONS
|
||||||
situations = competence.find("situations")
|
situations = competence.find("situations")
|
||||||
|
@ -21,7 +21,8 @@ class StatsMoyenne:
|
|||||||
Les valeurs NAN ou non numériques sont toujours enlevées.
|
Les valeurs NAN ou non numériques sont toujours enlevées.
|
||||||
Si vals is None, renvoie des zéros (utilisé pour UE bonus)
|
Si vals is None, renvoie des zéros (utilisé pour UE bonus)
|
||||||
"""
|
"""
|
||||||
if vals is None or len(vals) == 0:
|
try:
|
||||||
|
if vals is None or len(vals) == 0 or np.isnan(vals).all():
|
||||||
self.moy = self.min = self.max = self.size = self.nb_vals = 0
|
self.moy = self.min = self.max = self.size = self.nb_vals = 0
|
||||||
else:
|
else:
|
||||||
self.moy = np.nanmean(vals)
|
self.moy = np.nanmean(vals)
|
||||||
@ -29,6 +30,8 @@ class StatsMoyenne:
|
|||||||
self.max = np.nanmax(vals)
|
self.max = np.nanmax(vals)
|
||||||
self.size = len(vals)
|
self.size = len(vals)
|
||||||
self.nb_vals = self.size - np.count_nonzero(np.isnan(vals))
|
self.nb_vals = self.size - np.count_nonzero(np.isnan(vals))
|
||||||
|
except TypeError: # que des NaN dans un array d'objets, ou ce genre de choses exotiques...
|
||||||
|
self.moy = self.min = self.max = self.size = self.nb_vals = 0
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
"Tous les attributs dans un dict"
|
"Tous les attributs dans un dict"
|
||||||
|
@ -87,6 +87,8 @@ class BonusSport:
|
|||||||
for m in formsemestre.modimpls_sorted
|
for m in formsemestre.modimpls_sorted
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
if not len(modimpl_mask):
|
||||||
|
modimpl_mask = np.s_[:] # il n'y a rien, on prend tout donc rien
|
||||||
self.modimpls_spo = [
|
self.modimpls_spo = [
|
||||||
modimpl
|
modimpl
|
||||||
for i, modimpl in enumerate(formsemestre.modimpls_sorted)
|
for i, modimpl in enumerate(formsemestre.modimpls_sorted)
|
||||||
@ -134,6 +136,9 @@ class BonusSport:
|
|||||||
modimpl_inscr_spo, sem_modimpl_moys_no_nan, 0.0
|
modimpl_inscr_spo, sem_modimpl_moys_no_nan, 0.0
|
||||||
)
|
)
|
||||||
modimpl_coefs_spo = modimpl_coefs_spo.T
|
modimpl_coefs_spo = modimpl_coefs_spo.T
|
||||||
|
if nb_etuds == 0:
|
||||||
|
modimpl_coefs_etuds = modimpl_inscr_spo # vide
|
||||||
|
else:
|
||||||
modimpl_coefs_etuds = np.where(
|
modimpl_coefs_etuds = np.where(
|
||||||
modimpl_inscr_spo, np.stack([modimpl_coefs_spo] * nb_etuds), 0.0
|
modimpl_inscr_spo, np.stack([modimpl_coefs_spo] * nb_etuds), 0.0
|
||||||
)
|
)
|
||||||
@ -198,6 +203,9 @@ class BonusSportAdditif(BonusSport):
|
|||||||
En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
||||||
modimpl_coefs_etuds_no_nan:
|
modimpl_coefs_etuds_no_nan:
|
||||||
"""
|
"""
|
||||||
|
if 0 in sem_modimpl_moys_inscrits.shape:
|
||||||
|
# pas d'étudiants ou pas d'UE ou pas de module...
|
||||||
|
return
|
||||||
bonus_moy_arr = np.sum(
|
bonus_moy_arr = np.sum(
|
||||||
np.where(
|
np.where(
|
||||||
sem_modimpl_moys_inscrits > self.seuil_moy_gen,
|
sem_modimpl_moys_inscrits > self.seuil_moy_gen,
|
||||||
@ -249,6 +257,9 @@ class BonusSportMultiplicatif(BonusSport):
|
|||||||
# bonus = m_0 (a - 1)
|
# bonus = m_0 (a - 1)
|
||||||
def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan):
|
def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan):
|
||||||
"""calcul du bonus"""
|
"""calcul du bonus"""
|
||||||
|
if 0 in sem_modimpl_moys_inscrits.shape:
|
||||||
|
# pas d'étudiants ou pas d'UE ou pas de module...
|
||||||
|
return
|
||||||
# Calcule moyenne pondérée des notes de sport:
|
# Calcule moyenne pondérée des notes de sport:
|
||||||
notes = np.sum(
|
notes = np.sum(
|
||||||
sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1
|
sem_modimpl_moys_inscrits * modimpl_coefs_etuds_no_nan, axis=1
|
||||||
|
@ -48,14 +48,15 @@ def compute_sem_moys_apc(
|
|||||||
return moy_gen
|
return moy_gen
|
||||||
|
|
||||||
|
|
||||||
def comp_ranks_series(notes: pd.Series) -> dict[int, str]:
|
def comp_ranks_series(notes: pd.Series) -> (pd.Series, pd.Series):
|
||||||
"""Calcul rangs à partir d'une séries ("vecteur") de notes (index etudid, valeur
|
"""Calcul rangs à partir d'une séries ("vecteur") de notes (index etudid, valeur
|
||||||
numérique) en tenant compte des ex-aequos.
|
numérique) en tenant compte des ex-aequos.
|
||||||
|
|
||||||
Result: { etudid : rang:str } où rang est une chaine decrivant le rang.
|
Result: Series { etudid : rang:str } où rang est une chaine decrivant le rang.
|
||||||
"""
|
"""
|
||||||
notes = notes.sort_values(ascending=False) # Serie, tri par ordre décroissant
|
notes = notes.sort_values(ascending=False) # Serie, tri par ordre décroissant
|
||||||
rangs = pd.Series(index=notes.index, dtype=str) # le rang est une chaîne
|
rangs_str = pd.Series(index=notes.index, dtype=str) # le rang est une chaîne
|
||||||
|
rangs_int = pd.Series(index=notes.index, dtype=int) # le rang numérique pour tris
|
||||||
N = len(notes)
|
N = len(notes)
|
||||||
nb_ex = 0 # nb d'ex-aequo consécutifs en cours
|
nb_ex = 0 # nb d'ex-aequo consécutifs en cours
|
||||||
notes_i = notes.iat
|
notes_i = notes.iat
|
||||||
@ -67,6 +68,7 @@ def comp_ranks_series(notes: pd.Series) -> dict[int, str]:
|
|||||||
next = None
|
next = None
|
||||||
val = notes_i[i]
|
val = notes_i[i]
|
||||||
if nb_ex:
|
if nb_ex:
|
||||||
|
rangs_int[etudid] = i + 1 - nb_ex
|
||||||
srang = "%d ex" % (i + 1 - nb_ex)
|
srang = "%d ex" % (i + 1 - nb_ex)
|
||||||
if val == next:
|
if val == next:
|
||||||
nb_ex += 1
|
nb_ex += 1
|
||||||
@ -74,9 +76,11 @@ def comp_ranks_series(notes: pd.Series) -> dict[int, str]:
|
|||||||
nb_ex = 0
|
nb_ex = 0
|
||||||
else:
|
else:
|
||||||
if val == next:
|
if val == next:
|
||||||
|
rangs_int[etudid] = i + 1 - nb_ex
|
||||||
srang = "%d ex" % (i + 1 - nb_ex)
|
srang = "%d ex" % (i + 1 - nb_ex)
|
||||||
nb_ex = 1
|
nb_ex = 1
|
||||||
else:
|
else:
|
||||||
|
rangs_int[etudid] = i + 1
|
||||||
srang = "%d" % (i + 1)
|
srang = "%d" % (i + 1)
|
||||||
rangs[etudid] = srang
|
rangs_str[etudid] = srang
|
||||||
return rangs
|
return rangs_str, rangs_int
|
||||||
|
@ -136,8 +136,13 @@ def df_load_modimpl_coefs(
|
|||||||
)
|
)
|
||||||
|
|
||||||
for mod_coef in mod_coefs:
|
for mod_coef in mod_coefs:
|
||||||
modimpl_coefs_df[mod2impl[mod_coef.module_id]][mod_coef.ue_id] = mod_coef.coef
|
try:
|
||||||
|
modimpl_coefs_df[mod2impl[mod_coef.module_id]][
|
||||||
|
mod_coef.ue_id
|
||||||
|
] = mod_coef.coef
|
||||||
|
except IndexError:
|
||||||
|
# il peut y avoir en base des coefs sur des modules ou UE qui ont depuis été retirés de la formation
|
||||||
|
pass
|
||||||
# Initialisation des poids non fixés:
|
# Initialisation des poids non fixés:
|
||||||
# 0 pour modules normaux, 1. pour bonus (car par défaut, on veut qu'un bonus agisse
|
# 0 pour modules normaux, 1. pour bonus (car par défaut, on veut qu'un bonus agisse
|
||||||
# sur toutes les UE)
|
# sur toutes les UE)
|
||||||
@ -229,12 +234,12 @@ def compute_ue_moys_apc(
|
|||||||
modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl)
|
modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl)
|
||||||
modimpl_coefs_df: matrice coefficients (UE x modimpl), sans UEs bonus sport
|
modimpl_coefs_df: matrice coefficients (UE x modimpl), sans UEs bonus sport
|
||||||
|
|
||||||
Résultat: DataFrame columns UE (sans sport), rows etudid
|
Résultat: DataFrame columns UE (sans bonus), rows etudid
|
||||||
"""
|
"""
|
||||||
nb_etuds, nb_modules, nb_ues_no_bonus = sem_cube.shape
|
nb_etuds, nb_modules, nb_ues_no_bonus = sem_cube.shape
|
||||||
nb_ues_tot = len(ues)
|
nb_ues_tot = len(ues)
|
||||||
assert len(modimpls) == nb_modules
|
assert len(modimpls) == nb_modules
|
||||||
if nb_modules == 0 or nb_etuds == 0:
|
if nb_modules == 0 or nb_etuds == 0 or nb_ues_no_bonus == 0:
|
||||||
return pd.DataFrame(
|
return pd.DataFrame(
|
||||||
index=modimpl_inscr_df.index, columns=modimpl_coefs_df.index
|
index=modimpl_inscr_df.index, columns=modimpl_coefs_df.index
|
||||||
)
|
)
|
||||||
@ -310,6 +315,17 @@ def compute_ue_moys_classic(
|
|||||||
les coefficients effectifs de chaque UE pour chaque étudiant
|
les coefficients effectifs de chaque UE pour chaque étudiant
|
||||||
(sommes de coefs de modules pris en compte)
|
(sommes de coefs de modules pris en compte)
|
||||||
"""
|
"""
|
||||||
|
if (not len(modimpl_mask)) or (
|
||||||
|
sem_matrix.shape[0] == 0
|
||||||
|
): # aucun module ou aucun étudiant
|
||||||
|
# etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df
|
||||||
|
return (
|
||||||
|
pd.Series(
|
||||||
|
[0.0] * len(modimpl_inscr_df.index), index=modimpl_inscr_df.index
|
||||||
|
),
|
||||||
|
pd.DataFrame(columns=[ue.id for ue in ues], index=modimpl_inscr_df.index),
|
||||||
|
pd.DataFrame(columns=[ue.id for ue in ues], index=modimpl_inscr_df.index),
|
||||||
|
)
|
||||||
# Restreint aux modules sélectionnés:
|
# Restreint aux modules sélectionnés:
|
||||||
sem_matrix = sem_matrix[:, modimpl_mask]
|
sem_matrix = sem_matrix[:, modimpl_mask]
|
||||||
modimpl_inscr = modimpl_inscr_df.values[:, modimpl_mask]
|
modimpl_inscr = modimpl_inscr_df.values[:, modimpl_mask]
|
||||||
@ -391,8 +407,9 @@ def compute_malus(
|
|||||||
) -> pd.DataFrame:
|
) -> pd.DataFrame:
|
||||||
"""Calcul le malus sur les UE
|
"""Calcul le malus sur les UE
|
||||||
Dans chaque UE, on peut avoir un ou plusieurs modules de MALUS.
|
Dans chaque UE, on peut avoir un ou plusieurs modules de MALUS.
|
||||||
Leurs notes sont positives ou négatives. leur somme sera _soustraite_ à la moyenne
|
Leurs notes sont positives ou négatives.
|
||||||
de chaque UE.
|
La somme des notes de malus somme est _soustraite_ à la moyenne de chaque UE.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- sem_modimpl_moys :
|
- sem_modimpl_moys :
|
||||||
notes moyennes aux modules (tous les étuds x tous les modimpls)
|
notes moyennes aux modules (tous les étuds x tous les modimpls)
|
||||||
@ -415,6 +432,7 @@ def compute_malus(
|
|||||||
for m in formsemestre.modimpls_sorted
|
for m in formsemestre.modimpls_sorted
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
if len(modimpl_mask):
|
||||||
malus_moys = sem_modimpl_moys[:, modimpl_mask].sum(axis=1)
|
malus_moys = sem_modimpl_moys[:, modimpl_mask].sum(axis=1)
|
||||||
malus[ue.id] = malus_moys
|
malus[ue.id] = malus_moys
|
||||||
|
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
"""Résultats semestres BUT
|
"""Résultats semestres BUT
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
|
from app import 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_common import NotesTableCompat
|
from app.comp.res_common import NotesTableCompat
|
||||||
from app.comp.bonus_spo import BonusSport
|
from app.comp.bonus_spo import BonusSport
|
||||||
@ -30,8 +32,14 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
|||||||
super().__init__(formsemestre)
|
super().__init__(formsemestre)
|
||||||
|
|
||||||
if not self.load_cached():
|
if not self.load_cached():
|
||||||
|
t0 = time.time()
|
||||||
self.compute()
|
self.compute()
|
||||||
|
t1 = time.time()
|
||||||
self.store()
|
self.store()
|
||||||
|
t2 = time.time()
|
||||||
|
log(
|
||||||
|
f"ResultatsSemestreBUT: cached formsemestre_id={formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)"
|
||||||
|
)
|
||||||
|
|
||||||
def compute(self):
|
def compute(self):
|
||||||
"Charge les notes et inscriptions et calcule les moyennes d'UE et gen."
|
"Charge les notes et inscriptions et calcule les moyennes d'UE et gen."
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
"""Résultats semestres classiques (non APC)
|
"""Résultats semestres classiques (non APC)
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from sqlalchemy.sql import text
|
from sqlalchemy.sql import text
|
||||||
@ -40,8 +40,14 @@ class ResultatsSemestreClassic(NotesTableCompat):
|
|||||||
super().__init__(formsemestre)
|
super().__init__(formsemestre)
|
||||||
|
|
||||||
if not self.load_cached():
|
if not self.load_cached():
|
||||||
|
t0 = time.time()
|
||||||
self.compute()
|
self.compute()
|
||||||
|
t1 = time.time()
|
||||||
self.store()
|
self.store()
|
||||||
|
t2 = time.time()
|
||||||
|
log(
|
||||||
|
f"ResultatsSemestreClassic: cached formsemestre_id={formsemestre.id} ({(t1-t0):g}s +{(t2-t1):g}s)"
|
||||||
|
)
|
||||||
# recalculé (aussi rapide que de les cacher)
|
# recalculé (aussi rapide que de les cacher)
|
||||||
self.moy_min = self.etud_moy_gen.min()
|
self.moy_min = self.etud_moy_gen.min()
|
||||||
self.moy_max = self.etud_moy_gen.max()
|
self.moy_max = self.etud_moy_gen.max()
|
||||||
@ -110,9 +116,8 @@ class ResultatsSemestreClassic(NotesTableCompat):
|
|||||||
if bonus_mg is not None:
|
if bonus_mg is not None:
|
||||||
self.etud_moy_gen += bonus_mg
|
self.etud_moy_gen += bonus_mg
|
||||||
self.etud_moy_gen.clip(lower=0.0, upper=20.0, inplace=True)
|
self.etud_moy_gen.clip(lower=0.0, upper=20.0, inplace=True)
|
||||||
self.bonus = (
|
# compat nt, utilisé pour l'afficher sur les bulletins:
|
||||||
bonus_mg # compat nt, utilisé pour l'afficher sur les bulletins
|
self.bonus = bonus_mg
|
||||||
)
|
|
||||||
# --- UE capitalisées
|
# --- UE capitalisées
|
||||||
self.apply_capitalisation()
|
self.apply_capitalisation()
|
||||||
|
|
||||||
@ -209,6 +214,8 @@ def notes_sem_assemble_matrix(modimpls_notes: list[pd.Series]) -> np.ndarray:
|
|||||||
(Series rendus par compute_module_moy, index: etud)
|
(Series rendus par compute_module_moy, index: etud)
|
||||||
Resultat: ndarray (etud x module)
|
Resultat: ndarray (etud x module)
|
||||||
"""
|
"""
|
||||||
|
if not len(modimpls_notes):
|
||||||
|
return np.zeros((0, 0), dtype=float)
|
||||||
modimpls_notes_arr = [s.values for s in modimpls_notes]
|
modimpls_notes_arr = [s.values for s in modimpls_notes]
|
||||||
modimpls_notes = np.stack(modimpls_notes_arr)
|
modimpls_notes = np.stack(modimpls_notes_arr)
|
||||||
# passe de (mod x etud) à (etud x mod)
|
# passe de (mod x etud) à (etud x mod)
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
# See LICENSE
|
# See LICENSE
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from collections import defaultdict, Counter
|
from collections import Counter
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
|
from app import log
|
||||||
from app.comp.aux_stats import StatsMoyenne
|
from app.comp.aux_stats import StatsMoyenne
|
||||||
from app.comp import moy_sem
|
from app.comp import moy_sem
|
||||||
from app.comp.res_cache import ResultatsCache
|
from app.comp.res_cache import ResultatsCache
|
||||||
@ -19,8 +20,7 @@ from app.models import FormSemestreUECoef
|
|||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_cache import ResultatsSemestreCache
|
from app.scodoc.sco_cache import ResultatsSemestreCache
|
||||||
from app.scodoc.sco_codes_parcours import UE_SPORT, ATT, DEF
|
from app.scodoc.sco_codes_parcours import UE_SPORT, DEF
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
|
||||||
|
|
||||||
# Il faut bien distinguer
|
# Il faut bien distinguer
|
||||||
# - ce qui est caché de façon persistente (via redis):
|
# - ce qui est caché de façon persistente (via redis):
|
||||||
@ -51,6 +51,7 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
"etud_moy_ue: DataFrame columns UE, rows etudid"
|
"etud_moy_ue: DataFrame columns UE, rows etudid"
|
||||||
self.etud_moy_gen = {}
|
self.etud_moy_gen = {}
|
||||||
self.etud_moy_gen_ranks = {}
|
self.etud_moy_gen_ranks = {}
|
||||||
|
self.etud_moy_gen_ranks_int = {}
|
||||||
self.modimpls_results: ModuleImplResults = None
|
self.modimpls_results: ModuleImplResults = None
|
||||||
"Résultats de chaque modimpl: dict { modimpl.id : ModuleImplResults(Classique ou BUT) }"
|
"Résultats de chaque modimpl: dict { modimpl.id : ModuleImplResults(Classique ou BUT) }"
|
||||||
self.etud_coef_ue_df = None
|
self.etud_coef_ue_df = None
|
||||||
@ -183,7 +184,7 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
sum_coefs_ue = 0.0
|
sum_coefs_ue = 0.0
|
||||||
for ue in self.formsemestre.query_ues():
|
for ue in self.formsemestre.query_ues():
|
||||||
ue_cap = self.get_etud_ue_status(etudid, ue.id)
|
ue_cap = self.get_etud_ue_status(etudid, ue.id)
|
||||||
if ue_cap["is_capitalized"]:
|
if ue_cap and ue_cap["is_capitalized"]:
|
||||||
recompute_mg = True
|
recompute_mg = True
|
||||||
coef = ue_cap["coef_ue"]
|
coef = ue_cap["coef_ue"]
|
||||||
if not np.isnan(ue_cap["moy"]):
|
if not np.isnan(ue_cap["moy"]):
|
||||||
@ -213,15 +214,13 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
|
|
||||||
def get_etud_ue_status(self, etudid: int, ue_id: int) -> dict:
|
def get_etud_ue_status(self, etudid: int, ue_id: int) -> dict:
|
||||||
"""L'état de l'UE pour cet étudiant.
|
"""L'état de l'UE pour cet étudiant.
|
||||||
L'UE doit être du semestre.
|
Result: dict, ou None si l'UE n'est pas dans ce semestre.
|
||||||
Result: dict.
|
|
||||||
"""
|
"""
|
||||||
if not self.validations:
|
|
||||||
self.validations = res_sem.load_formsemestre_validations(self.formsemestre)
|
|
||||||
ue = UniteEns.query.get(ue_id) # TODO cacher nos UEs ?
|
ue = UniteEns.query.get(ue_id) # TODO cacher nos UEs ?
|
||||||
if ue.type == UE_SPORT:
|
if ue.type == UE_SPORT:
|
||||||
return {
|
return {
|
||||||
"is_capitalized": False,
|
"is_capitalized": False,
|
||||||
|
"was_capitalized": False,
|
||||||
"is_external": False,
|
"is_external": False,
|
||||||
"coef_ue": 0.0,
|
"coef_ue": 0.0,
|
||||||
"cur_moy_ue": 0.0,
|
"cur_moy_ue": 0.0,
|
||||||
@ -232,9 +231,16 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
"capitalized_ue_id": None,
|
"capitalized_ue_id": None,
|
||||||
"ects_pot": 0.0,
|
"ects_pot": 0.0,
|
||||||
}
|
}
|
||||||
|
if not ue_id in self.etud_moy_ue:
|
||||||
|
return None
|
||||||
|
if not self.validations:
|
||||||
|
self.validations = res_sem.load_formsemestre_validations(self.formsemestre)
|
||||||
cur_moy_ue = self.etud_moy_ue[ue_id][etudid]
|
cur_moy_ue = self.etud_moy_ue[ue_id][etudid]
|
||||||
moy_ue = cur_moy_ue
|
moy_ue = cur_moy_ue
|
||||||
is_capitalized = False
|
is_capitalized = False # si l'UE prise en compte est une UE capitalisée
|
||||||
|
was_capitalized = (
|
||||||
|
False # s'il y a precedemment une UE capitalisée (pas forcement meilleure)
|
||||||
|
)
|
||||||
if etudid in self.validations.ue_capitalisees.index:
|
if etudid in self.validations.ue_capitalisees.index:
|
||||||
ue_cap = self._get_etud_ue_cap(etudid, ue)
|
ue_cap = self._get_etud_ue_cap(etudid, ue)
|
||||||
if (
|
if (
|
||||||
@ -242,6 +248,7 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
and not ue_cap.empty
|
and not ue_cap.empty
|
||||||
and not np.isnan(ue_cap["moy_ue"])
|
and not np.isnan(ue_cap["moy_ue"])
|
||||||
):
|
):
|
||||||
|
was_capitalized = True
|
||||||
if ue_cap["moy_ue"] > cur_moy_ue or np.isnan(cur_moy_ue):
|
if ue_cap["moy_ue"] > cur_moy_ue or np.isnan(cur_moy_ue):
|
||||||
moy_ue = ue_cap["moy_ue"]
|
moy_ue = ue_cap["moy_ue"]
|
||||||
is_capitalized = True
|
is_capitalized = True
|
||||||
@ -250,6 +257,7 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"is_capitalized": is_capitalized,
|
"is_capitalized": is_capitalized,
|
||||||
|
"was_capitalized": was_capitalized,
|
||||||
"is_external": ue_cap["is_external"] if is_capitalized else ue.is_external,
|
"is_external": ue_cap["is_external"] if is_capitalized else ue.is_external,
|
||||||
"coef_ue": coef_ue,
|
"coef_ue": coef_ue,
|
||||||
"ects_pot": ue.ects or 0.0,
|
"ects_pot": ue.ects or 0.0,
|
||||||
@ -301,6 +309,7 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
"bonus_ues",
|
"bonus_ues",
|
||||||
"malus",
|
"malus",
|
||||||
"etud_moy_gen_ranks",
|
"etud_moy_gen_ranks",
|
||||||
|
"etud_moy_gen_ranks_int",
|
||||||
"ue_rangs",
|
"ue_rangs",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -311,41 +320,54 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
self.bonus = None # virtuel
|
self.bonus = None # virtuel
|
||||||
self.bonus_ues = None # virtuel
|
self.bonus_ues = None # virtuel
|
||||||
self.ue_rangs = {u.id: (None, nb_etuds) for u in self.ues}
|
self.ue_rangs = {u.id: (None, nb_etuds) for u in self.ues}
|
||||||
self.mod_rangs = {
|
self.mod_rangs = None # sera surchargé en Classic, mais pas en APC
|
||||||
m.id: (None, nb_etuds) for m in self.formsemestre.modimpls_sorted
|
|
||||||
}
|
|
||||||
self.moy_min = "NA"
|
self.moy_min = "NA"
|
||||||
self.moy_max = "NA"
|
self.moy_max = "NA"
|
||||||
self.moy_moy = "NA"
|
self.moy_moy = "NA"
|
||||||
self.expr_diagnostics = ""
|
self.expr_diagnostics = ""
|
||||||
self.parcours = self.formsemestre.formation.get_parcours()
|
self.parcours = self.formsemestre.formation.get_parcours()
|
||||||
|
|
||||||
def get_etudids(self, sorted=False) -> list[int]:
|
def get_inscrits(self, include_demdef=True, order_by=False) -> list[Identite]:
|
||||||
"""Liste des etudids inscrits, incluant les démissionnaires.
|
"""Liste des étudiants inscrits
|
||||||
Si sorted, triée par moy. générale décroissante
|
order_by = False|'nom'|'moy' tri sur nom ou sur moyenne générale (indicative)
|
||||||
Sinon, triée par ordre alphabetique de NOM
|
|
||||||
|
Note: pour récupérer les etudids des inscrits, non triés, il est plus efficace
|
||||||
|
d'utiliser `[ ins.etudid for ins in nt.formsemestre.inscriptions ]`
|
||||||
|
"""
|
||||||
|
etuds = self.formsemestre.get_inscrits(
|
||||||
|
include_demdef=include_demdef, order=(order_by == "nom")
|
||||||
|
)
|
||||||
|
if order_by == "moy":
|
||||||
|
etuds.sort(
|
||||||
|
key=lambda e: (
|
||||||
|
self.etud_moy_gen_ranks_int.get(e.id, 100000),
|
||||||
|
e.sort_key,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return etuds
|
||||||
|
|
||||||
|
def get_etudids(self) -> list[int]:
|
||||||
|
"""(deprecated)
|
||||||
|
Liste des etudids inscrits, incluant les démissionnaires.
|
||||||
|
triée par ordre alphabetique de NOM
|
||||||
|
(à éviter: renvoie les etudids, mais est moins efficace que get_inscrits)
|
||||||
"""
|
"""
|
||||||
# Note: pour avoir les inscrits non triés,
|
# Note: pour avoir les inscrits non triés,
|
||||||
# utiliser [ ins.etudid for ins in self.formsemestre.inscriptions ]
|
# utiliser [ ins.etudid for ins in self.formsemestre.inscriptions ]
|
||||||
if sorted:
|
|
||||||
# Tri par moy. generale décroissante
|
|
||||||
return [x[-1] for x in self.T]
|
|
||||||
|
|
||||||
return [x["etudid"] for x in self.inscrlist]
|
return [x["etudid"] for x in self.inscrlist]
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def sem(self) -> dict:
|
def sem(self) -> dict:
|
||||||
"""le formsemestre, comme un dict (nt.sem)"""
|
"""le formsemestre, comme un gros et gras dict (nt.sem)"""
|
||||||
return self.formsemestre.to_dict()
|
return self.formsemestre.get_infos_dict()
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def inscrlist(self) -> list[dict]: # utilisé par PE seulement
|
def inscrlist(self) -> list[dict]: # utilisé par PE
|
||||||
"""Liste des inscrits au semestre (avec DEM et DEF),
|
"""Liste des inscrits au semestre (avec DEM et DEF),
|
||||||
sous forme de dict etud,
|
sous forme de dict etud,
|
||||||
classée dans l'ordre alphabétique de noms.
|
classée dans l'ordre alphabétique de noms.
|
||||||
"""
|
"""
|
||||||
etuds = self.formsemestre.get_inscrits(include_demdef=True)
|
etuds = self.formsemestre.get_inscrits(include_demdef=True, order=True)
|
||||||
etuds.sort(key=lambda e: e.sort_key)
|
|
||||||
return [e.to_dict_scodoc7() for e in etuds]
|
return [e.to_dict_scodoc7() for e in etuds]
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
@ -387,11 +409,14 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
Moyenne générale: etud_moy_gen_ranks
|
Moyenne générale: etud_moy_gen_ranks
|
||||||
Par UE (sauf ue bonus)
|
Par UE (sauf ue bonus)
|
||||||
"""
|
"""
|
||||||
self.etud_moy_gen_ranks = moy_sem.comp_ranks_series(self.etud_moy_gen)
|
(
|
||||||
|
self.etud_moy_gen_ranks,
|
||||||
|
self.etud_moy_gen_ranks_int,
|
||||||
|
) = moy_sem.comp_ranks_series(self.etud_moy_gen)
|
||||||
for ue in self.formsemestre.query_ues():
|
for ue in self.formsemestre.query_ues():
|
||||||
moy_ue = self.etud_moy_ue[ue.id]
|
moy_ue = self.etud_moy_ue[ue.id]
|
||||||
self.ue_rangs[ue.id] = (
|
self.ue_rangs[ue.id] = (
|
||||||
moy_sem.comp_ranks_series(moy_ue),
|
moy_sem.comp_ranks_series(moy_ue)[0], # juste en chaine
|
||||||
int(moy_ue.count()),
|
int(moy_ue.count()),
|
||||||
)
|
)
|
||||||
# .count() -> nb of non NaN values
|
# .count() -> nb of non NaN values
|
||||||
@ -420,12 +445,27 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
|
|
||||||
Return: True|False, message explicatif
|
Return: True|False, message explicatif
|
||||||
"""
|
"""
|
||||||
return self.parcours.check_barre_ues(
|
ue_status_list = []
|
||||||
[
|
for ue in self.formsemestre.query_ues():
|
||||||
self.get_etud_ue_status(etudid, ue.id)
|
ue_status = self.get_etud_ue_status(etudid, ue.id)
|
||||||
for ue in self.formsemestre.query_ues()
|
if ue_status:
|
||||||
]
|
ue_status_list.append(ue_status)
|
||||||
)
|
return self.parcours.check_barre_ues(ue_status_list)
|
||||||
|
|
||||||
|
def all_etuds_have_sem_decisions(self):
|
||||||
|
"""True si tous les étudiants du semestre ont une décision de jury.
|
||||||
|
Ne regarde pas les décisions d'UE.
|
||||||
|
"""
|
||||||
|
for ins in self.formsemestre.inscriptions:
|
||||||
|
if ins.etat != scu.INSCRIT:
|
||||||
|
continue # skip démissionnaires
|
||||||
|
if self.get_etud_decision_sem(ins.etudid) is None:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def etud_has_decision(self, etudid):
|
||||||
|
"""True s'il y a une décision de jury pour cet étudiant"""
|
||||||
|
return self.get_etud_decision_ues(etudid) or self.get_etud_decision_sem(etudid)
|
||||||
|
|
||||||
def get_etud_decision_ues(self, etudid: int) -> dict:
|
def get_etud_decision_ues(self, etudid: int) -> dict:
|
||||||
"""Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu.
|
"""Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu.
|
||||||
@ -525,25 +565,32 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
Évaluation "complete" ssi toutes notes saisies ou en attente.
|
Évaluation "complete" ssi toutes notes saisies ou en attente.
|
||||||
"""
|
"""
|
||||||
modimpl = ModuleImpl.query.get(moduleimpl_id)
|
modimpl = ModuleImpl.query.get(moduleimpl_id)
|
||||||
|
modimpl_results = self.modimpls_results.get(moduleimpl_id)
|
||||||
|
if not modimpl_results:
|
||||||
|
return [] # safeguard
|
||||||
evals_results = []
|
evals_results = []
|
||||||
for e in modimpl.evaluations:
|
for e in modimpl.evaluations:
|
||||||
if self.modimpls_results[moduleimpl_id].evaluations_completes_dict[e.id]:
|
if modimpl_results.evaluations_completes_dict.get(e.id, False):
|
||||||
d = e.to_dict()
|
d = e.to_dict()
|
||||||
moduleimpl_results = self.modimpls_results[e.moduleimpl_id]
|
|
||||||
d["heure_debut"] = e.heure_debut # datetime.time
|
d["heure_debut"] = e.heure_debut # datetime.time
|
||||||
d["heure_fin"] = e.heure_fin
|
d["heure_fin"] = e.heure_fin
|
||||||
d["jour"] = e.jour # datetime
|
d["jour"] = e.jour # datetime
|
||||||
d["notes"] = {
|
d["notes"] = {
|
||||||
etud.id: {
|
etud.id: {
|
||||||
"etudid": etud.id,
|
"etudid": etud.id,
|
||||||
"value": moduleimpl_results.evals_notes[e.id][etud.id],
|
"value": modimpl_results.evals_notes[e.id][etud.id],
|
||||||
}
|
}
|
||||||
for etud in self.etuds
|
for etud in self.etuds
|
||||||
}
|
}
|
||||||
d["etat"] = {
|
d["etat"] = {
|
||||||
"evalattente": moduleimpl_results.evaluations_etat[e.id].nb_attente,
|
"evalattente": modimpl_results.evaluations_etat[e.id].nb_attente,
|
||||||
}
|
}
|
||||||
evals_results.append(d)
|
evals_results.append(d)
|
||||||
|
elif e.id not in modimpl_results.evaluations_completes_dict:
|
||||||
|
# ne devrait pas arriver ? XXX
|
||||||
|
log(
|
||||||
|
f"Warning: 220213 get_evals_in_mod {e.id} not in mod {moduleimpl_id} ?"
|
||||||
|
)
|
||||||
return evals_results
|
return evals_results
|
||||||
|
|
||||||
def get_evaluations_etats(self):
|
def get_evaluations_etats(self):
|
||||||
@ -608,7 +655,7 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
"""
|
"""
|
||||||
table_moyennes = []
|
table_moyennes = []
|
||||||
etuds_inscriptions = self.formsemestre.etuds_inscriptions
|
etuds_inscriptions = self.formsemestre.etuds_inscriptions
|
||||||
ues = self.formsemestre.query_ues() # sans bonus
|
ues = self.formsemestre.query_ues(with_sport=True) # avec bonus
|
||||||
for etudid in etuds_inscriptions:
|
for etudid in etuds_inscriptions:
|
||||||
moy_gen = self.etud_moy_gen.get(etudid, False)
|
moy_gen = self.etud_moy_gen.get(etudid, False)
|
||||||
if moy_gen is False:
|
if moy_gen is False:
|
||||||
@ -623,8 +670,11 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
ue_is_cap = {}
|
ue_is_cap = {}
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
ue_status = self.get_etud_ue_status(etudid, ue.id)
|
ue_status = self.get_etud_ue_status(etudid, ue.id)
|
||||||
|
if ue_status:
|
||||||
moy_ues.append(ue_status["moy"])
|
moy_ues.append(ue_status["moy"])
|
||||||
ue_is_cap[ue.id] = ue_status["is_capitalized"]
|
ue_is_cap[ue.id] = ue_status["is_capitalized"]
|
||||||
|
else:
|
||||||
|
moy_ues.append("?")
|
||||||
t = [moy_gen] + list(moy_ues)
|
t = [moy_gen] + list(moy_ues)
|
||||||
# Moyennes modules:
|
# Moyennes modules:
|
||||||
for modimpl in self.formsemestre.modimpls_sorted:
|
for modimpl in self.formsemestre.modimpls_sorted:
|
||||||
|
@ -25,7 +25,7 @@ def load_formsemestre_results(formsemestre: FormSemestre) -> ResultatsSemestre:
|
|||||||
"""
|
"""
|
||||||
# --- Try local cache (within the same request context)
|
# --- Try local cache (within the same request context)
|
||||||
if not hasattr(g, "formsemestre_results_cache"):
|
if not hasattr(g, "formsemestre_results_cache"):
|
||||||
g.formsemestre_results_cache = {} # pylint: disable=C0237
|
g.formsemestre_results_cache = {}
|
||||||
else:
|
else:
|
||||||
if formsemestre.id in g.formsemestre_results_cache:
|
if formsemestre.id in g.formsemestre_results_cache:
|
||||||
return g.formsemestre_results_cache[formsemestre.id]
|
return g.formsemestre_results_cache[formsemestre.id]
|
||||||
|
@ -81,6 +81,9 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
|||||||
)
|
)
|
||||||
formations = db.relationship("Formation", backref="referentiel_competence")
|
formations = db.relationship("Formation", backref="referentiel_competence")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<ApcReferentielCompetences {self.id} {self.specialite}>"
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
"""Représentation complète du ref. de comp.
|
"""Représentation complète du ref. de comp.
|
||||||
comme un dict.
|
comme un dict.
|
||||||
@ -110,7 +113,8 @@ class ApcCompetence(db.Model, XMLModel):
|
|||||||
db.Integer, db.ForeignKey("apc_referentiel_competences.id"), nullable=False
|
db.Integer, db.ForeignKey("apc_referentiel_competences.id"), nullable=False
|
||||||
)
|
)
|
||||||
# les compétences dans Orébut sont identifiées par leur id unique
|
# les compétences dans Orébut sont identifiées par leur id unique
|
||||||
id_orebut = db.Column(db.Text(), nullable=True, index=True, unique=True)
|
# (mais id_orebut n'est pas unique car le même ref. pourra être chargé dans plusieurs depts)
|
||||||
|
id_orebut = db.Column(db.Text(), nullable=True, index=True)
|
||||||
titre = db.Column(db.Text(), nullable=False, index=True)
|
titre = db.Column(db.Text(), nullable=False, index=True)
|
||||||
titre_long = db.Column(db.Text())
|
titre_long = db.Column(db.Text())
|
||||||
couleur = db.Column(db.Text())
|
couleur = db.Column(db.Text())
|
||||||
@ -139,6 +143,9 @@ class ApcCompetence(db.Model, XMLModel):
|
|||||||
cascade="all, delete-orphan",
|
cascade="all, delete-orphan",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<ApcCompetence {self.id} {self.titre}>"
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {
|
return {
|
||||||
"id_orebut": self.id_orebut,
|
"id_orebut": self.id_orebut,
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from flask import abort, url_for
|
from flask import abort, url_for
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app import models
|
from app import models
|
||||||
|
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app.scodoc.sco_bac import Baccalaureat
|
from app.scodoc.sco_bac import Baccalaureat
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
class Identite(db.Model):
|
class Identite(db.Model):
|
||||||
@ -73,6 +75,13 @@ class Identite(db.Model):
|
|||||||
"""
|
"""
|
||||||
return {"M": "M.", "F": "Mme", "X": ""}[self.civilite]
|
return {"M": "M.", "F": "Mme", "X": ""}[self.civilite]
|
||||||
|
|
||||||
|
def sex_nom(self, no_accents=False) -> str:
|
||||||
|
"'M. DUPONTÉ', ou si no_accents, 'M. DUPONTE'"
|
||||||
|
s = f"{self.civilite_str} {(self.nom_usuel or self.nom).upper()}"
|
||||||
|
if no_accents:
|
||||||
|
return scu.suppress_accents(s)
|
||||||
|
return s
|
||||||
|
|
||||||
def nom_disp(self) -> str:
|
def nom_disp(self) -> str:
|
||||||
"Nom à afficher"
|
"Nom à afficher"
|
||||||
if self.nom_usuel:
|
if self.nom_usuel:
|
||||||
@ -125,6 +134,7 @@ class Identite(db.Model):
|
|||||||
# ScoDoc7 output_formators: (backward compat)
|
# ScoDoc7 output_formators: (backward compat)
|
||||||
e["etudid"] = self.id
|
e["etudid"] = self.id
|
||||||
e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"])
|
e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"])
|
||||||
|
e["ne"] = {"M": "", "F": "ne"}.get(self.civilite, "(e)")
|
||||||
return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty
|
return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty
|
||||||
|
|
||||||
def to_dict_bul(self, include_urls=True):
|
def to_dict_bul(self, include_urls=True):
|
||||||
@ -302,6 +312,24 @@ class Admission(db.Model):
|
|||||||
"Le bac. utiliser bac.abbrev() pour avoir une chaine de caractères."
|
"Le bac. utiliser bac.abbrev() pour avoir une chaine de caractères."
|
||||||
return Baccalaureat(self.bac, specialite=self.specialite)
|
return Baccalaureat(self.bac, specialite=self.specialite)
|
||||||
|
|
||||||
|
def to_dict(self, no_nulls=False):
|
||||||
|
"""Représentation dictionnaire,"""
|
||||||
|
e = dict(self.__dict__)
|
||||||
|
e.pop("_sa_instance_state", None)
|
||||||
|
if no_nulls:
|
||||||
|
for k in e:
|
||||||
|
if e[k] is None:
|
||||||
|
col_type = getattr(
|
||||||
|
sqlalchemy.inspect(models.Admission).columns, "apb_groupe"
|
||||||
|
).expression.type
|
||||||
|
if isinstance(col_type, sqlalchemy.Text):
|
||||||
|
e[k] = ""
|
||||||
|
elif isinstance(col_type, sqlalchemy.Integer):
|
||||||
|
e[k] = 0
|
||||||
|
elif isinstance(col_type, sqlalchemy.Boolean):
|
||||||
|
e[k] = False
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
# Suivi scolarité / débouchés
|
# Suivi scolarité / débouchés
|
||||||
class ItemSuivi(db.Model):
|
class ItemSuivi(db.Model):
|
||||||
|
@ -2,12 +2,16 @@
|
|||||||
|
|
||||||
"""ScoDoc models: evaluations
|
"""ScoDoc models: evaluations
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import UniteEns
|
from app.models import formsemestre
|
||||||
|
from app.models.formsemestre import FormSemestre
|
||||||
|
from app.models.moduleimpls import ModuleImpl
|
||||||
|
from app.models.ues import UniteEns
|
||||||
|
|
||||||
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc import sco_evaluation_db
|
|
||||||
|
|
||||||
|
|
||||||
class Evaluation(db.Model):
|
class Evaluation(db.Model):
|
||||||
@ -51,11 +55,11 @@ class Evaluation(db.Model):
|
|||||||
e["evaluation_id"] = self.id
|
e["evaluation_id"] = self.id
|
||||||
e["jour"] = ndb.DateISOtoDMY(e["jour"])
|
e["jour"] = ndb.DateISOtoDMY(e["jour"])
|
||||||
e["numero"] = ndb.int_null_is_zero(e["numero"])
|
e["numero"] = ndb.int_null_is_zero(e["numero"])
|
||||||
return sco_evaluation_db.evaluation_enrich_dict(e)
|
return evaluation_enrich_dict(e)
|
||||||
|
|
||||||
def from_dict(self, data):
|
def from_dict(self, data):
|
||||||
"""Set evaluation attributes from given dict values."""
|
"""Set evaluation attributes from given dict values."""
|
||||||
sco_evaluation_db._check_evaluation_args(data)
|
check_evaluation_args(data)
|
||||||
for k in self.__dict__.keys():
|
for k in self.__dict__.keys():
|
||||||
if k != "_sa_instance_state" and k != "id" and k in data:
|
if k != "_sa_instance_state" and k != "id" and k in data:
|
||||||
setattr(self, k, data[k])
|
setattr(self, k, data[k])
|
||||||
@ -145,3 +149,89 @@ class EvaluationUEPoids(db.Model):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<EvaluationUEPoids {self.evaluation} {self.ue} poids={self.poids}>"
|
return f"<EvaluationUEPoids {self.evaluation} {self.ue} poids={self.poids}>"
|
||||||
|
|
||||||
|
|
||||||
|
# Fonction héritée de ScoDoc7 à refactorer
|
||||||
|
def evaluation_enrich_dict(e):
|
||||||
|
"""add or convert some fileds in an evaluation dict"""
|
||||||
|
# For ScoDoc7 compat
|
||||||
|
heure_debut_dt = e["heure_debut"] or datetime.time(
|
||||||
|
8, 00
|
||||||
|
) # au cas ou pas d'heure (note externe?)
|
||||||
|
heure_fin_dt = e["heure_fin"] or datetime.time(8, 00)
|
||||||
|
e["heure_debut"] = ndb.TimefromISO8601(e["heure_debut"])
|
||||||
|
e["heure_fin"] = ndb.TimefromISO8601(e["heure_fin"])
|
||||||
|
e["jouriso"] = ndb.DateDMYtoISO(e["jour"])
|
||||||
|
heure_debut, heure_fin = e["heure_debut"], e["heure_fin"]
|
||||||
|
d = ndb.TimeDuration(heure_debut, heure_fin)
|
||||||
|
if d is not None:
|
||||||
|
m = d % 60
|
||||||
|
e["duree"] = "%dh" % (d / 60)
|
||||||
|
if m != 0:
|
||||||
|
e["duree"] += "%02d" % m
|
||||||
|
else:
|
||||||
|
e["duree"] = ""
|
||||||
|
if heure_debut and (not heure_fin or heure_fin == heure_debut):
|
||||||
|
e["descrheure"] = " à " + heure_debut
|
||||||
|
elif heure_debut and heure_fin:
|
||||||
|
e["descrheure"] = " de %s à %s" % (heure_debut, heure_fin)
|
||||||
|
else:
|
||||||
|
e["descrheure"] = ""
|
||||||
|
# matin, apresmidi: utile pour se referer aux absences:
|
||||||
|
if heure_debut_dt < datetime.time(12, 00):
|
||||||
|
e["matin"] = 1
|
||||||
|
else:
|
||||||
|
e["matin"] = 0
|
||||||
|
if heure_fin_dt > datetime.time(12, 00):
|
||||||
|
e["apresmidi"] = 1
|
||||||
|
else:
|
||||||
|
e["apresmidi"] = 0
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def check_evaluation_args(args):
|
||||||
|
"Check coefficient, dates and duration, raises exception if invalid"
|
||||||
|
moduleimpl_id = args["moduleimpl_id"]
|
||||||
|
# check bareme
|
||||||
|
note_max = args.get("note_max", None)
|
||||||
|
if note_max is None:
|
||||||
|
raise ScoValueError("missing note_max")
|
||||||
|
try:
|
||||||
|
note_max = float(note_max)
|
||||||
|
except ValueError:
|
||||||
|
raise ScoValueError("Invalid note_max value")
|
||||||
|
if note_max < 0:
|
||||||
|
raise ScoValueError("Invalid note_max value (must be positive or null)")
|
||||||
|
# check coefficient
|
||||||
|
coef = args.get("coefficient", None)
|
||||||
|
if coef is None:
|
||||||
|
raise ScoValueError("missing coefficient")
|
||||||
|
try:
|
||||||
|
coef = float(coef)
|
||||||
|
except ValueError:
|
||||||
|
raise ScoValueError("Invalid coefficient value")
|
||||||
|
if coef < 0:
|
||||||
|
raise ScoValueError("Invalid coefficient value (must be positive or null)")
|
||||||
|
# check date
|
||||||
|
jour = args.get("jour", None)
|
||||||
|
args["jour"] = jour
|
||||||
|
if jour:
|
||||||
|
modimpl = ModuleImpl.query.get(moduleimpl_id)
|
||||||
|
formsemestre = modimpl.formsemestre
|
||||||
|
y, m, d = [int(x) for x in ndb.DateDMYtoISO(jour).split("-")]
|
||||||
|
jour = datetime.date(y, m, d)
|
||||||
|
if (jour > formsemestre.date_fin) or (jour < formsemestre.date_debut):
|
||||||
|
raise ScoValueError(
|
||||||
|
"La date de l'évaluation (%s/%s/%s) n'est pas dans le semestre !"
|
||||||
|
% (d, m, y),
|
||||||
|
dest_url="javascript:history.back();",
|
||||||
|
)
|
||||||
|
heure_debut = args.get("heure_debut", None)
|
||||||
|
args["heure_debut"] = heure_debut
|
||||||
|
heure_fin = args.get("heure_fin", None)
|
||||||
|
args["heure_fin"] = heure_fin
|
||||||
|
if jour and ((not heure_debut) or (not heure_fin)):
|
||||||
|
raise ScoValueError("Les heures doivent être précisées")
|
||||||
|
d = ndb.TimeDuration(heure_debut, heure_fin)
|
||||||
|
if d and ((d < 0) or (d > 60 * 12)):
|
||||||
|
raise ScoValueError("Heures de l'évaluation incohérentes !")
|
||||||
|
@ -117,10 +117,12 @@ class FormSemestre(db.Model):
|
|||||||
return f"<{self.__class__.__name__} {self.id} {self.titre_num()}>"
|
return f"<{self.__class__.__name__} {self.id} {self.titre_num()}>"
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
|
"dict (compatible ScoDoc7)"
|
||||||
d = dict(self.__dict__)
|
d = dict(self.__dict__)
|
||||||
d.pop("_sa_instance_state", None)
|
d.pop("_sa_instance_state", None)
|
||||||
# ScoDoc7 output_formators: (backward compat)
|
# ScoDoc7 output_formators: (backward compat)
|
||||||
d["formsemestre_id"] = self.id
|
d["formsemestre_id"] = self.id
|
||||||
|
d["titre_num"] = self.titre_num()
|
||||||
if self.date_debut:
|
if self.date_debut:
|
||||||
d["date_debut"] = self.date_debut.strftime("%d/%m/%Y")
|
d["date_debut"] = self.date_debut.strftime("%d/%m/%Y")
|
||||||
d["date_debut_iso"] = self.date_debut.isoformat()
|
d["date_debut_iso"] = self.date_debut.isoformat()
|
||||||
@ -144,6 +146,8 @@ class FormSemestre(db.Model):
|
|||||||
d["annee_debut"] = str(self.date_debut.year)
|
d["annee_debut"] = str(self.date_debut.year)
|
||||||
d["annee"] = d["annee_debut"]
|
d["annee"] = d["annee_debut"]
|
||||||
d["annee_fin"] = str(self.date_fin.year)
|
d["annee_fin"] = str(self.date_fin.year)
|
||||||
|
if d["annee_fin"] != d["annee_debut"]:
|
||||||
|
d["annee"] += "-" + str(d["annee_fin"])
|
||||||
d["mois_debut_ord"] = self.date_debut.month
|
d["mois_debut_ord"] = self.date_debut.month
|
||||||
d["mois_fin_ord"] = self.date_fin.month
|
d["mois_fin_ord"] = self.date_fin.month
|
||||||
# La période: considère comme "S1" (ou S3) les débuts en aout-sept-octobre
|
# La période: considère comme "S1" (ou S3) les débuts en aout-sept-octobre
|
||||||
@ -152,15 +156,8 @@ class FormSemestre(db.Model):
|
|||||||
d["periode"] = 1 # typiquement, début en septembre: S1, S3...
|
d["periode"] = 1 # typiquement, début en septembre: S1, S3...
|
||||||
else:
|
else:
|
||||||
d["periode"] = 2 # typiquement, début en février: S2, S4...
|
d["periode"] = 2 # typiquement, début en février: S2, S4...
|
||||||
d["titre_num"] = self.titre_num
|
d["titre_num"] = self.titre_num()
|
||||||
d["titreannee"] = "%s %s %s" % (
|
d["titreannee"] = self.titre_annee()
|
||||||
d["titre_num"],
|
|
||||||
self.modalite or "",
|
|
||||||
self.date_debut.year,
|
|
||||||
)
|
|
||||||
if d["annee_fin"] != d["annee_debut"]:
|
|
||||||
d["titreannee"] += "-" + str(d["annee_fin"])
|
|
||||||
d["annee"] += "-" + str(d["annee_fin"])
|
|
||||||
d["mois_debut"] = f"{self.date_debut.month} {self.date_debut.year}"
|
d["mois_debut"] = f"{self.date_debut.month} {self.date_debut.year}"
|
||||||
d["mois_fin"] = f"{self.date_fin.month} {self.date_fin.year}"
|
d["mois_fin"] = f"{self.date_fin.month} {self.date_fin.year}"
|
||||||
d["titremois"] = "%s %s (%s - %s)" % (
|
d["titremois"] = "%s %s (%s - %s)" % (
|
||||||
@ -332,6 +329,15 @@ class FormSemestre(db.Model):
|
|||||||
"-".join((imputation_dept, parcours_name, modalite, semestre_id, annee_sco))
|
"-".join((imputation_dept, parcours_name, modalite, semestre_id, annee_sco))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def titre_annee(self) -> str:
|
||||||
|
""" """
|
||||||
|
titre_annee = (
|
||||||
|
f"{self.titre_num()} {self.modalite or ''} {self.date_debut.year}"
|
||||||
|
)
|
||||||
|
if self.date_fin.year != self.date_debut.year:
|
||||||
|
titre_annee += "-" + str(self.date_fin.year)
|
||||||
|
return titre_annee
|
||||||
|
|
||||||
def titre_mois(self) -> str:
|
def titre_mois(self) -> str:
|
||||||
"""Le titre et les dates du semestre, pour affichage dans des listes
|
"""Le titre et les dates du semestre, pour affichage dans des listes
|
||||||
Ex: "BUT QLIO (PN 2022) semestre 1 FI (Sept 2022 - Jan 2023)"
|
Ex: "BUT QLIO (PN 2022) semestre 1 FI (Sept 2022 - Jan 2023)"
|
||||||
@ -359,15 +365,19 @@ class FormSemestre(db.Model):
|
|||||||
etudid, self.date_debut.isoformat(), self.date_fin.isoformat()
|
etudid, self.date_debut.isoformat(), self.date_fin.isoformat()
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_inscrits(self, include_demdef=False) -> list[Identite]:
|
def get_inscrits(self, include_demdef=False, order=False) -> list[Identite]:
|
||||||
"""Liste des étudiants inscrits à ce semestre
|
"""Liste des étudiants inscrits à ce semestre
|
||||||
Si include_demdef, tous les étudiants, avec les démissionnaires
|
Si include_demdef, tous les étudiants, avec les démissionnaires
|
||||||
et défaillants.
|
et défaillants.
|
||||||
|
Si order, tri par clé sort_key
|
||||||
"""
|
"""
|
||||||
if include_demdef:
|
if include_demdef:
|
||||||
return [ins.etud for ins in self.inscriptions]
|
etuds = [ins.etud for ins in self.inscriptions]
|
||||||
else:
|
else:
|
||||||
return [ins.etud for ins in self.inscriptions if ins.etat == scu.INSCRIT]
|
etuds = [ins.etud for ins in self.inscriptions if ins.etat == scu.INSCRIT]
|
||||||
|
if order:
|
||||||
|
etuds.sort(key=lambda e: e.sort_key)
|
||||||
|
return etuds
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def etudids_actifs(self) -> set:
|
def etudids_actifs(self) -> set:
|
||||||
|
@ -79,7 +79,7 @@ class ModuleImpl(db.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
"""as a dict, with the same conversions as in ScoDoc7"""
|
"""as a dict, with the same conversions as in ScoDoc7, including module"""
|
||||||
e = dict(self.__dict__)
|
e = dict(self.__dict__)
|
||||||
e.pop("_sa_instance_state", None)
|
e.pop("_sa_instance_state", None)
|
||||||
# ScoDoc7 output_formators: (backward compat)
|
# ScoDoc7 output_formators: (backward compat)
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import SHORT_STR_LEN
|
|
||||||
from app.models import CODE_STR_LEN
|
import app.scodoc.notesdb as ndb
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
class BulAppreciations(db.Model):
|
class BulAppreciations(db.Model):
|
||||||
@ -67,3 +68,32 @@ class NotesNotesLog(db.Model):
|
|||||||
comment = db.Column(db.Text) # texte libre
|
comment = db.Column(db.Text) # texte libre
|
||||||
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||||
uid = db.Column(db.Integer, db.ForeignKey("user.id"))
|
uid = db.Column(db.Integer, db.ForeignKey("user.id"))
|
||||||
|
|
||||||
|
|
||||||
|
def etud_has_notes_attente(etudid, formsemestre_id):
|
||||||
|
"""Vrai si cet etudiant a au moins une note en attente dans ce semestre.
|
||||||
|
(ne compte que les notes en attente dans des évaluation avec coef. non nul).
|
||||||
|
"""
|
||||||
|
# XXX ancienne méthode de notes_table à ré-écrire
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
|
cursor.execute(
|
||||||
|
"""SELECT n.*
|
||||||
|
FROM notes_notes n, notes_evaluation e, notes_moduleimpl m,
|
||||||
|
notes_moduleimpl_inscription i
|
||||||
|
WHERE n.etudid = %(etudid)s
|
||||||
|
and n.value = %(code_attente)s
|
||||||
|
and n.evaluation_id = e.id
|
||||||
|
and e.moduleimpl_id = m.id
|
||||||
|
and m.formsemestre_id = %(formsemestre_id)s
|
||||||
|
and e.coefficient != 0
|
||||||
|
and m.id = i.moduleimpl_id
|
||||||
|
and i.etudid=%(etudid)s
|
||||||
|
""",
|
||||||
|
{
|
||||||
|
"formsemestre_id": formsemestre_id,
|
||||||
|
"etudid": etudid,
|
||||||
|
"code_attente": scu.NOTES_ATTENTE,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return len(cursor.fetchall()) > 0
|
||||||
|
@ -87,7 +87,7 @@ def get_tags_latex(code_latex):
|
|||||||
"""
|
"""
|
||||||
if code_latex:
|
if code_latex:
|
||||||
# changé par EV: était r"([\*]{2}[a-zA-Z0-9:éèàâêëïôöù]+[\*]{2})"
|
# changé par EV: était r"([\*]{2}[a-zA-Z0-9:éèàâêëïôöù]+[\*]{2})"
|
||||||
res = re.findall(r"([\*]{2}[^ \t\n\r\f\v\*]+[\*]{2})", code_latex)
|
res = re.findall(r"([\*]{2}[^\t\n\r\f\v\*]+[\*]{2})", code_latex)
|
||||||
return [tag[2:-2] for tag in res]
|
return [tag[2:-2] for tag in res]
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
@ -46,9 +46,12 @@ import io
|
|||||||
import os
|
import os
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
|
|
||||||
from app.scodoc.gen_tables import GenTable, SeqGenTable
|
from app.scodoc.gen_tables import GenTable, SeqGenTable
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_codes_parcours # sco_codes_parcours.NEXT -> sem suivant
|
from app.scodoc import sco_codes_parcours # sco_codes_parcours.NEXT -> sem suivant
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
@ -174,6 +177,8 @@ class JuryPE(object):
|
|||||||
self.PARCOURSINFO_DICT = {} # Les parcours des étudiants
|
self.PARCOURSINFO_DICT = {} # Les parcours des étudiants
|
||||||
self.syntheseJury = {} # Le jury de synthèse
|
self.syntheseJury = {} # Le jury de synthèse
|
||||||
|
|
||||||
|
self.semestresDeScoDoc = sco_formsemestre.do_formsemestre_list()
|
||||||
|
|
||||||
# Calcul du jury PE
|
# Calcul du jury PE
|
||||||
self.exe_calculs_juryPE(semBase)
|
self.exe_calculs_juryPE(semBase)
|
||||||
self.synthetise_juryPE()
|
self.synthetise_juryPE()
|
||||||
@ -317,12 +322,10 @@ class JuryPE(object):
|
|||||||
etudiants = []
|
etudiants = []
|
||||||
for sem in semsListe: # pour chacun des semestres de la liste
|
for sem in semsListe: # pour chacun des semestres de la liste
|
||||||
|
|
||||||
# nt = self.get_notes_d_un_semestre( sem['formsemestre_id'] )
|
|
||||||
nt = self.get_cache_notes_d_un_semestre(sem["formsemestre_id"])
|
nt = self.get_cache_notes_d_un_semestre(sem["formsemestre_id"])
|
||||||
# sco_cache.NotesTableCache.get( sem['formsemestre_id'])
|
|
||||||
etudiantsDuSemestre = (
|
etudiantsDuSemestre = (
|
||||||
nt.get_etudids()
|
nt.get_etudids()
|
||||||
) # nt.identdict.keys() # identification des etudiants du semestre
|
) # identification des etudiants du semestre
|
||||||
|
|
||||||
if pe_tools.PE_DEBUG:
|
if pe_tools.PE_DEBUG:
|
||||||
pe_tools.pe_print(
|
pe_tools.pe_print(
|
||||||
@ -486,14 +489,14 @@ class JuryPE(object):
|
|||||||
lastdate = max(sesdates) # date de fin de l'inscription la plus récente
|
lastdate = max(sesdates) # date de fin de l'inscription la plus récente
|
||||||
|
|
||||||
# if PETable.AFFICHAGE_DEBUG_PE == True : pe_tools.pe_print(" derniere inscription = ", lastDateSem)
|
# if PETable.AFFICHAGE_DEBUG_PE == True : pe_tools.pe_print(" derniere inscription = ", lastDateSem)
|
||||||
semestresDeScoDoc = sco_formsemestre.do_formsemestre_list()
|
|
||||||
if sonDernierSidValide is None:
|
if sonDernierSidValide is None:
|
||||||
# si l'étudiant n'a validé aucun semestre, les prend tous ? (à vérifier)
|
# si l'étudiant n'a validé aucun semestre, les prend tous ? (à vérifier)
|
||||||
semestresSuperieurs = semestresDeScoDoc
|
semestresSuperieurs = self.semestresDeScoDoc
|
||||||
else:
|
else:
|
||||||
semestresSuperieurs = [
|
semestresSuperieurs = [
|
||||||
sem
|
sem
|
||||||
for sem in semestresDeScoDoc
|
for sem in self.semestresDeScoDoc
|
||||||
if sem["semestre_id"] > sonDernierSidValide
|
if sem["semestre_id"] > sonDernierSidValide
|
||||||
] # Semestre de rang plus élevé que son dernier sem valide
|
] # Semestre de rang plus élevé que son dernier sem valide
|
||||||
datesDesSemestresSuperieurs = [
|
datesDesSemestresSuperieurs = [
|
||||||
@ -1127,9 +1130,10 @@ class JuryPE(object):
|
|||||||
# ------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
def get_cache_notes_d_un_semestre(self, formsemestre_id): # inutile en realité !
|
def get_cache_notes_d_un_semestre(self, formsemestre_id: int) -> NotesTableCompat:
|
||||||
"""Charge la table des notes d'un formsemestre"""
|
"""Charge la table des notes d'un formsemestre"""
|
||||||
return sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
return res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -37,9 +37,13 @@ Created on Fri Sep 9 09:15:05 2016
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
|
from app.models.moduleimpls import ModuleImpl
|
||||||
|
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_tag_module
|
from app.scodoc import sco_tag_module
|
||||||
from app.pe import pe_tagtable
|
from app.pe import pe_tagtable
|
||||||
|
|
||||||
@ -52,7 +56,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
- nt: le tableau de notes du semestre considéré
|
- nt: le tableau de notes du semestre considéré
|
||||||
- nt.inscrlist: étudiants inscrits à ce semestre, par ordre alphabétique (avec demissions)
|
- nt.inscrlist: étudiants inscrits à ce semestre, par ordre alphabétique (avec demissions)
|
||||||
- nt.identdict: { etudid : ident }
|
- nt.identdict: { etudid : ident }
|
||||||
- nt._modimpls : liste des moduleimpl { ... 'module_id', ...}
|
- liste des moduleimpl { ... 'module_id', ...}
|
||||||
|
|
||||||
Attributs supplémentaires :
|
Attributs supplémentaires :
|
||||||
- inscrlist/identdict: étudiants inscrits hors démissionnaires ou défaillants
|
- inscrlist/identdict: étudiants inscrits hors démissionnaires ou défaillants
|
||||||
@ -97,7 +101,11 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
self.nt = notetable
|
self.nt = notetable
|
||||||
|
|
||||||
# Les attributs hérités : la liste des étudiants
|
# Les attributs hérités : la liste des étudiants
|
||||||
self.inscrlist = [etud for etud in self.nt.inscrlist if etud["etat"] == "I"]
|
self.inscrlist = [
|
||||||
|
etud
|
||||||
|
for etud in self.nt.inscrlist
|
||||||
|
if self.nt.get_etud_etat(etud["etudid"]) == "I"
|
||||||
|
]
|
||||||
self.identdict = {
|
self.identdict = {
|
||||||
etudid: ident
|
etudid: ident
|
||||||
for (etudid, ident) in self.nt.identdict.items()
|
for (etudid, ident) in self.nt.identdict.items()
|
||||||
@ -107,12 +115,15 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
# Les modules pris en compte dans le calcul des moyennes par tag => ceux des UE standards
|
# Les modules pris en compte dans le calcul des moyennes par tag => ceux des UE standards
|
||||||
self.modimpls = [
|
self.modimpls = [
|
||||||
modimpl
|
modimpl
|
||||||
for modimpl in self.nt._modimpls
|
for modimpl in self.nt.formsemestre.modimpls_sorted
|
||||||
if modimpl["ue"]["type"] == sco_codes_parcours.UE_STANDARD
|
if modimpl.module.ue.type == sco_codes_parcours.UE_STANDARD
|
||||||
] # la liste des modules (objet modimpl)
|
] # la liste des modules (objet modimpl)
|
||||||
# self._modimpl_ids = [modimpl['moduleimpl_id'] for modimpl in self._modimpls] # la liste de id des modules (modimpl_id)
|
|
||||||
self.somme_coeffs = sum(
|
self.somme_coeffs = sum(
|
||||||
[modimpl["module"]["coefficient"] for modimpl in self.modimpls]
|
[
|
||||||
|
modimpl.module.coefficient
|
||||||
|
for modimpl in self.modimpls
|
||||||
|
if modimpl.module.coefficient is not None
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@ -156,9 +167,9 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
tagdict = {}
|
tagdict = {}
|
||||||
|
|
||||||
for modimpl in self.modimpls:
|
for modimpl in self.modimpls:
|
||||||
modimpl_id = modimpl["moduleimpl_id"]
|
modimpl_id = modimpl.id
|
||||||
# liste des tags pour le modimpl concerné:
|
# liste des tags pour le modimpl concerné:
|
||||||
tags = sco_tag_module.module_tag_list(modimpl["module_id"])
|
tags = sco_tag_module.module_tag_list(modimpl.module.id)
|
||||||
|
|
||||||
for (
|
for (
|
||||||
tag
|
tag
|
||||||
@ -172,17 +183,13 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
|
|
||||||
# Ajout du modimpl au tagname considéré
|
# Ajout du modimpl au tagname considéré
|
||||||
tagdict[tagname][modimpl_id] = {
|
tagdict[tagname][modimpl_id] = {
|
||||||
"module_id": modimpl["module_id"], # les données sur le module
|
"module_id": modimpl.module.id, # les données sur le module
|
||||||
"coeff": modimpl["module"][
|
"coeff": modimpl.module.coefficient, # le coeff du module dans le semestre
|
||||||
"coefficient"
|
|
||||||
], # le coeff du module dans le semestre
|
|
||||||
"ponderation": ponderation, # la pondération demandée pour le tag sur le module
|
"ponderation": ponderation, # la pondération demandée pour le tag sur le module
|
||||||
"module_code": modimpl["module"][
|
"module_code": modimpl.module.code, # le code qui doit se retrouver à l'identique dans des ue capitalisee
|
||||||
"code"
|
"ue_id": modimpl.module.ue.id, # les données sur l'ue
|
||||||
], # le code qui doit se retrouver à l'identique dans des ue capitalisee
|
"ue_code": modimpl.module.ue.ue_code,
|
||||||
"ue_id": modimpl["ue"]["ue_id"], # les données sur l'ue
|
"ue_acronyme": modimpl.module.ue.acronyme,
|
||||||
"ue_code": modimpl["ue"]["ue_code"],
|
|
||||||
"ue_acronyme": modimpl["ue"]["acronyme"],
|
|
||||||
}
|
}
|
||||||
return tagdict
|
return tagdict
|
||||||
|
|
||||||
@ -218,7 +225,9 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
def get_moyennes_DUT(self):
|
def get_moyennes_DUT(self):
|
||||||
"""Lit les moyennes DUT du semestre pour tous les étudiants
|
"""Lit les moyennes DUT du semestre pour tous les étudiants
|
||||||
et les renvoie au même format que comp_MoyennesTag"""
|
et les renvoie au même format que comp_MoyennesTag"""
|
||||||
return [(self.nt.moy_gen[etudid], 1.0, etudid) for etudid in self.get_etudids()]
|
return [
|
||||||
|
(self.nt.etud_moy_gen[etudid], 1.0, etudid) for etudid in self.get_etudids()
|
||||||
|
]
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
def get_noteEtCoeff_modimpl(self, modimpl_id, etudid, profondeur=2):
|
||||||
@ -230,7 +239,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
"""
|
"""
|
||||||
(note, coeff_norm) = (None, None)
|
(note, coeff_norm) = (None, None)
|
||||||
|
|
||||||
modimpl = get_moduleimpl(self.nt, modimpl_id) # Le module considéré
|
modimpl = get_moduleimpl(modimpl_id) # Le module considéré
|
||||||
if modimpl == None or profondeur < 0:
|
if modimpl == None or profondeur < 0:
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
@ -238,14 +247,14 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
ue_capitalisees = self.get_ue_capitalisees(
|
ue_capitalisees = self.get_ue_capitalisees(
|
||||||
etudid
|
etudid
|
||||||
) # les ue capitalisées des étudiants
|
) # les ue capitalisées des étudiants
|
||||||
ue_capitalisees_id = [
|
ue_capitalisees_id = {
|
||||||
ue.id for ue in ue_capitalisees
|
ue_cap["ue_id"] for ue_cap in ue_capitalisees
|
||||||
] # les id des ue capitalisées
|
} # les id des ue capitalisées
|
||||||
|
|
||||||
# Si le module ne fait pas partie des UE capitalisées
|
# Si le module ne fait pas partie des UE capitalisées
|
||||||
if modimpl["module"]["ue_id"] not in ue_capitalisees_id:
|
if modimpl.module.ue.id not in ue_capitalisees_id:
|
||||||
note = self.nt.get_etud_mod_moy(modimpl_id, etudid) # lecture de la note
|
note = self.nt.get_etud_mod_moy(modimpl_id, etudid) # lecture de la note
|
||||||
coeff = modimpl["module"]["coefficient"] # le coeff
|
coeff = modimpl.module.coefficient # le coeff
|
||||||
coeff_norm = (
|
coeff_norm = (
|
||||||
coeff / self.somme_coeffs if self.somme_coeffs != 0 else 0
|
coeff / self.somme_coeffs if self.somme_coeffs != 0 else 0
|
||||||
) # le coeff normalisé
|
) # le coeff normalisé
|
||||||
@ -256,29 +265,30 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
self.nt, etudid, modimpl_id
|
self.nt, etudid, modimpl_id
|
||||||
) # la moyenne actuelle
|
) # la moyenne actuelle
|
||||||
# A quel semestre correspond l'ue capitalisée et quelles sont ses notes ?
|
# A quel semestre correspond l'ue capitalisée et quelles sont ses notes ?
|
||||||
# fid_prec = [ ue['formsemestre_id'] for ue in ue_capitalisees if ue['ue_id'] == modimpl['module']['ue_id'] ][0]
|
|
||||||
# semestre_id = modimpl['module']['semestre_id']
|
|
||||||
fids_prec = [
|
fids_prec = [
|
||||||
ue["formsemestre_id"]
|
ue_cap["formsemestre_id"]
|
||||||
for ue in ue_capitalisees
|
for ue_cap in ue_capitalisees
|
||||||
if ue.ue_code == modimpl["ue"]["ue_code"]
|
if ue_cap["ue_code"] == modimpl.module.ue.ue_code
|
||||||
] # and ue['semestre_id'] == semestre_id]
|
] # and ue['semestre_id'] == semestre_id]
|
||||||
if len(fids_prec) > 0:
|
if len(fids_prec) > 0:
|
||||||
# => le formsemestre_id du semestre dont vient la capitalisation
|
# => le formsemestre_id du semestre dont vient la capitalisation
|
||||||
fid_prec = fids_prec[0]
|
fid_prec = fids_prec[0]
|
||||||
# Lecture des notes de ce semestre
|
# Lecture des notes de ce semestre
|
||||||
nt_prec = sco_cache.NotesTableCache.get(
|
# le tableau de note du semestre considéré:
|
||||||
fid_prec
|
formsemestre_prec = FormSemestre.query.get_or_404(fid_prec)
|
||||||
) # le tableau de note du semestre considéré
|
nt_prec: NotesTableCompat = res_sem.load_formsemestre_results(
|
||||||
|
formsemestre_prec
|
||||||
|
)
|
||||||
|
|
||||||
# Y-a-t-il un module équivalent c'est à dire correspondant au même code (le module_id n'étant pas significatif en cas de changement de PPN)
|
# Y-a-t-il un module équivalent c'est à dire correspondant au même code (le module_id n'étant pas significatif en cas de changement de PPN)
|
||||||
|
|
||||||
modimpl_prec = [
|
modimpl_prec = [
|
||||||
module
|
modi
|
||||||
for module in nt_prec._modimpls
|
for modi in nt_prec.formsemestre.modimpls_sorted
|
||||||
if module["module"]["code"] == modimpl["module"]["code"]
|
if modi.module.code == modimpl.module.code
|
||||||
]
|
]
|
||||||
if len(modimpl_prec) > 0: # si une correspondance est trouvée
|
if len(modimpl_prec) > 0: # si une correspondance est trouvée
|
||||||
modprec_id = modimpl_prec[0]["moduleimpl_id"]
|
modprec_id = modimpl_prec[0].id
|
||||||
moy_ue_capitalisee = get_moy_ue_from_nt(nt_prec, etudid, modprec_id)
|
moy_ue_capitalisee = get_moy_ue_from_nt(nt_prec, etudid, modprec_id)
|
||||||
if (
|
if (
|
||||||
moy_ue_capitalisee is None
|
moy_ue_capitalisee is None
|
||||||
@ -286,7 +296,7 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
note = self.nt.get_etud_mod_moy(
|
note = self.nt.get_etud_mod_moy(
|
||||||
modimpl_id, etudid
|
modimpl_id, etudid
|
||||||
) # lecture de la note
|
) # lecture de la note
|
||||||
coeff = modimpl["module"]["coefficient"] # le coeff
|
coeff = modimpl.module.coefficient # le coeff
|
||||||
coeff_norm = (
|
coeff_norm = (
|
||||||
coeff / self.somme_coeffs if self.somme_coeffs != 0 else 0
|
coeff / self.somme_coeffs if self.somme_coeffs != 0 else 0
|
||||||
) # le coeff normalisé
|
) # le coeff normalisé
|
||||||
@ -300,13 +310,11 @@ class SemestreTag(pe_tagtable.TableTag):
|
|||||||
return (note, coeff_norm)
|
return (note, coeff_norm)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def get_ue_capitalisees(self, etudid) -> list[UniteEns]:
|
def get_ue_capitalisees(self, etudid) -> list[dict]:
|
||||||
"""Renvoie la liste des ue_id effectivement capitalisées par un étudiant"""
|
"""Renvoie la liste des capitalisation effectivement capitalisées par un étudiant"""
|
||||||
ue_ids = [
|
if etudid in self.nt.validations.ue_capitalisees.index:
|
||||||
ue_id
|
return self.nt.validations.ue_capitalisees.loc[[etudid]].to_dict("records")
|
||||||
for ue_id in self.nt.validations.ue_capitalisees.loc[[etudid]]["ue_id"]
|
return []
|
||||||
]
|
|
||||||
return [UniteEns.query.get(ue_id) for ue_id in ue_ids]
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid):
|
def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid):
|
||||||
@ -472,37 +480,27 @@ def comp_coeff_pond(coeffs, ponderations):
|
|||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def get_moduleimpl(nt, modimpl_id):
|
def get_moduleimpl(modimpl_id) -> dict:
|
||||||
"""Renvoie l'objet modimpl dont l'id est modimpl_id fourni dans la note table nt,
|
"""Renvoie l'objet modimpl dont l'id est modimpl_id"""
|
||||||
en utilisant l'attribut nt._modimpls"""
|
modimpl = ModuleImpl.query.get(modimpl_id)
|
||||||
modimplids = [
|
if modimpl:
|
||||||
modimpl["moduleimpl_id"] for modimpl in nt._modimpls
|
return modimpl
|
||||||
] # la liste de id des modules (modimpl_id)
|
|
||||||
if modimpl_id not in modimplids:
|
|
||||||
if SemestreTag.DEBUG:
|
if SemestreTag.DEBUG:
|
||||||
log(
|
log(
|
||||||
"SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas"
|
"SemestreTag.get_moduleimpl( %s ) : le modimpl recherche n'existe pas"
|
||||||
% (modimpl_id)
|
% (modimpl_id)
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
return nt._modimpls[modimplids.index(modimpl_id)]
|
|
||||||
|
|
||||||
|
|
||||||
# **********************************************
|
# **********************************************
|
||||||
def get_moy_ue_from_nt(nt, etudid, modimpl_id):
|
def get_moy_ue_from_nt(nt, etudid, modimpl_id) -> float:
|
||||||
"""Renvoie la moyenne de l'UE d'un etudid dans laquelle se trouve le module de modimpl_id
|
"""Renvoie la moyenne de l'UE d'un etudid dans laquelle se trouve
|
||||||
en partant du note table nt"""
|
le module de modimpl_id
|
||||||
mod = get_moduleimpl(nt, modimpl_id) # le module
|
"""
|
||||||
indice = 0
|
# ré-écrit
|
||||||
while indice < len(nt._ues):
|
modimpl = get_moduleimpl(modimpl_id) # le module
|
||||||
if (
|
ue_status = nt.get_etud_ue_status(etudid, modimpl.module.ue.id)
|
||||||
nt._ues[indice]["ue_id"] == mod["module"]["ue_id"]
|
if ue_status is None:
|
||||||
): # si les ue_id correspond
|
return None
|
||||||
data = [
|
return ue_status["moy"]
|
||||||
ligne for ligne in nt.T if ligne[-1] == etudid
|
|
||||||
] # les notes de l'étudiant
|
|
||||||
if data:
|
|
||||||
return data[0][indice + 1] # la moyenne à l'ue
|
|
||||||
else:
|
|
||||||
indice += 1
|
|
||||||
return None # si non trouvé
|
|
||||||
|
@ -68,7 +68,7 @@ class TableTag(object):
|
|||||||
self.taglist = []
|
self.taglist = []
|
||||||
|
|
||||||
self.resultats = {}
|
self.resultats = {}
|
||||||
self.etud_moy_gen_ranks = {}
|
self.rangs = {}
|
||||||
self.statistiques = {}
|
self.statistiques = {}
|
||||||
|
|
||||||
# *****************************************************************************************************************
|
# *****************************************************************************************************************
|
||||||
|
@ -254,13 +254,13 @@ class TF(object):
|
|||||||
continue # allowed empty field, skip
|
continue # allowed empty field, skip
|
||||||
# type
|
# type
|
||||||
typ = descr.get("type", "string")
|
typ = descr.get("type", "string")
|
||||||
if val != "" and val != None:
|
if val != "" and val is not None:
|
||||||
# check only non-null values
|
# check only non-null values
|
||||||
if typ[:3] == "int":
|
if typ[:3] == "int":
|
||||||
try:
|
try:
|
||||||
val = int(val)
|
val = int(val)
|
||||||
self.values[field] = val
|
self.values[field] = val
|
||||||
except:
|
except ValueError:
|
||||||
msg.append(
|
msg.append(
|
||||||
"La valeur du champ '%s' doit être un nombre entier" % field
|
"La valeur du champ '%s' doit être un nombre entier" % field
|
||||||
)
|
)
|
||||||
@ -270,30 +270,24 @@ class TF(object):
|
|||||||
try:
|
try:
|
||||||
val = float(val.replace(",", ".")) # allow ,
|
val = float(val.replace(",", ".")) # allow ,
|
||||||
self.values[field] = val
|
self.values[field] = val
|
||||||
except:
|
except ValueError:
|
||||||
msg.append(
|
msg.append(
|
||||||
"La valeur du champ '%s' doit être un nombre" % field
|
"La valeur du champ '%s' doit être un nombre" % field
|
||||||
)
|
)
|
||||||
ok = 0
|
ok = 0
|
||||||
if typ[:3] == "int" or typ == "float" or typ == "real":
|
|
||||||
if (
|
if (
|
||||||
val != ""
|
ok
|
||||||
|
and (typ[:3] == "int" or typ == "float" or typ == "real")
|
||||||
|
and val != ""
|
||||||
and val != None
|
and val != None
|
||||||
and "min_value" in descr
|
|
||||||
and val < descr["min_value"]
|
|
||||||
):
|
):
|
||||||
|
if "min_value" in descr and self.values[field] < descr["min_value"]:
|
||||||
msg.append(
|
msg.append(
|
||||||
"La valeur (%d) du champ '%s' est trop petite (min=%s)"
|
"La valeur (%d) du champ '%s' est trop petite (min=%s)"
|
||||||
% (val, field, descr["min_value"])
|
% (val, field, descr["min_value"])
|
||||||
)
|
)
|
||||||
ok = 0
|
ok = 0
|
||||||
|
if "max_value" in descr and self.values[field] > descr["max_value"]:
|
||||||
if (
|
|
||||||
val != ""
|
|
||||||
and val != None
|
|
||||||
and "max_value" in descr
|
|
||||||
and val > descr["max_value"]
|
|
||||||
):
|
|
||||||
msg.append(
|
msg.append(
|
||||||
"La valeur (%s) du champ '%s' est trop grande (max=%s)"
|
"La valeur (%s) du champ '%s' est trop grande (max=%s)"
|
||||||
% (val, field, descr["max_value"])
|
% (val, field, descr["max_value"])
|
||||||
|
@ -171,7 +171,7 @@ class NotesTable:
|
|||||||
|
|
||||||
def __init__(self, formsemestre_id):
|
def __init__(self, formsemestre_id):
|
||||||
# log(f"NotesTable( formsemestre_id={formsemestre_id} )")
|
# log(f"NotesTable( formsemestre_id={formsemestre_id} )")
|
||||||
# raise NotImplementedError() # XXX
|
raise NotImplementedError() # XXX
|
||||||
if not formsemestre_id:
|
if not formsemestre_id:
|
||||||
raise ValueError("invalid formsemestre_id (%s)" % formsemestre_id)
|
raise ValueError("invalid formsemestre_id (%s)" % formsemestre_id)
|
||||||
self.formsemestre_id = formsemestre_id
|
self.formsemestre_id = formsemestre_id
|
||||||
@ -954,9 +954,12 @@ class NotesTable:
|
|||||||
|
|
||||||
Return: True|False, message explicatif
|
Return: True|False, message explicatif
|
||||||
"""
|
"""
|
||||||
return self.parcours.check_barre_ues(
|
ue_status_list = []
|
||||||
[self.get_etud_ue_status(etudid, ue["ue_id"]) for ue in self._ues]
|
for ue in self._ues:
|
||||||
)
|
ue_status = self.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
|
if ue_status:
|
||||||
|
ue_status_list.append(ue_status)
|
||||||
|
return self.parcours.check_barre_ues(ue_status_list)
|
||||||
|
|
||||||
def get_table_moyennes_triees(self):
|
def get_table_moyennes_triees(self):
|
||||||
return self.T
|
return self.T
|
||||||
@ -1160,9 +1163,11 @@ class NotesTable:
|
|||||||
nt_cap = sco_cache.NotesTableCache.get(
|
nt_cap = sco_cache.NotesTableCache.get(
|
||||||
ue_cap["formsemestre_id"]
|
ue_cap["formsemestre_id"]
|
||||||
) # > UE capitalisees par un etud
|
) # > UE capitalisees par un etud
|
||||||
moy_ue_cap = nt_cap.get_etud_ue_status(etudid, ue_cap["ue_id"])[
|
ue_cap_status = nt_cap.get_etud_ue_status(etudid, ue_cap["ue_id"])
|
||||||
"moy"
|
if ue_cap_status:
|
||||||
]
|
moy_ue_cap = ue_cap_status["moy"]
|
||||||
|
else:
|
||||||
|
moy_ue_cap = ""
|
||||||
ue_cap["moy_ue"] = moy_ue_cap
|
ue_cap["moy_ue"] = moy_ue_cap
|
||||||
if (
|
if (
|
||||||
isinstance(moy_ue_cap, float)
|
isinstance(moy_ue_cap, float)
|
||||||
|
@ -479,7 +479,7 @@ def _get_abs_description(a, cursor=None):
|
|||||||
)
|
)
|
||||||
if Mlist:
|
if Mlist:
|
||||||
M = Mlist[0]
|
M = Mlist[0]
|
||||||
module += "%s " % M["module"]["code"]
|
module += "%s " % (M["module"]["code"] or "(module sans code)")
|
||||||
|
|
||||||
if desc:
|
if desc:
|
||||||
return "(%s) %s" % (desc, module)
|
return "(%s) %s" % (desc, module)
|
||||||
|
@ -33,7 +33,9 @@ import datetime
|
|||||||
from flask import url_for, g, request, abort
|
from flask import url_for, g, request, abort
|
||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
from app.models import Identite
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import Identite, FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
@ -118,13 +120,16 @@ def doSignaleAbsence(
|
|||||||
if moduleimpl_id and moduleimpl_id != "NULL":
|
if moduleimpl_id and moduleimpl_id != "NULL":
|
||||||
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)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
ues = nt.get_ues_stat_dict()
|
ues = nt.get_ues_stat_dict()
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
modimpls = nt.get_modimpls_dict(ue_id=ue["ue_id"])
|
modimpls = nt.get_modimpls_dict(ue_id=ue["ue_id"])
|
||||||
for modimpl in modimpls:
|
for modimpl in modimpls:
|
||||||
if modimpl["moduleimpl_id"] == moduleimpl_id:
|
if modimpl["moduleimpl_id"] == moduleimpl_id:
|
||||||
indication_module = "dans le module %s" % modimpl["module"]["code"]
|
indication_module = "dans le module %s" % (
|
||||||
|
modimpl["module"]["code"] or "(pas de code)"
|
||||||
|
)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
page_title=f"Signalement d'une absence pour {etud.nomprenom}",
|
page_title=f"Signalement d'une absence pour {etud.nomprenom}",
|
||||||
@ -179,11 +184,12 @@ def SignaleAbsenceEtud(): # etudid implied
|
|||||||
menu_module = ""
|
menu_module = ""
|
||||||
else:
|
else:
|
||||||
formsemestre_id = etud["cursem"]["formsemestre_id"]
|
formsemestre_id = etud["cursem"]["formsemestre_id"]
|
||||||
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
ues = nt.get_ues_stat_dict()
|
||||||
require_module = sco_preferences.get_preference(
|
require_module = sco_preferences.get_preference(
|
||||||
"abs_require_module", formsemestre_id
|
"abs_require_module", formsemestre_id
|
||||||
)
|
)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
|
||||||
ues = nt.get_ues_stat_dict()
|
|
||||||
if require_module:
|
if require_module:
|
||||||
menu_module = """
|
menu_module = """
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -214,7 +220,7 @@ def SignaleAbsenceEtud(): # etudid implied
|
|||||||
"""<option value="%(modimpl_id)s">%(modname)s</option>\n"""
|
"""<option value="%(modimpl_id)s">%(modname)s</option>\n"""
|
||||||
% {
|
% {
|
||||||
"modimpl_id": modimpl["moduleimpl_id"],
|
"modimpl_id": modimpl["moduleimpl_id"],
|
||||||
"modname": modimpl["module"]["code"],
|
"modname": modimpl["module"]["code"] or "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
menu_module += """</select></p>"""
|
menu_module += """</select></p>"""
|
||||||
@ -960,10 +966,10 @@ def _tables_abs_etud(
|
|||||||
ex.append(
|
ex.append(
|
||||||
f"""<a href="{url_for('notes.moduleimpl_status',
|
f"""<a href="{url_for('notes.moduleimpl_status',
|
||||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
||||||
">{mod["module"]["code"]}</a>"""
|
">{mod["module"]["code"] or "(module sans code)"}</a>"""
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ex.append(mod["module"]["code"])
|
ex.append(mod["module"]["code"] or "(module sans code)")
|
||||||
if ex:
|
if ex:
|
||||||
return ", ".join(ex)
|
return ", ".join(ex)
|
||||||
return ""
|
return ""
|
||||||
@ -978,10 +984,10 @@ def _tables_abs_etud(
|
|||||||
ex.append(
|
ex.append(
|
||||||
f"""<a href="{url_for('notes.moduleimpl_status',
|
f"""<a href="{url_for('notes.moduleimpl_status',
|
||||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
scodoc_dept=g.scodoc_dept, moduleimpl_id=mod["moduleimpl_id"])}
|
||||||
">{mod["module"]["code"]}</a>"""
|
">{mod["module"]["code"] or '(module sans code)'}</a>"""
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ex.append(mod["module"]["code"])
|
ex.append(mod["module"]["code"] or "(module sans code)")
|
||||||
if ex:
|
if ex:
|
||||||
return ", ".join(ex)
|
return ", ".join(ex)
|
||||||
return ""
|
return ""
|
||||||
|
@ -95,9 +95,12 @@ from flask import send_file
|
|||||||
# Pour la détection auto de l'encodage des fichiers Apogée:
|
# Pour la détection auto de l'encodage des fichiers Apogée:
|
||||||
from chardet import detect as chardet_detect
|
from chardet import detect as chardet_detect
|
||||||
|
|
||||||
|
from app import log
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
from app.models.config import ScoDocSiteConfig
|
from app.models.config import ScoDocSiteConfig
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
|
||||||
from app.scodoc.sco_exceptions import ScoValueError, ScoFormatError
|
from app.scodoc.sco_exceptions import ScoValueError, ScoFormatError
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||||
@ -370,7 +373,9 @@ class ApoEtud(dict):
|
|||||||
dict: with N, B, J, R keys, ou None si elt non trouvé
|
dict: with N, B, J, R keys, ou None si elt non trouvé
|
||||||
"""
|
"""
|
||||||
etudid = self.etud["etudid"]
|
etudid = self.etud["etudid"]
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
if etudid not in nt.identdict:
|
if etudid not in nt.identdict:
|
||||||
return None # etudiant non inscrit dans ce semestre
|
return None # etudiant non inscrit dans ce semestre
|
||||||
|
|
||||||
@ -419,7 +424,7 @@ class ApoEtud(dict):
|
|||||||
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
code_decision_ue = decisions_ue[ue["ue_id"]]["code"]
|
code_decision_ue = decisions_ue[ue["ue_id"]]["code"]
|
||||||
return dict(
|
return dict(
|
||||||
N=_apo_fmt_note(ue_status["moy"]),
|
N=_apo_fmt_note(ue_status["moy"] if ue_status else ""),
|
||||||
B=20,
|
B=20,
|
||||||
J="",
|
J="",
|
||||||
R=ScoDocSiteConfig.get_code_apo(code_decision_ue),
|
R=ScoDocSiteConfig.get_code_apo(code_decision_ue),
|
||||||
@ -476,7 +481,8 @@ class ApoEtud(dict):
|
|||||||
# l'étudiant n'a pas de semestre courant ?!
|
# l'étudiant n'a pas de semestre courant ?!
|
||||||
log("comp_elt_annuel: etudid %s has no cur_sem" % etudid)
|
log("comp_elt_annuel: etudid %s has no cur_sem" % etudid)
|
||||||
return VOID_APO_RES
|
return VOID_APO_RES
|
||||||
cur_nt = sco_cache.NotesTableCache.get(cur_sem["formsemestre_id"])
|
cur_formsemestre = FormSemestre.query.get_or_404(cur_sem["formsemestre_id"])
|
||||||
|
cur_nt: NotesTableCompat = res_sem.load_formsemestre_results(cur_formsemestre)
|
||||||
cur_decision = cur_nt.get_etud_decision_sem(etudid)
|
cur_decision = cur_nt.get_etud_decision_sem(etudid)
|
||||||
if not cur_decision:
|
if not cur_decision:
|
||||||
# pas de decision => pas de résultat annuel
|
# pas de decision => pas de résultat annuel
|
||||||
@ -493,7 +499,10 @@ class ApoEtud(dict):
|
|||||||
|
|
||||||
decision_apo = ScoDocSiteConfig.get_code_apo(cur_decision["code"])
|
decision_apo = ScoDocSiteConfig.get_code_apo(cur_decision["code"])
|
||||||
|
|
||||||
autre_nt = sco_cache.NotesTableCache.get(autre_sem["formsemestre_id"])
|
autre_formsemestre = FormSemestre.query.get_or_404(autre_sem["formsemestre_id"])
|
||||||
|
autre_nt: NotesTableCompat = res_sem.load_formsemestre_results(
|
||||||
|
autre_formsemestre
|
||||||
|
)
|
||||||
autre_decision = autre_nt.get_etud_decision_sem(etudid)
|
autre_decision = autre_nt.get_etud_decision_sem(etudid)
|
||||||
if not autre_decision:
|
if not autre_decision:
|
||||||
# pas de decision dans l'autre => pas de résultat annuel
|
# pas de decision dans l'autre => pas de résultat annuel
|
||||||
@ -554,7 +563,8 @@ class ApoEtud(dict):
|
|||||||
# prend le plus recent avec decision
|
# prend le plus recent avec decision
|
||||||
cur_sem = None
|
cur_sem = None
|
||||||
for sem in cur_sems:
|
for sem in cur_sems:
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
decision = nt.get_etud_decision_sem(self.etud["etudid"])
|
decision = nt.get_etud_decision_sem(self.etud["etudid"])
|
||||||
if decision:
|
if decision:
|
||||||
cur_sem = sem
|
cur_sem = sem
|
||||||
@ -614,7 +624,8 @@ class ApoEtud(dict):
|
|||||||
else:
|
else:
|
||||||
autre_sem = None
|
autre_sem = None
|
||||||
for sem in autres_sems:
|
for sem in autres_sems:
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
decision = nt.get_etud_decision_sem(self.etud["etudid"])
|
decision = nt.get_etud_decision_sem(self.etud["etudid"])
|
||||||
if decision:
|
if decision:
|
||||||
autre_sem = sem
|
autre_sem = sem
|
||||||
@ -947,7 +958,8 @@ class ApoData(object):
|
|||||||
s.add(code)
|
s.add(code)
|
||||||
continue
|
continue
|
||||||
# associé à une UE:
|
# associé à une UE:
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
for ue in nt.get_ues_stat_dict():
|
for ue in nt.get_ues_stat_dict():
|
||||||
if ue["code_apogee"] and code in ue["code_apogee"].split(","):
|
if ue["code_apogee"] and code in ue["code_apogee"].split(","):
|
||||||
s.add(code)
|
s.add(code)
|
||||||
|
@ -132,19 +132,29 @@ BACS_S = {t[0]: t[2:] for t in _BACS}
|
|||||||
|
|
||||||
class Baccalaureat:
|
class Baccalaureat:
|
||||||
def __init__(self, bac, specialite=""):
|
def __init__(self, bac, specialite=""):
|
||||||
self.bac = bac
|
self.bac = bac or ""
|
||||||
self.specialite = specialite
|
self.specialite = specialite or ""
|
||||||
self._abbrev, self._type = BACS_SSP.get((bac, specialite), (None, None))
|
self._abbrev, self._type = BACS_SSP.get(
|
||||||
|
(self.bac, self.specialite), (None, None)
|
||||||
|
)
|
||||||
# Parfois, la specialite commence par la serie: essaye
|
# Parfois, la specialite commence par la serie: essaye
|
||||||
if self._type is None and specialite and specialite.startswith(bac):
|
if (
|
||||||
specialite = specialite[len(bac) :].strip(" -")
|
self._type is None
|
||||||
self._abbrev, self._type = BACS_SSP.get((bac, specialite), (None, None))
|
and self.specialite
|
||||||
|
and self.specialite.startswith(self.bac)
|
||||||
|
):
|
||||||
|
specialite = self.specialite[len(self.bac) :].strip(" -")
|
||||||
|
self._abbrev, self._type = BACS_SSP.get(
|
||||||
|
(self.bac, specialite), (None, None)
|
||||||
|
)
|
||||||
# Cherche la forme serie specialite
|
# Cherche la forme serie specialite
|
||||||
if self._type is None and specialite:
|
if self._type is None and specialite:
|
||||||
self._abbrev, self._type = BACS_S.get(bac + " " + specialite, (None, None))
|
self._abbrev, self._type = BACS_S.get(
|
||||||
|
self.bac + " " + specialite, (None, None)
|
||||||
|
)
|
||||||
# Cherche avec juste le bac, sans specialite
|
# Cherche avec juste le bac, sans specialite
|
||||||
if self._type is None:
|
if self._type is None:
|
||||||
self._abbrev, self._type = BACS_S.get(bac, (None, None))
|
self._abbrev, self._type = BACS_S.get(self.bac, (None, None))
|
||||||
|
|
||||||
def abbrev(self):
|
def abbrev(self):
|
||||||
"abbreviation for this bac"
|
"abbreviation for this bac"
|
||||||
|
@ -28,30 +28,21 @@
|
|||||||
"""Génération des bulletins de notes
|
"""Génération des bulletins de notes
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from app.models import formsemestre
|
|
||||||
import time
|
|
||||||
import pprint
|
|
||||||
import email
|
import email
|
||||||
from email.mime.multipart import MIMEMultipart
|
import pprint
|
||||||
from email.mime.text import MIMEText
|
import time
|
||||||
from email.mime.base import MIMEBase
|
|
||||||
from email.header import Header
|
|
||||||
from reportlab.lib.colors import Color
|
|
||||||
import urllib
|
|
||||||
|
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from flask_mail import Message
|
from flask_mail import Message
|
||||||
from app.models.moduleimpls import ModuleImplInscription
|
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
from app import email
|
||||||
from app.scodoc.sco_utils import ModuleType
|
|
||||||
import app.scodoc.notesdb as ndb
|
|
||||||
from app import log
|
from app import log
|
||||||
|
from app.but import bulletin_but
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_common import NotesTableCompat
|
from app.comp.res_common import NotesTableCompat
|
||||||
from app.models import FormSemestre
|
from app.models import FormSemestre, Identite, ModuleImplInscription
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
@ -60,9 +51,9 @@ from app.scodoc import sco_abs
|
|||||||
from app.scodoc import sco_abs_views
|
from app.scodoc import sco_abs_views
|
||||||
from app.scodoc import sco_bulletins_generator
|
from app.scodoc import sco_bulletins_generator
|
||||||
from app.scodoc import sco_bulletins_json
|
from app.scodoc import sco_bulletins_json
|
||||||
|
from app.scodoc import sco_bulletins_pdf
|
||||||
from app.scodoc import sco_bulletins_xml
|
from app.scodoc import sco_bulletins_xml
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
@ -73,7 +64,9 @@ 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
|
||||||
from app.scodoc import sco_users
|
from app.scodoc import sco_users
|
||||||
from app import email
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
|
import app.scodoc.notesdb as ndb
|
||||||
|
|
||||||
# ----- CLASSES DE BULLETINS DE NOTES
|
# ----- CLASSES DE BULLETINS DE NOTES
|
||||||
from app.scodoc import sco_bulletins_standard
|
from app.scodoc import sco_bulletins_standard
|
||||||
@ -140,7 +133,6 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
|||||||
raise ValueError("invalid version code !")
|
raise ValueError("invalid version code !")
|
||||||
|
|
||||||
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
||||||
# nt = sco_cache.NotesTableCache.get(formsemestre_id) # > toutes notes
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
if not nt.get_etud_etat(etudid):
|
if not nt.get_etud_etat(etudid):
|
||||||
@ -191,28 +183,18 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
|||||||
show_mention=prefs["bul_show_mention"],
|
show_mention=prefs["bul_show_mention"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if dpv:
|
|
||||||
I["decision_sem"] = dpv["decisions"][0]["decision_sem"]
|
|
||||||
else:
|
|
||||||
I["decision_sem"] = ""
|
|
||||||
I.update(infos)
|
I.update(infos)
|
||||||
|
|
||||||
I["etud_etat_html"] = _get_etud_etat_html(
|
I["etud_etat_html"] = _get_etud_etat_html(
|
||||||
formsemestre.etuds_inscriptions[etudid].etat
|
formsemestre.etuds_inscriptions[etudid].etat
|
||||||
)
|
)
|
||||||
I["etud_etat"] = nt.get_etud_etat(etudid)
|
I["etud_etat"] = nt.get_etud_etat(etudid)
|
||||||
I["filigranne"] = ""
|
I["filigranne"] = sco_bulletins_pdf.get_filigranne(I["etud_etat"], prefs)
|
||||||
I["demission"] = ""
|
I["demission"] = ""
|
||||||
if I["etud_etat"] == "D":
|
if I["etud_etat"] == scu.DEMISSION:
|
||||||
I["demission"] = "(Démission)"
|
I["demission"] = "(Démission)"
|
||||||
I["filigranne"] = "Démission"
|
|
||||||
elif I["etud_etat"] == sco_codes_parcours.DEF:
|
elif I["etud_etat"] == sco_codes_parcours.DEF:
|
||||||
I["demission"] = "(Défaillant)"
|
I["demission"] = "(Défaillant)"
|
||||||
I["filigranne"] = "Défaillant"
|
|
||||||
elif (prefs["bul_show_temporary"] and not I["decision_sem"]) or prefs[
|
|
||||||
"bul_show_temporary_forced"
|
|
||||||
]:
|
|
||||||
I["filigranne"] = prefs["bul_temporary_txt"]
|
|
||||||
|
|
||||||
# --- Appreciations
|
# --- Appreciations
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
@ -363,10 +345,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
|||||||
>{u["ue_descr_txt"]} pouet</a>
|
>{u["ue_descr_txt"]} pouet</a>
|
||||||
"""
|
"""
|
||||||
if ue_status["moy"] != "NA" and ue_status["formsemestre_id"]:
|
if ue_status["moy"] != "NA" and ue_status["formsemestre_id"]:
|
||||||
# detail des modules de l'UE capitalisee
|
# détail des modules de l'UE capitalisée
|
||||||
# nt_cap = sco_cache.NotesTableCache.get(
|
|
||||||
# ue_status["formsemestre_id"]
|
|
||||||
# ) # > toutes notes
|
|
||||||
formsemestre_cap = FormSemestre.query.get_or_404(
|
formsemestre_cap = FormSemestre.query.get_or_404(
|
||||||
ue_status["formsemestre_id"]
|
ue_status["formsemestre_id"]
|
||||||
)
|
)
|
||||||
@ -518,7 +497,7 @@ def _ue_mod_bulletin(etudid, formsemestre_id, ue_id, modimpls, nt, version):
|
|||||||
)
|
)
|
||||||
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
||||||
mod["code"] = modimpl["module"]["code"]
|
mod["code"] = modimpl["module"]["code"]
|
||||||
mod["code_html"] = link_mod + mod["code"] + "</a>"
|
mod["code_html"] = link_mod + (mod["code"] or "") + "</a>"
|
||||||
else:
|
else:
|
||||||
mod["code"] = mod["code_html"] = ""
|
mod["code"] = mod["code_html"] = ""
|
||||||
mod["name"] = (
|
mod["name"] = (
|
||||||
@ -536,7 +515,7 @@ def _ue_mod_bulletin(etudid, formsemestre_id, ue_id, modimpls, nt, version):
|
|||||||
% (modimpl["moduleimpl_id"], mod_descr)
|
% (modimpl["moduleimpl_id"], mod_descr)
|
||||||
)
|
)
|
||||||
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
||||||
mod["code_txt"] = modimpl["module"]["code"]
|
mod["code_txt"] = modimpl["module"]["code"] or ""
|
||||||
mod["code_html"] = link_mod + mod["code_txt"] + "</a>"
|
mod["code_html"] = link_mod + mod["code_txt"] + "</a>"
|
||||||
else:
|
else:
|
||||||
mod["code_txt"] = ""
|
mod["code_txt"] = ""
|
||||||
@ -621,7 +600,12 @@ def _ue_mod_bulletin(etudid, formsemestre_id, ue_id, modimpls, nt, version):
|
|||||||
e["note_txt"] = e["note_html"] = ""
|
e["note_txt"] = e["note_html"] = ""
|
||||||
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
||||||
# Classement
|
# Classement
|
||||||
if bul_show_mod_rangs and mod["mod_moy_txt"] != "-" and not is_malus:
|
if (
|
||||||
|
bul_show_mod_rangs
|
||||||
|
and (nt.mod_rangs is not None)
|
||||||
|
and mod["mod_moy_txt"] != "-"
|
||||||
|
and not is_malus
|
||||||
|
):
|
||||||
rg = nt.mod_rangs[modimpl["moduleimpl_id"]]
|
rg = nt.mod_rangs[modimpl["moduleimpl_id"]]
|
||||||
if rg[0] is None:
|
if rg[0] is None:
|
||||||
mod["mod_rang_txt"] = ""
|
mod["mod_rang_txt"] = ""
|
||||||
@ -686,6 +670,7 @@ def etud_descr_situation_semestre(
|
|||||||
descr_defaillance : "Défaillant" ou vide si non défaillant.
|
descr_defaillance : "Défaillant" ou vide si non défaillant.
|
||||||
decision_jury : "Validé", "Ajourné", ... (code semestre)
|
decision_jury : "Validé", "Ajourné", ... (code semestre)
|
||||||
descr_decision_jury : "Décision jury: Validé" (une phrase)
|
descr_decision_jury : "Décision jury: Validé" (une phrase)
|
||||||
|
decision_sem :
|
||||||
decisions_ue : noms (acronymes) des UE validées, séparées par des virgules.
|
decisions_ue : noms (acronymes) des UE validées, séparées par des virgules.
|
||||||
descr_decisions_ue : ' UE acquises: UE1, UE2', ou vide si pas de dec. ou si pas show_uevalid
|
descr_decisions_ue : ' UE acquises: UE1, UE2', ou vide si pas de dec. ou si pas show_uevalid
|
||||||
descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention
|
descr_mention : 'Mention Bien', ou vide si pas de mention ou si pas show_mention
|
||||||
@ -695,7 +680,7 @@ def etud_descr_situation_semestre(
|
|||||||
|
|
||||||
# --- Situation et décisions jury
|
# --- Situation et décisions jury
|
||||||
|
|
||||||
# demission/inscription ?
|
# démission/inscription ?
|
||||||
events = sco_etud.scolar_events_list(
|
events = sco_etud.scolar_events_list(
|
||||||
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
|
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
|
||||||
)
|
)
|
||||||
@ -762,11 +747,15 @@ def etud_descr_situation_semestre(
|
|||||||
infos["situation"] += " " + infos["descr_defaillance"]
|
infos["situation"] += " " + infos["descr_defaillance"]
|
||||||
|
|
||||||
dpv = sco_pvjury.dict_pvjury(formsemestre_id, etudids=[etudid])
|
dpv = sco_pvjury.dict_pvjury(formsemestre_id, etudids=[etudid])
|
||||||
|
if dpv:
|
||||||
|
infos["decision_sem"] = dpv["decisions"][0]["decision_sem"]
|
||||||
|
else:
|
||||||
|
infos["decision_sem"] = ""
|
||||||
|
|
||||||
if not show_decisions:
|
if not show_decisions:
|
||||||
return infos, dpv
|
return infos, dpv
|
||||||
|
|
||||||
# Decisions de jury:
|
# Décisions de jury:
|
||||||
pv = dpv["decisions"][0]
|
pv = dpv["decisions"][0]
|
||||||
dec = ""
|
dec = ""
|
||||||
if pv["decision_sem_descr"]:
|
if pv["decision_sem_descr"]:
|
||||||
@ -818,11 +807,15 @@ def formsemestre_bulletinetud(
|
|||||||
except:
|
except:
|
||||||
sco_etud.log_unknown_etud()
|
sco_etud.log_unknown_etud()
|
||||||
raise ScoValueError("étudiant inconnu")
|
raise ScoValueError("étudiant inconnu")
|
||||||
# API, donc erreurs admises en ScoValueError
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True)
|
formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id)
|
||||||
|
if not formsemestre:
|
||||||
|
# API, donc erreurs admises
|
||||||
|
raise ScoValueError(f"semestre {formsemestre_id} inconnu !")
|
||||||
|
sem = formsemestre.to_dict()
|
||||||
|
|
||||||
bulletin = do_formsemestre_bulletinetud(
|
bulletin = do_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre,
|
||||||
etudid,
|
etudid,
|
||||||
format=format,
|
format=format,
|
||||||
version=version,
|
version=version,
|
||||||
@ -834,7 +827,6 @@ def formsemestre_bulletinetud(
|
|||||||
filename = scu.bul_filename(sem, etud, format)
|
filename = scu.bul_filename(sem, etud, format)
|
||||||
return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0])
|
return scu.send_file(bulletin, filename, mime=scu.get_mime_suffix(format)[0])
|
||||||
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
|
||||||
H = [
|
H = [
|
||||||
_formsemestre_bulletinetud_header_html(
|
_formsemestre_bulletinetud_header_html(
|
||||||
etud, etudid, sem, formsemestre_id, format, version
|
etud, etudid, sem, formsemestre_id, format, version
|
||||||
@ -891,14 +883,14 @@ def can_send_bulletin_by_mail(formsemestre_id):
|
|||||||
|
|
||||||
|
|
||||||
def do_formsemestre_bulletinetud(
|
def do_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre: FormSemestre,
|
||||||
etudid,
|
etudid: int,
|
||||||
version="long", # short, long, selectedevals
|
version="long", # short, long, selectedevals
|
||||||
format="html",
|
format="html",
|
||||||
nohtml=False,
|
nohtml=False,
|
||||||
xml_with_decisions=False, # force decisions dans XML
|
xml_with_decisions=False, # force décisions dans XML
|
||||||
force_publishing=False, # force publication meme si semestre non publie sur "portail"
|
force_publishing=False, # force publication meme si semestre non publié sur "portail"
|
||||||
prefer_mail_perso=False, # mails envoyes sur adresse perso si non vide
|
prefer_mail_perso=False, # mails envoyés sur adresse perso si non vide
|
||||||
):
|
):
|
||||||
"""Génère le bulletin au format demandé.
|
"""Génère le bulletin au format demandé.
|
||||||
Retourne: (bul, filigranne)
|
Retourne: (bul, filigranne)
|
||||||
@ -907,7 +899,7 @@ def do_formsemestre_bulletinetud(
|
|||||||
"""
|
"""
|
||||||
if format == "xml":
|
if format == "xml":
|
||||||
bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud(
|
bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre.id,
|
||||||
etudid,
|
etudid,
|
||||||
xml_with_decisions=xml_with_decisions,
|
xml_with_decisions=xml_with_decisions,
|
||||||
force_publishing=force_publishing,
|
force_publishing=force_publishing,
|
||||||
@ -918,7 +910,7 @@ def do_formsemestre_bulletinetud(
|
|||||||
|
|
||||||
elif format == "json":
|
elif format == "json":
|
||||||
bul = sco_bulletins_json.make_json_formsemestre_bulletinetud(
|
bul = sco_bulletins_json.make_json_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre.id,
|
||||||
etudid,
|
etudid,
|
||||||
xml_with_decisions=xml_with_decisions,
|
xml_with_decisions=xml_with_decisions,
|
||||||
force_publishing=force_publishing,
|
force_publishing=force_publishing,
|
||||||
@ -926,7 +918,12 @@ def do_formsemestre_bulletinetud(
|
|||||||
)
|
)
|
||||||
return bul, ""
|
return bul, ""
|
||||||
|
|
||||||
I = formsemestre_bulletinetud_dict(formsemestre_id, etudid)
|
if formsemestre.formation.is_apc():
|
||||||
|
etud = Identite.query.get(etudid)
|
||||||
|
r = bulletin_but.BulletinBUT(formsemestre)
|
||||||
|
I = r.bulletin_etud_complet(etud, formsemestre)
|
||||||
|
else:
|
||||||
|
I = formsemestre_bulletinetud_dict(formsemestre.id, etudid)
|
||||||
etud = I["etud"]
|
etud = I["etud"]
|
||||||
|
|
||||||
if format == "html":
|
if format == "html":
|
||||||
@ -953,7 +950,7 @@ def do_formsemestre_bulletinetud(
|
|||||||
elif format == "pdfmail":
|
elif format == "pdfmail":
|
||||||
# format pdfmail: envoie le pdf par mail a l'etud, et affiche le html
|
# format pdfmail: envoie le pdf par mail a l'etud, et affiche le html
|
||||||
# check permission
|
# check permission
|
||||||
if not can_send_bulletin_by_mail(formsemestre_id):
|
if not can_send_bulletin_by_mail(formsemestre.id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
|
|
||||||
if nohtml:
|
if nohtml:
|
||||||
@ -982,7 +979,7 @@ def do_formsemestre_bulletinetud(
|
|||||||
) + htm
|
) + htm
|
||||||
return h, I["filigranne"]
|
return h, I["filigranne"]
|
||||||
#
|
#
|
||||||
mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr)
|
mail_bulletin(formsemestre.id, I, pdfdata, filename, recipient_addr)
|
||||||
emaillink = '<a class="stdlink" href="mailto:%s">%s</a>' % (
|
emaillink = '<a class="stdlink" href="mailto:%s">%s</a>' % (
|
||||||
recipient_addr,
|
recipient_addr,
|
||||||
recipient_addr,
|
recipient_addr,
|
||||||
|
@ -99,7 +99,7 @@ def bulletin_get_class_name_displayed(formsemestre_id):
|
|||||||
return "invalide ! (voir paramètres)"
|
return "invalide ! (voir paramètres)"
|
||||||
|
|
||||||
|
|
||||||
class BulletinGenerator(object):
|
class BulletinGenerator:
|
||||||
"Virtual superclass for PDF bulletin generators" ""
|
"Virtual superclass for PDF bulletin generators" ""
|
||||||
# Here some helper methods
|
# Here some helper methods
|
||||||
# see sco_bulletins_standard.BulletinGeneratorStandard subclass for real methods
|
# see sco_bulletins_standard.BulletinGeneratorStandard subclass for real methods
|
||||||
|
@ -209,7 +209,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||||
titre=scu.quote_xml_attr(ue["titre"]),
|
titre=scu.quote_xml_attr(ue["titre"]),
|
||||||
note=dict(
|
note=dict(
|
||||||
value=scu.fmt_note(ue_status["cur_moy_ue"]),
|
value=scu.fmt_note(ue_status["cur_moy_ue"] if ue_status else ""),
|
||||||
min=scu.fmt_note(ue["min"]),
|
min=scu.fmt_note(ue["min"]),
|
||||||
max=scu.fmt_note(ue["max"]),
|
max=scu.fmt_note(ue["max"]),
|
||||||
moy=scu.fmt_note(
|
moy=scu.fmt_note(
|
||||||
@ -254,7 +254,10 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
m["note"][k] = scu.fmt_note(m["note"][k])
|
m["note"][k] = scu.fmt_note(m["note"][k])
|
||||||
|
|
||||||
u["module"].append(m)
|
u["module"].append(m)
|
||||||
if sco_preferences.get_preference("bul_show_mod_rangs", formsemestre_id):
|
if (
|
||||||
|
sco_preferences.get_preference("bul_show_mod_rangs", formsemestre_id)
|
||||||
|
and nt.mod_rangs is not None
|
||||||
|
):
|
||||||
m["rang"] = dict(
|
m["rang"] = dict(
|
||||||
value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid]
|
value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid]
|
||||||
)
|
)
|
||||||
|
@ -476,8 +476,8 @@ def _bulletin_pdf_table_legacy(I, version="long"):
|
|||||||
else:
|
else:
|
||||||
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
|
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
|
||||||
t = [
|
t = [
|
||||||
mod["code"],
|
mod["code"] or "",
|
||||||
mod["name"],
|
mod["name"] or "",
|
||||||
rang_minmax,
|
rang_minmax,
|
||||||
mod["mod_moy_txt"],
|
mod["mod_moy_txt"],
|
||||||
mod["mod_coef_txt"],
|
mod["mod_coef_txt"],
|
||||||
|
@ -56,19 +56,22 @@ import time
|
|||||||
import traceback
|
import traceback
|
||||||
from pydoc import html
|
from pydoc import html
|
||||||
|
|
||||||
from reportlab.platypus.doctemplate import PageTemplate, BaseDocTemplate
|
from reportlab.platypus.doctemplate import BaseDocTemplate
|
||||||
|
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
|
||||||
from app import log, ScoValueError
|
from app import log, ScoValueError
|
||||||
|
from app.models import FormSemestre
|
||||||
|
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_pdf
|
from app.scodoc import sco_pdf
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
import sco_version
|
|
||||||
from app.scodoc.sco_logos import find_logo
|
from app.scodoc.sco_logos import find_logo
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
|
import sco_version
|
||||||
|
|
||||||
|
|
||||||
def pdfassemblebulletins(
|
def pdfassemblebulletins(
|
||||||
@ -178,22 +181,21 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
|
|||||||
if cached:
|
if cached:
|
||||||
return cached[1], cached[0]
|
return cached[1], cached[0]
|
||||||
fragments = []
|
fragments = []
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
|
||||||
# Make each bulletin
|
# Make each bulletin
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etudids, get_sexnom
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
bookmarks = {}
|
bookmarks = {}
|
||||||
filigrannes = {}
|
filigrannes = {}
|
||||||
i = 1
|
i = 1
|
||||||
for etudid in nt.get_etudids():
|
for etud in formsemestre.get_inscrits(include_demdef=True, order=True):
|
||||||
frag, filigranne = sco_bulletins.do_formsemestre_bulletinetud(
|
frag, filigranne = sco_bulletins.do_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre,
|
||||||
etudid,
|
etud.id,
|
||||||
format="pdfpart",
|
format="pdfpart",
|
||||||
version=version,
|
version=version,
|
||||||
)
|
)
|
||||||
fragments += frag
|
fragments += frag
|
||||||
filigrannes[i] = filigranne
|
filigrannes[i] = filigranne
|
||||||
bookmarks[i] = scu.suppress_accents(nt.get_sexnom(etudid))
|
bookmarks[i] = etud.sex_nom(no_accents=True)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
#
|
#
|
||||||
infos = {"DeptName": sco_preferences.get_preference("DeptName", formsemestre_id)}
|
infos = {"DeptName": sco_preferences.get_preference("DeptName", formsemestre_id)}
|
||||||
@ -206,7 +208,7 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
|
|||||||
pdfdoc = pdfassemblebulletins(
|
pdfdoc = pdfassemblebulletins(
|
||||||
formsemestre_id,
|
formsemestre_id,
|
||||||
fragments,
|
fragments,
|
||||||
sem["titremois"],
|
formsemestre.titre_mois(),
|
||||||
infos,
|
infos,
|
||||||
bookmarks,
|
bookmarks,
|
||||||
filigranne=filigrannes,
|
filigranne=filigrannes,
|
||||||
@ -216,7 +218,7 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
|
|||||||
sco_pdf.PDFLOCK.release()
|
sco_pdf.PDFLOCK.release()
|
||||||
#
|
#
|
||||||
dt = time.strftime("%Y-%m-%d")
|
dt = time.strftime("%Y-%m-%d")
|
||||||
filename = "bul-%s-%s.pdf" % (sem["titre_num"], dt)
|
filename = "bul-%s-%s.pdf" % (formsemestre.titre_num(), dt)
|
||||||
filename = scu.unescape_html(filename).replace(" ", "_").replace("&", "")
|
filename = scu.unescape_html(filename).replace(" ", "_").replace("&", "")
|
||||||
# fill cache
|
# fill cache
|
||||||
sco_cache.SemBulletinsPDFCache.set(
|
sco_cache.SemBulletinsPDFCache.set(
|
||||||
@ -235,8 +237,9 @@ def get_etud_bulletins_pdf(etudid, version="selectedevals"):
|
|||||||
filigrannes = {}
|
filigrannes = {}
|
||||||
i = 1
|
i = 1
|
||||||
for sem in etud["sems"]:
|
for sem in etud["sems"]:
|
||||||
|
formsemestre = FormSemestre.query.get(sem["formsemestre_id"])
|
||||||
frag, filigranne = sco_bulletins.do_formsemestre_bulletinetud(
|
frag, filigranne = sco_bulletins.do_formsemestre_bulletinetud(
|
||||||
sem["formsemestre_id"],
|
formsemestre,
|
||||||
etudid,
|
etudid,
|
||||||
format="pdfpart",
|
format="pdfpart",
|
||||||
version=version,
|
version=version,
|
||||||
@ -271,3 +274,16 @@ def get_etud_bulletins_pdf(etudid, version="selectedevals"):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return pdfdoc, filename
|
return pdfdoc, filename
|
||||||
|
|
||||||
|
|
||||||
|
def get_filigranne(etud_etat: str, prefs) -> str:
|
||||||
|
"""Texte à placer en "filigranne" sur le bulletin pdf"""
|
||||||
|
if etud_etat == scu.DEMISSION:
|
||||||
|
return "Démission"
|
||||||
|
elif etud_etat == sco_codes_parcours.DEF:
|
||||||
|
return "Défaillant"
|
||||||
|
elif (prefs["bul_show_temporary"] and not I["decision_sem"]) or prefs[
|
||||||
|
"bul_show_temporary_forced"
|
||||||
|
]:
|
||||||
|
return prefs["bul_temporary_txt"]
|
||||||
|
return ""
|
||||||
|
@ -471,9 +471,10 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
ects_txt = str(int(ue["ects"]))
|
ects_txt = str(int(ue["ects"]))
|
||||||
except:
|
except:
|
||||||
ects_txt = "-"
|
ects_txt = "-"
|
||||||
|
titre = f"{ue['acronyme'] or ''} {ue['titre'] or ''}"
|
||||||
t = {
|
t = {
|
||||||
"titre": ue["acronyme"] + " " + ue["titre"],
|
"titre": titre,
|
||||||
"_titre_html": minuslink + ue["acronyme"] + " " + ue["titre"],
|
"_titre_html": minuslink + titre,
|
||||||
"_titre_colspan": 2,
|
"_titre_colspan": 2,
|
||||||
"module": ue["titre"],
|
"module": ue["titre"],
|
||||||
"rang": ue_descr,
|
"rang": ue_descr,
|
||||||
|
@ -217,7 +217,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
)
|
)
|
||||||
doc.append(x_ue)
|
doc.append(x_ue)
|
||||||
if ue["type"] != sco_codes_parcours.UE_SPORT:
|
if ue["type"] != sco_codes_parcours.UE_SPORT:
|
||||||
v = ue_status["cur_moy_ue"]
|
v = ue_status["cur_moy_ue"] if ue_status else ""
|
||||||
else:
|
else:
|
||||||
v = nt.bonus[etudid] if nt.bonus is not None else 0.0
|
v = nt.bonus[etudid] if nt.bonus is not None else 0.0
|
||||||
x_ue.append(
|
x_ue.append(
|
||||||
@ -252,7 +252,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
x_mod = Element(
|
x_mod = Element(
|
||||||
"module",
|
"module",
|
||||||
id=str(modimpl["moduleimpl_id"]),
|
id=str(modimpl["moduleimpl_id"]),
|
||||||
code=str(mod["code"]),
|
code=str(mod["code"] or ""),
|
||||||
coefficient=str(mod["coefficient"]),
|
coefficient=str(mod["coefficient"]),
|
||||||
numero=str(mod["numero"]),
|
numero=str(mod["numero"]),
|
||||||
titre=scu.quote_xml_attr(mod["titre"]),
|
titre=scu.quote_xml_attr(mod["titre"]),
|
||||||
@ -271,7 +271,10 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
moy=scu.fmt_note(modstat["moy"]),
|
moy=scu.fmt_note(modstat["moy"]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if sco_preferences.get_preference("bul_show_mod_rangs", formsemestre_id):
|
if (
|
||||||
|
sco_preferences.get_preference("bul_show_mod_rangs", formsemestre_id)
|
||||||
|
and nt.mod_rangs is not None
|
||||||
|
):
|
||||||
x_mod.append(
|
x_mod.append(
|
||||||
Element(
|
Element(
|
||||||
"rang",
|
"rang",
|
||||||
|
@ -65,7 +65,7 @@ def formsemestre_table_estim_cost(
|
|||||||
Mod = M["module"]
|
Mod = M["module"]
|
||||||
T.append(
|
T.append(
|
||||||
{
|
{
|
||||||
"code": Mod["code"],
|
"code": Mod["code"] or "",
|
||||||
"titre": Mod["titre"],
|
"titre": Mod["titre"],
|
||||||
"heures_cours": Mod["heures_cours"],
|
"heures_cours": Mod["heures_cours"],
|
||||||
"heures_td": Mod["heures_td"] * n_group_td,
|
"heures_td": Mod["heures_td"] * n_group_td,
|
||||||
|
@ -31,15 +31,17 @@ Rapport (table) avec dernier semestre fréquenté et débouché de chaque étudi
|
|||||||
import http
|
import http
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
|
|
||||||
|
from app import log
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
|
||||||
from app.scodoc.sco_exceptions import AccessDenied
|
from app.scodoc.sco_exceptions import AccessDenied
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc import safehtml
|
from app.scodoc import safehtml
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_permissions_check
|
from app.scodoc import sco_permissions_check
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_tag_module
|
from app.scodoc import sco_tag_module
|
||||||
@ -115,7 +117,7 @@ def get_etudids_with_debouche(start_year):
|
|||||||
|
|
||||||
|
|
||||||
def table_debouche_etudids(etudids, keep_numeric=True):
|
def table_debouche_etudids(etudids, keep_numeric=True):
|
||||||
"""Rapport pour ces etudiants"""
|
"""Rapport pour ces étudiants"""
|
||||||
L = []
|
L = []
|
||||||
for etudid in etudids:
|
for etudid in etudids:
|
||||||
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0]
|
||||||
@ -124,7 +126,8 @@ def table_debouche_etudids(etudids, keep_numeric=True):
|
|||||||
es = [(s["date_fin_iso"], i) for i, s in enumerate(sems)]
|
es = [(s["date_fin_iso"], i) for i, s in enumerate(sems)]
|
||||||
imax = max(es)[1]
|
imax = max(es)[1]
|
||||||
last_sem = sems[imax]
|
last_sem = sems[imax]
|
||||||
nt = sco_cache.NotesTableCache.get(last_sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(last_sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
row = {
|
row = {
|
||||||
"etudid": etudid,
|
"etudid": etudid,
|
||||||
"civilite": etud["civilite"],
|
"civilite": etud["civilite"],
|
||||||
|
@ -365,6 +365,7 @@ def ue_move(ue_id, after=0, redirect=1):
|
|||||||
if len({o.numero for o in others}) != len(others):
|
if len({o.numero for o in others}) != len(others):
|
||||||
# il y a des numeros identiques !
|
# il y a des numeros identiques !
|
||||||
scu.objects_renumber(db, others)
|
scu.objects_renumber(db, others)
|
||||||
|
ue.formation.invalidate_cached_sems()
|
||||||
if len(others) > 1:
|
if len(others) > 1:
|
||||||
idx = [u.id for u in others].index(ue.id)
|
idx = [u.id for u in others].index(ue.id)
|
||||||
neigh = None # object to swap with
|
neigh = None # object to swap with
|
||||||
|
@ -88,13 +88,14 @@ def do_matiere_create(args):
|
|||||||
r = _matiereEditor.create(cnx, args)
|
r = _matiereEditor.create(cnx, args)
|
||||||
|
|
||||||
# news
|
# news
|
||||||
F = sco_formations.formation_list(args={"formation_id": ue["formation_id"]})[0]
|
formation = Formation.query.get(ue["formation_id"])
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
typ=sco_news.NEWS_FORM,
|
typ=sco_news.NEWS_FORM,
|
||||||
object=ue["formation_id"],
|
object=ue["formation_id"],
|
||||||
text="Modification de la formation %(acronyme)s" % F,
|
text="Modification de la formation {formation.acronyme}",
|
||||||
max_frequency=3,
|
max_frequency=3,
|
||||||
)
|
)
|
||||||
|
formation.invalidate_cached_sems()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
@ -195,13 +196,14 @@ def do_matiere_delete(oid):
|
|||||||
_matiereEditor.delete(cnx, oid)
|
_matiereEditor.delete(cnx, oid)
|
||||||
|
|
||||||
# news
|
# news
|
||||||
F = sco_formations.formation_list(args={"formation_id": ue["formation_id"]})[0]
|
formation = Formation.query.get(ue["formation_id"])
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
typ=sco_news.NEWS_FORM,
|
typ=sco_news.NEWS_FORM,
|
||||||
object=ue["formation_id"],
|
object=ue["formation_id"],
|
||||||
text="Modification de la formation %(acronyme)s" % F,
|
text="Modification de la formation {formation.acronyme}",
|
||||||
max_frequency=3,
|
max_frequency=3,
|
||||||
)
|
)
|
||||||
|
formation.invalidate_cached_sems()
|
||||||
|
|
||||||
|
|
||||||
def matiere_delete(matiere_id=None):
|
def matiere_delete(matiere_id=None):
|
||||||
|
@ -41,7 +41,6 @@ from app.models import FormSemestre, ModuleImpl
|
|||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.sco_utils import ModuleType
|
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import (
|
||||||
@ -105,13 +104,14 @@ def do_module_create(args) -> int:
|
|||||||
r = _moduleEditor.create(cnx, args)
|
r = _moduleEditor.create(cnx, args)
|
||||||
|
|
||||||
# news
|
# news
|
||||||
F = sco_formations.formation_list(args={"formation_id": args["formation_id"]})[0]
|
formation = Formation.query.get(args["formation_id"])
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
typ=sco_news.NEWS_FORM,
|
typ=sco_news.NEWS_FORM,
|
||||||
object=args["formation_id"],
|
object=formation.id,
|
||||||
text="Modification de la formation %(acronyme)s" % F,
|
text=f"Modification de la formation {formation.acronyme}",
|
||||||
max_frequency=3,
|
max_frequency=3,
|
||||||
)
|
)
|
||||||
|
formation.invalidate_cached_sems()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
@ -196,7 +196,6 @@ def module_create(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
|
||||||
|
|
||||||
if is_apc:
|
if is_apc:
|
||||||
module_types = scu.ModuleType # tous les types
|
module_types = scu.ModuleType # tous les types
|
||||||
@ -396,13 +395,14 @@ def do_module_delete(oid):
|
|||||||
_moduleEditor.delete(cnx, oid)
|
_moduleEditor.delete(cnx, oid)
|
||||||
|
|
||||||
# news
|
# news
|
||||||
F = sco_formations.formation_list(args={"formation_id": mod["formation_id"]})[0]
|
formation = module.formation
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
typ=sco_news.NEWS_FORM,
|
typ=sco_news.NEWS_FORM,
|
||||||
object=mod["formation_id"],
|
object=mod["formation_id"],
|
||||||
text="Modification de la formation %(acronyme)s" % F,
|
text=f"Modification de la formation {formation.acronyme}",
|
||||||
max_frequency=3,
|
max_frequency=3,
|
||||||
)
|
)
|
||||||
|
formation.invalidate_cached_sems()
|
||||||
|
|
||||||
|
|
||||||
def module_delete(module_id=None):
|
def module_delete(module_id=None):
|
||||||
@ -451,8 +451,6 @@ def module_delete(module_id=None):
|
|||||||
|
|
||||||
def do_module_edit(vals: dict) -> None:
|
def do_module_edit(vals: dict) -> None:
|
||||||
"edit a module"
|
"edit a module"
|
||||||
from app.scodoc import sco_edit_formation
|
|
||||||
|
|
||||||
# check
|
# check
|
||||||
mod = module_list({"module_id": vals["module_id"]})[0]
|
mod = module_list({"module_id": vals["module_id"]})[0]
|
||||||
if module_is_locked(mod["module_id"]):
|
if module_is_locked(mod["module_id"]):
|
||||||
@ -546,7 +544,7 @@ def module_edit(module_id=None):
|
|||||||
# ne propose pas SAE et Ressources, sauf si déjà de ce type...
|
# ne propose pas SAE et Ressources, sauf si déjà de ce type...
|
||||||
module_types = (
|
module_types = (
|
||||||
set(scu.ModuleType) - {scu.ModuleType.RESSOURCE, scu.ModuleType.SAE}
|
set(scu.ModuleType) - {scu.ModuleType.RESSOURCE, scu.ModuleType.SAE}
|
||||||
) | {a_module.module_type}
|
) | {a_module.module_type or scu.ModuleType.STANDARD}
|
||||||
|
|
||||||
descr = [
|
descr = [
|
||||||
(
|
(
|
||||||
@ -845,7 +843,7 @@ def formation_add_malus_modules(formation_id, titre=None, redirect=True):
|
|||||||
[
|
[
|
||||||
mod
|
mod
|
||||||
for mod in module_list(args={"ue_id": ue["ue_id"]})
|
for mod in module_list(args={"ue_id": ue["ue_id"]})
|
||||||
if mod["module_type"] == ModuleType.MALUS
|
if mod["module_type"] == scu.ModuleType.MALUS
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if nb_mod_malus == 0:
|
if nb_mod_malus == 0:
|
||||||
@ -897,7 +895,7 @@ def ue_add_malus_module(ue_id, titre=None, code=None):
|
|||||||
"matiere_id": matiere_id,
|
"matiere_id": matiere_id,
|
||||||
"formation_id": ue["formation_id"],
|
"formation_id": ue["formation_id"],
|
||||||
"semestre_id": semestre_id,
|
"semestre_id": semestre_id,
|
||||||
"module_type": ModuleType.MALUS,
|
"module_type": scu.ModuleType.MALUS,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -128,13 +128,14 @@ def do_ue_create(args):
|
|||||||
formation = Formation.query.get(args["formation_id"])
|
formation = Formation.query.get(args["formation_id"])
|
||||||
formation.invalidate_module_coefs()
|
formation.invalidate_module_coefs()
|
||||||
# news
|
# news
|
||||||
F = sco_formations.formation_list(args={"formation_id": args["formation_id"]})[0]
|
formation = Formation.query.get(args["formation_id"])
|
||||||
sco_news.add(
|
sco_news.add(
|
||||||
typ=sco_news.NEWS_FORM,
|
typ=sco_news.NEWS_FORM,
|
||||||
object=args["formation_id"],
|
object=args["formation_id"],
|
||||||
text="Modification de la formation %(acronyme)s" % F,
|
text="Modification de la formation {formation.acronyme}",
|
||||||
max_frequency=3,
|
max_frequency=3,
|
||||||
)
|
)
|
||||||
|
formation.invalidate_cached_sems()
|
||||||
return ue_id
|
return ue_id
|
||||||
|
|
||||||
|
|
||||||
@ -250,7 +251,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
|
|||||||
title = f"Modification de l'UE {ue.acronyme} {ue.titre}"
|
title = f"Modification de l'UE {ue.acronyme} {ue.titre}"
|
||||||
initvalues = ue_dict
|
initvalues = ue_dict
|
||||||
submitlabel = "Modifier les valeurs"
|
submitlabel = "Modifier les valeurs"
|
||||||
can_change_semestre_id = ue.modules.count() == 0
|
can_change_semestre_id = (ue.modules.count() == 0) or (ue.semestre_idx is None)
|
||||||
else:
|
else:
|
||||||
ue = None
|
ue = None
|
||||||
title = "Création d'une UE"
|
title = "Création d'une UE"
|
||||||
@ -361,7 +362,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
|
|||||||
{
|
{
|
||||||
"size": 12,
|
"size": 12,
|
||||||
"title": "Code UE",
|
"title": "Code UE",
|
||||||
"explanation": "code interne (optionnel). Toutes les UE partageant le même code (et le même code de formation) sont compatibles (compensation de semestres, capitalisation d'UE). Voir liste ci-dessous.",
|
"explanation": "code interne (non vide). Toutes les UE partageant le même code (et le même code de formation) sont compatibles (compensation de semestres, capitalisation d'UE). Voir liste ci-dessous.",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -410,7 +411,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
|
|||||||
submitlabel=submitlabel,
|
submitlabel=submitlabel,
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
if ue and ue.modules.count():
|
if ue and ue.modules.count() and ue.semestre_idx is not None:
|
||||||
modules_div = f"""<div id="ue_list_modules">
|
modules_div = f"""<div id="ue_list_modules">
|
||||||
<div><b>{ue.modules.count()} modules sont rattachés
|
<div><b>{ue.modules.count()} modules sont rattachés
|
||||||
à cette UE</b> du semestre S{ue.semestre_idx},
|
à cette UE</b> du semestre S{ue.semestre_idx},
|
||||||
@ -575,7 +576,9 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
|
|||||||
semestre_ids = range(1, parcours.NB_SEM + 1)
|
semestre_ids = range(1, parcours.NB_SEM + 1)
|
||||||
# transition: on requete ici via l'ORM mais on utilise les fonctions ScoDoc7
|
# transition: on requete ici via l'ORM mais on utilise les fonctions ScoDoc7
|
||||||
# basées sur des dicts
|
# basées sur des dicts
|
||||||
ues_obj = UniteEns.query.filter_by(formation_id=formation_id, is_external=False)
|
ues_obj = UniteEns.query.filter_by(
|
||||||
|
formation_id=formation_id, is_external=False
|
||||||
|
).order_by(UniteEns.semestre_idx, UniteEns.numero)
|
||||||
ues_externes_obj = UniteEns.query.filter_by(
|
ues_externes_obj = UniteEns.query.filter_by(
|
||||||
formation_id=formation_id, is_external=True
|
formation_id=formation_id, is_external=True
|
||||||
)
|
)
|
||||||
@ -1415,15 +1418,15 @@ def ue_list_semestre_ids(ue: dict):
|
|||||||
|
|
||||||
|
|
||||||
UE_PALETTE = [
|
UE_PALETTE = [
|
||||||
"#EFA00B",
|
"#B80004", # rouge
|
||||||
"#99C24D",
|
"#F97B3D", # Orange Crayola
|
||||||
"#EC9192",
|
"#FEB40B", # Honey Yellow
|
||||||
"#0075C4",
|
"#80CB3F", # Yellow Green
|
||||||
"#D65108",
|
"#05162E", # Oxford Blue
|
||||||
"#DEC0F1",
|
"#548687", # Steel Teal
|
||||||
"#B02E0C",
|
"#444054", # Independence
|
||||||
"#151E3F",
|
"#889696", # Spanish Gray
|
||||||
"#FB3640",
|
"#0CA4A5", # Viridian Green
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -1436,8 +1439,8 @@ def colorie_anciennes_ues(ues: list[UniteEns]) -> None:
|
|||||||
last_sem_idx = 0
|
last_sem_idx = 0
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
if ue.semestre_idx != last_sem_idx:
|
if ue.semestre_idx != last_sem_idx:
|
||||||
last_sem_idx = ue.semestre_idx
|
|
||||||
index = 0
|
index = 0
|
||||||
|
last_sem_idx = ue.semestre_idx
|
||||||
if ue.color is None:
|
if ue.color is None:
|
||||||
ue.color = UE_PALETTE[index % nb_colors]
|
ue.color = UE_PALETTE[index % nb_colors]
|
||||||
index += 1
|
index += 1
|
||||||
|
@ -384,8 +384,8 @@ print apo_csv_list_stored_archives()
|
|||||||
|
|
||||||
groups_infos = sco_groups_view.DisplayedGroupsInfos( [sco_groups.get_default_group(formsemestre_id)], formsemestre_id=formsemestre_id)
|
groups_infos = sco_groups_view.DisplayedGroupsInfos( [sco_groups.get_default_group(formsemestre_id)], formsemestre_id=formsemestre_id)
|
||||||
|
|
||||||
nt = sco_cache.NotesTableCache.get( formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
#
|
#
|
||||||
s = SemSet('NSS29902')
|
s = SemSet('NSS29902')
|
||||||
apo_data = sco_apogee_csv.ApoData(open('/opt/scodoc/var/scodoc/archives/apo_csv/RT/2015-2/2016-07-10-11-26-15/V1RT.csv').read(), periode=1)
|
apo_data = sco_apogee_csv.ApoData(open('/opt/scodoc/var/scodoc/archives/apo_csv/RT/2015-2/2016-07-10-11-26-15/V1RT.csv').read(), periode=1)
|
||||||
|
@ -38,6 +38,7 @@ from flask_mail import Message
|
|||||||
|
|
||||||
from app import email
|
from app import email
|
||||||
from app import log
|
from app import log
|
||||||
|
from app.models import Admission
|
||||||
from app.models.etudiants import make_etud_args
|
from app.models.etudiants import make_etud_args
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
@ -859,19 +860,24 @@ def list_scolog(etudid):
|
|||||||
return cursor.dictfetchall()
|
return cursor.dictfetchall()
|
||||||
|
|
||||||
|
|
||||||
def fill_etuds_info(etuds):
|
def fill_etuds_info(etuds, add_admission=True):
|
||||||
"""etuds est une liste d'etudiants (mappings)
|
"""etuds est une liste d'etudiants (mappings)
|
||||||
Pour chaque etudiant, ajoute ou formatte les champs
|
Pour chaque etudiant, ajoute ou formatte les champs
|
||||||
-> informations pour fiche etudiant ou listes diverses
|
-> informations pour fiche etudiant ou listes diverses
|
||||||
"""
|
|
||||||
from app.scodoc import sco_formsemestre
|
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
|
||||||
|
|
||||||
|
Si add_admission: ajoute au dict le schamps "admission" s'il n'y sont pas déjà.
|
||||||
|
"""
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
# open('/tmp/t','w').write( str(etuds) )
|
|
||||||
for etud in etuds:
|
for etud in etuds:
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
etud["dept"] = g.scodoc_dept
|
etud["dept"] = g.scodoc_dept
|
||||||
|
# Admission
|
||||||
|
if add_admission and "nomlycee" not in etud:
|
||||||
|
admission = (
|
||||||
|
Admission.query.filter_by(etudid=etudid).first().to_dict(no_nulls=True)
|
||||||
|
)
|
||||||
|
etud.update(admission)
|
||||||
|
#
|
||||||
adrs = adresse_list(cnx, {"etudid": etudid})
|
adrs = adresse_list(cnx, {"etudid": etudid})
|
||||||
if not adrs:
|
if not adrs:
|
||||||
# certains "vieux" etudiants n'ont pas d'adresse
|
# certains "vieux" etudiants n'ont pas d'adresse
|
||||||
@ -884,6 +890,50 @@ def fill_etuds_info(etuds):
|
|||||||
etud.update(adr)
|
etud.update(adr)
|
||||||
format_etud_ident(etud)
|
format_etud_ident(etud)
|
||||||
|
|
||||||
|
etud.update(etud_inscriptions_infos(etudid, etud["ne"]))
|
||||||
|
|
||||||
|
# nettoyage champs souvent vides
|
||||||
|
if etud.get("nomlycee"):
|
||||||
|
etud["ilycee"] = "Lycée " + format_lycee(etud["nomlycee"])
|
||||||
|
if etud["villelycee"]:
|
||||||
|
etud["ilycee"] += " (%s)" % etud.get("villelycee", "")
|
||||||
|
etud["ilycee"] += "<br/>"
|
||||||
|
else:
|
||||||
|
if etud.get("codelycee"):
|
||||||
|
etud["ilycee"] = format_lycee_from_code(etud["codelycee"])
|
||||||
|
else:
|
||||||
|
etud["ilycee"] = ""
|
||||||
|
rap = ""
|
||||||
|
if etud.get("rapporteur") or etud.get("commentaire"):
|
||||||
|
rap = "Note du rapporteur"
|
||||||
|
if etud.get("rapporteur"):
|
||||||
|
rap += " (%s)" % etud["rapporteur"]
|
||||||
|
rap += ": "
|
||||||
|
if etud.get("commentaire"):
|
||||||
|
rap += "<em>%s</em>" % etud["commentaire"]
|
||||||
|
etud["rap"] = rap
|
||||||
|
|
||||||
|
# if etud['boursier_prec']:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
if etud.get("telephone"):
|
||||||
|
etud["telephonestr"] = "<b>Tél.:</b> " + format_telephone(etud["telephone"])
|
||||||
|
else:
|
||||||
|
etud["telephonestr"] = ""
|
||||||
|
if etud.get("telephonemobile"):
|
||||||
|
etud["telephonemobilestr"] = "<b>Mobile:</b> " + format_telephone(
|
||||||
|
etud["telephonemobile"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
etud["telephonemobilestr"] = ""
|
||||||
|
|
||||||
|
|
||||||
|
def etud_inscriptions_infos(etudid: int, ne="") -> dict:
|
||||||
|
"""Dict avec les informations sur les semestres passés et courant"""
|
||||||
|
from app.scodoc import sco_formsemestre
|
||||||
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
|
|
||||||
|
etud = {}
|
||||||
# Semestres dans lesquel il est inscrit
|
# Semestres dans lesquel il est inscrit
|
||||||
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
||||||
{"etudid": etudid}
|
{"etudid": etudid}
|
||||||
@ -908,13 +958,10 @@ def fill_etuds_info(etuds):
|
|||||||
etud["inscriptionstr"] = "Inscrit en " + cursem["titremois"]
|
etud["inscriptionstr"] = "Inscrit en " + cursem["titremois"]
|
||||||
etud["inscription_formsemestre_id"] = cursem["formsemestre_id"]
|
etud["inscription_formsemestre_id"] = cursem["formsemestre_id"]
|
||||||
etud["etatincursem"] = curi["etat"]
|
etud["etatincursem"] = curi["etat"]
|
||||||
etud["situation"] = descr_situation_etud(etudid, etud["ne"])
|
etud["situation"] = descr_situation_etud(etudid, ne)
|
||||||
# XXX est-ce utile ? sco_groups.etud_add_group_infos( etud, cursem)
|
|
||||||
else:
|
else:
|
||||||
if etud["sems"]:
|
if etud["sems"]:
|
||||||
if etud["sems"][0]["dateord"] > time.strftime(
|
if etud["sems"][0]["dateord"] > time.strftime("%Y-%m-%d", time.localtime()):
|
||||||
"%Y-%m-%d", time.localtime()
|
|
||||||
):
|
|
||||||
etud["inscription"] = "futur"
|
etud["inscription"] = "futur"
|
||||||
etud["situation"] = "futur élève"
|
etud["situation"] = "futur élève"
|
||||||
else:
|
else:
|
||||||
@ -925,47 +972,12 @@ def fill_etuds_info(etuds):
|
|||||||
etud["situation"] = etud["inscription"]
|
etud["situation"] = etud["inscription"]
|
||||||
etud["inscriptionstr"] = etud["inscription"]
|
etud["inscriptionstr"] = etud["inscription"]
|
||||||
etud["inscription_formsemestre_id"] = None
|
etud["inscription_formsemestre_id"] = None
|
||||||
# XXXetud['partitions'] = {} # ne va pas chercher les groupes des anciens semestres
|
|
||||||
etud["etatincursem"] = "?"
|
etud["etatincursem"] = "?"
|
||||||
|
return etud
|
||||||
# nettoyage champs souvents vides
|
|
||||||
if etud["nomlycee"]:
|
|
||||||
etud["ilycee"] = "Lycée " + format_lycee(etud["nomlycee"])
|
|
||||||
if etud["villelycee"]:
|
|
||||||
etud["ilycee"] += " (%s)" % etud["villelycee"]
|
|
||||||
etud["ilycee"] += "<br/>"
|
|
||||||
else:
|
|
||||||
if etud["codelycee"]:
|
|
||||||
etud["ilycee"] = format_lycee_from_code(etud["codelycee"])
|
|
||||||
else:
|
|
||||||
etud["ilycee"] = ""
|
|
||||||
rap = ""
|
|
||||||
if etud["rapporteur"] or etud["commentaire"]:
|
|
||||||
rap = "Note du rapporteur"
|
|
||||||
if etud["rapporteur"]:
|
|
||||||
rap += " (%s)" % etud["rapporteur"]
|
|
||||||
rap += ": "
|
|
||||||
if etud["commentaire"]:
|
|
||||||
rap += "<em>%s</em>" % etud["commentaire"]
|
|
||||||
etud["rap"] = rap
|
|
||||||
|
|
||||||
# if etud['boursier_prec']:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
if etud["telephone"]:
|
|
||||||
etud["telephonestr"] = "<b>Tél.:</b> " + format_telephone(etud["telephone"])
|
|
||||||
else:
|
|
||||||
etud["telephonestr"] = ""
|
|
||||||
if etud["telephonemobile"]:
|
|
||||||
etud["telephonemobilestr"] = "<b>Mobile:</b> " + format_telephone(
|
|
||||||
etud["telephonemobile"]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
etud["telephonemobilestr"] = ""
|
|
||||||
|
|
||||||
|
|
||||||
def descr_situation_etud(etudid, ne=""):
|
def descr_situation_etud(etudid: int, ne="") -> str:
|
||||||
"""chaine decrivant la situation actuelle de l'etudiant"""
|
"""chaîne décrivant la situation actuelle de l'étudiant"""
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
@ -982,7 +994,7 @@ def descr_situation_etud(etudid, ne=""):
|
|||||||
)
|
)
|
||||||
r = cursor.dictfetchone()
|
r = cursor.dictfetchone()
|
||||||
if not r:
|
if not r:
|
||||||
situation = "non inscrit"
|
situation = "non inscrit" + ne
|
||||||
else:
|
else:
|
||||||
sem = sco_formsemestre.get_formsemestre(r["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(r["formsemestre_id"])
|
||||||
if r["etat"] == "I":
|
if r["etat"] == "I":
|
||||||
|
@ -237,7 +237,11 @@ def formsemestre_check_absences_html(formsemestre_id):
|
|||||||
if evals:
|
if evals:
|
||||||
H.append(
|
H.append(
|
||||||
'<div class="module_check_absences"><h2><a href="moduleimpl_status?moduleimpl_id=%s">%s: %s</a></h2>'
|
'<div class="module_check_absences"><h2><a href="moduleimpl_status?moduleimpl_id=%s">%s: %s</a></h2>'
|
||||||
% (M["moduleimpl_id"], M["module"]["code"], M["module"]["abbrev"])
|
% (
|
||||||
|
M["moduleimpl_id"],
|
||||||
|
M["module"]["code"] or "",
|
||||||
|
M["module"]["abbrev"] or "",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
for E in evals:
|
for E in evals:
|
||||||
H.append(
|
H.append(
|
||||||
|
@ -36,6 +36,8 @@ from flask import url_for, g
|
|||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
|
|
||||||
|
from app.models.evaluations import evaluation_enrich_dict, check_evaluation_args
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
@ -81,43 +83,6 @@ _evaluationEditor = ndb.EditableTable(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def evaluation_enrich_dict(e):
|
|
||||||
"""add or convert some fileds in an evaluation dict"""
|
|
||||||
# For ScoDoc7 compat
|
|
||||||
heure_debut_dt = e["heure_debut"] or datetime.time(
|
|
||||||
8, 00
|
|
||||||
) # au cas ou pas d'heure (note externe?)
|
|
||||||
heure_fin_dt = e["heure_fin"] or datetime.time(8, 00)
|
|
||||||
e["heure_debut"] = ndb.TimefromISO8601(e["heure_debut"])
|
|
||||||
e["heure_fin"] = ndb.TimefromISO8601(e["heure_fin"])
|
|
||||||
e["jouriso"] = ndb.DateDMYtoISO(e["jour"])
|
|
||||||
heure_debut, heure_fin = e["heure_debut"], e["heure_fin"]
|
|
||||||
d = ndb.TimeDuration(heure_debut, heure_fin)
|
|
||||||
if d is not None:
|
|
||||||
m = d % 60
|
|
||||||
e["duree"] = "%dh" % (d / 60)
|
|
||||||
if m != 0:
|
|
||||||
e["duree"] += "%02d" % m
|
|
||||||
else:
|
|
||||||
e["duree"] = ""
|
|
||||||
if heure_debut and (not heure_fin or heure_fin == heure_debut):
|
|
||||||
e["descrheure"] = " à " + heure_debut
|
|
||||||
elif heure_debut and heure_fin:
|
|
||||||
e["descrheure"] = " de %s à %s" % (heure_debut, heure_fin)
|
|
||||||
else:
|
|
||||||
e["descrheure"] = ""
|
|
||||||
# matin, apresmidi: utile pour se referer aux absences:
|
|
||||||
if heure_debut_dt < datetime.time(12, 00):
|
|
||||||
e["matin"] = 1
|
|
||||||
else:
|
|
||||||
e["matin"] = 0
|
|
||||||
if heure_fin_dt > datetime.time(12, 00):
|
|
||||||
e["apresmidi"] = 1
|
|
||||||
else:
|
|
||||||
e["apresmidi"] = 0
|
|
||||||
return e
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_list(args, sortkey=None):
|
def do_evaluation_list(args, sortkey=None):
|
||||||
"""List evaluations, sorted by numero (or most recent date first).
|
"""List evaluations, sorted by numero (or most recent date first).
|
||||||
|
|
||||||
@ -127,7 +92,7 @@ def do_evaluation_list(args, sortkey=None):
|
|||||||
'apresmidi' : 1 (termine après 12:00) ou 0
|
'apresmidi' : 1 (termine après 12:00) ou 0
|
||||||
'descrheure' : ' de 15h00 à 16h30'
|
'descrheure' : ' de 15h00 à 16h30'
|
||||||
"""
|
"""
|
||||||
# Attention: transformation fonction ScoDc7 en SQLAlchemy
|
# Attention: transformation fonction ScoDoc7 en SQLAlchemy
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
evals = _evaluationEditor.list(cnx, args, sortkey=sortkey)
|
evals = _evaluationEditor.list(cnx, args, sortkey=sortkey)
|
||||||
# calcule duree (chaine de car.) de chaque evaluation et ajoute jouriso, matin, apresmidi
|
# calcule duree (chaine de car.) de chaque evaluation et ajoute jouriso, matin, apresmidi
|
||||||
@ -146,59 +111,6 @@ def do_evaluation_list_in_formsemestre(formsemestre_id):
|
|||||||
return evals
|
return evals
|
||||||
|
|
||||||
|
|
||||||
def _check_evaluation_args(args):
|
|
||||||
"Check coefficient, dates and duration, raises exception if invalid"
|
|
||||||
moduleimpl_id = args["moduleimpl_id"]
|
|
||||||
# check bareme
|
|
||||||
note_max = args.get("note_max", None)
|
|
||||||
if note_max is None:
|
|
||||||
raise ScoValueError("missing note_max")
|
|
||||||
try:
|
|
||||||
note_max = float(note_max)
|
|
||||||
except ValueError:
|
|
||||||
raise ScoValueError("Invalid note_max value")
|
|
||||||
if note_max < 0:
|
|
||||||
raise ScoValueError("Invalid note_max value (must be positive or null)")
|
|
||||||
# check coefficient
|
|
||||||
coef = args.get("coefficient", None)
|
|
||||||
if coef is None:
|
|
||||||
raise ScoValueError("missing coefficient")
|
|
||||||
try:
|
|
||||||
coef = float(coef)
|
|
||||||
except ValueError:
|
|
||||||
raise ScoValueError("Invalid coefficient value")
|
|
||||||
if coef < 0:
|
|
||||||
raise ScoValueError("Invalid coefficient value (must be positive or null)")
|
|
||||||
# check date
|
|
||||||
jour = args.get("jour", None)
|
|
||||||
args["jour"] = jour
|
|
||||||
if jour:
|
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
|
||||||
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
|
|
||||||
date_debut = datetime.date(y, m, d)
|
|
||||||
d, m, y = [int(x) for x in sem["date_fin"].split("/")]
|
|
||||||
date_fin = datetime.date(y, m, d)
|
|
||||||
# passe par ndb.DateDMYtoISO pour avoir date pivot
|
|
||||||
y, m, d = [int(x) for x in ndb.DateDMYtoISO(jour).split("-")]
|
|
||||||
jour = datetime.date(y, m, d)
|
|
||||||
if (jour > date_fin) or (jour < date_debut):
|
|
||||||
raise ScoValueError(
|
|
||||||
"La date de l'évaluation (%s/%s/%s) n'est pas dans le semestre !"
|
|
||||||
% (d, m, y),
|
|
||||||
dest_url="javascript:history.back();",
|
|
||||||
)
|
|
||||||
heure_debut = args.get("heure_debut", None)
|
|
||||||
args["heure_debut"] = heure_debut
|
|
||||||
heure_fin = args.get("heure_fin", None)
|
|
||||||
args["heure_fin"] = heure_fin
|
|
||||||
if jour and ((not heure_debut) or (not heure_fin)):
|
|
||||||
raise ScoValueError("Les heures doivent être précisées")
|
|
||||||
d = ndb.TimeDuration(heure_debut, heure_fin)
|
|
||||||
if d and ((d < 0) or (d > 60 * 12)):
|
|
||||||
raise ScoValueError("Heures de l'évaluation incohérentes !")
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_create(
|
def do_evaluation_create(
|
||||||
moduleimpl_id=None,
|
moduleimpl_id=None,
|
||||||
jour=None,
|
jour=None,
|
||||||
@ -220,7 +132,7 @@ def do_evaluation_create(
|
|||||||
)
|
)
|
||||||
args = locals()
|
args = locals()
|
||||||
log("do_evaluation_create: args=" + str(args))
|
log("do_evaluation_create: args=" + str(args))
|
||||||
_check_evaluation_args(args)
|
check_evaluation_args(args)
|
||||||
# Check numeros
|
# Check numeros
|
||||||
module_evaluation_renumber(moduleimpl_id, only_if_unumbered=True)
|
module_evaluation_renumber(moduleimpl_id, only_if_unumbered=True)
|
||||||
if not "numero" in args or args["numero"] is None:
|
if not "numero" in args or args["numero"] is None:
|
||||||
@ -263,6 +175,7 @@ def do_evaluation_create(
|
|||||||
|
|
||||||
# news
|
# news
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
|
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
||||||
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||||
@ -288,7 +201,7 @@ def do_evaluation_edit(args):
|
|||||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||||
)
|
)
|
||||||
args["moduleimpl_id"] = moduleimpl_id
|
args["moduleimpl_id"] = moduleimpl_id
|
||||||
_check_evaluation_args(args)
|
check_evaluation_args(args)
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
_evaluationEditor.edit(cnx, args)
|
_evaluationEditor.edit(cnx, args)
|
||||||
|
@ -122,7 +122,7 @@ def evaluation_create_form(
|
|||||||
#
|
#
|
||||||
mod_descr = '<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> %s' % (
|
mod_descr = '<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> %s' % (
|
||||||
moduleimpl_id,
|
moduleimpl_id,
|
||||||
mod["code"],
|
mod["code"] or "module sans code",
|
||||||
mod["titre"],
|
mod["titre"],
|
||||||
link,
|
link,
|
||||||
)
|
)
|
||||||
|
@ -403,8 +403,9 @@ def do_evaluation_etat_in_mod(nt, moduleimpl_id):
|
|||||||
|
|
||||||
def formsemestre_evaluations_cal(formsemestre_id):
|
def formsemestre_evaluations_cal(formsemestre_id):
|
||||||
"""Page avec calendrier de toutes les evaluations de ce semestre"""
|
"""Page avec calendrier de toutes les evaluations de ce semestre"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
sem = formsemestre.to_dict()
|
||||||
|
|
||||||
evals = nt.get_evaluations_etats()
|
evals = nt.get_evaluations_etats()
|
||||||
nb_evals = len(evals)
|
nb_evals = len(evals)
|
||||||
@ -538,8 +539,9 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
|
|
||||||
N'indique pas les évaluations de ratrapage ni celles des modules de bonus/malus.
|
N'indique pas les évaluations de ratrapage ni celles des modules de bonus/malus.
|
||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
sem = formsemestre.to_dict()
|
||||||
|
|
||||||
evals = nt.get_evaluations_etats()
|
evals = nt.get_evaluations_etats()
|
||||||
T = []
|
T = []
|
||||||
@ -635,7 +637,14 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
)
|
)
|
||||||
mod_descr = (
|
mod_descr = (
|
||||||
'<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> <span class="resp">(resp. <a title="%s">%s</a>)</span> %s'
|
'<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> <span class="resp">(resp. <a title="%s">%s</a>)</span> %s'
|
||||||
% (moduleimpl_id, Mod["code"], Mod["titre"], nomcomplet, resp, link)
|
% (
|
||||||
|
moduleimpl_id,
|
||||||
|
Mod["code"] or "",
|
||||||
|
Mod["titre"] or "?",
|
||||||
|
nomcomplet,
|
||||||
|
resp,
|
||||||
|
link,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
etit = E["description"] or ""
|
etit = E["description"] or ""
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
"""
|
"""
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
@ -77,7 +80,8 @@ def _build_results_table(start_date=None, end_date=None, types_parcours=[]):
|
|||||||
{}
|
{}
|
||||||
) # etudid : { formsemestre_id d'inscription le plus recent dans les dates considérées, etud }
|
) # etudid : { formsemestre_id d'inscription le plus recent dans les dates considérées, etud }
|
||||||
for formsemestre_id in formsemestre_ids_parcours:
|
for formsemestre_id in formsemestre_ids_parcours:
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etudids
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
etudids = nt.get_etudids()
|
etudids = nt.get_etudids()
|
||||||
for etudid in etudids:
|
for etudid in etudids:
|
||||||
if etudid not in etuds_infos: # pas encore traité ?
|
if etudid not in etuds_infos: # pas encore traité ?
|
||||||
|
@ -601,7 +601,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
"input_type": "text_suggest",
|
"input_type": "text_suggest",
|
||||||
"size": 50,
|
"size": 50,
|
||||||
"withcheckbox": True,
|
"withcheckbox": True,
|
||||||
"title": "%s %s" % (mod["code"], mod["titre"]),
|
"title": "%s %s" % (mod["code"] or "", mod["titre"] or ""),
|
||||||
"allowed_values": allowed_user_names,
|
"allowed_values": allowed_user_names,
|
||||||
"template": itemtemplate,
|
"template": itemtemplate,
|
||||||
"text_suggest_options": {
|
"text_suggest_options": {
|
||||||
@ -802,7 +802,9 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
}
|
}
|
||||||
moduleimpl_id = sco_moduleimpl.do_moduleimpl_create(modargs)
|
moduleimpl_id = sco_moduleimpl.do_moduleimpl_create(modargs)
|
||||||
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
||||||
msg += ["création de %s (%s)" % (mod["code"], mod["titre"])]
|
msg += [
|
||||||
|
"création de %s (%s)" % (mod["code"] or "?", mod["titre"] or "?")
|
||||||
|
]
|
||||||
# INSCRIPTIONS DES ETUDIANTS
|
# INSCRIPTIONS DES ETUDIANTS
|
||||||
log(
|
log(
|
||||||
'inscription module: %s = "%s"'
|
'inscription module: %s = "%s"'
|
||||||
@ -824,7 +826,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
)
|
)
|
||||||
msg += [
|
msg += [
|
||||||
"inscription de %d étudiants au module %s"
|
"inscription de %d étudiants au module %s"
|
||||||
% (len(etudids), mod["code"])
|
% (len(etudids), mod["code"] or "(module sans code)")
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
log(
|
log(
|
||||||
@ -919,11 +921,19 @@ def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
|
|||||||
if evals:
|
if evals:
|
||||||
msg += [
|
msg += [
|
||||||
'<b>impossible de supprimer %s (%s) car il y a %d évaluations définies (<a href="moduleimpl_status?moduleimpl_id=%s" class="stdlink">supprimer les d\'abord</a>)</b>'
|
'<b>impossible de supprimer %s (%s) car il y a %d évaluations définies (<a href="moduleimpl_status?moduleimpl_id=%s" class="stdlink">supprimer les d\'abord</a>)</b>'
|
||||||
% (mod["code"], mod["titre"], len(evals), moduleimpl_id)
|
% (
|
||||||
|
mod["code"] or "(module sans code)",
|
||||||
|
mod["titre"],
|
||||||
|
len(evals),
|
||||||
|
moduleimpl_id,
|
||||||
|
)
|
||||||
]
|
]
|
||||||
ok = False
|
ok = False
|
||||||
else:
|
else:
|
||||||
msg += ["suppression de %s (%s)" % (mod["code"], mod["titre"])]
|
msg += [
|
||||||
|
"suppression de %s (%s)"
|
||||||
|
% (mod["code"] or "(module sans code)", mod["titre"] or "")
|
||||||
|
]
|
||||||
sco_moduleimpl.do_moduleimpl_delete(
|
sco_moduleimpl.do_moduleimpl_delete(
|
||||||
moduleimpl_id, formsemestre_id=formsemestre_id
|
moduleimpl_id, formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
|
@ -37,6 +37,9 @@ import flask
|
|||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
@ -260,7 +263,8 @@ def formsemestre_ext_edit_ue_validations(formsemestre_id, etudid):
|
|||||||
|
|
||||||
|
|
||||||
def _make_page(etud, sem, tf, message=""):
|
def _make_page(etud, sem, tf, message=""):
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
moy_gen = nt.get_etud_moy_gen(etud["etudid"])
|
moy_gen = nt.get_etud_moy_gen(etud["etudid"])
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
|
@ -32,14 +32,16 @@ import time
|
|||||||
import flask
|
import flask
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
from app.scodoc.sco_exceptions import ScoException, ScoValueError
|
||||||
from app.scodoc.sco_permissions import Permission
|
|
||||||
from app.scodoc.sco_codes_parcours import UE_STANDARD, UE_SPORT, UE_TYPE_NAME
|
from app.scodoc.sco_codes_parcours import UE_STANDARD, UE_SPORT, UE_TYPE_NAME
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app.scodoc import sco_find_etud
|
from app.scodoc import sco_find_etud
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
@ -186,7 +188,9 @@ def do_formsemestre_desinscription(etudid, formsemestre_id):
|
|||||||
raise ScoValueError("desinscription impossible: semestre verrouille")
|
raise ScoValueError("desinscription impossible: semestre verrouille")
|
||||||
|
|
||||||
# -- Si decisions de jury, desinscription interdite
|
# -- Si decisions de jury, desinscription interdite
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
if nt.etud_has_decision(etudid):
|
if nt.etud_has_decision(etudid):
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"desinscription impossible: l'étudiant a une décision de jury (la supprimer avant si nécessaire)"
|
"desinscription impossible: l'étudiant a une décision de jury (la supprimer avant si nécessaire)"
|
||||||
@ -475,7 +479,8 @@ def formsemestre_inscription_option(etudid, formsemestre_id):
|
|||||||
raise ScoValueError("Modification impossible: semestre verrouille")
|
raise ScoValueError("Modification impossible: semestre verrouille")
|
||||||
|
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_ue_status
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
F = html_sco_header.sco_footer()
|
F = html_sco_header.sco_footer()
|
||||||
H = [
|
H = [
|
||||||
@ -503,7 +508,7 @@ def formsemestre_inscription_option(etudid, formsemestre_id):
|
|||||||
modimpls_by_ue_ids[ue_id].append(mod["moduleimpl_id"])
|
modimpls_by_ue_ids[ue_id].append(mod["moduleimpl_id"])
|
||||||
|
|
||||||
modimpls_by_ue_names[ue_id].append(
|
modimpls_by_ue_names[ue_id].append(
|
||||||
"%s %s" % (mod["module"]["code"], mod["module"]["titre"])
|
"%s %s" % (mod["module"]["code"] or "", mod["module"]["titre"] or "")
|
||||||
)
|
)
|
||||||
vals = scu.get_request_args()
|
vals = scu.get_request_args()
|
||||||
if not vals.get("tf_submitted", False):
|
if not vals.get("tf_submitted", False):
|
||||||
@ -527,7 +532,7 @@ def formsemestre_inscription_option(etudid, formsemestre_id):
|
|||||||
if ue["type"] != UE_STANDARD:
|
if ue["type"] != UE_STANDARD:
|
||||||
ue_descr += " <em>%s</em>" % UE_TYPE_NAME[ue["type"]]
|
ue_descr += " <em>%s</em>" % UE_TYPE_NAME[ue["type"]]
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
if ue_status["is_capitalized"]:
|
if ue_status and ue_status["is_capitalized"]:
|
||||||
sem_origin = sco_formsemestre.get_formsemestre(ue_status["formsemestre_id"])
|
sem_origin = sco_formsemestre.get_formsemestre(ue_status["formsemestre_id"])
|
||||||
ue_descr += ' <a class="discretelink" href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s">(capitalisée le %s)' % (
|
ue_descr += ' <a class="discretelink" href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s">(capitalisée le %s)' % (
|
||||||
sem_origin["formsemestre_id"],
|
sem_origin["formsemestre_id"],
|
||||||
@ -648,7 +653,7 @@ function chkbx_select(field_id, state) {
|
|||||||
"%s (%s)"
|
"%s (%s)"
|
||||||
% (
|
% (
|
||||||
modsdict[x]["module"]["titre"],
|
modsdict[x]["module"]["titre"],
|
||||||
modsdict[x]["module"]["code"],
|
modsdict[x]["module"]["code"] or "(module sans code)",
|
||||||
)
|
)
|
||||||
for x in a_desinscrire
|
for x in a_desinscrire
|
||||||
]
|
]
|
||||||
@ -667,7 +672,7 @@ function chkbx_select(field_id, state) {
|
|||||||
"%s (%s)"
|
"%s (%s)"
|
||||||
% (
|
% (
|
||||||
modsdict[x]["module"]["titre"],
|
modsdict[x]["module"]["titre"],
|
||||||
modsdict[x]["module"]["code"],
|
modsdict[x]["module"]["code"] or "(module sans code)",
|
||||||
)
|
)
|
||||||
for x in a_inscrire
|
for x in a_inscrire
|
||||||
]
|
]
|
||||||
@ -785,7 +790,9 @@ def list_inscrits_ailleurs(formsemestre_id):
|
|||||||
Pour chacun, donne la liste des semestres.
|
Pour chacun, donne la liste des semestres.
|
||||||
{ etudid : [ liste de sems ] }
|
{ etudid : [ liste de sems ] }
|
||||||
"""
|
"""
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etudids
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
etudids = nt.get_etudids()
|
etudids = nt.get_etudids()
|
||||||
d = {}
|
d = {}
|
||||||
for etudid in etudids:
|
for etudid in etudids:
|
||||||
|
@ -36,8 +36,8 @@ from flask_login import current_user
|
|||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
from app.models import Module
|
from app.models import Module
|
||||||
from app.models import formsemestre
|
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.sco_utils import ModuleType
|
from app.scodoc.sco_utils import ModuleType
|
||||||
@ -51,7 +51,6 @@ from app.scodoc import sco_archives
|
|||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_compute_moy
|
from app.scodoc import sco_compute_moy
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
@ -597,7 +596,8 @@ def formsemestre_description_table(formsemestre_id, with_evals=False):
|
|||||||
Liste des modules et de leurs coefficients
|
Liste des modules et de leurs coefficients
|
||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
|
use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
|
||||||
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
||||||
@ -638,7 +638,7 @@ def formsemestre_description_table(formsemestre_id, with_evals=False):
|
|||||||
)
|
)
|
||||||
l = {
|
l = {
|
||||||
"UE": M["ue"]["acronyme"],
|
"UE": M["ue"]["acronyme"],
|
||||||
"Code": M["module"]["code"],
|
"Code": M["module"]["code"] or "",
|
||||||
"Module": M["module"]["abbrev"] or M["module"]["titre"],
|
"Module": M["module"]["abbrev"] or M["module"]["titre"],
|
||||||
"_Module_class": "scotext",
|
"_Module_class": "scotext",
|
||||||
"Inscrits": len(ModInscrits),
|
"Inscrits": len(ModInscrits),
|
||||||
@ -991,7 +991,6 @@ def formsemestre_status(formsemestre_id=None):
|
|||||||
modimpls = sco_moduleimpl.moduleimpl_withmodule_list(
|
modimpls = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
formsemestre_id=formsemestre_id
|
formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
# nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt = res_sem.load_formsemestre_results(formsemestre)
|
nt = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ import time
|
|||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
from app.api.sco_api import formsemestre
|
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
@ -40,6 +39,7 @@ from app import log
|
|||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_common import NotesTableCompat
|
from app.comp.res_common import NotesTableCompat
|
||||||
from app.models import FormSemestre
|
from app.models import FormSemestre
|
||||||
|
from app.models.notes import etud_has_notes_attente
|
||||||
|
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
@ -53,9 +53,7 @@ from app.scodoc import sco_cache
|
|||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
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_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
from app.scodoc.sco_parcours_dut import etud_est_inscrit_ue
|
from app.scodoc.sco_parcours_dut import etud_est_inscrit_ue
|
||||||
from app.scodoc import sco_photos
|
from app.scodoc import sco_photos
|
||||||
@ -72,9 +70,8 @@ def formsemestre_validation_etud_form(
|
|||||||
sortcol=None,
|
sortcol=None,
|
||||||
readonly=True,
|
readonly=True,
|
||||||
):
|
):
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
formsemestre_id
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > get_table_moyennes_triees, get_etud_decision_sem
|
|
||||||
T = nt.get_table_moyennes_triees()
|
T = nt.get_table_moyennes_triees()
|
||||||
if not etudid and etud_index is None:
|
if not etudid and etud_index is None:
|
||||||
raise ValueError("formsemestre_validation_etud_form: missing argument etudid")
|
raise ValueError("formsemestre_validation_etud_form: missing argument etudid")
|
||||||
@ -202,7 +199,7 @@ def formsemestre_validation_etud_form(
|
|||||||
decision_jury = Se.nt.get_etud_decision_sem(etudid)
|
decision_jury = Se.nt.get_etud_decision_sem(etudid)
|
||||||
|
|
||||||
# Bloque si note en attente
|
# Bloque si note en attente
|
||||||
if nt.etud_has_notes_attente(etudid):
|
if etud_has_notes_attente(etudid, formsemestre_id):
|
||||||
H.append(
|
H.append(
|
||||||
tf_error_message(
|
tf_error_message(
|
||||||
f"""Impossible de statuer sur cet étudiant: il a des notes en
|
f"""Impossible de statuer sur cet étudiant: il a des notes en
|
||||||
@ -550,7 +547,6 @@ def formsemestre_recap_parcours_table(
|
|||||||
|
|
||||||
formsemestre = FormSemestre.query.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get(sem["formsemestre_id"])
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
# nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
|
||||||
if is_cur:
|
if is_cur:
|
||||||
type_sem = "*" # now unused
|
type_sem = "*" # now unused
|
||||||
class_sem = "sem_courant"
|
class_sem = "sem_courant"
|
||||||
@ -649,7 +645,7 @@ def formsemestre_recap_parcours_table(
|
|||||||
else:
|
else:
|
||||||
code = ""
|
code = ""
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
moy_ue = ue_status["moy"]
|
moy_ue = ue_status["moy"] if ue_status else ""
|
||||||
explanation_ue = [] # list of strings
|
explanation_ue = [] # list of strings
|
||||||
if code == ADM:
|
if code == ADM:
|
||||||
class_ue = "ue_adm"
|
class_ue = "ue_adm"
|
||||||
@ -657,12 +653,12 @@ def formsemestre_recap_parcours_table(
|
|||||||
class_ue = "ue_cmp"
|
class_ue = "ue_cmp"
|
||||||
else:
|
else:
|
||||||
class_ue = "ue"
|
class_ue = "ue"
|
||||||
if ue_status["is_external"]: # validation externe
|
if ue_status and ue_status["is_external"]: # validation externe
|
||||||
explanation_ue.append("UE externe.")
|
explanation_ue.append("UE externe.")
|
||||||
# log('x'*12+' EXTERNAL %s' % notes_table.fmt_note(moy_ue)) XXXXXXX
|
# log('x'*12+' EXTERNAL %s' % notes_table.fmt_note(moy_ue)) XXXXXXX
|
||||||
# log('UE=%s' % pprint.pformat(ue))
|
# log('UE=%s' % pprint.pformat(ue))
|
||||||
# log('explanation_ue=%s\n'%explanation_ue)
|
# log('explanation_ue=%s\n'%explanation_ue)
|
||||||
if ue_status["is_capitalized"]:
|
if ue_status and ue_status["is_capitalized"]:
|
||||||
class_ue += " ue_capitalized"
|
class_ue += " ue_capitalized"
|
||||||
explanation_ue.append(
|
explanation_ue.append(
|
||||||
"Capitalisée le %s." % (ue_status["event_date"] or "?")
|
"Capitalisée le %s." % (ue_status["event_date"] or "?")
|
||||||
@ -709,7 +705,10 @@ def formsemestre_recap_parcours_table(
|
|||||||
# ECTS validables dans chaque UE
|
# ECTS validables dans chaque UE
|
||||||
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"])
|
||||||
H.append('<td class="ue">%g</td>' % (ue_status["ects_pot"]))
|
H.append(
|
||||||
|
'<td class="ue">%g</td>'
|
||||||
|
% (ue_status["ects_pot"] if ue_status else "")
|
||||||
|
)
|
||||||
H.append("<td></td></tr>")
|
H.append("<td></td></tr>")
|
||||||
|
|
||||||
H.append("</table>")
|
H.append("</table>")
|
||||||
@ -878,9 +877,8 @@ def do_formsemestre_validation_auto(formsemestre_id):
|
|||||||
"Saisie automatisee des decisions d'un semestre"
|
"Saisie automatisee des decisions d'un semestre"
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
next_semestre_id = sem["semestre_id"] + 1
|
next_semestre_id = sem["semestre_id"] + 1
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
formsemestre_id
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > get_etudids, get_etud_decision_sem,
|
|
||||||
etudids = nt.get_etudids()
|
etudids = nt.get_etudids()
|
||||||
nb_valid = 0
|
nb_valid = 0
|
||||||
conflicts = [] # liste des etudiants avec decision differente déjà saisie
|
conflicts = [] # liste des etudiants avec decision differente déjà saisie
|
||||||
@ -899,7 +897,7 @@ def do_formsemestre_validation_auto(formsemestre_id):
|
|||||||
)
|
)
|
||||||
and Se.barre_moy_ok
|
and Se.barre_moy_ok
|
||||||
and Se.barres_ue_ok
|
and Se.barres_ue_ok
|
||||||
and not nt.etud_has_notes_attente(etudid)
|
and not etud_has_notes_attente(etudid, formsemestre_id)
|
||||||
):
|
):
|
||||||
# check: s'il existe une decision ou autorisation et qu'elles sont differentes,
|
# check: s'il existe une decision ou autorisation et qu'elles sont differentes,
|
||||||
# warning (et ne fait rien)
|
# warning (et ne fait rien)
|
||||||
@ -1133,9 +1131,11 @@ def do_formsemestre_validate_previous_ue(
|
|||||||
Si le coefficient est spécifié, modifie le coefficient de
|
Si le coefficient est spécifié, modifie le coefficient de
|
||||||
cette UE (utile seulement pour les semestres extérieurs).
|
cette UE (utile seulement pour les semestres extérieurs).
|
||||||
"""
|
"""
|
||||||
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_ue_status
|
|
||||||
if ue_coefficient != None:
|
if ue_coefficient != None:
|
||||||
sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
|
sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
|
||||||
cnx, formsemestre_id, ue_id, ue_coefficient
|
cnx, formsemestre_id, ue_id, ue_coefficient
|
||||||
|
@ -45,6 +45,9 @@ from flask import g, request
|
|||||||
from flask import url_for, make_response
|
from flask import url_for, make_response
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre, formsemestre
|
||||||
from app.models import GROUPNAME_STR_LEN, SHORT_STR_LEN
|
from app.models import GROUPNAME_STR_LEN, SHORT_STR_LEN
|
||||||
from app.models.groups import Partition
|
from app.models.groups import Partition
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
@ -488,17 +491,14 @@ def XMLgetGroupsInPartition(partition_id): # was XMLgetGroupesTD
|
|||||||
<group ...>
|
<group ...>
|
||||||
...
|
...
|
||||||
"""
|
"""
|
||||||
from app.scodoc import sco_formsemestre
|
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
|
||||||
|
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
partition = get_partition(partition_id)
|
partition = get_partition(partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
etuds_set = {ins.etudid for ins in formsemestre.inscriptions}
|
||||||
|
|
||||||
|
sem = formsemestre.get_infos_dict() # transition TODO
|
||||||
groups = get_partition_groups(partition)
|
groups = get_partition_groups(partition)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > inscrdict
|
|
||||||
etuds_set = set(nt.inscrdict)
|
|
||||||
# Build XML:
|
# Build XML:
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
doc = Element("ajax-response")
|
doc = Element("ajax-response")
|
||||||
@ -1277,13 +1277,13 @@ def groups_auto_repartition(partition_id=None):
|
|||||||
|
|
||||||
partition = get_partition(partition_id)
|
partition = get_partition(partition_id)
|
||||||
formsemestre_id = partition["formsemestre_id"]
|
formsemestre_id = partition["formsemestre_id"]
|
||||||
|
formsemestre = FormSemestre.query.get(formsemestre_id)
|
||||||
# renvoie sur page édition groupes
|
# renvoie sur page édition groupes
|
||||||
dest_url = url_for(
|
dest_url = url_for(
|
||||||
"scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=partition_id
|
"scolar.affect_groups", scodoc_dept=g.scodoc_dept, partition_id=partition_id
|
||||||
)
|
)
|
||||||
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
if not sco_permissions_check.can_change_groups(formsemestre_id):
|
||||||
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
|
||||||
|
|
||||||
descr = [
|
descr = [
|
||||||
("partition_id", {"input_type": "hidden"}),
|
("partition_id", {"input_type": "hidden"}),
|
||||||
@ -1301,7 +1301,7 @@ def groups_auto_repartition(partition_id=None):
|
|||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Répartition des groupes"),
|
html_sco_header.sco_header(page_title="Répartition des groupes"),
|
||||||
"<h2>Répartition des groupes de %s</h2>" % partition["partition_name"],
|
"<h2>Répartition des groupes de %s</h2>" % partition["partition_name"],
|
||||||
"<p>Semestre %s</p>" % sem["titreannee"],
|
f"<p>Semestre {formsemestre.titre_annee()}</p>",
|
||||||
"""<p class="help">Les groupes existants seront <b>effacés</b> et remplacés par
|
"""<p class="help">Les groupes existants seront <b>effacés</b> et remplacés par
|
||||||
ceux créés ici. La répartition aléatoire tente d'uniformiser le niveau
|
ceux créés ici. La répartition aléatoire tente d'uniformiser le niveau
|
||||||
des groupes (en utilisant la dernière moyenne générale disponible pour
|
des groupes (en utilisant la dernière moyenne générale disponible pour
|
||||||
@ -1343,7 +1343,7 @@ def groups_auto_repartition(partition_id=None):
|
|||||||
# return '\n'.join(H) + tf[1] + html_sco_header.sco_footer()
|
# return '\n'.join(H) + tf[1] + html_sco_header.sco_footer()
|
||||||
group_ids.append(create_group(partition_id, group_name))
|
group_ids.append(create_group(partition_id, group_name))
|
||||||
#
|
#
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > identdict
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
identdict = nt.identdict
|
identdict = nt.identdict
|
||||||
# build: { civilite : liste etudids trie par niveau croissant }
|
# build: { civilite : liste etudids trie par niveau croissant }
|
||||||
civilites = set([x["civilite"] for x in identdict.values()])
|
civilites = set([x["civilite"] for x in identdict.values()])
|
||||||
@ -1384,9 +1384,8 @@ def _get_prev_moy(etudid, formsemestre_id):
|
|||||||
etud = info[0]
|
etud = info[0]
|
||||||
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
|
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
|
||||||
if Se.prev:
|
if Se.prev:
|
||||||
nt = sco_cache.NotesTableCache.get(
|
prev_sem = FormSemestre.query.get(Se.prev["formsemestre_id"])
|
||||||
Se.prev["formsemestre_id"]
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(prev_sem)
|
||||||
) # > get_etud_moy_gen
|
|
||||||
return nt.get_etud_moy_gen(etudid)
|
return nt.get_etud_moy_gen(etudid)
|
||||||
else:
|
else:
|
||||||
return 0.0
|
return 0.0
|
||||||
|
@ -31,16 +31,17 @@
|
|||||||
import flask
|
import flask
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
|
|
||||||
from app import models
|
|
||||||
from app.models.evaluations import Evaluation
|
|
||||||
from app.models.moduleimpls import ModuleImpl
|
|
||||||
import app.scodoc.sco_utils as scu
|
|
||||||
import app.scodoc.notesdb as ndb
|
|
||||||
from app import log
|
from app import log
|
||||||
|
from app import models
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp import moy_mod
|
from app.comp import moy_mod
|
||||||
from app.comp.moy_mod import ModuleImplResults
|
from app.comp.moy_mod import ModuleImplResults
|
||||||
from app.comp.res_common import NotesTableCompat
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
|
from app.models.evaluations import Evaluation
|
||||||
|
from app.models.moduleimpls import ModuleImpl
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
@ -788,7 +789,9 @@ def _add_moymod_column(
|
|||||||
):
|
):
|
||||||
"""Ajoute la colonne moymod à rows"""
|
"""Ajoute la colonne moymod à rows"""
|
||||||
col_id = "moymod"
|
col_id = "moymod"
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_mod_moy
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
nb_notes = 0
|
nb_notes = 0
|
||||||
sum_notes = 0
|
sum_notes = 0
|
||||||
notes = [] # liste des notes numeriques, pour calcul histogramme uniquement
|
notes = [] # liste des notes numeriques, pour calcul histogramme uniquement
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
import psycopg2
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
@ -271,7 +272,12 @@ _moduleimpl_inscriptionEditor = ndb.EditableTable(
|
|||||||
def do_moduleimpl_inscription_create(args, formsemestre_id=None):
|
def do_moduleimpl_inscription_create(args, formsemestre_id=None):
|
||||||
"create a moduleimpl_inscription"
|
"create a moduleimpl_inscription"
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
|
try:
|
||||||
r = _moduleimpl_inscriptionEditor.create(cnx, args)
|
r = _moduleimpl_inscriptionEditor.create(cnx, args)
|
||||||
|
except psycopg2.errors.UniqueViolation as exc:
|
||||||
|
raise ScoValueError(
|
||||||
|
"Inscription impossible car déjà existante: vérifiez la situation"
|
||||||
|
)
|
||||||
sco_cache.invalidate_formsemestre(
|
sco_cache.invalidate_formsemestre(
|
||||||
formsemestre_id=formsemestre_id
|
formsemestre_id=formsemestre_id
|
||||||
) # > moduleimpl_inscription
|
) # > moduleimpl_inscription
|
||||||
|
@ -33,6 +33,10 @@ import flask
|
|||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import log
|
from app import log
|
||||||
@ -88,7 +92,11 @@ def moduleimpl_inscriptions_edit(moduleimpl_id, etuds=[], submitted=False):
|
|||||||
"Appliquer les modifications".
|
"Appliquer les modifications".
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
% (moduleimpl_id, mod["titre"], mod["code"]),
|
% (
|
||||||
|
moduleimpl_id,
|
||||||
|
mod["titre"] or "(module sans titre)",
|
||||||
|
mod["code"] or "(module sans code)",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
# Liste des inscrits à ce semestre
|
# Liste des inscrits à ce semestre
|
||||||
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
||||||
@ -304,8 +312,8 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
|
|||||||
H.append(
|
H.append(
|
||||||
'<tr class="formsemestre_status"><td>%s</td><td class="formsemestre_status_code">%s</td><td class="formsemestre_status_inscrits">%s</td><td>%s</td></tr>'
|
'<tr class="formsemestre_status"><td>%s</td><td class="formsemestre_status_code">%s</td><td class="formsemestre_status_inscrits">%s</td><td>%s</td></tr>'
|
||||||
% (
|
% (
|
||||||
mod["ue"]["acronyme"],
|
mod["ue"]["acronyme"] or "",
|
||||||
mod["module"]["code"],
|
mod["module"]["code"] or "(module sans code)",
|
||||||
mod["nb_inscrits"],
|
mod["nb_inscrits"],
|
||||||
c_link,
|
c_link,
|
||||||
)
|
)
|
||||||
@ -333,7 +341,11 @@ def moduleimpl_inscriptions_stats(formsemestre_id):
|
|||||||
c_link = mod["module"]["titre"]
|
c_link = mod["module"]["titre"]
|
||||||
H.append(
|
H.append(
|
||||||
'<tr class="formsemestre_status_green"><td>%s</td><td class="formsemestre_status_code">%s</td><td>%s</td></tr>'
|
'<tr class="formsemestre_status_green"><td>%s</td><td class="formsemestre_status_code">%s</td><td>%s</td></tr>'
|
||||||
% (mod["ue"]["acronyme"], mod["module"]["code"], c_link)
|
% (
|
||||||
|
mod["ue"]["acronyme"],
|
||||||
|
mod["module"]["code"] or "(module sans code)",
|
||||||
|
c_link,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
H.append("</table>")
|
H.append("</table>")
|
||||||
|
|
||||||
@ -479,21 +491,21 @@ 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 = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
formsemestre_id
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > 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_stat_dict()
|
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"])
|
ue_status = nt.get_etud_ue_status(etud["etudid"], ue["ue_id"])
|
||||||
if status["was_capitalized"]:
|
if ue_status and ue_status["was_capitalized"]:
|
||||||
UECaps[ue["ue_id"]].append(
|
UECaps[ue["ue_id"]].append(
|
||||||
{
|
{
|
||||||
"etudid": etud["etudid"],
|
"etudid": etud["etudid"],
|
||||||
"ue_status": status,
|
"ue_status": ue_status,
|
||||||
"is_ins": is_inscrit_ue(
|
"is_ins": is_inscrit_ue(
|
||||||
etud["etudid"], formsemestre_id, ue["ue_id"]
|
etud["etudid"], formsemestre_id, ue["ue_id"]
|
||||||
),
|
),
|
||||||
|
@ -203,7 +203,6 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
moduleimpl_id=M["moduleimpl_id"]
|
moduleimpl_id=M["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
# nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(modimpl.formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(modimpl.formsemestre)
|
||||||
|
|
||||||
mod_evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
mod_evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||||
|
@ -36,7 +36,7 @@ import app.scodoc.sco_utils as scu
|
|||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache, sco_etud
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc.sco_codes_parcours import (
|
from app.scodoc.sco_codes_parcours import (
|
||||||
@ -111,9 +111,6 @@ class DecisionSem(object):
|
|||||||
|
|
||||||
def SituationEtudParcours(etud, formsemestre_id):
|
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(
|
|
||||||
# formsemestre_id
|
|
||||||
# ) # > get_etud_decision_sem, get_etud_moy_gen, get_ues_stat_dict, get_etud_ue_status, etud_check_conditions_ues
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
parcours = nt.parcours
|
parcours = nt.parcours
|
||||||
@ -302,9 +299,6 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
sem["semestre_id"] == n1
|
sem["semestre_id"] == n1
|
||||||
and sem["formation_code"] == self.formation.formation_code
|
and sem["formation_code"] == self.formation.formation_code
|
||||||
):
|
):
|
||||||
# nt = sco_cache.NotesTableCache.get(
|
|
||||||
# sem["formsemestre_id"]
|
|
||||||
# ) # > get_etud_decision_sem
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(
|
||||||
formsemestre
|
formsemestre
|
||||||
@ -322,9 +316,6 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
sont validés. En sortie, sem_idx_set contient ceux qui n'ont pas été validés."""
|
sont validés. En sortie, sem_idx_set contient ceux qui n'ont pas été validés."""
|
||||||
for sem in self.get_semestres():
|
for sem in self.get_semestres():
|
||||||
if sem["formation_code"] == self.formation.formation_code:
|
if sem["formation_code"] == self.formation.formation_code:
|
||||||
# nt = sco_cache.NotesTableCache.get(
|
|
||||||
# sem["formsemestre_id"]
|
|
||||||
# ) # > get_etud_decision_sem
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
decision = nt.get_etud_decision_sem(self.etudid)
|
decision = nt.get_etud_decision_sem(self.etudid)
|
||||||
@ -336,15 +327,16 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
|
|
||||||
def _comp_semestres(self):
|
def _comp_semestres(self):
|
||||||
# etud['sems'] est trie par date decroissante (voir fill_etuds_info)
|
# etud['sems'] est trie par date decroissante (voir fill_etuds_info)
|
||||||
|
if not "sems" in self.etud:
|
||||||
|
self.etud["sems"] = sco_etud.etud_inscriptions_infos(
|
||||||
|
self.etud["etudid"], self.etud["ne"]
|
||||||
|
)["sems"]
|
||||||
sems = self.etud["sems"][:] # copy
|
sems = self.etud["sems"][:] # copy
|
||||||
sems.reverse()
|
sems.reverse()
|
||||||
# Nb max d'UE et acronymes
|
# Nb max d'UE et acronymes
|
||||||
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_stat_dict
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
ues = nt.get_ues_stat_dict(filter_sport=True)
|
ues = nt.get_ues_stat_dict(filter_sport=True)
|
||||||
@ -414,9 +406,6 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
if not sem:
|
if not sem:
|
||||||
code = "" # non inscrit à ce semestre
|
code = "" # non inscrit à ce semestre
|
||||||
else:
|
else:
|
||||||
# nt = sco_cache.NotesTableCache.get(
|
|
||||||
# sem["formsemestre_id"]
|
|
||||||
# ) # > get_etud_decision_sem
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
decision = nt.get_etud_decision_sem(self.etudid)
|
decision = nt.get_etud_decision_sem(self.etudid)
|
||||||
@ -486,7 +475,6 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
# Verifications basiques:
|
# Verifications basiques:
|
||||||
# ?
|
# ?
|
||||||
# Code etat du semestre precedent:
|
# Code etat du semestre precedent:
|
||||||
# nt = sco_cache.NotesTableCache.get(prev["formsemestre_id"])
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(prev["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(prev["formsemestre_id"])
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
self.prev_decision = nt.get_etud_decision_sem(self.etudid)
|
self.prev_decision = nt.get_etud_decision_sem(self.etudid)
|
||||||
@ -545,8 +533,6 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
sem["formation_code"] == self.formation.formation_code
|
sem["formation_code"] == self.formation.formation_code
|
||||||
and sem["semestre_id"] == s
|
and sem["semestre_id"] == s
|
||||||
):
|
):
|
||||||
# nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
|
||||||
# > get_etud_decision_sem
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(
|
||||||
formsemestre
|
formsemestre
|
||||||
@ -924,9 +910,6 @@ 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_stat_dict, get_etud_ue_status
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
ue_ids = [x["ue_id"] for x in nt.get_ues_stat_dict(filter_sport=True)]
|
ue_ids = [x["ue_id"] for x in nt.get_ues_stat_dict(filter_sport=True)]
|
||||||
@ -1005,7 +988,8 @@ def do_formsemestre_validate_ue(
|
|||||||
if code == ADM:
|
if code == ADM:
|
||||||
if moy_ue is None:
|
if moy_ue is None:
|
||||||
# stocke la moyenne d'UE capitalisée:
|
# stocke la moyenne d'UE capitalisée:
|
||||||
moy_ue = nt.get_etud_ue_status(etudid, ue_id)["moy"]
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
|
moy_ue = ue_status["moy"] if ue_status else ""
|
||||||
args["moy_ue"] = moy_ue
|
args["moy_ue"] = moy_ue
|
||||||
log("formsemestre_validate_ue: create %s" % args)
|
log("formsemestre_validate_ue: create %s" % args)
|
||||||
if code != None:
|
if code != None:
|
||||||
|
@ -257,7 +257,7 @@ class PlacementRunner:
|
|||||||
self.moduleimpl_data["formsemestre_id"]
|
self.moduleimpl_data["formsemestre_id"]
|
||||||
)
|
)
|
||||||
self.evalname = "%s-%s" % (
|
self.evalname = "%s-%s" % (
|
||||||
self.module_data["code"],
|
self.module_data["code"] or "?",
|
||||||
ndb.DateDMYtoISO(self.eval_data["jour"]),
|
ndb.DateDMYtoISO(self.eval_data["jour"]),
|
||||||
)
|
)
|
||||||
if self.eval_data["description"]:
|
if self.eval_data["description"]:
|
||||||
@ -266,7 +266,8 @@ class PlacementRunner:
|
|||||||
self.evaltitre = "évaluation du %s" % self.eval_data["jour"]
|
self.evaltitre = "évaluation du %s" % self.eval_data["jour"]
|
||||||
self.desceval = [ # une liste de chaines: description de l'evaluation
|
self.desceval = [ # une liste de chaines: description de l'evaluation
|
||||||
"%s" % self.sem["titreannee"],
|
"%s" % self.sem["titreannee"],
|
||||||
"Module : %s - %s" % (self.module_data["code"], self.module_data["abbrev"]),
|
"Module : %s - %s"
|
||||||
|
% (self.module_data["code"] or "?", self.module_data["abbrev"] or ""),
|
||||||
"Surveillants : %s" % self.surveillants,
|
"Surveillants : %s" % self.surveillants,
|
||||||
"Batiment : %(batiment)s - Salle : %(salle)s" % self.__dict__,
|
"Batiment : %(batiment)s - Salle : %(salle)s" % self.__dict__,
|
||||||
"Controle : %s (coef. %g)"
|
"Controle : %s (coef. %g)"
|
||||||
|
@ -33,6 +33,9 @@ import collections
|
|||||||
|
|
||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
@ -58,17 +61,25 @@ def etud_get_poursuite_info(sem, etud):
|
|||||||
for s in etud["sems"]:
|
for s in etud["sems"]:
|
||||||
if s["semestre_id"] == sem_id:
|
if s["semestre_id"] == sem_id:
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
nt = sco_cache.NotesTableCache.get(s["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
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_stat_dict(filter_sport=True)
|
ues = nt.get_ues_stat_dict(filter_sport=True)
|
||||||
moy_ues = [
|
moy_ues = []
|
||||||
|
for ue in ues:
|
||||||
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
|
if ue_status:
|
||||||
|
moy_ues.append(
|
||||||
(
|
(
|
||||||
ue["acronyme"],
|
ue["acronyme"],
|
||||||
scu.fmt_note(nt.get_etud_ue_status(etudid, ue["ue_id"])["moy"]),
|
scu.fmt_note(
|
||||||
|
nt.get_etud_ue_status(etudid, ue["ue_id"])["moy"]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
for ue in ues
|
)
|
||||||
]
|
else:
|
||||||
|
moy_ues.append((ue["acronyme"], ""))
|
||||||
rg_ues = [
|
rg_ues = [
|
||||||
("rang_" + ue["acronyme"], nt.ue_rangs[ue["ue_id"]][0][etudid])
|
("rang_" + ue["acronyme"], nt.ue_rangs[ue["ue_id"]][0][etudid])
|
||||||
for ue in ues
|
for ue in ues
|
||||||
@ -81,14 +92,17 @@ def etud_get_poursuite_info(sem, etud):
|
|||||||
for ue in ues: # on parcourt chaque UE
|
for ue in ues: # on parcourt chaque UE
|
||||||
for modimpl in modimpls: # dans chaque UE les modules
|
for modimpl in modimpls: # dans chaque UE les modules
|
||||||
if modimpl["module"]["ue_id"] == ue["ue_id"]:
|
if modimpl["module"]["ue_id"] == ue["ue_id"]:
|
||||||
codeModule = modimpl["module"]["code"]
|
codeModule = modimpl["module"]["code"] or ""
|
||||||
noteModule = scu.fmt_note(
|
noteModule = scu.fmt_note(
|
||||||
nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
||||||
)
|
)
|
||||||
if noteModule != "NI": # si étudiant inscrit au module
|
if noteModule != "NI": # si étudiant inscrit au module
|
||||||
rangModule = nt.mod_rangs[modimpl["moduleimpl_id"]][0][
|
if nt.mod_rangs is not None:
|
||||||
etudid
|
rangModule = nt.mod_rangs[modimpl["moduleimpl_id"]][
|
||||||
]
|
0
|
||||||
|
][etudid]
|
||||||
|
else:
|
||||||
|
rangModule = ""
|
||||||
modules.append([codeModule, noteModule])
|
modules.append([codeModule, noteModule])
|
||||||
rangs.append(["rang_" + codeModule, rangModule])
|
rangs.append(["rang_" + codeModule, rangModule])
|
||||||
|
|
||||||
|
@ -68,17 +68,17 @@ des tuples (name, value, formsemestre_id).
|
|||||||
Si formsemestre_id est NULL, la valeur concerne tous les semestres,
|
Si formsemestre_id est NULL, la valeur concerne tous les semestres,
|
||||||
sinon, elle ne concerne que le semestre indiqué.
|
sinon, elle ne concerne que le semestre indiqué.
|
||||||
|
|
||||||
* Utilisation dans ScoDoc8
|
* Utilisation dans ScoDoc 9
|
||||||
- lire une valeur:
|
- lire une valeur:
|
||||||
get_preference(name, formsemestre_id)
|
get_preference(name, formsemestre_id)
|
||||||
nb: les valeurs sont des chaines, sauf:
|
nb: les valeurs sont des chaines, sauf:
|
||||||
. si le type est spécfié (float ou int)
|
. si le type est spécifié (float ou int)
|
||||||
. les boolcheckbox qui sont des entiers 0 ou 1
|
. les boolcheckbox qui sont des entiers 0 ou 1
|
||||||
- avoir un mapping (read only) de toutes les valeurs:
|
- avoir un mapping (read only) de toutes les valeurs:
|
||||||
sco_preferences.SemPreferences(formsemestre_id)
|
sco_preferences.SemPreferences(formsemestre_id)
|
||||||
- editer les preferences globales:
|
- éditer les preferences globales:
|
||||||
sco_preferences.get_base_preferences(self).edit()
|
sco_preferences.get_base_preferences(self).edit()
|
||||||
- editer les preferences d'un semestre:
|
- éditer les preferences d'un semestre:
|
||||||
SemPreferences(formsemestre_id).edit()
|
SemPreferences(formsemestre_id).edit()
|
||||||
|
|
||||||
* Implémentation: sco_preferences.py
|
* Implémentation: sco_preferences.py
|
||||||
@ -123,22 +123,22 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
|
|||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
_SCO_BASE_PREFERENCES = {} # { dept_acronym: BasePreferences instance }
|
|
||||||
|
|
||||||
|
|
||||||
def clear_base_preferences():
|
def clear_base_preferences():
|
||||||
"""Clear cached preferences"""
|
"""Clear cached preferences"""
|
||||||
# usefull only for tests, where the same process may run
|
# usefull only for tests, where the same process may run
|
||||||
# successively on several databases
|
# successively on several databases
|
||||||
_SCO_BASE_PREFERENCES.clear()
|
g._SCO_BASE_PREFERENCES = {} # { dept_id: BasePreferences instance }
|
||||||
|
|
||||||
|
|
||||||
def get_base_preferences():
|
def get_base_preferences():
|
||||||
"""Return global preferences for the current department"""
|
"""Return global preferences for the current department"""
|
||||||
dept_acronym = g.scodoc_dept
|
dept_id = g.scodoc_dept_id
|
||||||
if not dept_acronym in _SCO_BASE_PREFERENCES:
|
if not hasattr(g, "_SCO_BASE_PREFERENCES"):
|
||||||
_SCO_BASE_PREFERENCES[dept_acronym] = BasePreferences(dept_acronym)
|
g._SCO_BASE_PREFERENCES = {}
|
||||||
return _SCO_BASE_PREFERENCES[dept_acronym]
|
if not dept_id in g._SCO_BASE_PREFERENCES:
|
||||||
|
g._SCO_BASE_PREFERENCES[dept_id] = BasePreferences(dept_id)
|
||||||
|
return g._SCO_BASE_PREFERENCES[dept_id]
|
||||||
|
|
||||||
|
|
||||||
def get_preference(name, formsemestre_id=None):
|
def get_preference(name, formsemestre_id=None):
|
||||||
@ -263,10 +263,10 @@ class BasePreferences(object):
|
|||||||
filter_nulls=False,
|
filter_nulls=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, dept_acronym: str):
|
def __init__(self, dept_id: int):
|
||||||
dept = Departement.query.filter_by(acronym=dept_acronym).first()
|
dept = Departement.query.get(dept_id)
|
||||||
if not dept:
|
if not dept:
|
||||||
raise ScoValueError(f"Invalid departement: {dept_acronym}")
|
raise ScoValueError(f"Invalid departement: {dept_id}")
|
||||||
self.dept_id = dept.id
|
self.dept_id = dept.id
|
||||||
self.init()
|
self.init()
|
||||||
self.load()
|
self.load()
|
||||||
@ -1859,7 +1859,7 @@ class BasePreferences(object):
|
|||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
"""Load all preferences from db"""
|
"""Load all preferences from db"""
|
||||||
log(f"loading preferences for dept_id={self.dept_id}")
|
# log(f"loading preferences for dept_id={self.dept_id}")
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
preflist = self._editor.list(cnx, {"dept_id": self.dept_id})
|
preflist = self._editor.list(cnx, {"dept_id": self.dept_id})
|
||||||
@ -2114,7 +2114,7 @@ class BasePreferences(object):
|
|||||||
return form
|
return form
|
||||||
|
|
||||||
|
|
||||||
class SemPreferences(object):
|
class SemPreferences:
|
||||||
"""Preferences for a formsemestre"""
|
"""Preferences for a formsemestre"""
|
||||||
|
|
||||||
def __init__(self, formsemestre_id=None):
|
def __init__(self, formsemestre_id=None):
|
||||||
@ -2270,9 +2270,8 @@ 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:
|
def bulletin_option_affichage(formsemestre_id: int, prefs: SemPreferences) -> dict:
|
||||||
"dict avec les options d'affichages (préférences) pour ce semestre"
|
"dict avec les options d'affichages (préférences) pour ce semestre"
|
||||||
prefs = SemPreferences(formsemestre_id)
|
|
||||||
fields = (
|
fields = (
|
||||||
"bul_show_abs",
|
"bul_show_abs",
|
||||||
"bul_show_abs_modules",
|
"bul_show_abs_modules",
|
||||||
|
@ -31,29 +31,30 @@ import time
|
|||||||
|
|
||||||
from openpyxl.styles.numbers import FORMAT_NUMBER_00
|
from openpyxl.styles.numbers import FORMAT_NUMBER_00
|
||||||
|
|
||||||
|
from flask import flash
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre, Identite
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_excel
|
from app.scodoc import sco_excel
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
from app.scodoc import sco_codes_parcours
|
|
||||||
import sco_version
|
|
||||||
from app.scodoc import sco_etud
|
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc.sco_excel import ScoExcelSheet
|
import app.scodoc.sco_utils as scu
|
||||||
|
import sco_version
|
||||||
|
|
||||||
|
|
||||||
def feuille_preparation_jury(formsemestre_id):
|
def feuille_preparation_jury(formsemestre_id):
|
||||||
"Feuille excel pour preparation des jurys"
|
"Feuille excel pour preparation des jurys"
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
formsemestre_id
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > get_etudids, get_etud_moy_gen, get_ues_stat_dict, get_etud_ue_status, get_etud_decision_sem, identdict,
|
etuds: Identite = nt.get_inscrits(order_by="moy") # 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)
|
||||||
|
|
||||||
etud_groups = sco_groups.formsemestre_get_etud_groupnames(formsemestre_id)
|
etud_groups = sco_groups.formsemestre_get_etud_groupnames(formsemestre_id)
|
||||||
@ -76,68 +77,65 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
groupestd = {} # etudid : nom groupe principal
|
groupestd = {} # etudid : nom groupe principal
|
||||||
nbabs = {}
|
nbabs = {}
|
||||||
nbabsjust = {}
|
nbabsjust = {}
|
||||||
for etudid in etudids:
|
for etud in etuds:
|
||||||
info = sco_etud.get_etud_info(etudid=etudid, filled=True)
|
Se = sco_parcours_dut.SituationEtudParcours(
|
||||||
if not info:
|
etud.to_dict_scodoc7(), formsemestre_id
|
||||||
continue # should not occur...
|
)
|
||||||
etud = info[0]
|
|
||||||
Se = sco_parcours_dut.SituationEtudParcours(etud, formsemestre_id)
|
|
||||||
if Se.prev:
|
if Se.prev:
|
||||||
ntp = sco_cache.NotesTableCache.get(
|
formsemestre_prev = FormSemestre.query.get_or_404(
|
||||||
Se.prev["formsemestre_id"]
|
Se.prev["formsemestre_id"]
|
||||||
) # > get_ues_stat_dict, get_etud_ue_status, get_etud_moy_gen, get_etud_decision_sem
|
)
|
||||||
|
ntp: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre_prev)
|
||||||
for ue in ntp.get_ues_stat_dict(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(etud.id, 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"]
|
||||||
) # code indentifiant l'UE
|
) # code indentifiant l'UE
|
||||||
prev_moy_ue[ue_code_s][etudid] = ue_status["moy"]
|
prev_moy_ue[ue_code_s][etud.id] = ue_status["moy"] if ue_status else ""
|
||||||
# prev_ue_acro[ue_code_s] = (ue['numero'], ue['acronyme'])
|
|
||||||
prev_ue_acro[ue_code_s] = (ue["numero"], ue["acronyme"], ue["titre"])
|
prev_ue_acro[ue_code_s] = (ue["numero"], ue["acronyme"], ue["titre"])
|
||||||
prev_moy[etudid] = ntp.get_etud_moy_gen(etudid)
|
prev_moy[etud.id] = ntp.get_etud_moy_gen(etud.id)
|
||||||
prev_decision = ntp.get_etud_decision_sem(etudid)
|
prev_decision = ntp.get_etud_decision_sem(etud.id)
|
||||||
if prev_decision:
|
if prev_decision:
|
||||||
prev_code[etudid] = prev_decision["code"]
|
prev_code[etud.id] = prev_decision["code"]
|
||||||
if prev_decision["compense_formsemestre_id"]:
|
if prev_decision["compense_formsemestre_id"]:
|
||||||
prev_code[etudid] += "+" # indique qu'il a servi a compenser
|
prev_code[etud.id] += "+" # indique qu'il a servi a compenser
|
||||||
|
|
||||||
moy[etudid] = nt.get_etud_moy_gen(etudid)
|
moy[etud.id] = nt.get_etud_moy_gen(etud.id)
|
||||||
for ue in nt.get_ues_stat_dict(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(etud.id, 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][etud.id] = ue_status["moy"] if ue_status else ""
|
||||||
# ue_acro[ue_code_s] = (ue['numero'], ue['acronyme'])
|
|
||||||
ue_acro[ue_code_s] = (ue["numero"], ue["acronyme"], ue["titre"])
|
ue_acro[ue_code_s] = (ue["numero"], ue["acronyme"], ue["titre"])
|
||||||
|
|
||||||
if Se.prev:
|
if Se.prev:
|
||||||
try:
|
try:
|
||||||
moy_inter[etudid] = (moy[etudid] + prev_moy[etudid]) / 2.0
|
moy_inter[etud.id] = (moy[etud.id] + prev_moy[etud.id]) / 2.0
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
decision = nt.get_etud_decision_sem(etudid)
|
decision = nt.get_etud_decision_sem(etud.id)
|
||||||
if decision:
|
if decision:
|
||||||
code[etudid] = decision["code"]
|
code[etud.id] = decision["code"]
|
||||||
if decision["compense_formsemestre_id"]:
|
if decision["compense_formsemestre_id"]:
|
||||||
code[etudid] += "+" # indique qu'il a servi a compenser
|
code[etud.id] += "+" # indique qu'il a servi a compenser
|
||||||
assidu[etudid] = {False: "Non", True: "Oui"}.get(decision["assidu"], "")
|
assidu[etud.id] = {False: "Non", True: "Oui"}.get(decision["assidu"], "")
|
||||||
aut_list = sco_parcours_dut.formsemestre_get_autorisation_inscription(
|
aut_list = sco_parcours_dut.formsemestre_get_autorisation_inscription(
|
||||||
etudid, formsemestre_id
|
etud.id, formsemestre_id
|
||||||
)
|
)
|
||||||
autorisations[etudid] = ", ".join(["S%s" % x["semestre_id"] for x in aut_list])
|
autorisations[etud.id] = ", ".join(["S%s" % x["semestre_id"] for x in aut_list])
|
||||||
# parcours:
|
# parcours:
|
||||||
parcours[etudid] = Se.get_parcours_descr()
|
parcours[etud.id] = Se.get_parcours_descr()
|
||||||
# groupe principal (td)
|
# groupe principal (td)
|
||||||
groupestd[etudid] = ""
|
groupestd[etud.id] = ""
|
||||||
for s in etud["sems"]:
|
for s in Se.etud["sems"]:
|
||||||
if s["formsemestre_id"] == formsemestre_id:
|
if s["formsemestre_id"] == formsemestre_id:
|
||||||
groupestd[etudid] = etud_groups.get(etudid, {}).get(
|
groupestd[etud.id] = etud_groups.get(etud.id, {}).get(
|
||||||
main_partition_id, ""
|
main_partition_id, ""
|
||||||
)
|
)
|
||||||
# absences:
|
# absences:
|
||||||
e_nbabs, e_nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
e_nbabs, e_nbabsjust = sco_abs.get_abs_count(etud.id, sem)
|
||||||
nbabs[etudid] = e_nbabs
|
nbabs[etud.id] = e_nbabs
|
||||||
nbabsjust[etudid] = e_nbabs - e_nbabsjust
|
nbabsjust[etud.id] = e_nbabs - e_nbabsjust
|
||||||
|
|
||||||
# Codes des UE "semestre précédent":
|
# Codes des UE "semestre précédent":
|
||||||
ue_prev_codes = list(prev_moy_ue.keys())
|
ue_prev_codes = list(prev_moy_ue.keys())
|
||||||
@ -229,26 +227,26 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
return x
|
return x
|
||||||
|
|
||||||
i = 1 # numero etudiant
|
i = 1 # numero etudiant
|
||||||
for etudid in etudids:
|
for etud in etuds:
|
||||||
cells = []
|
cells = []
|
||||||
etud = nt.identdict[etudid]
|
|
||||||
cells.append(ws.make_cell(str(i)))
|
cells.append(ws.make_cell(str(i)))
|
||||||
if sco_preferences.get_preference("prepa_jury_nip"):
|
if sco_preferences.get_preference("prepa_jury_nip"):
|
||||||
cells.append(ws.make_cell(etud["code_nip"]))
|
cells.append(ws.make_cell(etud.code_nip))
|
||||||
if sco_preferences.get_preference("prepa_jury_ine"):
|
if sco_preferences.get_preference("prepa_jury_ine"):
|
||||||
cells.append(ws.make_cell(etud["code_ine"]))
|
cells.append(ws.make_cell(etud.code_ine))
|
||||||
|
admission = etud.admission.first()
|
||||||
cells += ws.make_row(
|
cells += ws.make_row(
|
||||||
[
|
[
|
||||||
etudid,
|
etud.id,
|
||||||
etud["civilite_str"],
|
etud.civilite_str,
|
||||||
sco_etud.format_nom(etud["nom"]),
|
sco_etud.format_nom(etud.nom),
|
||||||
sco_etud.format_prenom(etud["prenom"]),
|
sco_etud.format_prenom(etud.prenom),
|
||||||
etud["date_naissance"],
|
etud.date_naissance,
|
||||||
etud["bac"],
|
admission.bac,
|
||||||
etud["specialite"],
|
admission.specialite,
|
||||||
etud["classement"],
|
admission.classement,
|
||||||
parcours[etudid],
|
parcours[etud.id],
|
||||||
groupestd[etudid],
|
groupestd[etud.id],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
co = len(cells)
|
co = len(cells)
|
||||||
@ -256,33 +254,35 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
for ue_acro in ue_prev_codes:
|
for ue_acro in ue_prev_codes:
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(
|
ws.make_cell(
|
||||||
fmt(prev_moy_ue.get(ue_acro, {}).get(etudid, "")), style_note
|
fmt(prev_moy_ue.get(ue_acro, {}).get(etud.id, "")), style_note
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
co += 1
|
co += 1
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(fmt(prev_moy.get(etudid, "")), style_bold)
|
ws.make_cell(fmt(prev_moy.get(etud.id, "")), style_bold)
|
||||||
) # moy gen prev
|
) # moy gen prev
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(fmt(prev_code.get(etudid, "")), style_moy)
|
ws.make_cell(fmt(prev_code.get(etud.id, "")), style_moy)
|
||||||
) # decision prev
|
) # decision prev
|
||||||
co += 2
|
co += 2
|
||||||
|
|
||||||
for ue_acro in ue_codes:
|
for ue_acro in ue_codes:
|
||||||
cells.append(
|
cells.append(
|
||||||
ws.make_cell(fmt(moy_ue.get(ue_acro, {}).get(etudid, "")), style_note)
|
ws.make_cell(fmt(moy_ue.get(ue_acro, {}).get(etud.id, "")), style_note)
|
||||||
)
|
)
|
||||||
co += 1
|
co += 1
|
||||||
cells.append(ws.make_cell(fmt(moy.get(etudid, "")), style_note_bold)) # moy gen
|
cells.append(
|
||||||
|
ws.make_cell(fmt(moy.get(etud.id, "")), style_note_bold)
|
||||||
|
) # moy gen
|
||||||
co += 1
|
co += 1
|
||||||
if moy_inter:
|
if moy_inter:
|
||||||
cells.append(ws.make_cell(fmt(moy_inter.get(etudid, "")), style_note))
|
cells.append(ws.make_cell(fmt(moy_inter.get(etud.id, "")), style_note))
|
||||||
cells.append(ws.make_cell(str(nbabs.get(etudid, "")), style_center))
|
cells.append(ws.make_cell(str(nbabs.get(etud.id, "")), style_center))
|
||||||
cells.append(ws.make_cell(str(nbabsjust.get(etudid, "")), style_center))
|
cells.append(ws.make_cell(str(nbabsjust.get(etud.id, "")), style_center))
|
||||||
if code:
|
if code:
|
||||||
cells.append(ws.make_cell(code.get(etudid, ""), style_moy))
|
cells.append(ws.make_cell(code.get(etud.id, ""), style_moy))
|
||||||
cells.append(ws.make_cell(autorisations.get(etudid, ""), style_moy))
|
cells.append(ws.make_cell(autorisations.get(etud.id, ""), style_moy))
|
||||||
# l.append(assidu.get(etudid, ''))
|
# l.append(assidu.get(etud.id, ''))
|
||||||
ws.append_row(cells)
|
ws.append_row(cells)
|
||||||
i += 1
|
i += 1
|
||||||
#
|
#
|
||||||
@ -326,6 +326,7 @@ def feuille_preparation_jury(formsemestre_id):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
xls = ws.generate()
|
xls = ws.generate()
|
||||||
|
flash("Feuille préparation jury générée")
|
||||||
return scu.send_file(
|
return scu.send_file(
|
||||||
xls,
|
xls,
|
||||||
f"PrepaJury{sn}",
|
f"PrepaJury{sn}",
|
||||||
|
@ -105,7 +105,7 @@ def _descr_decisions_ues(nt, etudid, decisions_ue, decision_sem):
|
|||||||
for ue_id in nt.validations.ue_capitalisees.loc[[etudid]]["ue_id"]:
|
for ue_id in nt.validations.ue_capitalisees.loc[[etudid]]["ue_id"]:
|
||||||
try:
|
try:
|
||||||
uelist.append(nt.get_etud_ue_status(etudid, ue_id)["ue"])
|
uelist.append(nt.get_etud_ue_status(etudid, ue_id)["ue"])
|
||||||
except KeyError:
|
except (KeyError, TypeError):
|
||||||
pass
|
pass
|
||||||
uelist.sort(key=itemgetter("numero"))
|
uelist.sort(key=itemgetter("numero"))
|
||||||
|
|
||||||
@ -162,13 +162,13 @@ def _comp_ects_by_ue_code(nt, decision_ues):
|
|||||||
return ects_by_ue_code
|
return ects_by_ue_code
|
||||||
|
|
||||||
|
|
||||||
def _comp_ects_capitalises_by_ue_code(nt, etudid):
|
def _comp_ects_capitalises_by_ue_code(nt: NotesTableCompat, etudid: int):
|
||||||
"""Calcul somme des ECTS des UE capitalisees"""
|
"""Calcul somme des ECTS des UE capitalisees"""
|
||||||
ues = nt.get_ues_stat_dict()
|
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"])
|
||||||
if ue_status["is_capitalized"]:
|
if ue_status and ue_status["is_capitalized"]:
|
||||||
ects_val = float(ue_status["ue"]["ects"] or 0.0)
|
ects_val = float(ue_status["ue"]["ects"] or 0.0)
|
||||||
ects_by_ue_code[ue["ue_code"]] = ects_val
|
ects_by_ue_code[ue["ue_code"]] = ects_val
|
||||||
|
|
||||||
@ -217,9 +217,6 @@ def dict_pvjury(
|
|||||||
'decisions_dict' : { etudid : decision (comme ci-dessus) },
|
'decisions_dict' : { etudid : decision (comme ci-dessus) },
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
# nt = sco_cache.NotesTableCache.get(
|
|
||||||
# formsemestre_id
|
|
||||||
# ) # > get_etudids, get_etud_etat, get_etud_decision_sem, get_etud_decision_ues
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
if etudids is None:
|
if etudids is None:
|
||||||
|
@ -50,7 +50,6 @@ from app.scodoc import sco_bulletins_json
|
|||||||
from app.scodoc import sco_bulletins_xml
|
from app.scodoc import sco_bulletins_xml
|
||||||
from app.scodoc import sco_bulletins, sco_excel
|
from app.scodoc import sco_bulletins, sco_excel
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
@ -307,8 +306,6 @@ def make_formsemestre_recapcomplet(
|
|||||||
)[0]
|
)[0]
|
||||||
parcours = formsemestre.formation.get_parcours()
|
parcours = formsemestre.formation.get_parcours()
|
||||||
|
|
||||||
# nt = sco_cache.NotesTableCache.get(formsemestre_id) # sco91
|
|
||||||
# sco92 :
|
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
modimpls = formsemestre.modimpls_sorted
|
modimpls = formsemestre.modimpls_sorted
|
||||||
ues = nt.get_ues_stat_dict() # incluant le(s) UE de sport
|
ues = nt.get_ues_stat_dict() # incluant le(s) UE de sport
|
||||||
@ -853,7 +850,13 @@ def _list_notes_evals_titles(codemodule: str, evals: list[Evaluation]) -> list[s
|
|||||||
L = []
|
L = []
|
||||||
eval_index = len(evals) - 1
|
eval_index = len(evals) - 1
|
||||||
for e in evals:
|
for e in evals:
|
||||||
L.append(codemodule + "-" + str(eval_index) + "-" + e.jour.isoformat())
|
L.append(
|
||||||
|
codemodule
|
||||||
|
+ "-"
|
||||||
|
+ str(eval_index)
|
||||||
|
+ "-"
|
||||||
|
+ (e.jour.isoformat() if e.jour else "")
|
||||||
|
)
|
||||||
eval_index -= 1
|
eval_index -= 1
|
||||||
return L
|
return L
|
||||||
|
|
||||||
@ -885,8 +888,8 @@ def _formsemestre_recapcomplet_xml(
|
|||||||
force_publishing=True,
|
force_publishing=True,
|
||||||
):
|
):
|
||||||
"XML export: liste tous les bulletins XML."
|
"XML export: liste tous les bulletins XML."
|
||||||
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_table_moyennes_triees
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
T = nt.get_table_moyennes_triees()
|
T = nt.get_table_moyennes_triees()
|
||||||
if not T:
|
if not T:
|
||||||
return "", "", "xml"
|
return "", "", "xml"
|
||||||
@ -956,7 +959,8 @@ def _formsemestre_recapcomplet_json(
|
|||||||
"bulletins": [],
|
"bulletins": [],
|
||||||
}
|
}
|
||||||
bulletins = J["bulletins"]
|
bulletins = J["bulletins"]
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_table_moyennes_triees
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
T = nt.get_table_moyennes_triees()
|
T = nt.get_table_moyennes_triees()
|
||||||
for t in T:
|
for t in T:
|
||||||
etudid = t[-1]
|
etudid = t[-1]
|
||||||
|
@ -39,14 +39,16 @@ from operator import itemgetter
|
|||||||
from flask import url_for, g, request
|
from flask import url_for, g, request
|
||||||
import pydot
|
import pydot
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.models import FormationModalite
|
from app.models import FormationModalite
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_excel
|
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
from app.scodoc import sco_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
@ -61,9 +63,9 @@ MAX_ETUD_IN_DESCR = 20
|
|||||||
|
|
||||||
def formsemestre_etuds_stats(sem, only_primo=False):
|
def formsemestre_etuds_stats(sem, only_primo=False):
|
||||||
"""Récupère liste d'etudiants avec etat et decision."""
|
"""Récupère liste d'etudiants avec etat et decision."""
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
sem["formsemestre_id"]
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > get_table_moyennes_triees, identdict, get_etud_decision_sem, get_etud_etat,
|
|
||||||
T = nt.get_table_moyennes_triees()
|
T = nt.get_table_moyennes_triees()
|
||||||
# Construit liste d'étudiants du semestre avec leur decision
|
# Construit liste d'étudiants du semestre avec leur decision
|
||||||
etuds = []
|
etuds = []
|
||||||
@ -400,9 +402,8 @@ def table_suivi_cohorte(
|
|||||||
|
|
||||||
logt("table_suivi_cohorte: start")
|
logt("table_suivi_cohorte: start")
|
||||||
# 1-- Liste des semestres posterieurs dans lesquels ont été les etudiants de sem
|
# 1-- Liste des semestres posterieurs dans lesquels ont été les etudiants de sem
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
formsemestre_id
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > get_etudids, get_etud_decision_sem
|
|
||||||
etudids = nt.get_etudids()
|
etudids = nt.get_etudids()
|
||||||
|
|
||||||
logt("A: orig etuds set")
|
logt("A: orig etuds set")
|
||||||
@ -456,9 +457,8 @@ def table_suivi_cohorte(
|
|||||||
s["members"] = orig_set.intersection(inset)
|
s["members"] = orig_set.intersection(inset)
|
||||||
nb_dipl = 0 # combien de diplomes dans ce semestre ?
|
nb_dipl = 0 # combien de diplomes dans ce semestre ?
|
||||||
if s["semestre_id"] == nt.parcours.NB_SEM:
|
if s["semestre_id"] == nt.parcours.NB_SEM:
|
||||||
nt = sco_cache.NotesTableCache.get(
|
s_formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"])
|
||||||
s["formsemestre_id"]
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(s_formsemestre)
|
||||||
) # > get_etud_decision_sem
|
|
||||||
for etudid in s["members"]:
|
for etudid in s["members"]:
|
||||||
dec = nt.get_etud_decision_sem(etudid)
|
dec = nt.get_etud_decision_sem(etudid)
|
||||||
if dec and code_semestre_validant(dec["code"]):
|
if dec and code_semestre_validant(dec["code"]):
|
||||||
@ -905,9 +905,9 @@ def _descr_etud_set(etudids):
|
|||||||
|
|
||||||
def _count_dem_reo(formsemestre_id, etudids):
|
def _count_dem_reo(formsemestre_id, etudids):
|
||||||
"count nb of demissions and reorientation in this etud set"
|
"count nb of demissions and reorientation in this etud set"
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
formsemestre_id
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > get_etud_etat, get_etud_decision_sem
|
|
||||||
dems = set()
|
dems = set()
|
||||||
reos = set()
|
reos = set()
|
||||||
for etudid in etudids:
|
for etudid in etudids:
|
||||||
@ -971,9 +971,9 @@ def get_codeparcoursetud(etud, prefix="", separator=""):
|
|||||||
i = len(sems) - 1
|
i = len(sems) - 1
|
||||||
while i >= 0:
|
while i >= 0:
|
||||||
s = sems[i] # 'sems' est a l'envers, du plus recent au plus ancien
|
s = sems[i] # 'sems' est a l'envers, du plus recent au plus ancien
|
||||||
nt = sco_cache.NotesTableCache.get(
|
s_formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"])
|
||||||
s["formsemestre_id"]
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(s_formsemestre)
|
||||||
) # > get_etud_etat, get_etud_decision_sem
|
|
||||||
p.append(_codesem(s, prefix=prefix))
|
p.append(_codesem(s, prefix=prefix))
|
||||||
# code decisions jury de chaque semestre:
|
# code decisions jury de chaque semestre:
|
||||||
if nt.get_etud_etat(etud["etudid"]) == "D":
|
if nt.get_etud_etat(etud["etudid"]) == "D":
|
||||||
@ -1017,7 +1017,8 @@ def tsp_etud_list(
|
|||||||
"""
|
"""
|
||||||
# log('tsp_etud_list(%s, bac="%s")' % (formsemestre_id,bac))
|
# log('tsp_etud_list(%s, bac="%s")' % (formsemestre_id,bac))
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etudids,
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
etudids = nt.get_etudids()
|
etudids = nt.get_etudids()
|
||||||
etuds = []
|
etuds = []
|
||||||
bacs = set()
|
bacs = set()
|
||||||
@ -1260,9 +1261,8 @@ def graph_parcours(
|
|||||||
nxt = {}
|
nxt = {}
|
||||||
etudid = etud["etudid"]
|
etudid = etud["etudid"]
|
||||||
for s in etud["sems"]: # du plus recent au plus ancien
|
for s in etud["sems"]: # du plus recent au plus ancien
|
||||||
nt = sco_cache.NotesTableCache.get(
|
s_formsemestre = FormSemestre.query.get_or_404(s["formsemestre_id"])
|
||||||
s["formsemestre_id"]
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(s_formsemestre)
|
||||||
) # > get_etud_decision_sem, get_etud_etat
|
|
||||||
dec = nt.get_etud_decision_sem(etudid)
|
dec = nt.get_etud_decision_sem(etudid)
|
||||||
if nxt:
|
if nxt:
|
||||||
if (
|
if (
|
||||||
|
@ -29,15 +29,16 @@
|
|||||||
|
|
||||||
Formulaire revu en juillet 2016
|
Formulaire revu en juillet 2016
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import datetime
|
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for, request
|
from flask import g, url_for, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.sco_utils import ModuleType
|
from app.scodoc.sco_utils import ModuleType
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
@ -49,7 +50,6 @@ from app.scodoc.sco_exceptions import (
|
|||||||
ScoGenError,
|
ScoGenError,
|
||||||
ScoValueError,
|
ScoValueError,
|
||||||
)
|
)
|
||||||
from app.scodoc.sco_permissions import Permission
|
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
||||||
from app.scodoc import html_sco_header, sco_users
|
from app.scodoc import html_sco_header, sco_users
|
||||||
from app.scodoc import htmlutils
|
from app.scodoc import htmlutils
|
||||||
@ -813,8 +813,8 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]):
|
|||||||
evaltitre = "évaluation du %s" % E["jour"]
|
evaltitre = "évaluation du %s" % E["jour"]
|
||||||
description = "%s en %s (%s) resp. %s" % (
|
description = "%s en %s (%s) resp. %s" % (
|
||||||
evaltitre,
|
evaltitre,
|
||||||
Mod["abbrev"],
|
Mod["abbrev"] or "",
|
||||||
Mod["code"],
|
Mod["code"] or "",
|
||||||
mod_responsable["prenomnom"],
|
mod_responsable["prenomnom"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -872,9 +872,8 @@ def has_existing_decision(M, E, etudid):
|
|||||||
Si oui, return True
|
Si oui, return True
|
||||||
"""
|
"""
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
formsemestre_id
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
) # > get_etud_decision_sem, get_etud_decision_ues
|
|
||||||
if nt.get_etud_decision_sem(etudid):
|
if nt.get_etud_decision_sem(etudid):
|
||||||
return True
|
return True
|
||||||
dec_ues = nt.get_etud_decision_ues(etudid)
|
dec_ues = nt.get_etud_decision_ues(etudid)
|
||||||
|
@ -42,6 +42,9 @@ sem_set_list()
|
|||||||
import flask
|
import flask
|
||||||
from flask import g
|
from flask import g
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_etape_apogee
|
from app.scodoc import sco_etape_apogee
|
||||||
@ -239,7 +242,8 @@ class SemSet(dict):
|
|||||||
self["etuds_without_nip"] = set() # etudids
|
self["etuds_without_nip"] = set() # etudids
|
||||||
self["jury_ok"] = True
|
self["jury_ok"] = True
|
||||||
for sem in self.sems:
|
for sem in self.sems:
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
sem["etuds"] = list(nt.identdict.values())
|
sem["etuds"] = list(nt.identdict.values())
|
||||||
sem["nips"] = {e["code_nip"] for e in sem["etuds"] if e["code_nip"]}
|
sem["nips"] = {e["code_nip"] for e in sem["etuds"] if e["code_nip"]}
|
||||||
sem["etuds_without_nip"] = {
|
sem["etuds_without_nip"] = {
|
||||||
|
@ -37,6 +37,9 @@ import http
|
|||||||
|
|
||||||
from flask import g, url_for
|
from flask import g, url_for
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
@ -269,7 +272,8 @@ def get_etud_tagged_modules(etudid, tagname):
|
|||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||||
R = []
|
R = []
|
||||||
for sem in etud["sems"]:
|
for sem in etud["sems"]:
|
||||||
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
|
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
modimpls = nt.get_modimpls_dict()
|
modimpls = nt.get_modimpls_dict()
|
||||||
for modimpl in modimpls:
|
for modimpl in modimpls:
|
||||||
tags = module_tag_list(module_id=modimpl["module_id"])
|
tags = module_tag_list(module_id=modimpl["module_id"])
|
||||||
|
@ -227,7 +227,10 @@ def get_mention(moy):
|
|||||||
moy = float(moy)
|
moy = float(moy)
|
||||||
except:
|
except:
|
||||||
return ""
|
return ""
|
||||||
|
if moy > 0.0:
|
||||||
return NOTES_MENTIONS_LABS[bisect.bisect_right(NOTES_MENTIONS_TH, moy)]
|
return NOTES_MENTIONS_LABS[bisect.bisect_right(NOTES_MENTIONS_TH, moy)]
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
class DictDefault(dict): # obsolete, use collections.defaultdict
|
class DictDefault(dict): # obsolete, use collections.defaultdict
|
||||||
|
@ -97,7 +97,8 @@ section>div:nth-child(1){
|
|||||||
.hide_coef .synthese em,
|
.hide_coef .synthese em,
|
||||||
.hide_coef .eval>em,
|
.hide_coef .eval>em,
|
||||||
.hide_date_inscr .dateInscription,
|
.hide_date_inscr .dateInscription,
|
||||||
.hide_ects .ects{
|
.hide_ects .ects,
|
||||||
|
.hide_rangs .rang{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +159,10 @@ section>div:nth-child(1){
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
.rang{
|
.rang{
|
||||||
text-decoration: underline var(--couleurIntense);
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.ue .rang{
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
.decision{
|
.decision{
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
@ -186,6 +190,9 @@ section>div:nth-child(1){
|
|||||||
.synthese h3{
|
.synthese h3{
|
||||||
background: var(--couleurFondTitresUE);
|
background: var(--couleurFondTitresUE);
|
||||||
}
|
}
|
||||||
|
.synthese .ue>div{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
.synthese em,
|
.synthese em,
|
||||||
.eval em{
|
.eval em{
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
@ -308,6 +315,14 @@ h3{
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 700px) {
|
||||||
|
section{
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.syntheseModule, .eval {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*.absences{
|
/*.absences{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto;
|
grid-template-columns: auto auto;
|
||||||
|
@ -254,6 +254,7 @@ class releveBUT extends HTMLElement {
|
|||||||
</h3>
|
</h3>
|
||||||
<div>
|
<div>
|
||||||
<div class=moyenne>Moyenne : ${dataUE.moyenne?.value || "-"}</div>
|
<div class=moyenne>Moyenne : ${dataUE.moyenne?.value || "-"}</div>
|
||||||
|
<div class=rang>Rang : ${dataUE.moyenne?.rang} / ${dataUE.moyenne?.total}</div>
|
||||||
<div class=info>
|
<div class=info>
|
||||||
Bonus : ${dataUE.bonus || 0} -
|
Bonus : ${dataUE.bonus || 0} -
|
||||||
Malus : ${dataUE.malus || 0}
|
Malus : ${dataUE.malus || 0}
|
||||||
@ -299,7 +300,7 @@ class releveBUT extends HTMLElement {
|
|||||||
Object.values(module.evaluations).forEach((evaluation) => {
|
Object.values(module.evaluations).forEach((evaluation) => {
|
||||||
output += `
|
output += `
|
||||||
<div class=syntheseModule>
|
<div class=syntheseModule>
|
||||||
<div>${module.titre} - ${evaluation.description}</div>
|
<div>${module.titre} - ${evaluation.description || "Note"}</div>
|
||||||
<div>
|
<div>
|
||||||
${evaluation.note.value ?? "-"}
|
${evaluation.note.value ?? "-"}
|
||||||
<em>Coef. ${evaluation.coef}</em>
|
<em>Coef. ${evaluation.coef}</em>
|
||||||
|
@ -6,10 +6,23 @@
|
|||||||
<h1>Charger un référentiel de compétences</h1>
|
<h1>Charger un référentiel de compétences</h1>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-5">
|
||||||
{{ wtf.quick_form(form) }}
|
{{ wtf.quick_form(form) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="{{ url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept, ) }}">
|
||||||
|
Liste des référentiels de compétences chargés</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ url_for('notes.refcomp_assoc_formation', scodoc_dept=g.scodoc_dept, formation_id=formation.id) }}">
|
||||||
|
Association à la formation {{ formation.acronyme }}</a>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -35,6 +35,11 @@
|
|||||||
<b>{{ue.acronyme}}</b> <a class="discretelink" href="{{
|
<b>{{ue.acronyme}}</b> <a class="discretelink" href="{{
|
||||||
url_for('notes.ue_infos', scodoc_dept=g.scodoc_dept, ue_id=ue.id)}}"
|
url_for('notes.ue_infos', scodoc_dept=g.scodoc_dept, ue_id=ue.id)}}"
|
||||||
>{{ue.titre}}</a>
|
>{{ue.titre}}</a>
|
||||||
|
{% set virg = joiner(", ") %}
|
||||||
|
<span class="ue_code">(
|
||||||
|
{%- if ue.ue_code -%}{{ virg() }}code {{ue.ue_code}} {%- endif -%}
|
||||||
|
{{ virg() }}{{ue.ects or 0}} ECTS)
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{% if editable and not ue.is_locked() %}
|
{% if editable and not ue.is_locked() %}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<li>{{ue.acronyme}}
|
<li>{{ue.acronyme}}
|
||||||
<ul>
|
<ul>
|
||||||
<li>Semestre: {{ue.semestre_idx}}</li>
|
<li>Semestre: {{ue.semestre_idx}}</li>
|
||||||
<li>Code: {{ue.code}}</li>
|
<li>Code: <tt>{{ue.ue_code}}</tt></li>
|
||||||
<li>Type: {{ue.type}}</li>
|
<li>Type: {{ue.type}}</li>
|
||||||
<li>Externe: {{ "oui" if ue.is_external else "non" }}</li>
|
<li>Externe: {{ "oui" if ue.is_external else "non" }}</li>
|
||||||
<li>Code Apogée: {{ue.code_apogee}}</li>
|
<li>Code Apogée: {{ue.code_apogee}}</li>
|
||||||
|
@ -60,22 +60,22 @@ from flask import g, request
|
|||||||
from flask import url_for
|
from flask import url_for
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app import log
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
from app.decorators import (
|
from app.decorators import (
|
||||||
scodoc,
|
scodoc,
|
||||||
scodoc7func,
|
scodoc7func,
|
||||||
permission_required,
|
permission_required,
|
||||||
admin_required,
|
|
||||||
login_required,
|
|
||||||
permission_required_compat_scodoc7,
|
permission_required_compat_scodoc7,
|
||||||
)
|
)
|
||||||
|
from app.models import FormSemestre
|
||||||
|
from app.models.absences import BilletAbsence
|
||||||
from app.views import absences_bp as bp
|
from app.views import absences_bp as bp
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
from app.models.absences import BilletAbsence
|
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app import log
|
|
||||||
from app.scodoc.scolog import logdb
|
from app.scodoc.scolog import logdb
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc.sco_exceptions import ScoValueError, APIInvalidParams
|
from app.scodoc.sco_exceptions import ScoValueError, APIInvalidParams
|
||||||
@ -83,15 +83,10 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
|
|||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_abs_notification
|
|
||||||
from app.scodoc import sco_abs_views
|
from app.scodoc import sco_abs_views
|
||||||
from app.scodoc import sco_cache
|
|
||||||
from app.scodoc import sco_compute_moy
|
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_excel
|
|
||||||
from app.scodoc import sco_find_etud
|
from app.scodoc import sco_find_etud
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_groups
|
|
||||||
from app.scodoc import sco_groups_view
|
from app.scodoc import sco_groups_view
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
@ -372,8 +367,12 @@ def SignaleAbsenceGrHebdo(
|
|||||||
else:
|
else:
|
||||||
# Si aucun etudiant n'est inscrit au module choisi...
|
# Si aucun etudiant n'est inscrit au module choisi...
|
||||||
moduleimpl_id = None
|
moduleimpl_id = None
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
|
||||||
sem = sco_formsemestre.do_formsemestre_list({"formsemestre_id": formsemestre_id})[0]
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
|
sem = formsemestre.to_dict()
|
||||||
|
# sem = sco_formsemestre.do_formsemestre_list({"formsemestre_id": formsemestre_id})[0]
|
||||||
|
|
||||||
# calcule dates jours de cette semaine
|
# calcule dates jours de cette semaine
|
||||||
# liste de dates iso "yyyy-mm-dd"
|
# liste de dates iso "yyyy-mm-dd"
|
||||||
@ -444,8 +443,9 @@ def SignaleAbsenceGrHebdo(
|
|||||||
% {
|
% {
|
||||||
"modimpl_id": modimpl["moduleimpl_id"],
|
"modimpl_id": modimpl["moduleimpl_id"],
|
||||||
"modname": modimpl["module"]["code"]
|
"modname": modimpl["module"]["code"]
|
||||||
|
or ""
|
||||||
+ " "
|
+ " "
|
||||||
+ (modimpl["module"]["abbrev"] or modimpl["module"]["titre"]),
|
+ (modimpl["module"]["abbrev"] or modimpl["module"]["titre"] or ""),
|
||||||
"sel": sel,
|
"sel": sel,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -493,10 +493,11 @@ def SignaleAbsenceGrSemestre(
|
|||||||
+ html_sco_header.sco_footer()
|
+ html_sco_header.sco_footer()
|
||||||
)
|
)
|
||||||
formsemestre_id = groups_infos.formsemestre_id
|
formsemestre_id = groups_infos.formsemestre_id
|
||||||
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
sem = formsemestre.to_dict()
|
||||||
require_module = sco_preferences.get_preference(
|
require_module = sco_preferences.get_preference(
|
||||||
"abs_require_module", formsemestre_id
|
"abs_require_module", formsemestre_id
|
||||||
)
|
)
|
||||||
sem = sco_formsemestre.do_formsemestre_list({"formsemestre_id": formsemestre_id})[0]
|
|
||||||
etuds = [
|
etuds = [
|
||||||
sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0]
|
sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0]
|
||||||
for m in groups_infos.members
|
for m in groups_infos.members
|
||||||
@ -526,7 +527,7 @@ def SignaleAbsenceGrSemestre(
|
|||||||
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
|
base_url = base_url_noweeks + "&nbweeks=%s" % nbweeks # sans le moduleimpl_id
|
||||||
|
|
||||||
if etuds:
|
if etuds:
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
work_saturday = sco_abs.is_work_saturday()
|
work_saturday = sco_abs.is_work_saturday()
|
||||||
jourdebut = sco_abs.ddmmyyyy(datedebut, work_saturday=work_saturday)
|
jourdebut = sco_abs.ddmmyyyy(datedebut, work_saturday=work_saturday)
|
||||||
@ -611,6 +612,7 @@ def SignaleAbsenceGrSemestre(
|
|||||||
% {
|
% {
|
||||||
"modimpl_id": modimpl["moduleimpl_id"],
|
"modimpl_id": modimpl["moduleimpl_id"],
|
||||||
"modname": modimpl["module"]["code"]
|
"modname": modimpl["module"]["code"]
|
||||||
|
or ""
|
||||||
+ " "
|
+ " "
|
||||||
+ (modimpl["module"]["abbrev"] or modimpl["module"]["titre"]),
|
+ (modimpl["module"]["abbrev"] or modimpl["module"]["titre"]),
|
||||||
"sel": sel,
|
"sel": sel,
|
||||||
@ -729,12 +731,13 @@ def _gen_form_saisie_groupe(
|
|||||||
# UE capitalisee dans semestre courant ?
|
# UE capitalisee dans semestre courant ?
|
||||||
cap = []
|
cap = []
|
||||||
if etud["cursem"]:
|
if etud["cursem"]:
|
||||||
nt = sco_cache.NotesTableCache.get(
|
formsemestre = FormSemestre.query.get_or_404(
|
||||||
etud["cursem"]["formsemestre_id"]
|
etud["cursem"]["formsemestre_id"]
|
||||||
) # > get_ues_stat_dict, get_etud_ue_status
|
)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
for ue in nt.get_ues_stat_dict():
|
for ue in nt.get_ues_stat_dict():
|
||||||
status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
if status["is_capitalized"]:
|
if ue_status and ue_status["is_capitalized"]:
|
||||||
cap.append(ue["acronyme"])
|
cap.append(ue["acronyme"])
|
||||||
if cap:
|
if cap:
|
||||||
capstr = ' <span class="capstr">(%s cap.)</span>' % ", ".join(cap)
|
capstr = ' <span class="capstr">(%s cap.)</span>' % ", ".join(cap)
|
||||||
|
@ -39,6 +39,9 @@ from flask import flash, jsonify, render_template, url_for
|
|||||||
from flask import current_app, g, request
|
from flask import current_app, g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from werkzeug.utils import redirect
|
from werkzeug.utils import redirect
|
||||||
|
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
from app.models.formsemestre import FormSemestreUEComputationExpr
|
from app.models.formsemestre import FormSemestreUEComputationExpr
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
@ -1319,7 +1322,7 @@ def formsemestre_enseignants_list(formsemestre_id, format="html"):
|
|||||||
# description textuelle des modules
|
# description textuelle des modules
|
||||||
for ens in sem_ens:
|
for ens in sem_ens:
|
||||||
sem_ens[ens]["descr_mods"] = ", ".join(
|
sem_ens[ens]["descr_mods"] = ", ".join(
|
||||||
[x["module"]["code"] for x in sem_ens[ens]["mods"]]
|
[x["module"]["code"] or "?" for x in sem_ens[ens]["mods"]]
|
||||||
)
|
)
|
||||||
|
|
||||||
# ajoute infos sur enseignant:
|
# ajoute infos sur enseignant:
|
||||||
@ -1427,13 +1430,14 @@ def formsemestre_desinscription(etudid, formsemestre_id, dialog_confirmed=False)
|
|||||||
S'il s'agit d'un semestre extérieur et qu'il n'y a plus d'inscrit,
|
S'il s'agit d'un semestre extérieur et qu'il n'y a plus d'inscrit,
|
||||||
le semestre sera supprimé.
|
le semestre sera supprimé.
|
||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
sem = formsemestre.to_dict() # compat
|
||||||
# -- check lock
|
# -- check lock
|
||||||
if not sem["etat"]:
|
if not formsemestre.etat:
|
||||||
raise ScoValueError("desinscription impossible: semestre verrouille")
|
raise ScoValueError("desinscription impossible: semestre verrouille")
|
||||||
|
|
||||||
# -- Si décisions de jury, désinscription interdite
|
# -- Si décisions de jury, désinscription interdite
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
if nt.etud_has_decision(etudid):
|
if nt.etud_has_decision(etudid):
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
"""Désinscription impossible: l'étudiant a une décision de jury
|
"""Désinscription impossible: l'étudiant a une décision de jury
|
||||||
@ -1446,7 +1450,7 @@ def formsemestre_desinscription(etudid, formsemestre_id, dialog_confirmed=False)
|
|||||||
)
|
)
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||||
if sem["modalite"] != "EXT":
|
if formsemestre.modalite != "EXT":
|
||||||
msg_ext = """
|
msg_ext = """
|
||||||
<p>%s sera désinscrit de tous les modules du semestre %s (%s - %s).</p>
|
<p>%s sera désinscrit de tous les modules du semestre %s (%s - %s).</p>
|
||||||
<p>Cette opération ne doit être utilisée que pour corriger une <b>erreur</b> !
|
<p>Cette opération ne doit être utilisée que pour corriger une <b>erreur</b> !
|
||||||
@ -1898,7 +1902,8 @@ def formsemestre_bulletins_mailetuds(
|
|||||||
):
|
):
|
||||||
"envoi a chaque etudiant (inscrit et ayant un mail) son bulletin"
|
"envoi a chaque etudiant (inscrit et ayant un mail) son bulletin"
|
||||||
prefer_mail_perso = int(prefer_mail_perso)
|
prefer_mail_perso = int(prefer_mail_perso)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etudids
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
etudids = nt.get_etudids()
|
etudids = nt.get_etudids()
|
||||||
#
|
#
|
||||||
if not sco_bulletins.can_send_bulletin_by_mail(formsemestre_id):
|
if not sco_bulletins.can_send_bulletin_by_mail(formsemestre_id):
|
||||||
@ -1920,7 +1925,7 @@ def formsemestre_bulletins_mailetuds(
|
|||||||
nb_send = 0
|
nb_send = 0
|
||||||
for etudid in etudids:
|
for etudid in etudids:
|
||||||
h, _ = sco_bulletins.do_formsemestre_bulletinetud(
|
h, _ = sco_bulletins.do_formsemestre_bulletinetud(
|
||||||
formsemestre_id,
|
formsemestre,
|
||||||
etudid,
|
etudid,
|
||||||
version=version,
|
version=version,
|
||||||
prefer_mail_perso=prefer_mail_perso,
|
prefer_mail_perso=prefer_mail_perso,
|
||||||
@ -2247,9 +2252,10 @@ def formsemestre_validation_suppress_etud(
|
|||||||
dest_url=scu.ScoURL(),
|
dest_url=scu.ScoURL(),
|
||||||
)
|
)
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_decision_sem
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
sem = formsemestre.to_dict()
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
decision_jury = nt.get_etud_decision_sem(etudid)
|
decision_jury = nt.get_etud_decision_sem(etudid)
|
||||||
if decision_jury:
|
if decision_jury:
|
||||||
existing = (
|
existing = (
|
||||||
|
@ -3,9 +3,11 @@ PN / Référentiel de compétences
|
|||||||
|
|
||||||
Emmanuel Viennet, 2021
|
Emmanuel Viennet, 2021
|
||||||
"""
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
from flask import url_for, flash
|
from flask import jsonify, flash, url_for
|
||||||
from flask import jsonify
|
from flask import Markup
|
||||||
from flask import current_app, g, request
|
from flask import current_app, g, request
|
||||||
from flask.templating import render_template
|
from flask.templating import render_template
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
@ -15,7 +17,7 @@ from werkzeug.utils import secure_filename
|
|||||||
from config import Config
|
from config import Config
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app import models
|
from app import log
|
||||||
|
|
||||||
from app.decorators import scodoc, permission_required
|
from app.decorators import scodoc, permission_required
|
||||||
from app.models import Formation
|
from app.models import Formation
|
||||||
@ -23,9 +25,8 @@ from app.models.but_refcomp import ApcReferentielCompetences
|
|||||||
from app.but.import_refcomp import orebut_import_refcomp
|
from app.but.import_refcomp import orebut_import_refcomp
|
||||||
from app.but.forms.refcomp_forms import FormationRefCompForm, RefCompLoadForm
|
from app.but.forms.refcomp_forms import FormationRefCompForm, RefCompLoadForm
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc import html_sidebar
|
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_exceptions import ScoFormatError
|
from app.scodoc.sco_exceptions import ScoFormatError, ScoValueError
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.views import notes_bp as bp
|
from app.views import notes_bp as bp
|
||||||
from app.views import ScoData
|
from app.views import ScoData
|
||||||
@ -171,14 +172,61 @@ def refcomp_load(formation_id=None):
|
|||||||
formation = Formation.query.get_or_404(formation_id)
|
formation = Formation.query.get_or_404(formation_id)
|
||||||
else:
|
else:
|
||||||
formation = None
|
formation = None
|
||||||
|
refs_distrib_files = sorted(
|
||||||
|
list(
|
||||||
|
(
|
||||||
|
Path(current_app.config["SCODOC_DIR"])
|
||||||
|
/ "ressources/referentiels/but2022/competences"
|
||||||
|
).glob("*.xml")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
refs_distrib_dict = [{"id": 0, "specialite": "Aucun", "created": "", "serial": ""}]
|
||||||
|
i = 1
|
||||||
|
for filename in refs_distrib_files:
|
||||||
|
m = re.match(r".*/but-([A-Za-z_]+)-([0-9]+)-([0-9]+).xml", str(filename))
|
||||||
|
if (
|
||||||
|
m
|
||||||
|
and ApcReferentielCompetences.query.filter_by(
|
||||||
|
scodoc_orig_filename=Path(filename).name, dept_id=g.scodoc_dept_id
|
||||||
|
).count()
|
||||||
|
== 0
|
||||||
|
):
|
||||||
|
refs_distrib_dict.append(
|
||||||
|
{
|
||||||
|
"id": i,
|
||||||
|
"specialite": m.group(1),
|
||||||
|
"created": m.group(2),
|
||||||
|
"serial": m.group(3),
|
||||||
|
"filename": str(filename),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
log(f"refcomp_load: ignoring {filename} (invalid filename)")
|
||||||
|
|
||||||
form = RefCompLoadForm()
|
form = RefCompLoadForm()
|
||||||
|
form.referentiel_standard.choices = [
|
||||||
|
(r["id"], f"{r['specialite']} ({r['created']}-{r['serial']})")
|
||||||
|
for r in refs_distrib_dict
|
||||||
|
]
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
|
if form.upload.data:
|
||||||
f = form.upload.data
|
f = form.upload.data
|
||||||
filename = secure_filename(f.filename)
|
filename = secure_filename(f.filename)
|
||||||
|
elif form.referentiel_standard.data:
|
||||||
|
try:
|
||||||
|
filename = refs_distrib_dict[int(form.referentiel_standard.data)][
|
||||||
|
"filename"
|
||||||
|
]
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
raise ScoValueError("choix invalide")
|
||||||
|
f = open(filename)
|
||||||
|
else:
|
||||||
|
raise ScoValueError("choix invalide")
|
||||||
try:
|
try:
|
||||||
xml_data = f.read()
|
xml_data = f.read()
|
||||||
_ = orebut_import_refcomp(
|
_ = orebut_import_refcomp(
|
||||||
xml_data, dept_id=g.scodoc_dept_id, orig_filename=filename
|
xml_data, dept_id=g.scodoc_dept_id, orig_filename=Path(filename).name
|
||||||
)
|
)
|
||||||
except TypeError as exc:
|
except TypeError as exc:
|
||||||
raise ScoFormatError(
|
raise ScoFormatError(
|
||||||
@ -187,6 +235,11 @@ def refcomp_load(formation_id=None):
|
|||||||
except ScoFormatError:
|
except ScoFormatError:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
flash(
|
||||||
|
Markup(f"Référentiel <tt>{Path(filename).name}</tt> chargé."),
|
||||||
|
category="info",
|
||||||
|
)
|
||||||
|
|
||||||
if formation is not None:
|
if formation is not None:
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for(
|
url_for(
|
||||||
|
@ -35,7 +35,15 @@ import io
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import abort, flash, url_for, redirect, render_template, send_file
|
from flask import (
|
||||||
|
abort,
|
||||||
|
flash,
|
||||||
|
make_response,
|
||||||
|
redirect,
|
||||||
|
render_template,
|
||||||
|
send_file,
|
||||||
|
url_for,
|
||||||
|
)
|
||||||
from flask import request
|
from flask import request
|
||||||
import flask_login
|
import flask_login
|
||||||
from flask_login.utils import login_required, current_user
|
from flask_login.utils import login_required, current_user
|
||||||
@ -54,6 +62,7 @@ from app.models import Departement, Identite
|
|||||||
from app.models import departements
|
from app.models import departements
|
||||||
from app.models import FormSemestre, FormSemestreInscription
|
from app.models import FormSemestre, FormSemestreInscription
|
||||||
from app.models import ScoDocSiteConfig
|
from app.models import ScoDocSiteConfig
|
||||||
|
from app.models import UniteEns
|
||||||
from app.scodoc import sco_codes_parcours, sco_logos
|
from app.scodoc import sco_codes_parcours, sco_logos
|
||||||
from app.scodoc import sco_find_etud
|
from app.scodoc import sco_find_etud
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
@ -264,11 +273,15 @@ def get_bonus_description(bonus_name: str):
|
|||||||
bonus_name = ""
|
bonus_name = ""
|
||||||
bonus_class = ScoDocSiteConfig.get_bonus_sport_class_from_name(bonus_name)
|
bonus_class = ScoDocSiteConfig.get_bonus_sport_class_from_name(bonus_name)
|
||||||
text = bonus_class.__doc__
|
text = bonus_class.__doc__
|
||||||
|
if text:
|
||||||
fields = re.split(r"\n\n", text, maxsplit=1)
|
fields = re.split(r"\n\n", text, maxsplit=1)
|
||||||
if len(fields) > 1:
|
if len(fields) > 1:
|
||||||
first_line, text = fields
|
first_line, text = fields
|
||||||
else:
|
else:
|
||||||
first_line, text = "", fields[0]
|
first_line, text = "", fields[0]
|
||||||
|
else:
|
||||||
|
text = ""
|
||||||
|
first_line = "pas de fonction bonus configurée."
|
||||||
|
|
||||||
return f"""<div class="bonus_description_head">{first_line}</div>
|
return f"""<div class="bonus_description_head">{first_line}</div>
|
||||||
<div>{text}</div>
|
<div>{text}</div>
|
||||||
@ -350,6 +363,29 @@ def get_logo(name: str, dept_id: int):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ---
|
||||||
|
@bp.route("/ScoDoc/ue_colors_css/<int:formation_id>/<int:semestre_idx>")
|
||||||
|
def ue_colors_css(formation_id: int, semestre_idx: int):
|
||||||
|
"""Feuille de style pour les couleurs d'UE"""
|
||||||
|
ues = UniteEns.query.filter_by(
|
||||||
|
formation_id=formation_id, semestre_idx=semestre_idx
|
||||||
|
).order_by(UniteEns.numero)
|
||||||
|
txt = (
|
||||||
|
":root{\n"
|
||||||
|
+ "\n".join(
|
||||||
|
[
|
||||||
|
f"--color-UE{semestre_idx}-{ue_idx+1}: {ue.color};"
|
||||||
|
for ue_idx, ue in enumerate(ues)
|
||||||
|
if ue.color
|
||||||
|
]
|
||||||
|
)
|
||||||
|
+ "\n}\n"
|
||||||
|
)
|
||||||
|
response = make_response(txt)
|
||||||
|
response.headers["Content-Type"] = "text/css"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
# essais
|
# essais
|
||||||
# @bp.route("/testlog")
|
# @bp.route("/testlog")
|
||||||
# def testlog():
|
# def testlog():
|
||||||
|
@ -35,7 +35,7 @@ import time
|
|||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import jsonify, url_for, flash, render_template, make_response
|
from flask import jsonify, url_for, flash, render_template, make_response
|
||||||
from flask import current_app, g, request
|
from flask import g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from flask_wtf.file import FileField, FileAllowed
|
from flask_wtf.file import FileField, FileAllowed
|
||||||
|
94
migrations/versions/bd2c1c3d866e_refcomp_orebut.py
Normal file
94
migrations/versions/bd2c1c3d866e_refcomp_orebut.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
"""refcomp orebut
|
||||||
|
|
||||||
|
Revision ID: bd2c1c3d866e
|
||||||
|
Revises: c95d5a3bf0de
|
||||||
|
Create Date: 2022-02-12 15:17:42.298699
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "bd2c1c3d866e"
|
||||||
|
down_revision = "c95d5a3bf0de"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
|
||||||
|
op.add_column("apc_competence", sa.Column("id_orebut", sa.Text(), nullable=True))
|
||||||
|
op.drop_constraint(
|
||||||
|
"apc_competence_referentiel_id_titre_key", "apc_competence", type_="unique"
|
||||||
|
)
|
||||||
|
op.create_index(
|
||||||
|
op.f("ix_apc_competence_id_orebut"),
|
||||||
|
"apc_competence",
|
||||||
|
["id_orebut"],
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"apc_referentiel_competences", sa.Column("annexe", sa.Text(), nullable=True)
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"apc_referentiel_competences",
|
||||||
|
sa.Column("type_structure", sa.Text(), nullable=True),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"apc_referentiel_competences",
|
||||||
|
sa.Column("type_departement", sa.Text(), nullable=True),
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
"apc_referentiel_competences",
|
||||||
|
sa.Column("version_orebut", sa.Text(), nullable=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_index(
|
||||||
|
op.f("ix_notes_formsemestre_uecoef_formsemestre_id"),
|
||||||
|
"notes_formsemestre_uecoef",
|
||||||
|
["formsemestre_id"],
|
||||||
|
unique=False,
|
||||||
|
)
|
||||||
|
op.create_index(
|
||||||
|
op.f("ix_notes_formsemestre_uecoef_ue_id"),
|
||||||
|
"notes_formsemestre_uecoef",
|
||||||
|
["ue_id"],
|
||||||
|
unique=False,
|
||||||
|
)
|
||||||
|
op.create_index(
|
||||||
|
op.f("ix_scolar_formsemestre_validation_is_external"),
|
||||||
|
"scolar_formsemestre_validation",
|
||||||
|
["is_external"],
|
||||||
|
unique=False,
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_index(
|
||||||
|
op.f("ix_scolar_formsemestre_validation_is_external"),
|
||||||
|
table_name="scolar_formsemestre_validation",
|
||||||
|
)
|
||||||
|
op.drop_index(
|
||||||
|
op.f("ix_notes_formsemestre_uecoef_ue_id"),
|
||||||
|
table_name="notes_formsemestre_uecoef",
|
||||||
|
)
|
||||||
|
op.drop_index(
|
||||||
|
op.f("ix_notes_formsemestre_uecoef_formsemestre_id"),
|
||||||
|
table_name="notes_formsemestre_uecoef",
|
||||||
|
)
|
||||||
|
|
||||||
|
op.drop_column("apc_referentiel_competences", "version_orebut")
|
||||||
|
op.drop_column("apc_referentiel_competences", "type_departement")
|
||||||
|
op.drop_column("apc_referentiel_competences", "type_structure")
|
||||||
|
op.drop_column("apc_referentiel_competences", "annexe")
|
||||||
|
op.drop_index(op.f("ix_apc_competence_id_orebut"), table_name="apc_competence")
|
||||||
|
op.create_unique_constraint(
|
||||||
|
"apc_competence_referentiel_id_titre_key",
|
||||||
|
"apc_competence",
|
||||||
|
["referentiel_id", "titre"],
|
||||||
|
)
|
||||||
|
op.drop_column("apc_competence", "id_orebut")
|
||||||
|
# ### end Alembic commands ###
|
@ -1,13 +1,14 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.1.50a"
|
SCOVERSION = "9.2a-57"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
SCONEWS = """
|
SCONEWS = """
|
||||||
<h4>Année 2021</h4>
|
<h4>Année 2021</h4>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>ScoDoc 9.1.50: nombreuses amélioration gestion BUT</li>
|
||||||
<li>ScoDoc 9.1: gestion des formations par compétences, type BUT.</li>
|
<li>ScoDoc 9.1: gestion des formations par compétences, type BUT.</li>
|
||||||
<li>ScoDoc 9.0: nouvelle architecture logicielle (Flask/Python3/Debian 11)</li>
|
<li>ScoDoc 9.0: nouvelle architecture logicielle (Flask/Python3/Debian 11)</li>
|
||||||
<li>Version mobile (en test)</li>
|
<li>Version mobile (en test)</li>
|
||||||
|
31
scodoc.py
31
scodoc.py
@ -14,6 +14,8 @@ import click
|
|||||||
import flask
|
import flask
|
||||||
from flask.cli import with_appcontext
|
from flask.cli import with_appcontext
|
||||||
from flask.templating import render_template
|
from flask.templating import render_template
|
||||||
|
import psycopg2
|
||||||
|
import sqlalchemy
|
||||||
|
|
||||||
from app import create_app, cli, db
|
from app import create_app, cli, db
|
||||||
from app import initialize_scodoc_database
|
from app import initialize_scodoc_database
|
||||||
@ -133,11 +135,11 @@ def user_create(username, role, dept, nom=None, prenom=None): # user-create
|
|||||||
"Create a new user"
|
"Create a new user"
|
||||||
r = Role.get_named_role(role)
|
r = Role.get_named_role(role)
|
||||||
if not r:
|
if not r:
|
||||||
sys.stderr.write("user_create: role {r} does not exist\n".format(r=role))
|
sys.stderr.write(f"user_create: role {role} does not exist\n")
|
||||||
return 1
|
return 1
|
||||||
u = User.query.filter_by(user_name=username).first()
|
u = User.query.filter_by(user_name=username).first()
|
||||||
if u:
|
if u:
|
||||||
sys.stderr.write("user_create: user {u} already exists\n".format(u=u))
|
sys.stderr.write(f"user_create: user {u} already exists\n")
|
||||||
return 2
|
return 2
|
||||||
if dept == "@all":
|
if dept == "@all":
|
||||||
dept = None
|
dept = None
|
||||||
@ -145,11 +147,26 @@ def user_create(username, role, dept, nom=None, prenom=None): # user-create
|
|||||||
u.add_role(r, dept)
|
u.add_role(r, dept)
|
||||||
db.session.add(u)
|
db.session.add(u)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo(
|
click.echo(f"created user, login: {u.user_name}, with role {r} in dept. {dept}")
|
||||||
"created user, login: {u.user_name}, with role {r} in dept. {dept}".format(
|
|
||||||
u=u, r=r, dept=dept
|
|
||||||
)
|
@app.cli.command()
|
||||||
|
@click.argument("username")
|
||||||
|
def user_delete(username): # user-delete
|
||||||
|
"Try to delete this user. Fails if it's associated to some scodoc objects."
|
||||||
|
u = User.query.filter_by(user_name=username).first()
|
||||||
|
if not u:
|
||||||
|
sys.stderr.write(f"user_delete: user {username} not found\n")
|
||||||
|
return 2
|
||||||
|
db.session.delete(u)
|
||||||
|
try:
|
||||||
|
db.session.commit()
|
||||||
|
except (sqlalchemy.exc.IntegrityError, psycopg2.errors.ForeignKeyViolation):
|
||||||
|
sys.stderr.write(
|
||||||
|
f"""\nuser_delete: ne peux pas supprimer l'utilisateur {username}\ncar il est associé à des objets dans ScoDoc (modules, notes, ...).\n"""
|
||||||
)
|
)
|
||||||
|
return 1
|
||||||
|
click.echo(f"deleted user, login: {username}")
|
||||||
|
|
||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
@ -417,6 +434,7 @@ def localize_logo(logo: str = None, dept: str = None): # migrate-scodoc7-dept-l
|
|||||||
@click.argument("xlsfile", type=click.File("rb"))
|
@click.argument("xlsfile", type=click.File("rb"))
|
||||||
@click.argument("zipfile", type=click.File("rb"))
|
@click.argument("zipfile", type=click.File("rb"))
|
||||||
def photos_import_files(formsemestre_id: int, xlsfile: str, zipfile: str):
|
def photos_import_files(formsemestre_id: int, xlsfile: str, zipfile: str):
|
||||||
|
"""Import des photos d'étudiants à partir d'une liste excel et d'un zip avec les images."""
|
||||||
import app as mapp
|
import app as mapp
|
||||||
from app.scodoc import sco_trombino, sco_photos
|
from app.scodoc import sco_trombino, sco_photos
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
@ -485,6 +503,7 @@ def recursive_help(cmd, parent=None):
|
|||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
def dumphelp():
|
def dumphelp():
|
||||||
|
"""Génère la page d'aide complète pour la doc."""
|
||||||
recursive_help(app.cli)
|
recursive_help(app.cli)
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,6 +13,9 @@ from flask import current_app, g
|
|||||||
|
|
||||||
import app
|
import app
|
||||||
from app import db
|
from app import db
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
@ -24,7 +27,7 @@ from tests.unit.test_sco_basic import run_sco_basic
|
|||||||
DEPT = TestConfig.DEPT_TEST
|
DEPT = TestConfig.DEPT_TEST
|
||||||
|
|
||||||
|
|
||||||
def test_notes_table(test_client):
|
def test_notes_table(test_client): # XXX A REVOIR POUR TESTER RES TODO
|
||||||
"""Test construction et cache de NotesTable."""
|
"""Test construction et cache de NotesTable."""
|
||||||
app.set_sco_dept(DEPT)
|
app.set_sco_dept(DEPT)
|
||||||
assert g.scodoc_dept == DEPT
|
assert g.scodoc_dept == DEPT
|
||||||
@ -35,7 +38,8 @@ def test_notes_table(test_client):
|
|||||||
assert len(sems)
|
assert len(sems)
|
||||||
sem = sems[0]
|
sem = sems[0]
|
||||||
formsemestre_id = sem["formsemestre_id"]
|
formsemestre_id = sem["formsemestre_id"]
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
assert nt
|
assert nt
|
||||||
assert sco_cache.NotesTableCache.get(formsemestre_id, compute=False)
|
assert sco_cache.NotesTableCache.get(formsemestre_id, compute=False)
|
||||||
sco_cache.invalidate_formsemestre(formsemestre_id)
|
sco_cache.invalidate_formsemestre(formsemestre_id)
|
||||||
|
@ -10,6 +10,9 @@ from tests.unit import sco_fake_gen
|
|||||||
from flask import g
|
from flask import g
|
||||||
|
|
||||||
import app
|
import app
|
||||||
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
from app.scodoc import sco_bulletins, sco_formsemestre
|
from app.scodoc import sco_bulletins, sco_formsemestre
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
@ -33,7 +36,8 @@ def check_nt(
|
|||||||
(peut changer dans le futur, ne pas utiliser hors ScoDoc !)
|
(peut changer dans le futur, ne pas utiliser hors ScoDoc !)
|
||||||
ne vérifie que les valeurs expected non False
|
ne vérifie que les valeurs expected non False
|
||||||
"""
|
"""
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
mod_moy = nt.get_etud_mod_moy(moduleimpl_id, etudid)
|
mod_moy = nt.get_etud_mod_moy(moduleimpl_id, etudid)
|
||||||
if expected_moy_ue is not False:
|
if expected_moy_ue is not False:
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
@ -262,7 +266,8 @@ def test_notes_modules(test_client):
|
|||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=12.5)
|
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=12.5)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
assert ue_status["nb_missing"] == 1 # 1 même si etud non inscrit à l'autre module
|
assert ue_status["nb_missing"] == 1 # 1 même si etud non inscrit à l'autre module
|
||||||
assert ue_status["nb_notes"] == 1
|
assert ue_status["nb_notes"] == 1
|
||||||
@ -276,7 +281,8 @@ def test_notes_modules(test_client):
|
|||||||
{"etudid": etuds[1]["etudid"], "moduleimpl_id": moduleimpl_id2},
|
{"etudid": etuds[1]["etudid"], "moduleimpl_id": moduleimpl_id2},
|
||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
)
|
)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
assert ue_status["nb_missing"] == 1 # mi2 n'a pas encore de note
|
assert ue_status["nb_missing"] == 1 # mi2 n'a pas encore de note
|
||||||
assert ue_status["nb_notes"] == 1
|
assert ue_status["nb_notes"] == 1
|
||||||
@ -288,7 +294,8 @@ def test_notes_modules(test_client):
|
|||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(evaluation=e_m2, etud=etud, note=19.5)
|
_, _, _ = G.create_note(evaluation=e_m2, etud=etud, note=19.5)
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
assert ue_status["nb_missing"] == 1 # manque une note
|
assert ue_status["nb_missing"] == 1 # manque une note
|
||||||
assert ue_status["nb_notes"] == 1
|
assert ue_status["nb_notes"] == 1
|
||||||
|
@ -19,7 +19,10 @@ from config import TestConfig
|
|||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
|
|
||||||
import app
|
import app
|
||||||
from app.scodoc import notesdb as ndb, sco_formsemestre
|
from app.comp import res_sem
|
||||||
|
from app.comp.res_common import NotesTableCompat
|
||||||
|
from app.models import FormSemestre
|
||||||
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_abs_views
|
from app.scodoc import sco_abs_views
|
||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
@ -208,7 +211,8 @@ def run_sco_basic(verbose=False):
|
|||||||
redirect=False,
|
redirect=False,
|
||||||
)
|
)
|
||||||
# Vérifie que toutes les UE des étudiants notés ont été acquises:
|
# Vérifie que toutes les UE des étudiants notés ont été acquises:
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
for etud in etuds[:5]:
|
for etud in etuds[:5]:
|
||||||
dec_ues = nt.get_etud_decision_ues(etud["etudid"])
|
dec_ues = nt.get_etud_decision_ues(etud["etudid"])
|
||||||
for ue_id in dec_ues:
|
for ue_id in dec_ues:
|
||||||
|
@ -483,7 +483,7 @@ SCO7_TABLES_ORDONNEES = [
|
|||||||
), # (relation) avait un id modules_enseignants_id
|
), # (relation) avait un id modules_enseignants_id
|
||||||
("partition", "partition_id"),
|
("partition", "partition_id"),
|
||||||
("identite", "etudid"),
|
("identite", "etudid"),
|
||||||
("entreprises", "entreprise_id"),
|
# ("entreprises", "entreprise_id"),
|
||||||
("notes_evaluation", "evaluation_id"),
|
("notes_evaluation", "evaluation_id"),
|
||||||
("group_descr", "group_id"),
|
("group_descr", "group_id"),
|
||||||
("group_membership", "group_membership_id"), # (relation, qui avait un id)
|
("group_membership", "group_membership_id"), # (relation, qui avait un id)
|
||||||
@ -498,8 +498,8 @@ SCO7_TABLES_ORDONNEES = [
|
|||||||
("scolog", ""),
|
("scolog", ""),
|
||||||
("etud_annotations", "id"),
|
("etud_annotations", "id"),
|
||||||
("billet_absence", "billet_id"),
|
("billet_absence", "billet_id"),
|
||||||
("entreprise_correspondant", "entreprise_corresp_id"),
|
# ("entreprise_correspondant", "entreprise_corresp_id"),
|
||||||
("entreprise_contact", "entreprise_contact_id"),
|
# ("entreprise_contact", "entreprise_contact_id"),
|
||||||
("absences_notifications", ""),
|
("absences_notifications", ""),
|
||||||
# ("notes_form_modalites", "form_modalite_id"), : déjà initialisées
|
# ("notes_form_modalites", "form_modalite_id"), : déjà initialisées
|
||||||
("notes_appreciations", "id"),
|
("notes_appreciations", "id"),
|
||||||
|
Loading…
Reference in New Issue
Block a user