ScoDoc/app/scodoc/sco_evaluation_recap.py

165 lines
5.9 KiB
Python

##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""Tableau recap. de toutes les évaluations d'un semestre
avec leur état.
Sur une idée de Pascal Bouron, de Lyon.
"""
import time
from flask import g, render_template, url_for
from app import db
from app.models import Evaluation, FormSemestre
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.comp.moy_mod import ModuleImplResults
from app.scodoc import html_sco_header
import app.scodoc.sco_utils as scu
def evaluations_recap(formsemestre_id: int) -> str:
"""Page récap. de toutes les évaluations d'un semestre"""
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
rows, titles = evaluations_recap_table(formsemestre)
column_ids = titles.keys()
filename = scu.sanitize_filename(
f"""evaluations-{formsemestre.titre_num()}-{time.strftime("%Y-%m-%d")}"""
)
if not rows:
return '<div class="evaluations_recap"><div class="message">aucune évaluation</div></div>'
H = [
f"""<h2>Évaluations du semestre</h2>
<div>
<a class="stdlink" href="{url_for(
'notes.formsemestre_check_absences_html',
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id,
)}">Vérifier les absences aux évaluations</a>
</div>
<div class="evaluations_recap"><table class="evaluations_recap compact {
'apc' if formsemestre.formation.is_apc() else 'classic'
}"
data-filename="{filename}">""",
]
# header
H.append(
f"""
<thead>
{scu.gen_row(column_ids, titles, "th", with_col_classes=True)}
</thead>
"""
)
# body
H.append("<tbody>")
for row in rows:
H.append(f"{scu.gen_row(column_ids, row, with_col_classes=True)}\n")
H.append(
"""</tbody></table></div>
<div class="help">Les étudiants démissionnaires ou défaillants ne sont
pas pris en compte dans cette table.</div>
"""
)
H.append(
html_sco_header.sco_footer(),
)
return render_template(
"sco_page.j2",
title="Évaluations du semestre",
javascripts=["js/evaluations_recap.js"],
content="".join(H),
)
def evaluations_recap_table(formsemestre: FormSemestre) -> list[dict]:
"""Tableau recap. de toutes les évaluations d'un semestre
Colonnes:
- code (UE ou module),
- titre
- type évaluation
- complete
- inscrits (non dem. ni def.)
- nb notes manquantes
- nb ATT
- nb ABS
- nb EXC
"""
rows = []
titles = {
"type": "",
"code": "Module",
"titre": "",
"date": "Date",
"type_evaluation": "Type",
"complete": "Comptée",
"inscrits": "Inscrits",
"manquantes": "Manquantes", # notes eval non entrées
"nb_abs": "ABS",
"nb_att": "ATT",
"nb_exc": "EXC",
}
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
line_idx = 0
for modimpl in nt.formsemestre.modimpls_sorted:
modimpl_results: ModuleImplResults = nt.modimpls_results[modimpl.id]
row = {
"type": modimpl.module.type_abbrv().upper(),
"_type_order": f"{line_idx:04d}",
"code": modimpl.module.code,
"_code_target": url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=modimpl.id,
),
"titre": modimpl.module.titre,
"_titre_class": "titre",
"inscrits": modimpl_results.nb_inscrits_module,
"date": "-",
"_date_order": "",
"_tr_class": f"module {modimpl.module.type_abbrv()}",
}
rows.append(row)
line_idx += 1
for evaluation_id in modimpl_results.evals_notes:
e: Evaluation = db.session.get(Evaluation, evaluation_id)
if e is None:
continue # ignore errors (rare race conditions?)
eval_etat = modimpl_results.evaluations_etat[evaluation_id]
row = {
"type": "",
"_type_order": f"{line_idx:04d}",
"titre": e.description or "sans titre",
"_titre_target": url_for(
"notes.evaluation_listenotes",
scodoc_dept=g.scodoc_dept,
evaluation_id=evaluation_id,
),
"_titre_target_attrs": 'class="discretelink"',
"date": e.date_debut.strftime(scu.DATE_FMT) if e.date_debut else "",
"_date_order": e.date_debut.isoformat() if e.date_debut else "",
"type_evaluation": e.type_abbrev(),
"complete": "oui" if eval_etat.is_complete else "non",
"_complete_target": "#",
"_complete_target_attrs": (
'class="bull_link" title="prise en compte dans les moyennes"'
if eval_etat.is_complete
else 'class="bull_link incomplete" title="il manque des notes"'
),
"manquantes": len(modimpl_results.evals_etudids_sans_note[e.id]),
"inscrits": modimpl_results.nb_inscrits_module,
"nb_abs": sum(modimpl_results.evals_notes[e.id] == scu.NOTES_ABSENCE),
"nb_att": eval_etat.nb_attente,
"nb_exc": sum(
modimpl_results.evals_notes[e.id] == scu.NOTES_NEUTRALISE
),
"_tr_class": "evaluation"
+ (" incomplete" if not eval_etat.is_complete else ""),
}
rows.append(row)
line_idx += 1
return rows, titles