Merge branch 'refactor_nt' of https://scodoc.org/git/ScoDoc/ScoDoc into entreprises
This commit is contained in:
commit
2cc5e1f164
@ -41,7 +41,6 @@ from app import db
|
|||||||
from app.models import ModuleImpl, Evaluation, EvaluationUEPoids
|
from app.models import ModuleImpl, Evaluation, EvaluationUEPoids
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_codes_parcours import UE_SPORT
|
from app.scodoc.sco_codes_parcours import UE_SPORT
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
|
||||||
|
|
||||||
from app.scodoc.sco_utils import ModuleType
|
from app.scodoc.sco_utils import ModuleType
|
||||||
|
|
||||||
@ -92,6 +91,10 @@ class ModuleImplResults:
|
|||||||
ne donnent pas de coef vers cette UE.
|
ne donnent pas de coef vers cette UE.
|
||||||
"""
|
"""
|
||||||
self.load_notes()
|
self.load_notes()
|
||||||
|
self.etuds_use_session2 = pd.Series(False, index=self.evals_notes.index)
|
||||||
|
"""1 bool par etud, indique si sa moyenne de module vient de la session2"""
|
||||||
|
self.etuds_use_rattrapage = pd.Series(False, index=self.evals_notes.index)
|
||||||
|
"""1 bool par etud, indique si sa moyenne de module utilise la note de rattrapage"""
|
||||||
|
|
||||||
def load_notes(self): # ré-écriture de df_load_modimpl_notes
|
def load_notes(self): # ré-écriture de df_load_modimpl_notes
|
||||||
"""Charge toutes les notes de toutes les évaluations du module.
|
"""Charge toutes les notes de toutes les évaluations du module.
|
||||||
@ -135,8 +138,11 @@ class ModuleImplResults:
|
|||||||
eval_df = self._load_evaluation_notes(evaluation)
|
eval_df = self._load_evaluation_notes(evaluation)
|
||||||
# is_complete ssi tous les inscrits (non dem) au semestre ont une note
|
# is_complete ssi tous les inscrits (non dem) au semestre ont une note
|
||||||
# ou évaluation déclarée "à prise en compte immédiate"
|
# ou évaluation déclarée "à prise en compte immédiate"
|
||||||
is_complete = evaluation.publish_incomplete or (
|
# Les évaluations de rattrapage et 2eme session sont toujours incomplètes
|
||||||
not (inscrits_module - set(eval_df.index))
|
# car on calcule leur moyenne à part.
|
||||||
|
is_complete = (evaluation.evaluation_type == scu.EVALUATION_NORMALE) and (
|
||||||
|
evaluation.publish_incomplete
|
||||||
|
or (not (inscrits_module - set(eval_df.index)))
|
||||||
)
|
)
|
||||||
self.evaluations_completes.append(is_complete)
|
self.evaluations_completes.append(is_complete)
|
||||||
self.evaluations_completes_dict[evaluation.id] = is_complete
|
self.evaluations_completes_dict[evaluation.id] = is_complete
|
||||||
@ -212,6 +218,33 @@ class ModuleImplResults:
|
|||||||
self.evals_notes.values > scu.NOTES_ABSENCE, self.evals_notes.values, 0.0
|
self.evals_notes.values > scu.NOTES_ABSENCE, self.evals_notes.values, 0.0
|
||||||
) / [e.note_max / 20.0 for e in moduleimpl.evaluations]
|
) / [e.note_max / 20.0 for e in moduleimpl.evaluations]
|
||||||
|
|
||||||
|
def get_evaluation_rattrapage(self, moduleimpl: ModuleImpl):
|
||||||
|
"""L'évaluation de rattrapage de ce module, ou None s'il n'en a pas.
|
||||||
|
Rattrapage: la moyenne du module est la meilleure note entre moyenne
|
||||||
|
des autres évals et la note eval rattrapage.
|
||||||
|
"""
|
||||||
|
eval_list = [
|
||||||
|
e
|
||||||
|
for e in moduleimpl.evaluations
|
||||||
|
if e.evaluation_type == scu.EVALUATION_RATTRAPAGE
|
||||||
|
]
|
||||||
|
if eval_list:
|
||||||
|
return eval_list[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_evaluation_session2(self, moduleimpl: ModuleImpl):
|
||||||
|
"""L'évaluation de deuxième session de ce module, ou None s'il n'en a pas.
|
||||||
|
Session 2: remplace la note de moyenne des autres évals.
|
||||||
|
"""
|
||||||
|
eval_list = [
|
||||||
|
e
|
||||||
|
for e in moduleimpl.evaluations
|
||||||
|
if e.evaluation_type == scu.EVALUATION_SESSION2
|
||||||
|
]
|
||||||
|
if eval_list:
|
||||||
|
return eval_list[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ModuleImplResultsAPC(ModuleImplResults):
|
class ModuleImplResultsAPC(ModuleImplResults):
|
||||||
"Calcul des moyennes de modules à la mode BUT"
|
"Calcul des moyennes de modules à la mode BUT"
|
||||||
@ -229,7 +262,7 @@ class ModuleImplResultsAPC(ModuleImplResults):
|
|||||||
ou NaN si les évaluations (dans lesquelles l'étudiant a des notes)
|
ou NaN si les évaluations (dans lesquelles l'étudiant a des notes)
|
||||||
ne donnent pas de coef vers cette UE.
|
ne donnent pas de coef vers cette UE.
|
||||||
"""
|
"""
|
||||||
moduleimpl = ModuleImpl.query.get(self.moduleimpl_id)
|
modimpl = ModuleImpl.query.get(self.moduleimpl_id)
|
||||||
nb_etuds, nb_evals = self.evals_notes.shape
|
nb_etuds, nb_evals = self.evals_notes.shape
|
||||||
nb_ues = evals_poids_df.shape[1]
|
nb_ues = evals_poids_df.shape[1]
|
||||||
assert evals_poids_df.shape[0] == nb_evals # compat notes/poids
|
assert evals_poids_df.shape[0] == nb_evals # compat notes/poids
|
||||||
@ -237,11 +270,11 @@ class ModuleImplResultsAPC(ModuleImplResults):
|
|||||||
return pd.DataFrame(index=[], columns=evals_poids_df.columns)
|
return pd.DataFrame(index=[], columns=evals_poids_df.columns)
|
||||||
if nb_ues == 0:
|
if nb_ues == 0:
|
||||||
return pd.DataFrame(index=self.evals_notes.index, columns=[])
|
return pd.DataFrame(index=self.evals_notes.index, columns=[])
|
||||||
evals_coefs = self.get_evaluations_coefs(moduleimpl)
|
evals_coefs = self.get_evaluations_coefs(modimpl)
|
||||||
evals_poids = evals_poids_df.values * evals_coefs
|
evals_poids = evals_poids_df.values * evals_coefs
|
||||||
# -> evals_poids shape : (nb_evals, nb_ues)
|
# -> evals_poids shape : (nb_evals, nb_ues)
|
||||||
assert evals_poids.shape == (nb_evals, nb_ues)
|
assert evals_poids.shape == (nb_evals, nb_ues)
|
||||||
evals_notes_20 = self.get_eval_notes_sur_20(moduleimpl)
|
evals_notes_20 = self.get_eval_notes_sur_20(modimpl)
|
||||||
|
|
||||||
# Les poids des évals pour chaque étudiant: là où il a des notes
|
# Les poids des évals pour chaque étudiant: là où il a des notes
|
||||||
# non neutralisées
|
# non neutralisées
|
||||||
@ -262,6 +295,45 @@ class ModuleImplResultsAPC(ModuleImplResults):
|
|||||||
etuds_moy_module = np.sum(
|
etuds_moy_module = np.sum(
|
||||||
evals_poids_etuds * evals_notes_stacked, axis=1
|
evals_poids_etuds * evals_notes_stacked, axis=1
|
||||||
) / np.sum(evals_poids_etuds, axis=1)
|
) / np.sum(evals_poids_etuds, axis=1)
|
||||||
|
|
||||||
|
# Session2 : quand elle existe, remplace la note de module
|
||||||
|
eval_session2 = self.get_evaluation_session2(modimpl)
|
||||||
|
if eval_session2:
|
||||||
|
notes_session2 = self.evals_notes[eval_session2.id].values
|
||||||
|
# n'utilise que les notes valides (pas ATT, EXC, ABS, NaN)
|
||||||
|
etuds_use_session2 = notes_session2 > scu.NOTES_ABSENCE
|
||||||
|
etuds_moy_module = np.where(
|
||||||
|
etuds_use_session2[:, np.newaxis],
|
||||||
|
np.tile(
|
||||||
|
(notes_session2 / (eval_session2.note_max / 20.0))[:, np.newaxis],
|
||||||
|
nb_ues,
|
||||||
|
),
|
||||||
|
etuds_moy_module,
|
||||||
|
)
|
||||||
|
self.etuds_use_session2 = pd.Series(
|
||||||
|
etuds_use_session2, index=self.evals_notes.index
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Rattrapage: remplace la note de module ssi elle est supérieure
|
||||||
|
eval_rat = self.get_evaluation_rattrapage(modimpl)
|
||||||
|
if eval_rat:
|
||||||
|
notes_rat = self.evals_notes[eval_rat.id].values
|
||||||
|
# remplace les notes invalides (ATT, EXC...) par des NaN
|
||||||
|
notes_rat = np.where(
|
||||||
|
notes_rat > scu.NOTES_ABSENCE,
|
||||||
|
notes_rat / (eval_rat.note_max / 20.0),
|
||||||
|
np.nan,
|
||||||
|
)
|
||||||
|
# prend le max
|
||||||
|
etuds_use_rattrapage = notes_rat > etuds_moy_module
|
||||||
|
etuds_moy_module = np.where(
|
||||||
|
etuds_use_rattrapage[:, np.newaxis],
|
||||||
|
np.tile(notes_rat[:, np.newaxis], nb_ues),
|
||||||
|
etuds_moy_module,
|
||||||
|
)
|
||||||
|
self.etuds_use_rattrapage = pd.Series(
|
||||||
|
etuds_use_rattrapage, index=self.evals_notes.index
|
||||||
|
)
|
||||||
self.etuds_moy_module = pd.DataFrame(
|
self.etuds_moy_module = pd.DataFrame(
|
||||||
etuds_moy_module,
|
etuds_moy_module,
|
||||||
index=self.evals_notes.index,
|
index=self.evals_notes.index,
|
||||||
@ -371,8 +443,42 @@ class ModuleImplResultsClassic(ModuleImplResults):
|
|||||||
evals_coefs_etuds * evals_notes_20, axis=1
|
evals_coefs_etuds * evals_notes_20, axis=1
|
||||||
) / np.sum(evals_coefs_etuds, axis=1)
|
) / np.sum(evals_coefs_etuds, axis=1)
|
||||||
|
|
||||||
|
# Session2 : quand elle existe, remplace la note de module
|
||||||
|
eval_session2 = self.get_evaluation_session2(modimpl)
|
||||||
|
if eval_session2:
|
||||||
|
notes_session2 = self.evals_notes[eval_session2.id].values
|
||||||
|
# n'utilise que les notes valides (pas ATT, EXC, ABS, NaN)
|
||||||
|
etuds_use_session2 = notes_session2 > scu.NOTES_ABSENCE
|
||||||
|
etuds_moy_module = np.where(
|
||||||
|
etuds_use_session2,
|
||||||
|
notes_session2 / (eval_session2.note_max / 20.0),
|
||||||
|
etuds_moy_module,
|
||||||
|
)
|
||||||
|
self.etuds_use_session2 = pd.Series(
|
||||||
|
etuds_use_session2, index=self.evals_notes.index
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Rattrapage: remplace la note de module ssi elle est supérieure
|
||||||
|
eval_rat = self.get_evaluation_rattrapage(modimpl)
|
||||||
|
if eval_rat:
|
||||||
|
notes_rat = self.evals_notes[eval_rat.id].values
|
||||||
|
# remplace les notes invalides (ATT, EXC...) par des NaN
|
||||||
|
notes_rat = np.where(
|
||||||
|
notes_rat > scu.NOTES_ABSENCE,
|
||||||
|
notes_rat / (eval_rat.note_max / 20.0),
|
||||||
|
np.nan,
|
||||||
|
)
|
||||||
|
# prend le max
|
||||||
|
etuds_use_rattrapage = notes_rat > etuds_moy_module
|
||||||
|
etuds_moy_module = np.where(
|
||||||
|
etuds_use_rattrapage, notes_rat, etuds_moy_module
|
||||||
|
)
|
||||||
|
self.etuds_use_rattrapage = pd.Series(
|
||||||
|
etuds_use_rattrapage, index=self.evals_notes.index
|
||||||
|
)
|
||||||
self.etuds_moy_module = pd.Series(
|
self.etuds_moy_module = pd.Series(
|
||||||
etuds_moy_module,
|
etuds_moy_module,
|
||||||
index=self.evals_notes.index,
|
index=self.evals_notes.index,
|
||||||
)
|
)
|
||||||
|
|
||||||
return self.etuds_moy_module
|
return self.etuds_moy_module
|
||||||
|
@ -162,6 +162,7 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
_cached_attrs = ResultatsSemestre._cached_attrs + (
|
_cached_attrs = ResultatsSemestre._cached_attrs + (
|
||||||
"bonus",
|
"bonus",
|
||||||
"bonus_ues",
|
"bonus_ues",
|
||||||
|
"malus",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, formsemestre: FormSemestre):
|
def __init__(self, formsemestre: FormSemestre):
|
||||||
|
@ -22,6 +22,7 @@ from app.models.etudiants import Identite
|
|||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
|
|
||||||
class FormSemestre(db.Model):
|
class FormSemestre(db.Model):
|
||||||
@ -169,14 +170,24 @@ class FormSemestre(db.Model):
|
|||||||
else:
|
else:
|
||||||
modimpls.sort(
|
modimpls.sort(
|
||||||
key=lambda m: (
|
key=lambda m: (
|
||||||
m.module.ue.numero,
|
m.module.ue.numero or 0,
|
||||||
m.module.matiere.numero,
|
m.module.matiere.numero or 0,
|
||||||
m.module.numero,
|
m.module.numero or 0,
|
||||||
m.module.code,
|
m.module.code or "",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return modimpls
|
return modimpls
|
||||||
|
|
||||||
|
def can_be_edited_by(self, user):
|
||||||
|
"""Vrai si user peut modifier ce semestre"""
|
||||||
|
if not user.has_permission(Permission.ScoImplement): # pas chef
|
||||||
|
if not self.resp_can_edit or user.id not in [
|
||||||
|
resp.id for resp in self.responsables
|
||||||
|
]:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def est_courant(self) -> bool:
|
def est_courant(self) -> bool:
|
||||||
"""Vrai si la date actuelle (now) est dans le semestre
|
"""Vrai si la date actuelle (now) est dans le semestre
|
||||||
(les dates de début et fin sont incluses)
|
(les dates de début et fin sont incluses)
|
||||||
@ -425,7 +436,7 @@ class FormSemestreUECoef(db.Model):
|
|||||||
|
|
||||||
|
|
||||||
class FormSemestreUEComputationExpr(db.Model):
|
class FormSemestreUEComputationExpr(db.Model):
|
||||||
"""Formules utilisateurs pour calcul moyenne UE"""
|
"""Formules utilisateurs pour calcul moyenne UE (désactivées en 9.2+)."""
|
||||||
|
|
||||||
__tablename__ = "notes_formsemestre_ue_computation_expr"
|
__tablename__ = "notes_formsemestre_ue_computation_expr"
|
||||||
__table_args__ = (db.UniqueConstraint("formsemestre_id", "ue_id"),)
|
__table_args__ = (db.UniqueConstraint("formsemestre_id", "ue_id"),)
|
||||||
|
@ -619,7 +619,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
prefs=prefs,
|
prefs=prefs,
|
||||||
)
|
)
|
||||||
|
|
||||||
if nbeval: # boite autour des evaluations (en pdf)
|
if nbeval: # boite autour des évaluations (en pdf)
|
||||||
P[-1]["_pdf_style"].append(
|
P[-1]["_pdf_style"].append(
|
||||||
("BOX", (1, 1 - nbeval), (-1, 0), 0.2, self.PDF_LIGHT_GRAY)
|
("BOX", (1, 1 - nbeval), (-1, 0), 0.2, self.PDF_LIGHT_GRAY)
|
||||||
)
|
)
|
||||||
|
@ -289,7 +289,10 @@ def module_create(
|
|||||||
"type": "int",
|
"type": "int",
|
||||||
"title": "UE de rattachement",
|
"title": "UE de rattachement",
|
||||||
"explanation": "utilisée notamment pour les malus",
|
"explanation": "utilisée notamment pour les malus",
|
||||||
"labels": [f"{u.acronyme} {u.titre}" for u in ues],
|
"labels": [
|
||||||
|
f"S{u.semestre_idx if u.semestre_idx is not None else '.'} / {u.acronyme} {u.titre}"
|
||||||
|
for u in ues
|
||||||
|
],
|
||||||
"allowed_values": [u.id for u in ues],
|
"allowed_values": [u.id for u in ues],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -231,13 +231,17 @@ def do_ue_delete(ue_id, delete_validations=False, force=False):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def ue_create(formation_id=None):
|
def ue_create(formation_id=None, default_semestre_idx=None):
|
||||||
"""Creation d'une UE"""
|
"""Formulaire création d'une UE"""
|
||||||
return ue_edit(create=True, formation_id=formation_id)
|
return ue_edit(
|
||||||
|
create=True,
|
||||||
|
formation_id=formation_id,
|
||||||
|
default_semestre_idx=default_semestre_idx,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def ue_edit(ue_id=None, create=False, formation_id=None):
|
def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=None):
|
||||||
"""Modification ou création d'une UE"""
|
"""Formulaire modification ou création d'une UE"""
|
||||||
create = int(create)
|
create = int(create)
|
||||||
if not create:
|
if not create:
|
||||||
U = ue_list(args={"ue_id": ue_id})
|
U = ue_list(args={"ue_id": ue_id})
|
||||||
@ -250,7 +254,7 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
|
|||||||
submitlabel = "Modifier les valeurs"
|
submitlabel = "Modifier les valeurs"
|
||||||
else:
|
else:
|
||||||
title = "Création d'une UE"
|
title = "Création d'une UE"
|
||||||
initvalues = {}
|
initvalues = {"semestre_idx": default_semestre_idx}
|
||||||
submitlabel = "Créer cette UE"
|
submitlabel = "Créer cette UE"
|
||||||
formation = Formation.query.get(formation_id)
|
formation = Formation.query.get(formation_id)
|
||||||
if not formation:
|
if not formation:
|
||||||
|
@ -207,7 +207,7 @@ def evaluation_create_form(
|
|||||||
{
|
{
|
||||||
"size": 6,
|
"size": 6,
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"explanation": "coef. dans le module (choisi librement par l'enseignant)",
|
"explanation": "coef. dans le module (choisi librement par l'enseignant, non utilisé pour rattrapage et 2ème session)",
|
||||||
"allow_null": False,
|
"allow_null": False,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -118,10 +118,16 @@ def formsemestre_editwithmodules(formsemestre_id):
|
|||||||
vals = scu.get_request_args()
|
vals = scu.get_request_args()
|
||||||
if not vals.get("tf_submitted", False):
|
if not vals.get("tf_submitted", False):
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="help">Seuls les modules cochés font partie de ce semestre. Pour les retirer, les décocher et appuyer sur le bouton "modifier".
|
"""<p class="help">Seuls les modules cochés font partie de ce semestre.
|
||||||
</p>
|
Pour les retirer, les décocher et appuyer sur le bouton "modifier".
|
||||||
<p class="help">Attention : s'il y a déjà des évaluations dans un module, il ne peut pas être supprimé !</p>
|
</p>
|
||||||
<p class="help">Les modules ont toujours un responsable. Par défaut, c'est le directeur des études.</p>"""
|
<p class="help">Attention : s'il y a déjà des évaluations dans un module,
|
||||||
|
il ne peut pas être supprimé !</p>
|
||||||
|
<p class="help">Les modules ont toujours un responsable.
|
||||||
|
Par défaut, c'est le directeur des études.</p>
|
||||||
|
<p class="help">Un semestre ne peut comporter qu'une seule UE "bonus
|
||||||
|
sport/culture"</p>
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
return "\n".join(H) + html_sco_header.sco_footer()
|
return "\n".join(H) + html_sco_header.sco_footer()
|
||||||
@ -739,6 +745,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
# Modules sélectionnés:
|
# Modules sélectionnés:
|
||||||
# (retire le "MI" du début du nom de champs)
|
# (retire le "MI" du début du nom de champs)
|
||||||
module_ids_checked = [int(x[2:]) for x in tf[2]["tf-checked"]]
|
module_ids_checked = [int(x[2:]) for x in tf[2]["tf-checked"]]
|
||||||
|
_formsemestre_check_ue_bonus_unicity(module_ids_checked)
|
||||||
if not edit:
|
if not edit:
|
||||||
if formation.is_apc():
|
if formation.is_apc():
|
||||||
_formsemestre_check_module_list(
|
_formsemestre_check_module_list(
|
||||||
@ -882,6 +889,18 @@ def _formsemestre_check_module_list(module_ids, semestre_idx):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _formsemestre_check_ue_bonus_unicity(module_ids):
|
||||||
|
"""Vérifie qu'il n'y a qu'une seule UE bonus associée aux modules choisis"""
|
||||||
|
ues = [Module.query.get_or_404(module_id).ue for module_id in module_ids]
|
||||||
|
ues_bonus = {ue.id for ue in ues if ue.type == sco_codes_parcours.UE_SPORT}
|
||||||
|
if len(ues_bonus) > 1:
|
||||||
|
raise ScoValueError(
|
||||||
|
"""Les modules de bonus sélectionnés ne sont pas tous dans la même UE bonus.
|
||||||
|
Changez la sélection ou modifiez la structure du programme de formation.""",
|
||||||
|
dest_url="javascript:history.back();",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
|
def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
|
||||||
"""Delete moduleimpls
|
"""Delete moduleimpls
|
||||||
module_ids_to_del: list of module_id (warning: not moduleimpl)
|
module_ids_to_del: list of module_id (warning: not moduleimpl)
|
||||||
|
@ -1152,30 +1152,19 @@ def formsemestre_tableau_modules(
|
|||||||
f"""<tr class="formsemestre_status_ue"><td colspan="4">
|
f"""<tr class="formsemestre_status_ue"><td colspan="4">
|
||||||
<span class="status_ue_acro">{ue["acronyme"]}</span>
|
<span class="status_ue_acro">{ue["acronyme"]}</span>
|
||||||
<span class="status_ue_title">{titre}</span>
|
<span class="status_ue_title">{titre}</span>
|
||||||
</td><td>"""
|
</td><td colspan="2">"""
|
||||||
)
|
)
|
||||||
if can_edit:
|
|
||||||
H.append(
|
|
||||||
' <a href="edit_ue_expr?formsemestre_id=%s&ue_id=%s">'
|
|
||||||
% (formsemestre_id, ue["ue_id"])
|
|
||||||
)
|
|
||||||
H.append(
|
|
||||||
scu.icontag(
|
|
||||||
"formula",
|
|
||||||
title="Mode calcul moyenne d'UE",
|
|
||||||
style="vertical-align:middle",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if can_edit:
|
|
||||||
H.append("</a>")
|
|
||||||
|
|
||||||
expr = sco_compute_moy.get_ue_expression(
|
expr = sco_compute_moy.get_ue_expression(
|
||||||
formsemestre_id, ue["ue_id"], html_quote=True
|
formsemestre_id, ue["ue_id"], html_quote=True
|
||||||
)
|
)
|
||||||
if expr:
|
if expr:
|
||||||
H.append(
|
H.append(
|
||||||
""" <span class="formula" title="mode de calcul de la moyenne d'UE">%s</span>"""
|
f""" <span class="formula" title="mode de calcul de la moyenne d'UE">{expr}</span>
|
||||||
% expr
|
<span class="warning">formule inutilisée en 9.2: <a href="{
|
||||||
|
url_for("notes.delete_ue_expr", scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, ue_id=ue["ue_id"] )
|
||||||
|
}
|
||||||
|
">supprimer</a></span>"""
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append("</td></tr>")
|
H.append("</td></tr>")
|
||||||
|
@ -46,16 +46,17 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endfor %}
|
|
||||||
{% if editable %}
|
{% if editable %}
|
||||||
<ul>
|
<ul>
|
||||||
<li class="notes_ue_list notes_ue_list_add"><a class="stdlink" href="{{
|
<li class="notes_ue_list notes_ue_list_add"><a class="stdlink" href="{{
|
||||||
url_for('notes.ue_create',
|
url_for('notes.ue_create',
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=formation.id,
|
formation_id=formation.id,
|
||||||
|
default_semestre_idx=semestre_idx,
|
||||||
)}}"
|
)}}"
|
||||||
>ajouter une UE</a>
|
>ajouter une UE</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
@ -30,23 +30,19 @@ Module notes: issu de ScoDoc7 / ZNotes.py
|
|||||||
|
|
||||||
Emmanuel Viennet, 2021
|
Emmanuel Viennet, 2021
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import datetime
|
|
||||||
import pprint
|
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, jsonify, render_template
|
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.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
|
from app.models.formsemestre import FormSemestreUEComputationExpr
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
|
|
||||||
from config import Config
|
|
||||||
|
|
||||||
from app import api
|
from app import api
|
||||||
from app import db
|
from app import db
|
||||||
from app import models
|
from app import models
|
||||||
@ -1245,76 +1241,28 @@ def view_module_abs(moduleimpl_id, format="html"):
|
|||||||
return "\n".join(H) + tab.html() + html_sco_header.sco_footer()
|
return "\n".join(H) + tab.html() + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/edit_ue_expr", methods=["GET", "POST"])
|
@bp.route("/delete_ue_expr/<int:formsemestre_id>/<int:ue_id>", methods=["GET", "POST"])
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
def delete_ue_expr(formsemestre_id: int, ue_id: int):
|
||||||
@scodoc7func
|
"""Efface une expression de calcul d'UE"""
|
||||||
def edit_ue_expr(formsemestre_id, ue_id):
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
"""Edition formule calcul moyenne UE"""
|
if not formsemestre.can_be_edited_by(current_user):
|
||||||
# Check access
|
|
||||||
sem = sco_formsemestre_edit.can_edit_sem(formsemestre_id)
|
|
||||||
if not sem:
|
|
||||||
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")
|
||||||
cnx = ndb.GetDBConnexion()
|
expr = FormSemestreUEComputationExpr.query.filter_by(
|
||||||
#
|
formsemestre_id=formsemestre_id, ue_id=ue_id
|
||||||
ue = sco_edit_ue.ue_list({"ue_id": ue_id})[0]
|
).first()
|
||||||
H = [
|
if expr is not None:
|
||||||
html_sco_header.html_sem_header(
|
db.session.delete(expr)
|
||||||
"Modification règle de calcul de l'UE %s (%s)"
|
db.session.commit()
|
||||||
% (ue["acronyme"], ue["titre"]),
|
flash("formule supprimée")
|
||||||
),
|
return flask.redirect(
|
||||||
_EXPR_HELP % {"target": "de l'UE", "objs": "modules", "ordre": ""},
|
url_for(
|
||||||
]
|
"notes.formsemestre_status",
|
||||||
el = sco_compute_moy.formsemestre_ue_computation_expr_list(
|
scodoc_dept=g.scodoc_dept,
|
||||||
cnx, {"formsemestre_id": formsemestre_id, "ue_id": ue_id}
|
formsemestre_id=formsemestre_id,
|
||||||
)
|
head_message="formule supprimée",
|
||||||
if el:
|
|
||||||
initvalues = el[0]
|
|
||||||
else:
|
|
||||||
initvalues = {}
|
|
||||||
form = [
|
|
||||||
("ue_id", {"input_type": "hidden"}),
|
|
||||||
("formsemestre_id", {"input_type": "hidden"}),
|
|
||||||
(
|
|
||||||
"computation_expr",
|
|
||||||
{
|
|
||||||
"title": "Formule de calcul",
|
|
||||||
"input_type": "textarea",
|
|
||||||
"rows": 4,
|
|
||||||
"cols": 60,
|
|
||||||
"explanation": "formule de calcul (expérimental)",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
tf = TrivialFormulator(
|
|
||||||
request.base_url,
|
|
||||||
scu.get_request_args(),
|
|
||||||
form,
|
|
||||||
submitlabel="Modifier formule de calcul",
|
|
||||||
cancelbutton="Annuler",
|
|
||||||
initvalues=initvalues,
|
|
||||||
)
|
|
||||||
if tf[0] == 0:
|
|
||||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
|
||||||
elif tf[0] == -1:
|
|
||||||
return flask.redirect(
|
|
||||||
"formsemestre_status?formsemestre_id=" + str(formsemestre_id)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if el:
|
|
||||||
el[0]["computation_expr"] = tf[2]["computation_expr"]
|
|
||||||
sco_compute_moy.formsemestre_ue_computation_expr_edit(cnx, el[0])
|
|
||||||
else:
|
|
||||||
sco_compute_moy.formsemestre_ue_computation_expr_create(cnx, tf[2])
|
|
||||||
|
|
||||||
sco_cache.invalidate_formsemestre(
|
|
||||||
formsemestre_id=formsemestre_id
|
|
||||||
) # > modif regle calcul
|
|
||||||
return flask.redirect(
|
|
||||||
"formsemestre_status?formsemestre_id="
|
|
||||||
+ str(formsemestre_id)
|
|
||||||
+ "&head_message=règle%20de%20calcul%20modifiée"
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/formsemestre_enseignants_list")
|
@bp.route("/formsemestre_enseignants_list")
|
||||||
|
@ -269,7 +269,6 @@ def create_user_form(user_name=None, edit=0, all_roles=False):
|
|||||||
for i in range(len(displayed_roles_strings)):
|
for i in range(len(displayed_roles_strings)):
|
||||||
if displayed_roles_strings[i] not in editable_roles_strings:
|
if displayed_roles_strings[i] not in editable_roles_strings:
|
||||||
disabled_roles[i] = True
|
disabled_roles[i] = True
|
||||||
breakpoint()
|
|
||||||
descr = [
|
descr = [
|
||||||
("edit", {"input_type": "hidden", "default": edit}),
|
("edit", {"input_type": "hidden", "default": edit}),
|
||||||
("nom", {"title": "Nom", "size": 20, "allow_null": False}),
|
("nom", {"title": "Nom", "size": 20, "allow_null": False}),
|
||||||
|
Loading…
Reference in New Issue
Block a user