From 75232a18a380c177d96ea940480581e75e56caf4 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 15 Feb 2022 13:15:56 +0100 Subject: [PATCH 01/30] =?UTF-8?q?Am=C3=A9liore=20quelques=20routes=20et=20?= =?UTF-8?q?msg=20erreurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_groups_view.py | 7 ++++++- app/views/notes.py | 2 +- app/views/pn_modules.py | 2 +- app/views/scodoc.py | 2 +- sco_version.py | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py index 603627d14..5b89ab44f 100644 --- a/app/scodoc/sco_groups_view.py +++ b/app/scodoc/sco_groups_view.py @@ -302,7 +302,12 @@ class DisplayedGroupsInfos(object): if group_ids: group_ids = [group_ids] # cas ou un seul parametre, pas de liste else: - group_ids = [int(g) for g in group_ids] + try: + group_ids = [int(g) for g in group_ids] + except ValueError as exc: + raise ScoValueError( + "identifiant de groupe invalide (mettre à jour vos bookmarks ?)" + ) from exc if not formsemestre_id and moduleimpl_id: mods = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id) if len(mods) != 1: diff --git a/app/views/notes.py b/app/views/notes.py index efad2808b..7be106444 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -397,7 +397,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): ) -@bp.route("/ue_infos/") +@bp.route("/ue_infos/") @scodoc @permission_required(Permission.ScoView) def ue_infos(ue_id): diff --git a/app/views/pn_modules.py b/app/views/pn_modules.py index 565bc210f..935020e62 100644 --- a/app/views/pn_modules.py +++ b/app/views/pn_modules.py @@ -68,7 +68,7 @@ from app.scodoc.sco_permissions import Permission @bp.route("/table_modules_ue_coefs/") -@bp.route("/table_modules_ue_coefs//") +@bp.route("/table_modules_ue_coefs//") @scodoc @permission_required(Permission.ScoView) def table_modules_ue_coefs(formation_id, semestre_idx=None): diff --git a/app/views/scodoc.py b/app/views/scodoc.py index e65c4e666..809d8e463 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -121,7 +121,7 @@ def create_dept(): ) -@bp.route("/ScoDoc/toggle_dept_vis/", methods=["GET", "POST"]) +@bp.route("/ScoDoc/toggle_dept_vis/", methods=["GET", "POST"]) @admin_required def toggle_dept_vis(dept_id): """Cache ou rend visible un dept""" diff --git a/sco_version.py b/sco_version.py index 23fba0069..1e9561b08 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.56" +SCOVERSION = "9.1.57" SCONAME = "ScoDoc" From 15aa786ddb7b91aac27f508d36acca24aefd2750 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 15 Feb 2022 13:21:57 +0100 Subject: [PATCH 02/30] Fix: calcul moy. gen. classique si aucun coef (mauvaise gestion du NaN). --- app/comp/moy_ue.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index b0a534e51..e4aac3353 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -38,8 +38,8 @@ from app.comp import moy_mod from app.models.formsemestre import FormSemestre from app.scodoc import sco_codes_parcours from app.scodoc import sco_preferences -from app.scodoc.sco_codes_parcours import UE_SPORT -from app.scodoc.sco_utils import ModuleType +from app.scodoc.sco_codes_parcours import NOTES_TOLERANCE, UE_SPORT +from app.scodoc.sco_utils import NOTES_PRECISION, ModuleType def df_load_module_coefs(formation_id: int, semestre_idx: int = None) -> pd.DataFrame: @@ -358,10 +358,12 @@ def compute_ue_moys_classic( ) # nb_ue x nb_etuds x nb_mods : coefs prenant en compte NaN et inscriptions coefs = (modimpl_coefs_etuds_no_nan_stacked * ue_modules).swapaxes(1, 2) - with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) - etud_moy_ue = ( - np.sum(coefs * sem_matrix_inscrits, axis=2) / np.sum(coefs, axis=2) - ).T + # Ici c'est une division apr un scalaire, pas NumPy: il faut tester + sum_coefs = np.sum(coefs, axis=2) + if abs(sum_coefs) > NOTES_PRECISION: + etud_moy_ue = (np.sum(coefs * sem_matrix_inscrits, axis=2) / sum_coefs).T + else: + etud_moy_ue = np.nan etud_moy_ue_df = pd.DataFrame( etud_moy_ue, index=modimpl_inscr_df.index, columns=[ue.id for ue in ues] ) From 15a59749505b685ff915c1ed3f8b319ede4f7b5d Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 15 Feb 2022 13:30:22 +0100 Subject: [PATCH 03/30] Revert "Fix: calcul moy. gen. classique si aucun coef (mauvaise gestion du NaN)." This reverts commit 15aa786ddb7b91aac27f508d36acca24aefd2750. --- app/comp/moy_ue.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index e4aac3353..b0a534e51 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -38,8 +38,8 @@ from app.comp import moy_mod from app.models.formsemestre import FormSemestre from app.scodoc import sco_codes_parcours from app.scodoc import sco_preferences -from app.scodoc.sco_codes_parcours import NOTES_TOLERANCE, UE_SPORT -from app.scodoc.sco_utils import NOTES_PRECISION, ModuleType +from app.scodoc.sco_codes_parcours import UE_SPORT +from app.scodoc.sco_utils import ModuleType def df_load_module_coefs(formation_id: int, semestre_idx: int = None) -> pd.DataFrame: @@ -358,12 +358,10 @@ def compute_ue_moys_classic( ) # nb_ue x nb_etuds x nb_mods : coefs prenant en compte NaN et inscriptions coefs = (modimpl_coefs_etuds_no_nan_stacked * ue_modules).swapaxes(1, 2) - # Ici c'est une division apr un scalaire, pas NumPy: il faut tester - sum_coefs = np.sum(coefs, axis=2) - if abs(sum_coefs) > NOTES_PRECISION: - etud_moy_ue = (np.sum(coefs * sem_matrix_inscrits, axis=2) / sum_coefs).T - else: - etud_moy_ue = np.nan + with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) + etud_moy_ue = ( + np.sum(coefs * sem_matrix_inscrits, axis=2) / np.sum(coefs, axis=2) + ).T etud_moy_ue_df = pd.DataFrame( etud_moy_ue, index=modimpl_inscr_df.index, columns=[ue.id for ue in ues] ) From a8e15c839ede8f958118a1a93080dcdfc42bacd7 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 15 Feb 2022 13:58:44 +0100 Subject: [PATCH 04/30] orthographe --- app/comp/bonus_spo.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 1c7fc5437..26bd460dd 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -295,7 +295,7 @@ class BonusDirect(BonusSportAdditif): class BonusBethune(BonusSportMultiplicatif): - """Calcul bonus modules optionels (sport), règle IUT de Béthune. + """Calcul bonus modules optionnels (sport), règle IUT de Béthune. Les points au dessus de la moyenne de 10 apportent un bonus pour le semestre. Ce bonus est égal au nombre de points divisé par 200 et multiplié par la @@ -309,7 +309,7 @@ class BonusBethune(BonusSportMultiplicatif): class BonusBezier(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT de Bézier. + """Calcul bonus modules optionnels (sport, culture), règle IUT de Bézier. Les étudiants de l'IUT peuvent suivre des enseignements optionnels sport , etc) non rattachés à une unité d'enseignement. Les points @@ -330,7 +330,7 @@ class BonusBezier(BonusSportAdditif): class BonusBordeaux1(BonusSportMultiplicatif): - """Calcul bonus modules optionels (sport, culture), règle IUT Bordeaux 1, sur moyenne générale + """Calcul bonus modules optionnels (sport, culture), règle IUT Bordeaux 1, sur moyenne générale et UE. Les étudiants de l'IUT peuvent suivre des enseignements optionnels @@ -351,7 +351,7 @@ class BonusBordeaux1(BonusSportMultiplicatif): class BonusColmar(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT Colmar. + """Calcul bonus modules optionnels (sport, culture), règle IUT Colmar. Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'U.H.A. (sports, musique, deuxième langue, culture, etc) non @@ -411,7 +411,7 @@ class BonusGrenobleIUT1(BonusSportMultiplicatif): class BonusLaRochelle(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT de La Rochelle. + """Calcul bonus modules optionnels (sport, culture), règle IUT de La Rochelle. Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point. Si la note de sport est comprise entre 10 et 20 : ajout de 1% de cette @@ -471,7 +471,7 @@ class BonusLeMans(BonusSportAdditif): # Bonus simple, mais avec changement de paramètres en 2010 ! class BonusLille(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT Villeneuve d'Ascq + """Calcul bonus modules optionnels (sport, culture), règle IUT Villeneuve d'Ascq Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Lille (sports, etc) non rattachés à une unité d'enseignement. @@ -565,7 +565,7 @@ class BonusRoanne(BonusSportAdditif): class BonusStDenis(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT Saint-Denis + """Calcul bonus modules optionnels (sport, culture), règle IUT Saint-Denis Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Paris 13 (sports, musique, deuxième langue, @@ -611,7 +611,7 @@ class BonusTours(BonusDirect): class BonusVilleAvray(BonusSport): - """Bonus modules optionels (sport, culture), règle IUT Ville d'Avray. + """Bonus modules optionnels (sport, culture), règle IUT Ville d'Avray. Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Paris 10 (C2I) non rattachés à une unité d'enseignement. @@ -645,7 +645,7 @@ class BonusVilleAvray(BonusSport): class BonusIUTV(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT Villetaneuse + """Calcul bonus modules optionnels (sport, culture), règle IUT Villetaneuse Les étudiants de l'IUT peuvent suivre des enseignements optionnels de l'Université Paris 13 (sports, musique, deuxième langue, From 41b41c6c556c57e7d0d2143befa061db981f5a89 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 15 Feb 2022 21:55:21 +0100 Subject: [PATCH 05/30] module_type non null --- app/models/modules.py | 2 +- .../b9aadc10227f_module_type_non_null.py | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 migrations/versions/b9aadc10227f_module_type_non_null.py diff --git a/app/models/modules.py b/app/models/modules.py index 393cc8c0f..5a5f47618 100644 --- a/app/models/modules.py +++ b/app/models/modules.py @@ -34,7 +34,7 @@ class Module(db.Model): # id de l'element pedagogique Apogee correspondant: code_apogee = db.Column(db.String(APO_CODE_STR_LEN)) # Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum) - module_type = db.Column(db.Integer) + module_type = db.Column(db.Integer, nullable=False, default=0, server_default="0") # Relations: modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic") ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True) diff --git a/migrations/versions/b9aadc10227f_module_type_non_null.py b/migrations/versions/b9aadc10227f_module_type_non_null.py new file mode 100644 index 000000000..1758c3d23 --- /dev/null +++ b/migrations/versions/b9aadc10227f_module_type_non_null.py @@ -0,0 +1,41 @@ +"""module_type_non_null + +Revision ID: b9aadc10227f +Revises: bd2c1c3d866e +Create Date: 2022-02-15 21:47:29.212329 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql +from sqlalchemy.orm import sessionmaker # added by ev + +# revision identifiers, used by Alembic. +revision = "b9aadc10227f" +down_revision = "bd2c1c3d866e" +branch_labels = None +depends_on = None + +Session = sessionmaker() + + +def upgrade(): + # Added by ev: remove duplicates + bind = op.get_bind() + session = Session(bind=bind) + session.execute( + """UPDATE notes_modules SET module_type=0 WHERE module_type IS NULL;""" + ) + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column( + "notes_modules", "module_type", existing_type=sa.INTEGER(), nullable=False + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column( + "notes_modules", "module_type", existing_type=sa.INTEGER(), nullable=True + ) + # ### end Alembic commands ### From 9a57f362dc3d45be564fd1d2ef75932104d50055 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 15 Feb 2022 22:20:17 +0100 Subject: [PATCH 06/30] =?UTF-8?q?Divisions=20par=20z=C3=A9ro=20non=20contr?= =?UTF-8?q?ol=C3=A9es=20si=20les=20arrays=20vides=20passent=20en=20object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/comp/moy_ue.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index b0a534e51..84a7e2bf1 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -266,6 +266,8 @@ def compute_ue_moys_apc( ) # Annule les coefs des modules NaN modimpl_coefs_etuds_no_nan = np.where(np.isnan(sem_cube), 0.0, modimpl_coefs_etuds) + if modimpl_coefs_etuds_no_nan.dtype == np.object: # arrive sur des tableaux vides + modimpl_coefs_etuds_no_nan = modimpl_coefs_etuds_no_nan.astype(np.float) # # Version vectorisée # @@ -348,7 +350,8 @@ def compute_ue_moys_classic( modimpl_coefs_etuds_no_nan = np.where( np.isnan(sem_matrix), 0.0, modimpl_coefs_etuds ) - + if modimpl_coefs_etuds_no_nan.dtype == np.object: # arrive sur des tableaux vides + modimpl_coefs_etuds_no_nan = modimpl_coefs_etuds_no_nan.astype(np.float) # --------------------- Calcul des moyennes d'UE ue_modules = np.array( [[m.module.ue == ue for m in formsemestre.modimpls_sorted] for ue in ues] @@ -358,6 +361,8 @@ def compute_ue_moys_classic( ) # nb_ue x nb_etuds x nb_mods : coefs prenant en compte NaN et inscriptions coefs = (modimpl_coefs_etuds_no_nan_stacked * ue_modules).swapaxes(1, 2) + if coefs.dtype == np.object: # arrive sur des tableaux vides + coefs = coefs.astype(np.float) with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) etud_moy_ue = ( np.sum(coefs * sem_matrix_inscrits, axis=2) / np.sum(coefs, axis=2) From 7f164b1e1f42661d915c50bec700e89dc3259193 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Wed, 16 Feb 2022 00:43:22 +0100 Subject: [PATCH 07/30] Bonus Annecy --- app/comp/bonus_spo.py | 53 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 26bd460dd..098bd1286 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -13,6 +13,7 @@ Les classes de Bonus fournissent deux méthodes: """ import datetime +import math import numpy as np import pandas as pd @@ -106,6 +107,8 @@ class BonusSport: # sem_modimpl_moys_spo est (nb_etuds, nb_mod_sport) # ou (nb_etuds, nb_mod_sport, nb_ues_non_bonus) nb_etuds, nb_mod_sport = sem_modimpl_moys_spo.shape[:2] + if nb_etuds == 0 or nb_mod_sport == 0: + return # no bonus at all # Enlève les NaN du numérateur: sem_modimpl_moys_no_nan = np.nan_to_num(sem_modimpl_moys_spo, nan=0.0) @@ -157,7 +160,8 @@ class BonusSport: """Calcul des bonus: méthode virtuelle à écraser. Arguments: - sem_modimpl_moys_inscrits: - ndarray (nb_etuds, mod_sport) ou en APC (nb_etuds, mods_sport, nb_ue_non_bonus) + ndarray (nb_etuds, mod_sport) + ou en APC (nb_etuds, mods_sport, nb_ue_non_bonus) les notes aux modules sports auxquel l'étudiant est inscrit, 0 sinon. Pas de nans. - modimpl_coefs_etuds_no_nan: les coefficients: float ndarray @@ -236,10 +240,6 @@ class BonusSportAdditif(BonusSport): bonus_moy_arr, index=self.etuds_idx, dtype=float ) - # if len(bonus_moy_arr.shape) > 1: - # bonus_moy_arr = bonus_moy_arr.sum(axis=1) - # Laisse bonus_moy_gen à None, en APC le bonus moy. gen. sera réparti sur les UEs. - class BonusSportMultiplicatif(BonusSport): """Bonus sport qui multiplie les moyennes d'UE par un facteur""" @@ -294,6 +294,49 @@ class BonusDirect(BonusSportAdditif): proportion_point = 1.0 +class BonusAnnecy(BonusSport): + """Calcul bonus modules optionnels (sport), règle IUT d'Annecy. + Il peut y avoir plusieurs modules de bonus. + Prend pour chaque étudiant la meilleure de ses notes bonus et + ajoute à chaque UE : + 0.05 point si >=10, + 0.1 point si >=12, + 0.15 point si >=14, + 0.2 point si >=16, + 0.25 point si >=18. + """ + + name = "bonus_iut_annecy" + displayed_name = "IUT d'Annecy" + + def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): + """calcul du bonus""" + # if math.prod(sem_modimpl_moys_inscrits.shape) == 0: + # return # no etuds or no mod sport + # Prend la note de chaque modimpl, sans considération d'UE + if len(sem_modimpl_moys_inscrits.shape) > 2: # apc + sem_modimpl_moys_inscrits = sem_modimpl_moys_inscrits[:, :, 0] + # ici sem_modimpl_moys_inscrits est nb_etuds x nb_mods_bonus, en APC et en classic + note_bonus_max = np.max(sem_modimpl_moys_inscrits, axis=1) # 1d, nb_etuds + bonus = np.zeros(note_bonus_max.shape) + bonus[note_bonus_max >= 18.0] = 0.25 + bonus[note_bonus_max >= 16.0] = 0.20 + bonus[note_bonus_max >= 14.0] = 0.15 + bonus[note_bonus_max >= 12.0] = 0.10 + bonus[note_bonus_max >= 10.0] = 0.05 + + # Bonus moyenne générale et sur les UE + self.bonus_moy_gen = pd.Series(bonus, index=self.etuds_idx, dtype=float) + ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)] + nb_ues_no_bonus = len(ues_idx) + self.bonus_ues = pd.DataFrame( + np.stack([bonus] * nb_ues_no_bonus, axis=1), + columns=ues_idx, + index=self.etuds_idx, + dtype=float, + ) + + class BonusBethune(BonusSportMultiplicatif): """Calcul bonus modules optionnels (sport), règle IUT de Béthune. From 1dbb199d2cde9d577b481e0c177322dfead20dd3 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 17 Feb 2022 18:13:04 +0100 Subject: [PATCH 08/30] Ajout relations pour acces aux partitions et groupes via l'ORM --- app/models/formsemestre.py | 5 +++++ app/models/groups.py | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 245142484..a6411f70f 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -104,6 +104,11 @@ class FormSemestre(db.Model): lazy=True, backref=db.backref("formsemestres", lazy=True), ) + partitions = db.relationship( + "Partition", + backref=db.backref("formsemestre", lazy=True), + lazy="dynamic", + ) # Ancien id ScoDoc7 pour les migrations de bases anciennes # ne pas utiliser après migrate_scodoc7_dept_archives scodoc7_id = db.Column(db.Text(), nullable=True) diff --git a/app/models/groups.py b/app/models/groups.py index 902298ccf..976d465be 100644 --- a/app/models/groups.py +++ b/app/models/groups.py @@ -31,6 +31,11 @@ class Partition(db.Model): show_in_lists = db.Column( db.Boolean(), nullable=False, default=True, server_default="true" ) + groups = db.relationship( + "GroupDescr", + backref=db.backref("partition", lazy=True), + lazy="dynamic", + ) def __init__(self, **kwargs): super(Partition, self).__init__(**kwargs) @@ -42,6 +47,9 @@ class Partition(db.Model): else: self.numero = 1 + def __repr__(self): + return f"""<{self.__class__.__name__} {self.id} "{self.partition_name or '(default)'}">""" + class GroupDescr(db.Model): """Description d'un groupe d'une partition""" @@ -55,6 +63,11 @@ class GroupDescr(db.Model): # "A", "C2", ... (NULL for 'all'): group_name = db.Column(db.String(GROUPNAME_STR_LEN)) + def __repr__(self): + return ( + f"""<{self.__class__.__name__} {self.id} "{self.group_name or '(tous)'}">""" + ) + group_membership = db.Table( "group_membership", From 98e7f7a7105bbadf78cd4313b2969beb3b2f3337 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 17 Feb 2022 22:40:11 +0100 Subject: [PATCH 09/30] Corrige affichage numero version sur templates Jinja --- app/templates/sidebar.html | 2 +- app/views/__init__.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/templates/sidebar.html b/app/templates/sidebar.html index c5b06a6f3..5ed8ee883 100644 --- a/app/templates/sidebar.html +++ b/app/templates/sidebar.html @@ -4,7 +4,7 @@ From cca72dfed27089f9308cf3d6ce13df994110a4cc Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 19 Feb 2022 00:28:24 +0100 Subject: [PATCH 28/30] Bonus IUT Amiens --- app/comp/bonus_spo.py | 15 +++++++++++++++ sco_version.py | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index ed4bf5db3..65f6c03b9 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -295,6 +295,21 @@ class BonusDirect(BonusSportAdditif): proportion_point = 1.0 +class BonusAmiens(BonusSportAdditif): + """Bonus IUT Amiens pour les modules optionnels (sport, culture, ...). + + Toute note non nulle, peu importe sa valeur, entraine un bonus de 0,1 point + sur toutes les moyennes d'UE. + """ + + name = "bonus_amiens" + displayed_name = "IUT d'Amiens" + seuil_moy_gen = 0.0 # tous les points sont comptés + proportion_point = 1e10 + bonus_max = 0.1 + classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP + + # Finalement ils n'en veulent pas. # class BonusAnnecy(BonusSport): # """Calcul bonus modules optionnels (sport), règle IUT d'Annecy. diff --git a/sco_version.py b/sco_version.py index 04070622d..96ef7d1da 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.59" +SCOVERSION = "9.1.60" SCONAME = "ScoDoc" From 63784e341ad1d33f1bdb7060b88e25e0b3ad4d9e Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 19 Feb 2022 01:00:40 +0100 Subject: [PATCH 29/30] Correction pour Amiens, Roanne --- app/comp/bonus_spo.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 65f6c03b9..0a95621e8 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -205,7 +205,8 @@ class BonusSportAdditif(BonusSport): """calcul du bonus sem_modimpl_moys_inscrits: les notes de sport En APC: ndarray (nb_etuds, nb_mod_sport, nb_ues_non_bonus) - modimpl_coefs_etuds_no_nan: + En classic: ndarray (nb_etuds, nb_mod_sport) + modimpl_coefs_etuds_no_nan: même shape, les coefs. """ if 0 in sem_modimpl_moys_inscrits.shape: # pas d'étudiants ou pas d'UE ou pas de module... @@ -228,12 +229,22 @@ class BonusSportAdditif(BonusSport): bonus_moy_arr = np.clip(bonus_moy_arr, 0.0, 20.0, out=bonus_moy_arr) # en APC, bonus_moy_arr est (nb_etuds, nb_ues_non_bonus) - if self.formsemestre.formation.is_apc() or self.classic_use_bonus_ues: + if self.formsemestre.formation.is_apc(): # Bonus sur les UE et None sur moyenne générale ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)] self.bonus_ues = pd.DataFrame( bonus_moy_arr, index=self.etuds_idx, columns=ues_idx, dtype=float ) + elif self.classic_use_bonus_ues: + # Formations classiques apppliquant le bonus sur les UEs + # ici bonus_moy_arr = ndarray 1d nb_etuds + ues_idx = [ue.id for ue in self.formsemestre.query_ues(with_sport=False)] + self.bonus_ues = pd.DataFrame( + np.stack([bonus_moy_arr] * len(ues_idx)).T, + index=self.etuds_idx, + columns=ues_idx, + dtype=float, + ) else: # Bonus sur la moyenne générale seulement self.bonus_moy_gen = pd.Series( @@ -693,7 +704,7 @@ class BonusRoanne(BonusSportAdditif): displayed_name = "IUT de Roanne" seuil_moy_gen = 0.0 bonus_max = 0.6 # plafonnement à 0.6 points - apply_bonus_mg_to_ues = True # sur les UE, même en DUT et LP + classic_use_bonus_ues = True # sur les UE, même en DUT et LP class BonusStDenis(BonusSportAdditif): @@ -792,7 +803,7 @@ class BonusIUTV(BonusSportAdditif): name = "bonus_iutv" displayed_name = "IUT de Villetaneuse" - pass # oui, c'ets le bonus par défaut + pass # oui, c'est le bonus par défaut def get_bonus_class_dict(start=BonusSport, d=None): From 44123c022eac799449173f8d92734bcebb75f8c1 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 19 Feb 2022 16:16:52 +0100 Subject: [PATCH 30/30] =?UTF-8?q?Am=C3=A9liore=20=C3=A9dition=20programmes?= =?UTF-8?q?=20classiques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_edit_ue.py | 34 +++++++++++++++++------ app/scodoc/sco_formsemestre_validation.py | 16 +++++++---- app/static/css/scodoc.css | 4 +++ sco_version.py | 2 +- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 17cdc8c07..061bf43c6 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -601,7 +601,12 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list _add_ue_semestre_id(ues_externes, is_apc) ues.sort(key=lambda u: (u["semestre_id"], u["numero"])) ues_externes.sort(key=lambda u: (u["semestre_id"], u["numero"])) - has_duplicate_ue_codes = len(set([ue["ue_code"] for ue in ues])) != len(ues) + # Codes dupliqués (pour aider l'utilisateur) + seen = set() + duplicated_codes = { + ue["ue_code"] for ue in ues if ue["ue_code"] in seen or seen.add(ue["ue_code"]) + } + ues_with_duplicated_code = [ue for ue in ues if ue["ue_code"] in duplicated_codes] has_perm_change = current_user.has_permission(Permission.ScoChangeFormation) # editable = (not locked) and has_perm_change @@ -664,11 +669,17 @@ du programme" (menu "Semestre") si vous avez un semestre en cours); if msg: H.append('

' + msg + "

") - if has_duplicate_ue_codes: + if ues_with_duplicated_code: H.append( - """
Attention: plusieurs UE de cette - formation ont le même code. Il faut corriger cela ci-dessous, - sinon les calculs d'ECTS seront erronés !
""" + f"""
Attention: plusieurs UE de cette + formation ont le même code : { + ', '.join([ + '' + ue["acronyme"] + " (code " + ue["ue_code"] + ")" + for ue in ues_with_duplicated_code ]) + }. + Il faut corriger cela, sinon les capitalisations et ECTS seront + erronés !
""" ) # Description de la formation @@ -930,8 +941,8 @@ def _ue_table_ues( if cur_ue_semestre_id != ue["semestre_id"]: cur_ue_semestre_id = ue["semestre_id"] - if iue > 0: - H.append("") + # if iue > 0: + # H.append("") if ue["semestre_id"] == sco_codes_parcours.UE_SEM_DEFAULT: lab = "Pas d'indication de semestre:" else: @@ -953,7 +964,6 @@ def _ue_table_ues( ) else: H.append(arrow_none) - iue += 1 ue["acro_titre"] = str(ue["acronyme"]) if ue["titre"] != ue["acronyme"]: ue["acro_titre"] += " " + str(ue["titre"]) @@ -1001,6 +1011,14 @@ def _ue_table_ues( delete_disabled_icon, ) ) + if (iue >= len(ues) - 1) or ue["semestre_id"] != ues[iue + 1]["semestre_id"]: + H.append( + f"""""" + ) + iue += 1 + return "\n".join(H) diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index f755bb118..987dc962f 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -1250,7 +1250,7 @@ def check_formation_ues(formation_id): for ue in ues: # formsemestres utilisant cette ue ? sems = ndb.SimpleDictFetch( - """SELECT DISTINCT sem.id AS formsemestre_id, sem.* + """SELECT DISTINCT sem.id AS formsemestre_id, sem.* FROM notes_formsemestre sem, notes_modules mod, notes_moduleimpl mi WHERE sem.formation_id = %(formation_id)s AND mod.id = mi.module_id @@ -1269,11 +1269,11 @@ def check_formation_ues(formation_id): return "", {} # Genere message HTML: H = [ - """
Attention: les UE suivantes de cette formation + """
Attention: les UE suivantes de cette formation sont utilisées dans des - semestres de rangs différents (eg S1 et S3).
Cela peut engendrer des problèmes pour - la capitalisation des UE. Il serait préférable d'essayer de rectifier cette situation: - soit modifier le programme de la formation (définir des UE dans chaque semestre), + semestres de rangs différents (eg S1 et S3).
Cela peut engendrer des problèmes pour + la capitalisation des UE. Il serait préférable d'essayer de rectifier cette situation: + soit modifier le programme de la formation (définir des UE dans chaque semestre), soit veiller à saisir le bon indice de semestre dans le menu lors de la validation d'une UE extérieure.
    @@ -1286,7 +1286,11 @@ def check_formation_ues(formation_id): for x in ue_multiples[ue["ue_id"]] ] slist = ", ".join( - ["%(titreannee)s (semestre %(semestre_id)s)" % s for s in sems] + [ + """%(titreannee)s (semestre %(semestre_id)s)""" + % s + for s in sems + ] ) H.append("
  • %s : %s
  • " % (ue["acronyme"], slist)) H.append("
") diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index e88930857..ecd8b0ab0 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1707,6 +1707,9 @@ ul.notes_ue_list { li.notes_ue_list { margin-top: 9px; list-style-type: none; + border: 1px solid maroon; + border-radius: 10px; + padding-bottom: 5px; } span.ue_type_1 { color: green; @@ -1749,6 +1752,7 @@ ul.notes_matiere_list { background-color: rgb(220,220,220); font-weight: normal; font-style: italic; + border-top: 1px solid maroon; } ul.notes_module_list { diff --git a/sco_version.py b/sco_version.py index 96ef7d1da..9e02cffd1 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.60" +SCOVERSION = "9.1.61" SCONAME = "ScoDoc"