diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py
index 0d09b3ba1b73fae416ed5fe3d047a18ee6002f04..e24836064dcc6ef7f14db459585523fc1d16b011 100644
--- a/app/scodoc/sco_bulletins.py
+++ b/app/scodoc/sco_bulletins.py
@@ -1261,6 +1261,14 @@ def make_menu_autres_operations(
# possible slt si on a un mail...
"enabled": etud_perso and can_send_bulletin_by_mail(formsemestre.id),
},
+ {
+ "title": "Exporter toutes les notes d'évaluations",
+ "endpoint": "notes.formsemestre_etud_export_all_notes",
+ "args": {
+ "formsemestre_id": formsemestre.id,
+ "etudid": etud.id,
+ },
+ },
{
"title": "Version json",
"endpoint": endpoint,
diff --git a/app/scodoc/sco_saisie_notes.py b/app/scodoc/sco_saisie_notes.py
index a53e4607306603b1613d15e315e3b59e166f5bd6..7146dd0bcb023a29e60a3312fbd484ea2f3bf51b 100644
--- a/app/scodoc/sco_saisie_notes.py
+++ b/app/scodoc/sco_saisie_notes.py
@@ -48,7 +48,7 @@ from app.models import (
NotesNotes,
)
from app.models.etudiants import Identite
-
+from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_exceptions import (
AccessDenied,
NoteProcessError,
@@ -63,6 +63,7 @@ from app.scodoc import sco_evaluations
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_groups
from app.scodoc import sco_groups_view
+from app.scodoc import sco_preferences
from app.scodoc import sco_undo_notes
import app.scodoc.notesdb as ndb
from app.scodoc.TrivialFormulator import TF
@@ -902,6 +903,23 @@ def get_data(formsemestre: FormSemestre, etud: Identite) -> DataForm:
return data
+def _formsemestre_module_type_order(formsemestre: FormSemestre) -> list[ModuleType]:
+ """Liste des types de modules, pour avoir l'ordre d'affichage.
+ Dépend du type de formation."""
+ if formsemestre.formation.is_apc():
+ return [
+ ModuleType.RESSOURCE,
+ ModuleType.SAE,
+ ModuleType.STANDARD,
+ ModuleType.MALUS,
+ ]
+ # Formations classiques:
+ return [
+ ModuleType.STANDARD,
+ ModuleType.MALUS,
+ ]
+
+
def saisie_notes_par_etu(formsemestre: FormSemestre, etud: Identite):
"Formulaire de saisie de toutes les notes d'un semestre pour un étudiant"
# Check access
@@ -928,18 +946,8 @@ def saisie_notes_par_etu(formsemestre: FormSemestre, etud: Identite):
if inscription.etat != scu.INSCRIT:
raise ScoValueError("Étudiant démissionnaire ou défaillant")
data = get_data(formsemestre, etud)
- if formsemestre.formation.is_apc():
- module_type_order = [
- ModuleType.RESSOURCE,
- ModuleType.SAE,
- ModuleType.STANDARD,
- ModuleType.MALUS,
- ]
- else:
- module_type_order = [
- ModuleType.STANDARD,
- ModuleType.MALUS,
- ]
+ module_type_order = _formsemestre_module_type_order(formsemestre)
+
return render_template(
"etud/saisie_notes_par_etu.j2",
title="Saisie notes par étudiant",
@@ -958,6 +966,61 @@ def get_evaluation_etud_note(evaluation: Evaluation, etudid: int) -> NotesNotes
).first()
+def formsemestre_etud_export_all_notes(
+ formsemestre: FormSemestre, etud: Identite
+) -> GenTable:
+ """Table avec toutes les notes de toutes les évaluations du formsemestre,
+ sans aucun calcul de moyennes.
+ """
+ data = get_data(formsemestre, etud)
+ titles = {
+ "modimpl_id": "modimpl_id",
+ "code_module": "Module",
+ "evaluation_id": "evaluation_id",
+ "evaluation_description": "Description",
+ "date_debut": "Date début",
+ "date_fin": "Date fin",
+ "evaluation_type": "Type",
+ "coef": "Coef",
+ "note": "Note",
+ "bareme": "Barème",
+ }
+ columns_ids = titles.keys()
+ # poids_{ue_acronyme} (une colonne par UE)
+ rows = []
+ for module_type in _formsemestre_module_type_order(formsemestre):
+ for data_modimpl in data.data_sections[module_type].data_modimpl:
+ for data_eval in data_modimpl.data_evals:
+ rows.append(
+ {
+ "modimpl_id": data_modimpl.modimpl.id,
+ "code_module": data_modimpl.module_code or "",
+ "evaluation_id": data_eval.evaluation.id,
+ "evaluation_description": data_eval.evaluation.description
+ or "",
+ "bareme": data_eval.evaluation.note_max,
+ "coef": data_eval.evaluation.coefficient,
+ "date_debut": data_eval.evaluation.date_debut or "",
+ "date_fin": data_eval.evaluation.date_fin or "",
+ "evaluation_type": data_eval.evaluation.type_abbrev(),
+ "note": (
+ scu.fmt_note(data_eval.note.value, keep_numeric=True)
+ if data_eval.note
+ else ""
+ ),
+ }
+ )
+ name = scu.make_filename(f"notes_{etud.nomprenom}_{formsemestre.titre_num()}")
+ return GenTable(
+ titles=titles,
+ columns_ids=columns_ids,
+ rows=rows,
+ preferences=sco_preferences.SemPreferences(formsemestre.id),
+ xls_sheet_name=name,
+ filename=name + scu.XLSX_SUFFIX,
+ )
+
+
def get_sorted_etuds_notes(
evaluation: Evaluation, etudids: list, formsemestre_id: int
) -> list[dict]:
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index e1ee3286d176b54f54626393ca07c30f9879810d..b6aecabd1871c66fa04aa6710e03b41939cb9ea4 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -655,7 +655,8 @@ def fmt_note(
val, note_max=None, keep_numeric=False, fixed_precision_str=True
) -> str | float:
"""conversion note en str pour affichage dans tables HTML ou PDF.
- Si keep_numeric, laisse les valeur numeriques telles quelles (pour export Excel)
+ Si keep_numeric, laisse les valeur numeriques telles quelles (pour export Excel).
+ Si note_max > 0, normalise sur cette valeur.
Si fixed_precision_str (défaut), formatte sur 4 chiffres ("01.23"),
sinon utilise %g (chaine précision variable, pour les formulaires)
"""
diff --git a/app/views/notes.py b/app/views/notes.py
index 8f5929a270c991e4dc5a292e244886b80831d465..c3ca15a9594f5c488983a03b402aaacb4c40bfe0 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -1942,6 +1942,25 @@ def moduleimpl_feuille_import_notes(moduleimpl_id: int):
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE)
+# --- Export des notes
+@bp.route("formsemestre_etud_export_all_notes/<int:formsemestre_id>/<int:etudid>")
+@scodoc
+@permission_required(Permission.ScoView)
+def formsemestre_etud_export_all_notes(formsemestre_id: int, etudid: int):
+ """Exporte un classeur xlsx avec toutes les notes de l'étudiant
+ aux évaluations de ce semestre (sans les moyennes).
+ """
+ formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
+ etud = Identite.get_etud(etudid)
+ table = sco_saisie_notes.formsemestre_etud_export_all_notes(formsemestre, etud)
+ return scu.send_file(
+ table.excel(),
+ table.filename,
+ scu.XLSX_SUFFIX,
+ mime=scu.XLSX_MIMETYPE,
+ )
+
+
# --- Bulletins
@bp.route("/formsemestre_bulletins_pdf")
@scodoc