forked from ScoDoc/ScoDoc
162 lines
5.8 KiB
Python
162 lines
5.8 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
|
|
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>
|
|
"""
|
|
)
|
|
|
|
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
|