Tableau bord module: avertissement si poids d'évaluation nuls. Début de #411.

This commit is contained in:
Emmanuel Viennet 2022-10-01 18:55:32 +02:00
parent 268b75d441
commit 06cbd65365
3 changed files with 348 additions and 283 deletions

View File

@ -44,7 +44,9 @@ class Evaluation(db.Model):
ues = db.relationship("UniteEns", secondary="evaluation_ue_poids", viewonly=True)
def __repr__(self):
return f"""<Evaluation {self.id} {self.jour.isoformat() if self.jour else ''} "{self.description[:16] if self.description else ''}">"""
return f"""<Evaluation {self.id} {
self.jour.isoformat() if self.jour else ''} "{
self.description[:16] if self.description else ''}">"""
def to_dict(self) -> dict:
"Représentation dict, pour json"
@ -74,6 +76,17 @@ class Evaluation(db.Model):
if k != "_sa_instance_state" and k != "id" and k in data:
setattr(self, k, data[k])
def descr_heure(self) -> str:
"Description de la plage horaire pour affichages"
if self.heure_debut and (
not self.heure_fin or self.heure_fin == self.heure_debut
):
return f"""à {self.heure_debut.strftime("%H:%M")}"""
elif self.heure_debut and self.heure_fin:
return f"""de {self.heure_debut.strftime("%H:%M")} à {self.heure_fin.strftime("%H:%M")}"""
else:
return ""
def clone(self, not_copying=()):
"""Clone, not copying the given attrs
Attention: la copie n'a pas d'id avant le prochain commit
@ -164,7 +177,7 @@ class EvaluationUEPoids(db.Model):
# Fonction héritée de ScoDoc7 à refactorer
def evaluation_enrich_dict(e):
def evaluation_enrich_dict(e: dict):
"""add or convert some fields in an evaluation dict"""
# For ScoDoc7 compat
heure_debut_dt = e["heure_debut"] or datetime.time(

View File

@ -37,6 +37,7 @@ from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import ModuleImpl
from app.models.evaluations import Evaluation
from app.models.ues import UniteEns
import app.scodoc.sco_utils as scu
from app.scodoc.sco_exceptions import ScoInvalidIdType
from app.scodoc.sco_cursus_dut import formsemestre_has_decisions
@ -425,16 +426,93 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
H.append("""<table class="moduleimpl_evaluations">""")
eval_index = len(mod_evals) - 1
first_eval = True
for eval in mod_evals:
evaluation: Evaluation = Evaluation.query.get(
eval["evaluation_id"]
) # TODO unifier
for eval_dict in mod_evals:
H.append(
_ligne_evaluation(
modimpl,
eval_dict,
first_eval=first_eval,
partition_id=partition_id,
arrow_down=arrow_down,
arrow_none=arrow_none,
arrow_up=arrow_up,
can_edit_evals=can_edit_evals,
can_edit_notes=can_edit_notes,
eval_index=eval_index,
has_expression=has_expression,
nb_evals=len(mod_evals),
)
)
eval_index -= 1
first_eval = False
#
H.append("""<tr><td colspan="8">""")
if sem_locked:
H.append(f"""{scu.icontag("lock32_img")} semestre verrouillé""")
elif can_edit_evals:
H.append(top_table_links)
H.append(
f"""</td></tr>
</table>
</div>
<!-- LEGENDE -->
<hr>
<h4>Légende</h4>
<ul>
<li>{scu.icontag("edit_img")} : modifie description de l'évaluation
(date, heure, coefficient, ...)
</li>
<li>{scu.icontag("notes_img")} : saisie des notes</li>
<li>{scu.icontag("delete_img")} : indique qu'il n'y a aucune note
entrée (cliquer pour supprimer cette évaluation)
</li>
<li>{scu.icontag("status_orange_img")} : indique qu'il manque
quelques notes dans cette évaluation
</li>
<li>{scu.icontag("status_green_img")} : toutes les notes sont
entrées (cliquer pour les afficher)
</li>
<li>{scu.icontag("status_visible_img")} : indique que cette évaluation
sera mentionnée dans les bulletins au format "intermédiaire"
</li>
</ul>
<p>Rappel : seules les notes des évaluations complètement saisies
(affichées en vert) apparaissent dans les bulletins.
</p>
"""
)
H.append(html_sco_header.sco_footer())
return "".join(H)
def _ligne_evaluation(
modimpl: ModuleImpl,
eval_dict: dict,
first_eval: bool = True,
partition_id=None,
arrow_down=None,
arrow_none=None,
arrow_up=None,
can_edit_evals: bool = False,
can_edit_notes: bool = False,
eval_index: int = 0,
has_expression: bool = False,
nb_evals: int = 0,
) -> str:
"""Ligne <tr> décrivant une évaluation dans le tableau de bord moduleimpl."""
H = []
# TODO unifier pour ne plus utiliser eval_dict
evaluation: Evaluation = Evaluation.query.get(eval_dict["evaluation_id"])
etat = sco_evaluations.do_evaluation_etat(
eval["evaluation_id"],
evaluation.id,
partition_id=partition_id,
select_first_partition=True,
)
if eval["evaluation_type"] in (
if evaluation.evaluation_type in (
scu.EVALUATION_RATTRAPAGE,
scu.EVALUATION_SESSION2,
):
@ -445,63 +523,79 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
if not first_eval:
H.append("""<tr><td colspan="8">&nbsp;</td></tr>""")
tr_class_1 += " mievr_spaced"
H.append("""<tr class="%s"><td class="mievr_tit" colspan="8">""" % tr_class_1)
if eval["jour"]:
H.append("""Le %(jour)s%(descrheure)s""" % eval)
H.append(f"""<tr class="{tr_class_1}"><td class="mievr_tit" colspan="8">""")
if evaluation.jour:
H.append(
f"""Le {evaluation.jour.strftime("%d/%m/%Y")} {evaluation.descr_heure()}"""
)
else:
H.append(
"""<a href="evaluation_edit?evaluation_id=%(evaluation_id)s" class="mievr_evalnodate">Evaluation sans date</a>"""
% eval
f"""<a href="{url_for("notes.evaluation_edit",
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}" class="mievr_evalnodate">Évaluation sans date</a>"""
)
H.append("&nbsp;&nbsp;&nbsp; <em>%(description)s</em>" % eval)
if eval["evaluation_type"] == scu.EVALUATION_RATTRAPAGE:
H.append(f"&nbsp;&nbsp;&nbsp; <em>{evaluation.description or ''}</em>")
if evaluation.evaluation_type == scu.EVALUATION_RATTRAPAGE:
H.append(
"""<span class="mievr_rattr" title="remplace si meilleure note">rattrapage</span>"""
)
elif eval["evaluation_type"] == scu.EVALUATION_SESSION2:
elif evaluation.evaluation_type == scu.EVALUATION_SESSION2:
H.append(
"""<span class="mievr_rattr" title="remplace autres notes">session 2</span>"""
)
# Avertissement si coefs/poids nuls
if (
evaluation.coefficient * sum(evaluation.get_ue_poids_dict().values())
< scu.NOTES_PRECISION
):
H.append("""<span class="eval_warning_coef">coef. nul !</span>""")
#
if etat["last_modif"]:
H.append(
"""<span class="mievr_lastmodif">(dernière modif le %s)</span>"""
% etat["last_modif"].strftime("%d/%m/%Y à %Hh%M")
f"""<span class="mievr_lastmodif">(dernière modif le {
etat["last_modif"].strftime("%d/%m/%Y à %Hh%M")})</span>"""
)
#
H.append('<span class="evalindex_cont">')
if has_expression or True:
H.append(
"""<span class="evalindex" title="Indice dans les vecteurs (formules)">%2d</span>"""
% eval_index
f"""<span class="evalindex" title="Indice dans les vecteurs (formules)">{
eval_index:2}</span>"""
)
# Fleches:
H.append('<span class="eval_arrows_chld">')
if eval_index != (len(mod_evals) - 1) and can_edit_evals:
if eval_index != (nb_evals - 1) and can_edit_evals:
H.append(
'<a href="module_evaluation_move?evaluation_id=%s&after=0" class="aud">%s</a>'
% (eval["evaluation_id"], arrow_up)
% (evaluation.id, arrow_up)
)
else:
H.append(arrow_none)
if (eval_index > 0) and can_edit_evals:
H.append(
'<a href="module_evaluation_move?evaluation_id=%s&after=1" class="aud">%s</a>'
% (eval["evaluation_id"], arrow_down)
% (evaluation.id, arrow_down)
)
else:
H.append(arrow_none)
H.append("</span></span>")
eval_index -= 1
H.append("""</td></tr>""")
H.append(
"""<tr class="%s"><th class="moduleimpl_evaluations" colspan="2">&nbsp;</th><th class="moduleimpl_evaluations">Durée</th><th class="moduleimpl_evaluations">Coef.</th><th class="moduleimpl_evaluations">Notes</th><th class="moduleimpl_evaluations">Abs</th><th class="moduleimpl_evaluations">N</th><th class="moduleimpl_evaluations">Moyenne """
% tr_class
f"""</span></span></td>
</tr>
<tr class="{tr_class}">
<th class="moduleimpl_evaluations" colspan="2">&nbsp;</th>
<th class="moduleimpl_evaluations">Durée</th>
<th class="moduleimpl_evaluations">Coef.</th>
<th class="moduleimpl_evaluations">Notes</th>
<th class="moduleimpl_evaluations">Abs</th>
<th class="moduleimpl_evaluations">N</th>
<th class="moduleimpl_evaluations">Moyenne """
)
if etat["evalcomplete"]:
etat_txt = """(prise en compte)"""
etat_descr = "notes utilisées dans les moyennes"
elif eval["publish_incomplete"]:
elif eval_dict["publish_incomplete"]:
etat_txt = """(prise en compte <b>immédiate</b>)"""
etat_descr = (
"il manque des notes, mais la prise en compte immédiate a été demandée"
@ -512,71 +606,62 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
else:
etat_txt = ""
if can_edit_evals and etat_txt:
etat_txt = (
'<a href="evaluation_edit?evaluation_id=%s" title="%s">%s</a>'
% (eval["evaluation_id"], etat_descr, etat_txt)
)
H.append(etat_txt)
H.append("""</th></tr>""")
etat_txt = f"""<a href="{ url_for("notes.evaluation_edit",
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}" title="{etat_descr}">{etat_txt}</a>"""
H.append("""<tr class="%s"><td class="mievr">""" % tr_class)
H.append(
f"""{etat_txt}</th>
</tr>
<tr class="{tr_class}"><td class="mievr">"""
)
if can_edit_evals:
H.append(
"""<a class="smallbutton" href="evaluation_edit?evaluation_id=%s">%s</a>"""
% (
eval["evaluation_id"],
scu.icontag(
"edit_img", alt="modifier", title="Modifier informations"
),
)
f"""<a class="smallbutton" href="{url_for('notes.evaluation_edit',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">{scu.icontag("edit_img", alt="modifier", title="Modifier informations")}</a>"""
)
if can_edit_notes:
H.append(
"""<a class="smallbutton" href="saisie_notes?evaluation_id=%s">%s</a>"""
% (
eval["evaluation_id"],
scu.icontag(
"notes_img", alt="saisie notes", title="Saisie des notes"
),
)
f"""<a class="smallbutton" href="{url_for('notes.saisie_notes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">{scu.icontag("notes_img", alt="saisie notes", title="Saisie des notes")}</a>"""
)
if etat["nb_notes"] == 0:
if can_edit_evals:
H.append(
"""<a class="smallbutton" href="evaluation_delete?evaluation_id=%(evaluation_id)s">"""
% eval
f"""<a class="smallbutton" href="{url_for('notes.evaluation_delete',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">"""
)
H.append(scu.icontag("delete_img", alt="supprimer", title="Supprimer"))
if can_edit_evals:
H.append("""</a>""")
elif etat["evalcomplete"]:
H.append(
"""<a class="smallbutton" href="evaluation_listenotes?evaluation_id=%s">%s</a>"""
% (eval["evaluation_id"], scu.icontag("status_green_img", title="ok"))
f"""<a class="smallbutton" href="{url_for('notes.evaluation_listenotes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">{scu.icontag("status_green_img", title="ok")}</a>"""
)
else:
if etat["evalattente"]:
H.append(
"""<a class="smallbutton" href="evaluation_listenotes?evaluation_id=%s">%s</a>"""
% (
eval["evaluation_id"],
scu.icontag(
f"""<a class="smallbutton" href="{url_for('notes.evaluation_listenotes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">{scu.icontag(
"status_greenorange_img",
file_format="gif",
title="notes en attente",
),
)
)}</a>"""
)
else:
H.append(
"""<a class="smallbutton" href="evaluation_listenotes?evaluation_id=%s">%s</a>"""
% (
eval["evaluation_id"],
scu.icontag("status_orange_img", title="il manque des notes"),
)
f"""<a class="smallbutton" href="{url_for('notes.evaluation_listenotes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">{scu.icontag("status_orange_img", title="il manque des notes")}</a>"""
)
#
if eval["visibulletin"]:
if eval_dict["visibulletin"]:
H.append(
scu.icontag(
"status_visible_img", title="visible dans bulletins intermédiaires"
@ -588,16 +673,15 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
if can_edit_notes:
H.append(
moduleimpl_evaluation_menu(
eval["evaluation_id"],
evaluation.id,
nbnotes=etat["nb_notes"],
)
)
H.append("</td>")
#
H.append(
"""
"""</td>
<td class="mievr_dur">%s</td><td class="rightcell mievr_coef">%s</td>"""
% (eval["duree"], "%g" % eval["coefficient"])
% (eval_dict["duree"], "%g" % eval_dict["coefficient"])
)
H.append(
"""<td class="rightcell mievr_nbnotes">%(nb_notes)s / %(nb_inscrits)s</td>
@ -607,20 +691,23 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
% etat
)
if etat["moy"]:
H.append("<b>%s / %g</b>" % (etat["moy"], eval["note_max"]))
H.append("<b>%s / %g</b>" % (etat["moy"], eval_dict["note_max"]))
H.append(
"""&nbsp; (<a href="evaluation_listenotes?evaluation_id=%s">afficher</a>)"""
% (eval["evaluation_id"],)
f"""&nbsp; (<a href="{url_for('notes.evaluation_listenotes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">afficher</a>)"""
)
else:
H.append(
"""<a class="redlink" href="saisie_notes?evaluation_id=%s">saisir notes</a>"""
% (eval["evaluation_id"])
f"""<a class="redlink" href="{url_for('notes.saisie_notes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">saisir notes</a>
"""
)
H.append("""</td></tr>""")
#
if etat["nb_notes"] == 0:
H.append("""<tr class="%s"><td></td>""" % tr_class)
H.append(f"""<tr class="{tr_class}"><td></td>""")
if modimpl.module.is_apc():
H.append(
f"""<td colspan="7" class="eval_poids">{
@ -633,8 +720,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
gr_moyennes = etat["gr_moyennes"]
first_group = True
for gr_moyenne in gr_moyennes:
H.append("""<tr class="%s">""" % tr_class)
H.append("""<td>&nbsp;</td>""")
H.append(f"""<tr class="{tr_class}"><td>&nbsp;</td>""")
if first_group and modimpl.module.is_apc():
H.append(
f"""<td class="eval_poids" colspan="3">{
@ -646,32 +732,29 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
if gr_moyenne["group_name"] is None:
name = "Tous" # tous
else:
name = "Groupe %s" % gr_moyenne["group_name"]
H.append(
"""<td colspan="3" class="mievr_grtit">%s &nbsp;</td><td>""" % name
)
name = f"""Groupe {gr_moyenne["group_name"]}"""
H.append(f"""<td colspan="3" class="mievr_grtit">{name} &nbsp;</td><td>""")
if gr_moyenne["gr_nb_notes"] > 0:
H.append("%(gr_moy)s" % gr_moyenne)
H.append(
"""&nbsp; (<a href="evaluation_listenotes?tf_submitted=1&evaluation_id=%s&group_ids%%3Alist=%s">%s notes</a>"""
% (
eval["evaluation_id"],
gr_moyenne["group_id"],
gr_moyenne["gr_nb_notes"],
)
f"""{gr_moyenne["gr_moy"]}&nbsp; (<a href="{
url_for('notes.evaluation_listenotes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id,
tf_submitted=1, **{'group_ids:list': gr_moyenne["group_id"]})
}">{gr_moyenne["gr_nb_notes"]} notes</a>"""
)
if gr_moyenne["gr_nb_att"] > 0:
H.append(
""", <span class="redboldtext">%s en attente</span>"""
% gr_moyenne["gr_nb_att"]
f""", <span class="redboldtext">{gr_moyenne["gr_nb_att"]} en attente</span>"""
)
H.append(""")""")
if gr_moyenne["group_id"] in etat["gr_incomplets"]:
H.append("""[<font color="red">""")
if can_edit_notes:
H.append(
"""<a class="redlink" href="saisie_notes?evaluation_id=%s&group_ids:list=%s">incomplet</a></font>]"""
% (eval["evaluation_id"], gr_moyenne["group_id"])
f"""<a class="redlink" href="{url_for('notes.saisie_notes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id,
**{'group_ids:list': gr_moyenne["group_id"]})
}">incomplet</a></font>]"""
)
else:
H.append("""incomplet</font>]""")
@ -679,53 +762,14 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
H.append("""<span class="redboldtext">&nbsp; """)
if can_edit_notes:
H.append(
"""<a class="redlink" href="saisie_notes?evaluation_id=%s&group_ids:list=%s">"""
% (eval["evaluation_id"], gr_moyenne["group_id"])
f"""<a class="redlink" href="{url_for('notes.saisie_notes',
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id,
**{'group_ids:list': gr_moyenne["group_id"]})
}"""
)
H.append("pas de notes")
if can_edit_notes:
H.append("""</a>""")
H.append("</span>")
H.append("""</td></tr>""")
first_eval = False
#
H.append("""<tr><td colspan="8">""")
if sem_locked:
H.append(f"""{scu.icontag("lock32_img")} semestre verrouillé""")
elif can_edit_evals:
H.append(top_table_links)
H.append(
"""</td></tr>
</table>
</div>
<!-- LEGENDE -->
<hr>
<h4>Légende</h4>
<ul>
<li>%s : modifie description de l'évaluation (date, heure, coefficient, ...)</li>
<li>%s : saisie des notes</li>
<li>%s : indique qu'il n'y a aucune note entrée (cliquer pour supprimer cette évaluation)</li>
<li>%s : indique qu'il manque quelques notes dans cette évaluation</li>
<li>%s : toutes les notes sont entrées (cliquer pour les afficher)</li>
<li>%s : indique que cette évaluation sera mentionnée dans les bulletins au format "intermédiaire"
</ul>
<p>Rappel : seules les notes des évaluations complètement saisies (affichées en vert) apparaissent dans les bulletins.
</p>
"""
% (
scu.icontag("edit_img"),
scu.icontag("notes_img"),
scu.icontag("delete_img"),
scu.icontag("status_orange_img"),
scu.icontag("status_green_img"),
scu.icontag("status_visible_img"),
)
)
H.append(html_sco_header.sco_footer())
return "".join(H)
return "\n".join(H)

View File

@ -1862,6 +1862,14 @@ a.mievr_evalnodate:hover {
text-decoration: underline;
}
span.eval_warning_coef {
color: red;
margin: 2px;
padding-left: 3px;
padding-right: 3px;
background-color: rgb(255, 225, 0);
}
span.evalindex_cont {
float: right;
}