diff --git a/app/comp/moy_sem.py b/app/comp/moy_sem.py
index db42616c8..2b73b9df4 100644
--- a/app/comp/moy_sem.py
+++ b/app/comp/moy_sem.py
@@ -30,7 +30,8 @@
import numpy as np
import pandas as pd
-from flask import flash
+from flask import flash, g, Markup, url_for
+from app.models.formations import Formation
def compute_sem_moys_apc_using_coefs(
@@ -51,7 +52,7 @@ def compute_sem_moys_apc_using_coefs(
def compute_sem_moys_apc_using_ects(
- etud_moy_ue_df: pd.DataFrame, ects: list, formation_id=None
+ etud_moy_ue_df: pd.DataFrame, ects: list, formation_id=None, skip_empty_ues=False
) -> pd.Series:
"""Calcule les moyennes générales indicatives de tous les étudiants
= moyenne des moyennes d'UE, pondérée par leurs ECTS.
@@ -59,13 +60,29 @@ def compute_sem_moys_apc_using_ects(
etud_moy_ue_df: DataFrame, colonnes ue_id, lignes etudid
ects: liste de floats ou None, 1 par UE
+ Si skip_empty_ues: ne compte pas les UE non notées.
+ Sinon (par défaut), une UE non notée compte comme zéro.
+
Result: panda Series, index etudid, valeur float (moyenne générale)
"""
try:
- moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / sum(ects)
+ if skip_empty_ues:
+ # annule les coefs des UE sans notes (NaN)
+ ects = np.where(etud_moy_ue_df.isna(), 0, np.array(ects))
+ # ects est devenu nb_etuds x nb_ues
+ moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / ects.sum(axis=1)
+ else:
+ moy_gen = (etud_moy_ue_df * ects).sum(axis=1) / sum(ects)
except TypeError:
if None in ects:
- flash("""Calcul moyenne générale impossible: ECTS des UE manquants !""")
+ formation = Formation.query.get(formation_id)
+ flash(
+ Markup(
+ f"""Calcul moyenne générale impossible: ECTS des UE manquants !
+ (formation: {formation.get_titre_version()})"""
+ )
+ )
moy_gen = pd.Series(np.NaN, index=etud_moy_ue_df.index)
else:
raise
diff --git a/app/comp/res_but.py b/app/comp/res_but.py
index 228c6506b..3ffed6700 100644
--- a/app/comp/res_but.py
+++ b/app/comp/res_but.py
@@ -17,6 +17,7 @@ from app.comp.bonus_spo import BonusSport
from app.models import ScoDocSiteConfig
from app.models.moduleimpls import ModuleImpl
from app.models.ues import UniteEns
+from app.scodoc import sco_preferences
from app.scodoc.sco_codes_parcours import UE_SPORT
@@ -113,6 +114,9 @@ class ResultatsSemestreBUT(NotesTableCompat):
self.etud_moy_ue,
[ue.ects for ue in self.ues if ue.type != UE_SPORT],
formation_id=self.formsemestre.formation_id,
+ skip_empty_ues=sco_preferences.get_preference(
+ "but_moy_skip_empty_ues", self.formsemestre.id
+ ),
)
# --- UE capitalisées
self.apply_capitalisation()
diff --git a/app/models/formations.py b/app/models/formations.py
index edd57097d..c0f375ddc 100644
--- a/app/models/formations.py
+++ b/app/models/formations.py
@@ -59,6 +59,10 @@ class Formation(db.Model):
"""get l'instance de TypeParcours de cette formation"""
return sco_codes_parcours.get_parcours_from_code(self.type_parcours)
+ def get_titre_version(self) -> str:
+ """Titre avec version"""
+ return f"{self.acronyme} {self.titre} v{self.version}"
+
def is_apc(self):
"True si formation APC avec SAE (BUT)"
return self.get_parcours().APC_SAE
diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py
index b320c164e..ba2229dba 100644
--- a/app/scodoc/sco_preferences.py
+++ b/app/scodoc/sco_preferences.py
@@ -358,8 +358,22 @@ class BasePreferences(object):
"use_ue_coefs",
{
"initvalue": 0,
- "title": "Utiliser les coefficients d'UE pour calculer la moyenne générale",
- "explanation": """Calcule les moyennes dans chaque UE, puis pondère ces résultats pour obtenir la moyenne générale. Par défaut, le coefficient d'une UE est simplement la somme des coefficients des modules dans lesquels l'étudiant a des notes. Attention: changer ce réglage va modifier toutes les moyennes du semestre !""",
+ "title": "Utiliser les coefficients d'UE pour calculer la moyenne générale (hors BUT)",
+ "explanation": """Calcule les moyennes dans chaque UE, puis pondère ces résultats pour obtenir la moyenne générale. Par défaut, le coefficient d'une UE est simplement la somme des coefficients des modules dans lesquels l'étudiant a des notes. Attention: changer ce réglage va modifier toutes les moyennes du semestre !. Aucun effet en BUT.""",
+ "input_type": "boolcheckbox",
+ "category": "misc",
+ "labels": ["non", "oui"],
+ "only_global": False,
+ },
+ ),
+ (
+ "but_moy_skip_empty_ues",
+ {
+ "initvalue": 0,
+ "title": "BUT: moyenne générale sans les UE sans notes",
+ "explanation": """La moyenne générale indicative BUT est basée sur les moyennes d'UE pondérées par leurs ECTS.
+ Si cette option est cochée, ne prend pas en compte les UEs sans notes. Attention: changer ce réglage va modifier toutes
+ les moyennes du semestre !. Aucun effet dans les formations non BUT.""",
"input_type": "boolcheckbox",
"category": "misc",
"labels": ["non", "oui"],