From 772ea2941b41a233abed3666c66abab9f49e32f2 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 1 Nov 2022 17:39:18 +0100 Subject: [PATCH] Flag pour bloquer calcul moyenne generale BUT + reimplemente flag blocage moyennes --- app/comp/moy_ue.py | 14 +++++--- app/comp/res_but.py | 23 +++++++----- app/comp/res_classic.py | 1 + app/models/formsemestre.py | 4 +++ app/scodoc/sco_formsemestre.py | 2 ++ app/scodoc/sco_formsemestre_edit.py | 8 +++++ ...c077f_ajout_flag_block_moyenne_generale.py | 36 +++++++++++++++++++ tests/api/README.md | 6 ++-- tests/api/test_api_etudiants.py | 1 + tests/api/test_api_formsemestre.py | 2 ++ tests/api/tools_test_api.py | 3 +- tests/unit/sco_fake_gen.py | 1 + 12 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 migrations/versions/52f5f35c077f_ajout_flag_block_moyenne_generale.py diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index b6f47d663..a5d9077ec 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -219,6 +219,7 @@ def compute_ue_moys_apc( modimpl_inscr_df: pd.DataFrame, modimpl_coefs_df: pd.DataFrame, modimpl_mask: np.array, + block: bool = False, ) -> pd.DataFrame: """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 @@ -234,13 +235,13 @@ def compute_ue_moys_apc( modimpl_mask: liste de booléens, indiquants le module doit être pris ou pas. (utilisé pour éliminer les bonus, et pourra servir à cacluler 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 """ nb_etuds, nb_modules, nb_ues_no_bonus = sem_cube.shape nb_ues_tot = len(ues) 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( 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_coefs: np.array, modimpl_mask: np.array, + block: bool = False, ) -> 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, ...). @@ -312,6 +314,7 @@ def compute_ue_moys_classic( modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl) modimpl_coefs: vecteur des coefficients de modules modimpl_mask: masque des modimpls à prendre en compte + block: si vrai, ne calcule rien et renvoie des NaNs Résultat: - 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 (sommes de coefs de modules pris en compte) """ - if (not len(modimpl_mask)) or ( - sem_matrix.shape[0] == 0 + if ( + block or (len(modimpl_mask) == 0) or (sem_matrix.shape[0] == 0) ): # aucun module ou aucun étudiant # etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df + val = np.nan if block else 0.0 return ( 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), diff --git a/app/comp/res_but.py b/app/comp/res_but.py index 7b8a20576..6ae6285f5 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -71,7 +71,6 @@ class ResultatsSemestreBUT(NotesTableCompat): modimpl.module.ue.type != UE_SPORT for modimpl in self.formsemestre.modimpls_sorted ] - self.etud_moy_ue = moy_ue.compute_ue_moys_apc( self.sem_cube, self.etuds, @@ -80,6 +79,7 @@ class ResultatsSemestreBUT(NotesTableCompat): self.modimpl_inscr_df, self.modimpl_coefs_df, modimpls_mask, + block=self.formsemestre.block_moyennes, ) # Les coefficients d'UE ne sont pas utilisés en APC self.etud_coef_ue_df = pd.DataFrame( @@ -125,14 +125,19 @@ class ResultatsSemestreBUT(NotesTableCompat): # self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_coefs( # self.etud_moy_ue, self.modimpl_coefs_df # ) - self.etud_moy_gen = moy_sem.compute_sem_moys_apc_using_ects( - self.etud_moy_ue, - ects, - formation_id=self.formsemestre.formation_id, - skip_empty_ues=sco_preferences.get_preference( - "but_moy_skip_empty_ues", self.formsemestre.id - ), - ) + 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_ue, + ects, + 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/comp/res_classic.py b/app/comp/res_classic.py index 5577546b7..f23936765 100644 --- a/app/comp/res_classic.py +++ b/app/comp/res_classic.py @@ -90,6 +90,7 @@ class ResultatsSemestreClassic(NotesTableCompat): self.modimpl_inscr_df, self.modimpl_coefs, modimpl_standards_mask, + block=self.formsemestre.block_moyennes, ) # --- Modules de MALUS sur les UEs et la moyenne générale self.malus = moy_ue.compute_malus( diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index f376ef740..71b6d6050 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -78,6 +78,10 @@ class FormSemestre(db.Model): block_moyennes = db.Column( 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): gestion_semestrielle = db.Column( db.Boolean(), nullable=False, default=False, server_default="false" diff --git a/app/scodoc/sco_formsemestre.py b/app/scodoc/sco_formsemestre.py index bf9905f94..50da1edd8 100644 --- a/app/scodoc/sco_formsemestre.py +++ b/app/scodoc/sco_formsemestre.py @@ -62,6 +62,7 @@ _formsemestreEditor = ndb.EditableTable( "etat", "bul_hide_xml", "block_moyennes", + "block_moyenne_generale", "bul_bgcolor", "modalite", "resp_can_edit", @@ -83,6 +84,7 @@ _formsemestreEditor = ndb.EditableTable( "gestion_compensation": bool, "bul_hide_xml": bool, "block_moyennes": bool, + "block_moyenne_generale": bool, "gestion_semestrielle": bool, "gestion_compensation": bool, "gestion_semestrielle": bool, diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py index f3afb4d79..80fdf3d7f 100644 --- a/app/scodoc/sco_formsemestre_edit.py +++ b/app/scodoc/sco_formsemestre_edit.py @@ -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.", }, ), + ( + "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 if is_apc: diff --git a/migrations/versions/52f5f35c077f_ajout_flag_block_moyenne_generale.py b/migrations/versions/52f5f35c077f_ajout_flag_block_moyenne_generale.py new file mode 100644 index 000000000..d3de7781d --- /dev/null +++ b/migrations/versions/52f5f35c077f_ajout_flag_block_moyenne_generale.py @@ -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 ### diff --git a/tests/api/README.md b/tests/api/README.md index 483da78af..77e4f8160 100644 --- a/tests/api/README.md +++ b/tests/api/README.md @@ -7,21 +7,21 @@ Démarche générale: 1. modifier /opt/scodoc/.env pour indiquer - ``` + ```bash FLASK_ENV=test_api FLASK_DEBUG=1 ``` 2. En tant qu'utilisateur scodoc, lancer: - ``` + ```bash tools/create_database.sh --drop SCODOC_TEST_API flask db upgrade flask sco-db-init --erase 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 ``` diff --git a/tests/api/test_api_etudiants.py b/tests/api/test_api_etudiants.py index e0f7249ce..b4fc97f3b 100644 --- a/tests/api/test_api_etudiants.py +++ b/tests/api/test_api_etudiants.py @@ -253,6 +253,7 @@ def test_etudiant_formsemestres(api_headers): ) assert isinstance(formsemestre["titre"], str) assert isinstance(formsemestre["block_moyennes"], bool) + assert isinstance(formsemestre["block_moyenne_generale"], bool) assert formsemestre["scodoc7_id"] is None or isinstance( formsemestre["scodoc7_id"], int ) diff --git a/tests/api/test_api_formsemestre.py b/tests/api/test_api_formsemestre.py index edc5ff350..258aeaa2a 100644 --- a/tests/api/test_api_formsemestre.py +++ b/tests/api/test_api_formsemestre.py @@ -77,6 +77,7 @@ def test_formsemestre(api_headers): formsemestre = r.json() assert verify_fields(formsemestre, FSEM_FIELDS) assert isinstance(formsemestre["block_moyennes"], bool) + assert isinstance(formsemestre["block_moyenne_generale"], bool) assert isinstance(formsemestre["bul_bgcolor"], str) assert isinstance(formsemestre["bul_hide_xml"], bool) assert isinstance(formsemestre["date_debut_iso"], str) @@ -136,6 +137,7 @@ def test_formsemestre_apo(api_headers): assert isinstance(formsemestre, dict) assert verify_fields(formsemestre, FSEM_FIELDS) assert isinstance(formsemestre["block_moyennes"], bool) + assert isinstance(formsemestre["block_moyenne_generale"], bool) assert isinstance(formsemestre["bul_bgcolor"], str) assert isinstance(formsemestre["bul_hide_xml"], bool) assert isinstance(formsemestre["date_debut_iso"], str) diff --git a/tests/api/tools_test_api.py b/tests/api/tools_test_api.py index 6de79adea..64bfd3589 100644 --- a/tests/api/tools_test_api.py +++ b/tests/api/tools_test_api.py @@ -154,7 +154,7 @@ FORMSEMESTRE_FIELDS = [ "bul_hide_xml", "elt_annee_apo", "block_moyennes", - "formsemestre_id", + "block_moyenne_generale" "formsemestre_id", "titre_num", "titre_formation", "date_debut_iso", @@ -164,6 +164,7 @@ FORMSEMESTRE_FIELDS = [ FSEM_FIELDS = { "block_moyennes", + "block_moyenne_generale", "bul_bgcolor", "bul_hide_xml", "date_debut_iso", diff --git a/tests/unit/sco_fake_gen.py b/tests/unit/sco_fake_gen.py index 0c9931ad1..26c244023 100644 --- a/tests/unit/sco_fake_gen.py +++ b/tests/unit/sco_fake_gen.py @@ -224,6 +224,7 @@ class ScoFake(object): gestion_compensation=None, bul_hide_xml=None, block_moyennes=None, + block_moyenne_generale=None, gestion_semestrielle=None, bul_bgcolor=None, modalite=FormationModalite.DEFAULT_MODALITE,