Flag pour bloquer calcul moyenne generale BUT + reimplemente flag blocage moyennes

This commit is contained in:
Emmanuel Viennet 2022-11-01 17:39:18 +01:00 committed by iziram
parent a63349382e
commit a730bf759b
12 changed files with 83 additions and 18 deletions

View File

@ -219,6 +219,7 @@ def compute_ue_moys_apc(
modimpl_inscr_df: pd.DataFrame, modimpl_inscr_df: pd.DataFrame,
modimpl_coefs_df: pd.DataFrame, modimpl_coefs_df: pd.DataFrame,
modimpl_mask: np.array, modimpl_mask: np.array,
block: bool = False,
) -> pd.DataFrame: ) -> pd.DataFrame:
"""Calcul de la moyenne d'UE en mode APC (BUT). """Calcul de la moyenne d'UE en mode APC (BUT).
La moyenne d'UE est un nombre (note/20), ou NaN si pas de notes disponibles La moyenne d'UE est un nombre (note/20), ou NaN si pas de notes disponibles
@ -234,13 +235,13 @@ def compute_ue_moys_apc(
modimpl_mask: liste de booléens, indiquants le module doit être pris ou pas. modimpl_mask: liste de booléens, indiquants le module doit être pris ou pas.
(utilisé pour éliminer les bonus, et pourra servir à cacluler (utilisé pour éliminer les bonus, et pourra servir à cacluler
sur des sous-ensembles de modules) sur des sous-ensembles de modules)
block: si vrai, ne calcule rien et renvoie des NaNs
Résultat: DataFrame columns UE (sans bonus), rows etudid Résultat: DataFrame columns UE (sans bonus), rows etudid
""" """
nb_etuds, nb_modules, nb_ues_no_bonus = sem_cube.shape nb_etuds, nb_modules, nb_ues_no_bonus = sem_cube.shape
nb_ues_tot = len(ues) nb_ues_tot = len(ues)
assert len(modimpls) == nb_modules assert len(modimpls) == nb_modules
if nb_modules == 0 or nb_etuds == 0 or nb_ues_no_bonus == 0: if block or nb_modules == 0 or nb_etuds == 0 or nb_ues_no_bonus == 0:
return pd.DataFrame( return pd.DataFrame(
index=modimpl_inscr_df.index, columns=modimpl_coefs_df.index index=modimpl_inscr_df.index, columns=modimpl_coefs_df.index
) )
@ -291,6 +292,7 @@ def compute_ue_moys_classic(
modimpl_inscr_df: pd.DataFrame, modimpl_inscr_df: pd.DataFrame,
modimpl_coefs: np.array, modimpl_coefs: np.array,
modimpl_mask: np.array, modimpl_mask: np.array,
block: bool = False,
) -> tuple[pd.Series, pd.DataFrame, pd.DataFrame]: ) -> tuple[pd.Series, pd.DataFrame, pd.DataFrame]:
"""Calcul de la moyenne d'UE et de la moy. générale en mode classique (DUT, LMD, ...). """Calcul de la moyenne d'UE et de la moy. générale en mode classique (DUT, LMD, ...).
@ -312,6 +314,7 @@ def compute_ue_moys_classic(
modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl) modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl)
modimpl_coefs: vecteur des coefficients de modules modimpl_coefs: vecteur des coefficients de modules
modimpl_mask: masque des modimpls à prendre en compte modimpl_mask: masque des modimpls à prendre en compte
block: si vrai, ne calcule rien et renvoie des NaNs
Résultat: Résultat:
- moyennes générales: pd.Series, index etudid - moyennes générales: pd.Series, index etudid
@ -320,13 +323,14 @@ def compute_ue_moys_classic(
les coefficients effectifs de chaque UE pour chaque étudiant les coefficients effectifs de chaque UE pour chaque étudiant
(sommes de coefs de modules pris en compte) (sommes de coefs de modules pris en compte)
""" """
if (not len(modimpl_mask)) or ( if (
sem_matrix.shape[0] == 0 block or (len(modimpl_mask) == 0) or (sem_matrix.shape[0] == 0)
): # aucun module ou aucun étudiant ): # aucun module ou aucun étudiant
# etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df # etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df
val = np.nan if block else 0.0
return ( return (
pd.Series( pd.Series(
[0.0] * len(modimpl_inscr_df.index), index=modimpl_inscr_df.index [val] * len(modimpl_inscr_df.index), index=modimpl_inscr_df.index
), ),
pd.DataFrame(columns=[ue.id for ue in ues], index=modimpl_inscr_df.index), pd.DataFrame(columns=[ue.id for ue in ues], index=modimpl_inscr_df.index),
pd.DataFrame(columns=[ue.id for ue in ues], index=modimpl_inscr_df.index), pd.DataFrame(columns=[ue.id for ue in ues], index=modimpl_inscr_df.index),

View File

@ -71,7 +71,6 @@ class ResultatsSemestreBUT(NotesTableCompat):
modimpl.module.ue.type != UE_SPORT modimpl.module.ue.type != UE_SPORT
for modimpl in self.formsemestre.modimpls_sorted for modimpl in self.formsemestre.modimpls_sorted
] ]
self.etud_moy_ue = moy_ue.compute_ue_moys_apc( self.etud_moy_ue = moy_ue.compute_ue_moys_apc(
self.sem_cube, self.sem_cube,
self.etuds, self.etuds,
@ -80,6 +79,7 @@ class ResultatsSemestreBUT(NotesTableCompat):
self.modimpl_inscr_df, self.modimpl_inscr_df,
self.modimpl_coefs_df, self.modimpl_coefs_df,
modimpls_mask, modimpls_mask,
block=self.formsemestre.block_moyennes,
) )
# Les coefficients d'UE ne sont pas utilisés en APC # Les coefficients d'UE ne sont pas utilisés en APC
self.etud_coef_ue_df = pd.DataFrame( self.etud_coef_ue_df = pd.DataFrame(
@ -125,6 +125,11 @@ class ResultatsSemestreBUT(NotesTableCompat):
# self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_coefs( # self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_coefs(
# self.etud_moy_ue, self.modimpl_coefs_df # self.etud_moy_ue, self.modimpl_coefs_df
# ) # )
if self.formsemestre.block_moyenne_generale or self.formsemestre.block_moyennes:
self.etud_moy_gen = pd.Series(
index=self.etud_moy_ue.index, dtype=float
) # NaNs
else:
self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_ects( self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_ects(
self.etud_moy_ue, self.etud_moy_ue,
ects, ects,

View File

@ -90,6 +90,7 @@ class ResultatsSemestreClassic(NotesTableCompat):
self.modimpl_inscr_df, self.modimpl_inscr_df,
self.modimpl_coefs, self.modimpl_coefs,
modimpl_standards_mask, modimpl_standards_mask,
block=self.formsemestre.block_moyennes,
) )
# --- Modules de MALUS sur les UEs et la moyenne générale # --- Modules de MALUS sur les UEs et la moyenne générale
self.malus = moy_ue.compute_malus( self.malus = moy_ue.compute_malus(

View File

@ -78,6 +78,10 @@ class FormSemestre(db.Model):
block_moyennes = db.Column( block_moyennes = db.Column(
db.Boolean(), nullable=False, default=False, server_default="false" db.Boolean(), nullable=False, default=False, server_default="false"
) )
# Bloque le calcul de la moyenne générale (utile pour BUT)
block_moyenne_generale = db.Column(
db.Boolean(), nullable=False, default=False, server_default="false"
)
# semestres decales (pour gestion jurys): # semestres decales (pour gestion jurys):
gestion_semestrielle = db.Column( gestion_semestrielle = db.Column(
db.Boolean(), nullable=False, default=False, server_default="false" db.Boolean(), nullable=False, default=False, server_default="false"

View File

@ -62,6 +62,7 @@ _formsemestreEditor = ndb.EditableTable(
"etat", "etat",
"bul_hide_xml", "bul_hide_xml",
"block_moyennes", "block_moyennes",
"block_moyenne_generale",
"bul_bgcolor", "bul_bgcolor",
"modalite", "modalite",
"resp_can_edit", "resp_can_edit",
@ -83,6 +84,7 @@ _formsemestreEditor = ndb.EditableTable(
"gestion_compensation": bool, "gestion_compensation": bool,
"bul_hide_xml": bool, "bul_hide_xml": bool,
"block_moyennes": bool, "block_moyennes": bool,
"block_moyenne_generale": bool,
"gestion_semestrielle": bool, "gestion_semestrielle": bool,
"gestion_compensation": bool, "gestion_compensation": bool,
"gestion_semestrielle": bool, "gestion_semestrielle": bool,

View File

@ -528,6 +528,14 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
"explanation": "empêcher le calcul des moyennes d'UE et générale.", "explanation": "empêcher le calcul des moyennes d'UE et générale.",
}, },
), ),
(
"block_moyenne_generale",
{
"input_type": "boolcheckbox",
"title": "Pas de moyenne générale",
"explanation": "ne pas calculer la moyenne générale indicative (en BUT)",
},
),
] ]
# Choix des parcours # Choix des parcours
if is_apc: if is_apc:

View File

@ -0,0 +1,36 @@
"""Ajout flag block_moyenne_generale
Revision ID: 52f5f35c077f
Revises: dbb4a0b19dbb
Create Date: 2022-11-01 17:14:06.508637
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "52f5f35c077f"
down_revision = "dbb4a0b19dbb"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"notes_formsemestre",
sa.Column(
"block_moyenne_generale",
sa.Boolean(),
server_default="false",
nullable=False,
),
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("notes_formsemestre", "block_moyenne_generale")
# ### end Alembic commands ###

View File

@ -7,21 +7,21 @@ Démarche générale:
1. modifier /opt/scodoc/.env pour indiquer 1. modifier /opt/scodoc/.env pour indiquer
``` ```bash
FLASK_ENV=test_api FLASK_ENV=test_api
FLASK_DEBUG=1 FLASK_DEBUG=1
``` ```
2. En tant qu'utilisateur scodoc, lancer: 2. En tant qu'utilisateur scodoc, lancer:
``` ```bash
tools/create_database.sh --drop SCODOC_TEST_API tools/create_database.sh --drop SCODOC_TEST_API
flask db upgrade flask db upgrade
flask sco-db-init --erase flask sco-db-init --erase
flask init-test-database flask init-test-database
``` ```
en plus court: ``` en plus court: ```bash
tools/create_database.sh --drop SCODOC_TEST_API && flask db upgrade &&flask sco-db-init --erase && flask init-test-database tools/create_database.sh --drop SCODOC_TEST_API && flask db upgrade &&flask sco-db-init --erase && flask init-test-database
``` ```

View File

@ -253,6 +253,7 @@ def test_etudiant_formsemestres(api_headers):
) )
assert isinstance(formsemestre["titre"], str) assert isinstance(formsemestre["titre"], str)
assert isinstance(formsemestre["block_moyennes"], bool) assert isinstance(formsemestre["block_moyennes"], bool)
assert isinstance(formsemestre["block_moyenne_generale"], bool)
assert formsemestre["scodoc7_id"] is None or isinstance( assert formsemestre["scodoc7_id"] is None or isinstance(
formsemestre["scodoc7_id"], int formsemestre["scodoc7_id"], int
) )

View File

@ -77,6 +77,7 @@ def test_formsemestre(api_headers):
formsemestre = r.json() formsemestre = r.json()
assert verify_fields(formsemestre, FSEM_FIELDS) assert verify_fields(formsemestre, FSEM_FIELDS)
assert isinstance(formsemestre["block_moyennes"], bool) assert isinstance(formsemestre["block_moyennes"], bool)
assert isinstance(formsemestre["block_moyenne_generale"], bool)
assert isinstance(formsemestre["bul_bgcolor"], str) assert isinstance(formsemestre["bul_bgcolor"], str)
assert isinstance(formsemestre["bul_hide_xml"], bool) assert isinstance(formsemestre["bul_hide_xml"], bool)
assert isinstance(formsemestre["date_debut_iso"], str) assert isinstance(formsemestre["date_debut_iso"], str)
@ -136,6 +137,7 @@ def test_formsemestre_apo(api_headers):
assert isinstance(formsemestre, dict) assert isinstance(formsemestre, dict)
assert verify_fields(formsemestre, FSEM_FIELDS) assert verify_fields(formsemestre, FSEM_FIELDS)
assert isinstance(formsemestre["block_moyennes"], bool) assert isinstance(formsemestre["block_moyennes"], bool)
assert isinstance(formsemestre["block_moyenne_generale"], bool)
assert isinstance(formsemestre["bul_bgcolor"], str) assert isinstance(formsemestre["bul_bgcolor"], str)
assert isinstance(formsemestre["bul_hide_xml"], bool) assert isinstance(formsemestre["bul_hide_xml"], bool)
assert isinstance(formsemestre["date_debut_iso"], str) assert isinstance(formsemestre["date_debut_iso"], str)

View File

@ -154,7 +154,7 @@ FORMSEMESTRE_FIELDS = [
"bul_hide_xml", "bul_hide_xml",
"elt_annee_apo", "elt_annee_apo",
"block_moyennes", "block_moyennes",
"formsemestre_id", "block_moyenne_generale" "formsemestre_id",
"titre_num", "titre_num",
"titre_formation", "titre_formation",
"date_debut_iso", "date_debut_iso",
@ -164,6 +164,7 @@ FORMSEMESTRE_FIELDS = [
FSEM_FIELDS = { FSEM_FIELDS = {
"block_moyennes", "block_moyennes",
"block_moyenne_generale",
"bul_bgcolor", "bul_bgcolor",
"bul_hide_xml", "bul_hide_xml",
"date_debut_iso", "date_debut_iso",

View File

@ -224,6 +224,7 @@ class ScoFake(object):
gestion_compensation=None, gestion_compensation=None,
bul_hide_xml=None, bul_hide_xml=None,
block_moyennes=None, block_moyennes=None,
block_moyenne_generale=None,
gestion_semestrielle=None, gestion_semestrielle=None,
bul_bgcolor=None, bul_bgcolor=None,
modalite=FormationModalite.DEFAULT_MODALITE, modalite=FormationModalite.DEFAULT_MODALITE,