Edition modules: interdit changement de semestre si utilisés. + doc + bug poids vers UE d'autres semestres

This commit is contained in:
Emmanuel Viennet 2022-01-20 13:00:25 +01:00
parent e5fb9f4365
commit fa5fcc8f57
9 changed files with 102 additions and 17 deletions

View File

@ -40,6 +40,7 @@ from app import log
from app import models from app import models
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_exceptions import ScoValueError
def df_load_evaluations_poids( def df_load_evaluations_poids(
@ -60,7 +61,10 @@ def df_load_evaluations_poids(
for eval_poids in EvaluationUEPoids.query.join( for eval_poids in EvaluationUEPoids.query.join(
EvaluationUEPoids.evaluation EvaluationUEPoids.evaluation
).filter_by(moduleimpl_id=moduleimpl_id): ).filter_by(moduleimpl_id=moduleimpl_id):
df[eval_poids.ue_id][eval_poids.evaluation_id] = eval_poids.poids try:
df[eval_poids.ue_id][eval_poids.evaluation_id] = eval_poids.poids
except KeyError as exc:
pass # poids vers des UE qui n'existent plus ou sont dans un autre semestre...
if default_poids is not None: if default_poids is not None:
df.fillna(value=default_poids, inplace=True) df.fillna(value=default_poids, inplace=True)
return df, ues return df, ues

View File

@ -103,7 +103,16 @@ class Evaluation(db.Model):
Note: si les poids ne sont pas initialisés (poids par défaut), Note: si les poids ne sont pas initialisés (poids par défaut),
ils ne sont pas affichés. ils ne sont pas affichés.
""" """
return ", ".join([f"{p.ue.acronyme}: {p.poids}" for p in self.ue_poids]) # restreint aux UE du semestre dans lequel est cette évaluation
# au cas où le module ait changé de semestre et qu'il reste des poids
evaluation_semestre_idx = self.moduleimpl.module.semestre_id
return ", ".join(
[
f"{p.ue.acronyme}: {p.poids}"
for p in self.ue_poids
if evaluation_semestre_idx == p.ue.semestre_idx
]
)
class EvaluationUEPoids(db.Model): class EvaluationUEPoids(db.Model):

View File

@ -224,7 +224,7 @@ class FormSemestre(db.Model):
self.date_fin.year})""" self.date_fin.year})"""
def titre_num(self) -> str: def titre_num(self) -> str:
"""Le titre est le semestre, ex ""DUT Informatique semestre 2"" """ """Le titre et le semestre, ex ""DUT Informatique semestre 2"" """
if self.semestre_id == sco_codes_parcours.NO_SEMESTRE_ID: if self.semestre_id == sco_codes_parcours.NO_SEMESTRE_ID:
return self.titre return self.titre
return f"{self.titre} {self.formation.get_parcours().SESSION_NAME} {self.semestre_id}" return f"{self.titre} {self.formation.get_parcours().SESSION_NAME} {self.semestre_id}"

View File

@ -37,6 +37,7 @@ from app import log
from app import models from app import models
from app.models import APO_CODE_STR_LEN from app.models import APO_CODE_STR_LEN
from app.models import Formation, Matiere, Module, UniteEns from app.models import Formation, Matiere, Module, UniteEns
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
@ -473,16 +474,31 @@ def module_edit(module_id=None):
formation_id = module["formation_id"] formation_id = module["formation_id"]
formation = sco_formations.formation_list(args={"formation_id": formation_id})[0] formation = sco_formations.formation_list(args={"formation_id": formation_id})[0]
parcours = sco_codes_parcours.get_parcours_from_code(formation["type_parcours"]) parcours = sco_codes_parcours.get_parcours_from_code(formation["type_parcours"])
is_apc = parcours.APC_SAE is_apc = parcours.APC_SAE # BUT
ues_matieres = ndb.SimpleDictFetch( in_use = len(a_module.modimpls.all()) > 0 # il y a des modimpls
"""SELECT ue.acronyme, mat.*, mat.id AS matiere_id if in_use:
FROM notes_matieres mat, notes_ue ue # matières du même semestre seulement
WHERE mat.ue_id = ue.id ues_matieres = ndb.SimpleDictFetch(
AND ue.formation_id = %(formation_id)s """SELECT ue.acronyme, mat.*, mat.id AS matiere_id
ORDER BY ue.numero, mat.numero FROM notes_matieres mat, notes_ue ue
""", WHERE mat.ue_id = ue.id
{"formation_id": formation_id}, AND ue.formation_id = %(formation_id)s
) AND ue.semestre_idx = %(semestre_idx)s
ORDER BY ue.numero, mat.numero
""",
{"formation_id": formation_id, "semestre_idx": a_module.ue.semestre_idx},
)
else:
# matières de la formation
ues_matieres = ndb.SimpleDictFetch(
"""SELECT ue.acronyme, mat.*, mat.id AS matiere_id
FROM notes_matieres mat, notes_ue ue
WHERE mat.ue_id = ue.id
AND ue.formation_id = %(formation_id)s
ORDER BY ue.numero, mat.numero
""",
{"formation_id": formation_id},
)
mat_names = ["%s / %s" % (x["acronyme"], x["titre"]) for x in ues_matieres] mat_names = ["%s / %s" % (x["acronyme"], x["titre"]) for x in ues_matieres]
ue_mat_ids = ["%s!%s" % (x["ue_id"], x["matiere_id"]) for x in ues_matieres] ue_mat_ids = ["%s!%s" % (x["ue_id"], x["matiere_id"]) for x in ues_matieres]
module["ue_matiere_id"] = "%s!%s" % (module["ue_id"], module["matiere_id"]) module["ue_matiere_id"] = "%s!%s" % (module["ue_id"], module["matiere_id"])
@ -501,12 +517,25 @@ def module_edit(module_id=None):
), ),
"""<h2>Modification du module %(titre)s""" % module, """<h2>Modification du module %(titre)s""" % module,
""" (formation %(acronyme)s, version %(version)s)</h2>""" % formation, """ (formation %(acronyme)s, version %(version)s)</h2>""" % formation,
render_template("scodoc/help/modules.html", is_apc=is_apc), render_template(
"scodoc/help/modules.html",
is_apc=is_apc,
formsemestres=FormSemestre.query.filter(
ModuleImpl.formsemestre_id == FormSemestre.id,
ModuleImpl.module_id == module_id,
).all(),
),
] ]
if not unlocked: if not unlocked:
H.append( H.append(
"""<div class="ue_warning"><span>Formation verrouillée, seuls certains éléments peuvent être modifiés</span></div>""" """<div class="ue_warning"><span>Formation verrouillée, seuls certains éléments peuvent être modifiés</span></div>"""
) )
if in_use:
H.append(
"""<div class="ue_warning"><span>Module déjà utilisé dans des semestres,
soyez prudents !
</span></div>"""
)
descr = [ descr = [
( (
@ -679,6 +708,13 @@ def module_edit(module_id=None):
else: else:
# l'UE peut changer # l'UE peut changer
tf[2]["ue_id"], tf[2]["matiere_id"] = tf[2]["ue_matiere_id"].split("!") tf[2]["ue_id"], tf[2]["matiere_id"] = tf[2]["ue_matiere_id"].split("!")
old_ue_id = a_module.ue.id
new_ue_id = int(tf[2]["ue_id"])
if (old_ue_id != new_ue_id) and in_use:
# pas changer de semestre un module utilisé !
raise ScoValueError(
"Module utilisé: il ne peut pas être changé de semestre !"
)
# En APC, force le semestre égal à celui de l'UE # En APC, force le semestre égal à celui de l'UE
if is_apc: if is_apc:
selected_ue = UniteEns.query.get(tf[2]["ue_id"]) selected_ue = UniteEns.query.get(tf[2]["ue_id"])

View File

@ -143,6 +143,7 @@ def evaluation_create_form(
if vals.get("tf_submitted", False) and "visibulletinlist" not in vals: if vals.get("tf_submitted", False) and "visibulletinlist" not in vals:
vals["visibulletinlist"] = [] vals["visibulletinlist"] = []
# #
ue_coef_dict = {}
if is_apc: # BUT: poids vers les UE if is_apc: # BUT: poids vers les UE
ue_coef_dict = ModuleImpl.query.get(moduleimpl_id).module.get_ue_coef_dict() ue_coef_dict = ModuleImpl.query.get(moduleimpl_id).module.get_ue_coef_dict()
for ue in sem_ues: for ue in sem_ues:
@ -290,7 +291,10 @@ def evaluation_create_form(
"title": f"Poids {ue.acronyme}", "title": f"Poids {ue.acronyme}",
"size": 2, "size": 2,
"type": "float", "type": "float",
"explanation": f"{ue.titre}", "explanation": f"""
<span class="eval_coef_ue" title="coef. du module dans cette UE">{ue_coef_dict.get(ue.id, 0.)}</span>
<span class="eval_coef_ue_titre">{ue.titre}</span>
""",
"allow_null": False, "allow_null": False,
}, },
), ),

View File

@ -397,7 +397,9 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
eval_index = len(mod_evals) - 1 eval_index = len(mod_evals) - 1
first_eval = True first_eval = True
for eval in mod_evals: for eval in mod_evals:
evaluation = Evaluation.query.get(eval["evaluation_id"]) # TODO unifier evaluation: Evaluation = Evaluation.query.get(
eval["evaluation_id"]
) # TODO unifier
etat = sco_evaluations.do_evaluation_etat( etat = sco_evaluations.do_evaluation_etat(
eval["evaluation_id"], eval["evaluation_id"],
partition_id=partition_id, partition_id=partition_id,

View File

@ -1491,6 +1491,16 @@ table.moduleimpl_evaluations td.eval_poids {
color:rgb(0, 0, 255); color:rgb(0, 0, 255);
} }
span.eval_coef_ue {
color:rgb(6, 73, 6);
font-style: normal;
font-size: 80%;
margin-right: 2em;
}
span.eval_coef_ue_titre {
}
/* Formulaire edition des partitions */ /* Formulaire edition des partitions */
form#editpart table { form#editpart table {
border: 1px solid gray; border: 1px solid gray;

View File

@ -24,4 +24,24 @@
<a href="https://scodoc.org/BUT" target="_blank">la documentation</a>. <a href="https://scodoc.org/BUT" target="_blank">la documentation</a>.
</p> </p>
{%endif%} {%endif%}
{% if formsemestres %}
<p class="help">
Ce module est utilisé dans des semestres déjà mis en place, il faut prêter attention
aux conséquences des changements effectués ici: par exemple les coefficients vont modifier
les notes moyennes calculées. Les modules déjà utilisés ne peuvent pas être changés de semestre, ni détruits.
Si vous souhaitez faire cela, allez d'abord modifier les semestres concernés pour déselectionner le module.
</p>
<h4>Semestres utilisant ce module:</h4>
<ul>
{%for formsemestre in formsemestres %}
<li><a class="stdlink" href="{{
url_for('notes.formsemestre_status',
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id)
}}">{{formsemestre.titre_mois()}}</a>
</li>
{% endfor %}
</ul>
{%endif%}
</div> </div>

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.1.28" SCOVERSION = "9.1.29"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"