forked from ScoDoc/DocScoDoc
Merge branch 'refactor_nt' of https://scodoc.org/git/ScoDoc/ScoDoc into entreprises
This commit is contained in:
commit
e85149f4a6
@ -71,7 +71,7 @@ class BulletinBUT(ResultatsSemestreBUT):
|
|||||||
"bonus": fmt_note(self.bonus_ues[ue.id][etud.id])
|
"bonus": fmt_note(self.bonus_ues[ue.id][etud.id])
|
||||||
if self.bonus_ues is not None and ue.id in self.bonus_ues
|
if self.bonus_ues is not None and ue.id in self.bonus_ues
|
||||||
else fmt_note(0.0),
|
else fmt_note(0.0),
|
||||||
"malus": None, # XXX TODO voir ce qui est ici
|
"malus": self.malus[ue.id][etud.id],
|
||||||
"capitalise": None, # "AAAA-MM-JJ" TODO
|
"capitalise": None, # "AAAA-MM-JJ" TODO
|
||||||
"ressources": self.etud_ue_mod_results(etud, ue, self.ressources),
|
"ressources": self.etud_ue_mod_results(etud, ue, self.ressources),
|
||||||
"saes": self.etud_ue_mod_results(etud, ue, self.saes),
|
"saes": self.etud_ue_mod_results(etud, ue, self.saes),
|
||||||
|
@ -104,7 +104,6 @@ class BonusSport:
|
|||||||
# sem_modimpl_moys_spo est (nb_etuds, nb_mod_sport)
|
# sem_modimpl_moys_spo est (nb_etuds, nb_mod_sport)
|
||||||
# ou (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
# ou (nb_etuds, nb_mod_sport, nb_ues_non_bonus)
|
||||||
nb_etuds, nb_mod_sport = sem_modimpl_moys_spo.shape[:2]
|
nb_etuds, nb_mod_sport = sem_modimpl_moys_spo.shape[:2]
|
||||||
nb_ues = len(ues)
|
|
||||||
# Enlève les NaN du numérateur:
|
# Enlève les NaN du numérateur:
|
||||||
sem_modimpl_moys_no_nan = np.nan_to_num(sem_modimpl_moys_spo, nan=0.0)
|
sem_modimpl_moys_no_nan = np.nan_to_num(sem_modimpl_moys_spo, nan=0.0)
|
||||||
|
|
||||||
@ -124,7 +123,7 @@ class BonusSport:
|
|||||||
# Annule les coefs des modules où l'étudiant n'est pas inscrit:
|
# Annule les coefs des modules où l'étudiant n'est pas inscrit:
|
||||||
modimpl_coefs_etuds = np.where(
|
modimpl_coefs_etuds = np.where(
|
||||||
modimpl_inscr_spo_stacked,
|
modimpl_inscr_spo_stacked,
|
||||||
np.stack([modimpl_coefs_spo.T] * nb_etuds),
|
np.stack([modimpl_coefs_spo] * nb_etuds),
|
||||||
0.0,
|
0.0,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -162,7 +161,7 @@ class BonusSport:
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError("méthode virtuelle")
|
raise NotImplementedError("méthode virtuelle")
|
||||||
|
|
||||||
def get_bonus_ues(self) -> pd.Series:
|
def get_bonus_ues(self) -> pd.DataFrame:
|
||||||
"""Les bonus à appliquer aux UE
|
"""Les bonus à appliquer aux UE
|
||||||
Résultat: DataFrame de float, index etudid, columns: ue.id
|
Résultat: DataFrame de float, index etudid, columns: ue.id
|
||||||
"""
|
"""
|
||||||
|
@ -43,6 +43,8 @@ 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_exceptions import ScoValueError
|
||||||
|
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class EvaluationEtat:
|
class EvaluationEtat:
|
||||||
@ -233,6 +235,8 @@ class ModuleImplResultsAPC(ModuleImplResults):
|
|||||||
assert evals_poids_df.shape[0] == nb_evals # compat notes/poids
|
assert evals_poids_df.shape[0] == nb_evals # compat notes/poids
|
||||||
if nb_etuds == 0:
|
if nb_etuds == 0:
|
||||||
return pd.DataFrame(index=[], columns=evals_poids_df.columns)
|
return pd.DataFrame(index=[], columns=evals_poids_df.columns)
|
||||||
|
if nb_ues == 0:
|
||||||
|
return pd.DataFrame(index=self.evals_notes.index, columns=[])
|
||||||
evals_coefs = self.get_evaluations_coefs(moduleimpl)
|
evals_coefs = self.get_evaluations_coefs(moduleimpl)
|
||||||
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)
|
||||||
@ -289,7 +293,12 @@ def load_evaluations_poids(moduleimpl_id: int) -> tuple[pd.DataFrame, list]:
|
|||||||
pass # poids vers des UE qui n'existent plus ou sont dans un autre semestre...
|
pass # poids vers des UE qui n'existent plus ou sont dans un autre semestre...
|
||||||
|
|
||||||
# Initialise poids non enregistrés:
|
# Initialise poids non enregistrés:
|
||||||
default_poids = 1.0 if modimpl.module.ue.type == UE_SPORT else 0.0
|
default_poids = (
|
||||||
|
1.0
|
||||||
|
if modimpl.module.ue.type == UE_SPORT
|
||||||
|
or modimpl.module.module_type == ModuleType.MALUS
|
||||||
|
else 0.0
|
||||||
|
)
|
||||||
|
|
||||||
if np.isnan(evals_poids.values.flat).any():
|
if np.isnan(evals_poids.values.flat).any():
|
||||||
ue_coefs = modimpl.module.get_ue_coef_dict()
|
ue_coefs = modimpl.module.get_ue_coef_dict()
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
"""Fonctions de calcul des moyennes d'UE (classiques ou BUT)
|
"""Fonctions de calcul des moyennes d'UE (classiques ou BUT)
|
||||||
"""
|
"""
|
||||||
|
from re import X
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
@ -263,9 +264,10 @@ def compute_ue_moys_apc(
|
|||||||
#
|
#
|
||||||
# Version vectorisée
|
# Version vectorisée
|
||||||
#
|
#
|
||||||
etud_moy_ue = np.sum(
|
with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN)
|
||||||
modimpl_coefs_etuds_no_nan * sem_cube_inscrits, axis=1
|
etud_moy_ue = np.sum(
|
||||||
) / np.sum(modimpl_coefs_etuds_no_nan, axis=1)
|
modimpl_coefs_etuds_no_nan * sem_cube_inscrits, axis=1
|
||||||
|
) / np.sum(modimpl_coefs_etuds_no_nan, axis=1)
|
||||||
return pd.DataFrame(
|
return pd.DataFrame(
|
||||||
etud_moy_ue,
|
etud_moy_ue,
|
||||||
index=modimpl_inscr_df.index, # les etudids
|
index=modimpl_inscr_df.index, # les etudids
|
||||||
@ -379,3 +381,42 @@ def compute_ue_moys_classic(
|
|||||||
etud_moy_gen_s = pd.Series(etud_moy_gen, index=modimpl_inscr_df.index)
|
etud_moy_gen_s = pd.Series(etud_moy_gen, index=modimpl_inscr_df.index)
|
||||||
|
|
||||||
return etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df
|
return etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df
|
||||||
|
|
||||||
|
|
||||||
|
def compute_malus(
|
||||||
|
formsemestre: FormSemestre,
|
||||||
|
sem_modimpl_moys: np.array,
|
||||||
|
ues: list[UniteEns],
|
||||||
|
modimpl_inscr_df: pd.DataFrame,
|
||||||
|
) -> pd.DataFrame:
|
||||||
|
"""Calcul le malus sur les UE
|
||||||
|
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
|
||||||
|
de chaque UE.
|
||||||
|
Arguments:
|
||||||
|
- sem_modimpl_moys :
|
||||||
|
notes moyennes aux modules (tous les étuds x tous les modimpls)
|
||||||
|
floats avec des NaN.
|
||||||
|
En classique: sem_matrix, ndarray (etuds x modimpls)
|
||||||
|
En APC: sem_cube, ndarray (etuds x modimpls x UEs non bonus)
|
||||||
|
- ues: les ues du semestre (incluant le bonus sport)
|
||||||
|
- modimpl_inscr_df: matrice d'inscription aux modules du semestre (etud x modimpl)
|
||||||
|
|
||||||
|
Résultat: DataFrame de float, index etudid, columns: ue.id (sans NaN)
|
||||||
|
"""
|
||||||
|
ues_idx = [ue.id for ue in ues]
|
||||||
|
malus = pd.DataFrame(index=modimpl_inscr_df.index, columns=ues_idx, dtype=float)
|
||||||
|
for ue in ues:
|
||||||
|
if ue.type != UE_SPORT:
|
||||||
|
modimpl_mask = np.array(
|
||||||
|
[
|
||||||
|
(m.module.module_type == ModuleType.MALUS)
|
||||||
|
and (m.module.ue.id == ue.id)
|
||||||
|
for m in formsemestre.modimpls_sorted
|
||||||
|
]
|
||||||
|
)
|
||||||
|
malus_moys = sem_modimpl_moys[:, modimpl_mask].sum(axis=1)
|
||||||
|
malus[ue.id] = malus_moys
|
||||||
|
|
||||||
|
malus.fillna(0.0, inplace=True)
|
||||||
|
return malus
|
||||||
|
@ -68,6 +68,12 @@ class ResultatsSemestreBUT(NotesTableCompat):
|
|||||||
1.0, index=self.etud_moy_ue.index, columns=self.etud_moy_ue.columns
|
1.0, index=self.etud_moy_ue.index, columns=self.etud_moy_ue.columns
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- Modules de MALUS sur les UEs
|
||||||
|
self.malus = moy_ue.compute_malus(
|
||||||
|
self.formsemestre, self.sem_cube, self.ues, self.modimpl_inscr_df
|
||||||
|
)
|
||||||
|
self.etud_moy_ue -= self.malus
|
||||||
|
|
||||||
# --- Bonus Sport & Culture
|
# --- Bonus Sport & Culture
|
||||||
if len(modimpls_sport) > 0:
|
if len(modimpls_sport) > 0:
|
||||||
bonus_class = ScoDocSiteConfig.get_bonus_sport_class()
|
bonus_class = ScoDocSiteConfig.get_bonus_sport_class()
|
||||||
|
@ -71,6 +71,16 @@ class ResultatsSemestreClassic(NotesTableCompat):
|
|||||||
self.modimpl_coefs,
|
self.modimpl_coefs,
|
||||||
modimpl_standards_mask,
|
modimpl_standards_mask,
|
||||||
)
|
)
|
||||||
|
# --- Modules de MALUS sur les UEs et la moyenne générale
|
||||||
|
self.malus = moy_ue.compute_malus(
|
||||||
|
self.formsemestre, self.sem_matrix, self.ues, self.modimpl_inscr_df
|
||||||
|
)
|
||||||
|
self.etud_moy_ue -= self.malus
|
||||||
|
# ajuste la moyenne générale (à l'aide des coefs d'UE)
|
||||||
|
self.etud_moy_gen -= (self.etud_coef_ue_df * self.malus).sum(
|
||||||
|
axis=1
|
||||||
|
) / self.etud_coef_ue_df.sum(axis=1)
|
||||||
|
|
||||||
# --- Bonus Sport & Culture
|
# --- Bonus Sport & Culture
|
||||||
bonus_class = ScoDocSiteConfig.get_bonus_sport_class()
|
bonus_class = ScoDocSiteConfig.get_bonus_sport_class()
|
||||||
if bonus_class is not None:
|
if bonus_class is not None:
|
||||||
|
@ -70,7 +70,7 @@ class CodesDecisionsForm(FlaskForm):
|
|||||||
ATT = _build_code_field("ATT")
|
ATT = _build_code_field("ATT")
|
||||||
CMP = _build_code_field("CMP")
|
CMP = _build_code_field("CMP")
|
||||||
DEF = _build_code_field("DEF")
|
DEF = _build_code_field("DEF")
|
||||||
DEM = _build_code_field("DEF")
|
DEM = _build_code_field("DEM")
|
||||||
NAR = _build_code_field("NAR")
|
NAR = _build_code_field("NAR")
|
||||||
RAT = _build_code_field("RAT")
|
RAT = _build_code_field("RAT")
|
||||||
submit = SubmitField("Valider")
|
submit = SubmitField("Valider")
|
||||||
|
@ -178,7 +178,7 @@ class ScoDocSiteConfig(db.Model):
|
|||||||
return getattr(bonus_sport, func_name)
|
return getattr(bonus_sport, func_name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
f"""Fonction de calcul maison inexistante: {func_name}.
|
f"""Fonction de calcul de l'UE bonus inexistante: "{func_name}".
|
||||||
(contacter votre administrateur local)."""
|
(contacter votre administrateur local)."""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -276,14 +276,24 @@ class TF(object):
|
|||||||
)
|
)
|
||||||
ok = 0
|
ok = 0
|
||||||
if typ[:3] == "int" or typ == "float" or typ == "real":
|
if typ[:3] == "int" or typ == "float" or typ == "real":
|
||||||
if "min_value" in descr and val < descr["min_value"]:
|
if (
|
||||||
|
val != ""
|
||||||
|
and val != None
|
||||||
|
and "min_value" in descr
|
||||||
|
and val < 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 val > 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"])
|
||||||
|
@ -456,6 +456,11 @@ def bonus_iutbeziers(notes_sport, coefs, infos=None):
|
|||||||
return bonus
|
return bonus
|
||||||
|
|
||||||
|
|
||||||
|
def bonus_iutlemans(notes_sport, coefs, infos=None):
|
||||||
|
"fake: formule inutilisée en ScoDoc 9.2 mais doiut être présente"
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
|
||||||
def bonus_iutlr(notes_sport, coefs, infos=None):
|
def bonus_iutlr(notes_sport, coefs, infos=None):
|
||||||
"""Calcul bonus modules optionels (sport, culture), règle IUT La Rochelle
|
"""Calcul bonus modules optionels (sport, culture), règle IUT La Rochelle
|
||||||
Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point
|
Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point
|
||||||
|
@ -125,8 +125,8 @@ APO_NEWLINE = "\r\n"
|
|||||||
|
|
||||||
def _apo_fmt_note(note):
|
def _apo_fmt_note(note):
|
||||||
"Formatte une note pour Apogée (séparateur décimal: ',')"
|
"Formatte une note pour Apogée (séparateur décimal: ',')"
|
||||||
if not note and isinstance(note, float):
|
# if not note and isinstance(note, float): changé le 31/1/2022, étrange ?
|
||||||
return ""
|
# return ""
|
||||||
try:
|
try:
|
||||||
val = float(note)
|
val = float(note)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -141,7 +141,7 @@ BUG = "BUG"
|
|||||||
|
|
||||||
ALL = "ALL"
|
ALL = "ALL"
|
||||||
|
|
||||||
# Explication des codes (de demestre ou d'UE)
|
# Explication des codes (de semestre ou d'UE)
|
||||||
CODES_EXPL = {
|
CODES_EXPL = {
|
||||||
ADC: "Validé par compensation",
|
ADC: "Validé par compensation",
|
||||||
ADJ: "Validé par le Jury",
|
ADJ: "Validé par le Jury",
|
||||||
@ -154,6 +154,7 @@ CODES_EXPL = {
|
|||||||
DEF: "Défaillant",
|
DEF: "Défaillant",
|
||||||
NAR: "Échec, non autorisé à redoubler",
|
NAR: "Échec, non autorisé à redoubler",
|
||||||
RAT: "En attente d'un rattrapage",
|
RAT: "En attente d'un rattrapage",
|
||||||
|
DEM: "Démission",
|
||||||
}
|
}
|
||||||
# Nota: ces explications sont personnalisables via le fichier
|
# Nota: ces explications sont personnalisables via le fichier
|
||||||
# de config locale /opt/scodoc/var/scodoc/config/scodoc_local.py
|
# de config locale /opt/scodoc/var/scodoc/config/scodoc_local.py
|
||||||
|
@ -115,22 +115,30 @@ def do_module_create(args) -> int:
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
def module_create(
|
||||||
"""Création d'un module"""
|
matiere_id=None, module_type=None, semestre_id=None, formation_id=None
|
||||||
|
):
|
||||||
|
"""Formulaire de création d'un module
|
||||||
|
Si matiere_id est spécifié, le module sera créé dans cette matière (cas normal).
|
||||||
|
Sinon, donne le choix de l'UE de rattachement et utilise la première
|
||||||
|
matière de cette UE (si elle n'existe pas, la crée).
|
||||||
|
"""
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
|
|
||||||
matiere = Matiere.query.get_or_404(matiere_id)
|
if matiere_id:
|
||||||
if matiere is None:
|
matiere = Matiere.query.get_or_404(matiere_id)
|
||||||
raise ScoValueError("invalid matiere !")
|
ue = matiere.ue
|
||||||
ue = matiere.ue
|
formation = ue.formation
|
||||||
parcours = ue.formation.get_parcours()
|
else:
|
||||||
|
formation = Formation.query.get_or_404(formation_id)
|
||||||
|
parcours = formation.get_parcours()
|
||||||
is_apc = parcours.APC_SAE
|
is_apc = parcours.APC_SAE
|
||||||
ues = ue.formation.ues.order_by(
|
ues = formation.ues.order_by(
|
||||||
UniteEns.semestre_idx, UniteEns.numero, UniteEns.acronyme
|
UniteEns.semestre_idx, UniteEns.numero, UniteEns.acronyme
|
||||||
).all()
|
).all()
|
||||||
# cherche le numero adéquat (pour placer le module en fin de liste)
|
# cherche le numero adéquat (pour placer le module en fin de liste)
|
||||||
modules = matiere.ue.formation.modules.all()
|
modules = formation.modules.all()
|
||||||
if modules:
|
if modules:
|
||||||
default_num = max([m.numero or 0 for m in modules]) + 10
|
default_num = max([m.numero or 0 for m in modules]) + 10
|
||||||
else:
|
else:
|
||||||
@ -143,9 +151,11 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title=f"Création {object_name}"),
|
html_sco_header.sco_header(page_title=f"Création {object_name}"),
|
||||||
]
|
]
|
||||||
if is_apc:
|
if not matiere_id:
|
||||||
H += [
|
H += [
|
||||||
f"""<h2>Création {object_name} dans la formation {ue.formation.acronyme}, Semestre {ue.semestre_idx}, {ue.acronyme}</h2>"""
|
f"""<h2>Création {object_name} dans la formation {formation.acronyme}
|
||||||
|
</h2>
|
||||||
|
"""
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
H += [
|
H += [
|
||||||
@ -158,7 +168,6 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
render_template(
|
render_template(
|
||||||
"scodoc/help/modules.html",
|
"scodoc/help/modules.html",
|
||||||
is_apc=is_apc,
|
is_apc=is_apc,
|
||||||
ue=ue,
|
|
||||||
semestre_id=semestre_id,
|
semestre_id=semestre_id,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@ -170,7 +179,7 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
"size": 10,
|
"size": 10,
|
||||||
"explanation": "code du module, ressource ou SAÉ. Exemple M1203, R2.01, ou SAÉ 3.4. Ce code doit être unique dans la formation.",
|
"explanation": "code du module, ressource ou SAÉ. Exemple M1203, R2.01, ou SAÉ 3.4. Ce code doit être unique dans la formation.",
|
||||||
"allow_null": False,
|
"allow_null": False,
|
||||||
"validator": lambda val, field, formation_id=ue.formation_id: check_module_code_unicity(
|
"validator": lambda val, field, formation_id=formation_id: check_module_code_unicity(
|
||||||
val, field, formation_id
|
val, field, formation_id
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -192,6 +201,15 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
]
|
]
|
||||||
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
||||||
|
|
||||||
|
if is_apc:
|
||||||
|
module_types = scu.ModuleType # tous les types
|
||||||
|
else:
|
||||||
|
# ne propose pas SAE et Ressources:
|
||||||
|
module_types = set(scu.ModuleType) - {
|
||||||
|
scu.ModuleType.RESSOURCE,
|
||||||
|
scu.ModuleType.SAE,
|
||||||
|
}
|
||||||
|
|
||||||
descr += [
|
descr += [
|
||||||
(
|
(
|
||||||
"module_type",
|
"module_type",
|
||||||
@ -199,8 +217,8 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"title": "Type",
|
"title": "Type",
|
||||||
"explanation": "",
|
"explanation": "",
|
||||||
"labels": [x.name.capitalize() for x in scu.ModuleType],
|
"labels": [x.name.capitalize() for x in module_types],
|
||||||
"allowed_values": [str(int(x)) for x in scu.ModuleType],
|
"allowed_values": [str(int(x)) for x in module_types],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -256,11 +274,30 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if matiere_id:
|
||||||
|
descr += [
|
||||||
|
("ue_id", {"default": ue.id, "input_type": "hidden"}),
|
||||||
|
("matiere_id", {"default": matiere_id, "input_type": "hidden"}),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# choix de l'UE de rattachement
|
||||||
|
descr += [
|
||||||
|
(
|
||||||
|
"ue_id",
|
||||||
|
{
|
||||||
|
"input_type": "menu",
|
||||||
|
"type": "int",
|
||||||
|
"title": "UE de rattachement",
|
||||||
|
"explanation": "utilisée notamment pour les malus",
|
||||||
|
"labels": [f"{u.acronyme} {u.titre}" for u in ues],
|
||||||
|
"allowed_values": [u.id for u in ues],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
descr += [
|
descr += [
|
||||||
# ('ects', { 'size' : 4, 'type' : 'float', 'title' : 'ECTS', 'explanation' : 'nombre de crédits ECTS (inutilisés: les crédits sont associés aux UE)' }),
|
# ('ects', { 'size' : 4, 'type' : 'float', 'title' : 'ECTS', 'explanation' : 'nombre de crédits ECTS (inutilisés: les crédits sont associés aux UE)' }),
|
||||||
("formation_id", {"default": ue.formation_id, "input_type": "hidden"}),
|
("formation_id", {"default": formation.id, "input_type": "hidden"}),
|
||||||
("ue_id", {"default": ue.id, "input_type": "hidden"}),
|
|
||||||
("matiere_id", {"default": matiere.id, "input_type": "hidden"}),
|
|
||||||
(
|
(
|
||||||
"code_apogee",
|
"code_apogee",
|
||||||
{
|
{
|
||||||
@ -290,6 +327,20 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
|
||||||
else:
|
else:
|
||||||
|
if not matiere_id:
|
||||||
|
# formulaire avec choix UE de rattachement
|
||||||
|
ue = UniteEns.query.get(tf[2]["ue_id"])
|
||||||
|
if ue is None:
|
||||||
|
raise ValueError("UE invalide")
|
||||||
|
matiere = ue.matieres.first()
|
||||||
|
if matiere:
|
||||||
|
tf[2]["matiere_id"] = matiere.id
|
||||||
|
else:
|
||||||
|
matiere_id = sco_edit_matiere.do_matiere_create(
|
||||||
|
{"ue_id": ue.id, "titre": ue.titre, "numero": 1},
|
||||||
|
)
|
||||||
|
tf[2]["matiere_id"] = matiere_id
|
||||||
|
|
||||||
tf[2]["semestre_id"] = ue.semestre_idx
|
tf[2]["semestre_id"] = ue.semestre_idx
|
||||||
|
|
||||||
_ = do_module_create(tf[2])
|
_ = do_module_create(tf[2])
|
||||||
@ -298,7 +349,7 @@ def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
|||||||
url_for(
|
url_for(
|
||||||
"notes.ue_table",
|
"notes.ue_table",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=ue.formation_id,
|
formation_id=formation.id,
|
||||||
semestre_idx=tf[2]["semestre_id"],
|
semestre_idx=tf[2]["semestre_id"],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -493,6 +544,13 @@ def module_edit(module_id=None):
|
|||||||
soyez prudents !
|
soyez prudents !
|
||||||
</span></div>"""
|
</span></div>"""
|
||||||
)
|
)
|
||||||
|
if is_apc:
|
||||||
|
module_types = scu.ModuleType # tous les types
|
||||||
|
else:
|
||||||
|
# ne propose pas SAE et Ressources, sauf si déjà de ce type...
|
||||||
|
module_types = (
|
||||||
|
set(scu.ModuleType) - {scu.ModuleType.RESSOURCE, scu.ModuleType.SAE}
|
||||||
|
) | {a_module.module_type}
|
||||||
|
|
||||||
descr = [
|
descr = [
|
||||||
(
|
(
|
||||||
@ -514,8 +572,8 @@ def module_edit(module_id=None):
|
|||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"title": "Type",
|
"title": "Type",
|
||||||
"explanation": "",
|
"explanation": "",
|
||||||
"labels": [x.name.capitalize() for x in scu.ModuleType],
|
"labels": [x.name.capitalize() for x in module_types],
|
||||||
"allowed_values": [str(int(x)) for x in scu.ModuleType],
|
"allowed_values": [str(int(x)) for x in module_types],
|
||||||
"enabled": unlocked,
|
"enabled": unlocked,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -998,6 +998,7 @@ def _ue_table_matieres(
|
|||||||
H.append(
|
H.append(
|
||||||
_ue_table_modules(
|
_ue_table_modules(
|
||||||
parcours,
|
parcours,
|
||||||
|
ue,
|
||||||
mat,
|
mat,
|
||||||
modules,
|
modules,
|
||||||
editable,
|
editable,
|
||||||
@ -1031,6 +1032,7 @@ def _ue_table_matieres(
|
|||||||
|
|
||||||
def _ue_table_modules(
|
def _ue_table_modules(
|
||||||
parcours,
|
parcours,
|
||||||
|
ue,
|
||||||
mat,
|
mat,
|
||||||
modules,
|
modules,
|
||||||
editable,
|
editable,
|
||||||
@ -1121,8 +1123,12 @@ def _ue_table_modules(
|
|||||||
tag_cls,
|
tag_cls,
|
||||||
",".join(sco_tag_module.module_tag_list(mod["module_id"])),
|
",".join(sco_tag_module.module_tag_list(mod["module_id"])),
|
||||||
)
|
)
|
||||||
|
if ue["semestre_idx"] is not None and mod["semestre_id"] != ue["semestre_idx"]:
|
||||||
|
warning_semestre = ' <span class="red">incohérent ?</span>'
|
||||||
|
else:
|
||||||
|
warning_semestre = ""
|
||||||
H.append(
|
H.append(
|
||||||
" %s %s" % (parcours.SESSION_NAME, mod["semestre_id"])
|
" %s %s%s" % (parcours.SESSION_NAME, mod["semestre_id"], warning_semestre)
|
||||||
+ " (%s)" % heurescoef
|
+ " (%s)" % heurescoef
|
||||||
+ tag_edit
|
+ tag_edit
|
||||||
)
|
)
|
||||||
|
@ -546,7 +546,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
|||||||
for mod in mods:
|
for mod in mods:
|
||||||
if mod["semestre_id"] == semestre_id and (
|
if mod["semestre_id"] == semestre_id and (
|
||||||
(not edit) # creation => tous modules
|
(not edit) # creation => tous modules
|
||||||
or (not formation.is_apc()) # pas BUT, on peux mixer les semestres
|
or (not formation.is_apc()) # pas BUT, on peut mixer les semestres
|
||||||
or (semestre_id == formsemestre.semestre_id) # module du semestre
|
or (semestre_id == formsemestre.semestre_id) # module du semestre
|
||||||
or (mod["module_id"] in module_ids_set) # module déjà présent
|
or (mod["module_id"] in module_ids_set) # module déjà présent
|
||||||
):
|
):
|
||||||
|
@ -219,7 +219,9 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
page_title=f"{mod_type_name} {Mod['code']} {Mod['titre']}"
|
page_title=f"{mod_type_name} {Mod['code']} {Mod['titre']}"
|
||||||
),
|
),
|
||||||
f"""<h2 class="formsemestre">{mod_type_name}
|
f"""<h2 class="formsemestre">{mod_type_name}
|
||||||
<tt>{Mod['code']}</tt> {Mod['titre']}</h2>
|
<tt>{Mod['code']}</tt> {Mod['titre']}
|
||||||
|
{"dans l'UE " + modimpl.module.ue.acronyme if modimpl.module.module_type == scu.ModuleType.MALUS else ""}
|
||||||
|
</h2>
|
||||||
<div class="moduleimpl_tableaubord moduleimpl_type_{
|
<div class="moduleimpl_tableaubord moduleimpl_type_{
|
||||||
scu.ModuleType(Mod['module_type']).name.lower()}">
|
scu.ModuleType(Mod['module_type']).name.lower()}">
|
||||||
<table>
|
<table>
|
||||||
|
@ -71,14 +71,22 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if editable and matiere_parent %}
|
{% if editable %}
|
||||||
<li><a class="stdlink" href="{{
|
<li><a class="stdlink" href=
|
||||||
|
{% if matiere_parent %}"{{
|
||||||
url_for("notes.module_create",
|
url_for("notes.module_create",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
module_type=module_type|int,
|
module_type=module_type|int,
|
||||||
matiere_id=matiere_parent.id
|
matiere_id=matiere_parent.id
|
||||||
)}}"
|
)}}"
|
||||||
>{{create_element_msg}}</a>
|
{% else %}"{{
|
||||||
|
url_for("notes.module_create",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
module_type=module_type|int,
|
||||||
|
formation_id=formation.id
|
||||||
|
)}}"
|
||||||
|
{% endif %}
|
||||||
|
>{{create_element_msg}}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -191,7 +191,7 @@ def get_etud_dept():
|
|||||||
# le choix a peu d'importance...
|
# le choix a peu d'importance...
|
||||||
last_etud = etuds[-1]
|
last_etud = etuds[-1]
|
||||||
|
|
||||||
return Departement.query.get(last_etud.dept_id).acronym
|
return Departement.query.get_or_404(last_etud.dept_id).acronym
|
||||||
|
|
||||||
|
|
||||||
# Bricolage pour le portail IUTV avec ScoDoc 7: (DEPRECATED: NE PAS UTILISER !)
|
# Bricolage pour le portail IUTV avec ScoDoc 7: (DEPRECATED: NE PAS UTILISER !)
|
||||||
|
@ -149,7 +149,7 @@ def user_info(user_name, format="json"):
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoUsersAdmin)
|
@permission_required(Permission.ScoUsersAdmin)
|
||||||
@scodoc7func
|
@scodoc7func
|
||||||
def create_user_form(user_name=None, edit=0, all_roles=1):
|
def create_user_form(user_name=None, edit=0, all_roles=False):
|
||||||
"form. création ou édition utilisateur"
|
"form. création ou édition utilisateur"
|
||||||
if user_name is not None: # scodoc7func converti en int !
|
if user_name is not None: # scodoc7func converti en int !
|
||||||
user_name = str(user_name)
|
user_name = str(user_name)
|
||||||
@ -218,9 +218,11 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
}
|
}
|
||||||
if current_user.is_administrator():
|
if current_user.is_administrator():
|
||||||
editable_roles_set |= {
|
editable_roles_set |= {
|
||||||
(Role.get_named_role(r), "")
|
(Role.get_named_role(r), None)
|
||||||
for r in sco_roles_default.ROLES_ATTRIBUABLES_SCODOC
|
for r in sco_roles_default.ROLES_ATTRIBUABLES_SCODOC
|
||||||
}
|
}
|
||||||
|
# Un super-admin peut nommer d'autres super-admin:
|
||||||
|
editable_roles_set |= {(Role.get_named_role("SuperAdmin"), None)}
|
||||||
#
|
#
|
||||||
if not edit:
|
if not edit:
|
||||||
submitlabel = "Créer utilisateur"
|
submitlabel = "Créer utilisateur"
|
||||||
@ -251,16 +253,23 @@ def create_user_form(user_name=None, edit=0, all_roles=1):
|
|||||||
orig_roles_strings = {r.name + "_" + (dept or "") for (r, dept) in orig_roles}
|
orig_roles_strings = {r.name + "_" + (dept or "") for (r, dept) in orig_roles}
|
||||||
# add existing user roles
|
# add existing user roles
|
||||||
displayed_roles = list(editable_roles_set.union(orig_roles))
|
displayed_roles = list(editable_roles_set.union(orig_roles))
|
||||||
displayed_roles.sort(key=lambda x: (x[1] or "", x[0].name or ""))
|
displayed_roles.sort(
|
||||||
|
key=lambda x: (
|
||||||
|
x[1] or "",
|
||||||
|
(x[0].name or "") if x[0].name != "SuperAdmin" else "A",
|
||||||
|
)
|
||||||
|
)
|
||||||
displayed_roles_strings = [
|
displayed_roles_strings = [
|
||||||
r.name + "_" + (dept or "") for (r, dept) in displayed_roles
|
r.name + "_" + (dept or "") for (r, dept) in displayed_roles
|
||||||
]
|
]
|
||||||
displayed_roles_labels = [f"{dept}: {r.name}" for (r, dept) in displayed_roles]
|
displayed_roles_labels = [
|
||||||
|
f"{dept or '<em>tout dépt.</em>'}: {r.name}" for (r, dept) in displayed_roles
|
||||||
|
]
|
||||||
disabled_roles = {} # pour désactiver les roles que l'on ne peut pas éditer
|
disabled_roles = {} # pour désactiver les roles que l'on ne peut pas éditer
|
||||||
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