diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index 06a7bde76..6cf0767f0 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -266,6 +266,8 @@ class BonusSportMultiplicatif(BonusSport): amplitude = 0.005 # multiplie les points au dessus du seuil # En classique, les bonus multiplicatifs agissent par défaut sur les UE: classic_use_bonus_ues = True + # Facteur multiplicatif max: (bonus = moy_ue*factor) + factor_max = 1000.0 # infini # C'est un bonus "multiplicatif": on l'exprime en additif, # sur chaque moyenne d'UE m_0 @@ -285,6 +287,8 @@ class BonusSportMultiplicatif(BonusSport): notes = np.nan_to_num(notes, copy=False) factor = (notes - self.seuil_moy_gen) * self.amplitude # 5% si note=20 factor[factor <= 0] = 0.0 # note < seuil_moy_gen, pas de bonus + # note < seuil_moy_gen, pas de bonus: pas de facteur négatif, ni + factor.clip(0.0, self.factor_max, out=factor) # Ne s'applique qu'aux moyennes d'UE if len(factor.shape) == 1: # classic @@ -705,13 +709,15 @@ class BonusGrenobleIUT1(BonusSportMultiplicatif): class BonusIUTRennes1(BonusSportAdditif): """Calcul bonus optionnels (sport, langue vivante, engagement étudiant), - règle IUT de l'Université de Rennes 1 (Lannion, St Malo). + règle IUT de l'Université de Rennes 1 (Lannion, Rennes, St Brieuc, St Malo).
Exemple: une moyenne d'UE de 10/20 avec un total des bonus de 6% donne + une moyenne de 10,6.
+Les bonifications s'appliquent aussi au classement général du semestre + et de l'année. +
""" - name = "bonus_iut_stmalo" - displayed_name = "IUT de Saint-Malo" + + name = "bonus_iutSN" + displayed_name = "IUT de Saint-Nazaire" + classic_use_bonus_ues = True # s'applique aux UEs en DUT et LP + seuil_moy_gen = 0.0 # tous les points comptent + amplitude = 0.01 / 4 # 4pt => 1% + factor_max = 0.1 # 10% max -class BonusTarbes(BonusSportAdditif): +class BonusTarbes(BonusIUTRennes1): """Calcul bonus optionnels (sport, culture), règle IUT de Tarbes.Impossible de supprimer cette formation, car les sessions suivantes l'utilisent:
-Impossible de supprimer cette formation, + car les sessions suivantes l'utilisent:
+Module : %s
' + 'Évaluation%sModule : %s
' % (etit, mod_descr) ] if Mod["module_type"] == ModuleType.MALUS: @@ -689,12 +687,16 @@ def evaluation_describe(evaluation_id="", edit_in_place=True): modifier l'évaluation - + """ + ) + if link_saisie: + H.append( + f""" saisie des notes """ - ) + ) H.append("") return '""") diff --git a/app/scodoc/sco_ue_external.py b/app/scodoc/sco_ue_external.py index b90afd0dd..825982286 100644 --- a/app/scodoc/sco_ue_external.py +++ b/app/scodoc/sco_ue_external.py @@ -56,6 +56,7 @@ Solution proposée (nov 2014): import flask from flask import request from flask_login import current_user +from app.models.formsemestre import FormSemestre import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu @@ -65,7 +66,6 @@ from app.scodoc import sco_codes_parcours from app.scodoc import sco_edit_matiere from app.scodoc import sco_edit_module from app.scodoc import sco_edit_ue -from app.scodoc import sco_evaluations from app.scodoc import sco_evaluation_db from app.scodoc import sco_formations from app.scodoc import sco_formsemestre @@ -85,17 +85,21 @@ def external_ue_create( ects=0.0, ): """Crée UE/matiere/module/evaluation puis saisie les notes""" - log("external_ue_create( formsemestre_id=%s, titre=%s )" % (formsemestre_id, titre)) - sem = sco_formsemestre.get_formsemestre(formsemestre_id) + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + log(f"creating external UE in {formsemestre}: {acronyme}") + # Contrôle d'accès: if not current_user.has_permission(Permission.ScoImplement): - if not sem["resp_can_edit"] or (current_user.id not in sem["responsables"]): + if (not formsemestre.resp_can_edit) or ( + current_user.id not in [u.id for u in formsemestre.responsables] + ): raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération") # - formation_id = sem["formation_id"] - log("creating external UE in %s: %s" % (formsemestre_id, acronyme)) + formation_id = formsemestre.formation.id - numero = sco_edit_ue.next_ue_numero(formation_id, semestre_id=sem["semestre_id"]) + numero = sco_edit_ue.next_ue_numero( + formation_id, semestre_id=formsemestre.semestre_id + ) ue_id = sco_edit_ue.do_ue_create( { "formation_id": formation_id, @@ -120,7 +124,8 @@ def external_ue_create( "ue_id": ue_id, "matiere_id": matiere_id, "formation_id": formation_id, - "semestre_id": sem["semestre_id"], + "semestre_id": formsemestre.semestre_id, + "module_type": scu.ModuleType.STANDARD, }, ) @@ -129,17 +134,23 @@ def external_ue_create( "module_id": module_id, "formsemestre_id": formsemestre_id, # affecte le 1er responsable du semestre comme resp. du module - "responsable_id": sem["responsables"][0], + "responsable_id": formsemestre.responsables[0].id + if len(formsemestre.responsables) + else None, }, ) return moduleimpl_id -def external_ue_inscrit_et_note(moduleimpl_id, formsemestre_id, notes_etuds): +def external_ue_inscrit_et_note( + moduleimpl_id: int, formsemestre_id: int, notes_etuds: dict +): + """Inscrit les étudiants au moduleimpl, crée au besoin une évaluation + et enregistre les notes. + """ log( - "external_ue_inscrit_et_note(moduleimpl_id=%s, notes_etuds=%s)" - % (moduleimpl_id, notes_etuds) + f"external_ue_inscrit_et_note(moduleimpl_id={moduleimpl_id}, notes_etuds={notes_etuds})" ) # Inscription des étudiants sco_moduleimpl.do_moduleimpl_inscrit_etuds( @@ -175,17 +186,17 @@ def external_ue_inscrit_et_note(moduleimpl_id, formsemestre_id, notes_etuds): ) -def get_existing_external_ue(formation_id): - "la liste de toutes les UE externes définies dans cette formation" +def get_existing_external_ue(formation_id: int) -> list[dict]: + "Liste de toutes les UE externes définies dans cette formation" return sco_edit_ue.ue_list(args={"formation_id": formation_id, "is_external": True}) -def get_external_moduleimpl_id(formsemestre_id, ue_id): +def get_external_moduleimpl_id(formsemestre_id: int, ue_id: int) -> int: "moduleimpl correspondant à l'UE externe indiquée de ce formsemestre" r = ndb.SimpleDictFetch( """ SELECT mi.id AS moduleimpl_id FROM notes_moduleimpl mi, notes_modules mo - WHERE mi.id = %(formsemestre_id)s + WHERE mi.formsemestre_id = %(formsemestre_id)s AND mi.module_id = mo.id AND mo.ue_id = %(ue_id)s """, @@ -194,11 +205,14 @@ def get_external_moduleimpl_id(formsemestre_id, ue_id): if r: return r[0]["moduleimpl_id"] else: - raise ScoValueError("aucun module externe ne correspond") + raise ScoValueError( + f"""Aucun module externe ne correspond + (formsemestre_id={formsemestre_id}, ue_id={ue_id})""" + ) # Web function -def external_ue_create_form(formsemestre_id, etudid): +def external_ue_create_form(formsemestre_id: int, etudid: int): """Formulaire création UE externe + inscription étudiant et saisie note - Demande UE: peut-être existante (liste les UE externes de cette formation), ou sinon spécifier titre, acronyme, type, ECTS @@ -233,7 +247,9 @@ def external_ue_create_form(formsemestre_id, etudid): html_footer = html_sco_header.sco_footer() Fo = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0] parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"]) - ue_types = parcours.ALLOWED_UE_TYPES + ue_types = [ + typ for typ in parcours.ALLOWED_UE_TYPES if typ != sco_codes_parcours.UE_SPORT + ] ue_types.sort() ue_types_names = [sco_codes_parcours.UE_TYPE_NAME[k] for k in ue_types] ue_types = [str(x) for x in ue_types] @@ -255,7 +271,7 @@ def external_ue_create_form(formsemestre_id, etudid): "input_type": "menu", "title": "UE externe existante:", "allowed_values": [""] - + [ue["ue_id"] for ue in existing_external_ue], + + [str(ue["ue_id"]) for ue in existing_external_ue], "labels": [default_label] + [ "%s (%s)" % (ue["titre"], ue["acronyme"]) @@ -337,7 +353,7 @@ def external_ue_create_form(formsemestre_id, etudid): + html_footer ) if tf[2]["existing_ue"]: - ue_id = tf[2]["existing_ue"] + ue_id = int(tf[2]["existing_ue"]) moduleimpl_id = get_external_moduleimpl_id(formsemestre_id, ue_id) else: acronyme = tf[2]["acronyme"].strip() diff --git a/app/static/js/sco_ue_external.js b/app/static/js/sco_ue_external.js index 24cd2157c..fb57807f4 100644 --- a/app/static/js/sco_ue_external.js +++ b/app/static/js/sco_ue_external.js @@ -9,19 +9,22 @@ function toggle_new_ue_form(state) { text_color = 'rgb(0,0,0)'; } - $("#tf_extue_titre td:eq(1) input").prop( "disabled", state ); - $("#tf_extue_titre td:eq(1) input").css('color', text_color) + $("#tf_extue_titre td:eq(1) input").prop("disabled", state); + $("#tf_extue_titre").css('color', text_color) - $("#tf_extue_acronyme td:eq(1) input").prop( "disabled", state ); - $("#tf_extue_acronyme td:eq(1) input").css('color', text_color) + $("#tf_extue_acronyme td:eq(1) input").prop("disabled", state); + $("#tf_extue_acronyme").css('color', text_color) - $("#tf_extue_ects td:eq(1) input").prop( "disabled", state ); - $("#tf_extue_ects td:eq(1) input").css('color', text_color) + $("#tf_extue_type td:eq(1) select").prop("disabled", state); + $("#tf_extue_type").css('color', text_color) + + $("#tf_extue_ects td:eq(1) input").prop("disabled", state); + $("#tf_extue_ects").css('color', text_color) } function update_external_ue_form() { - var state = (tf.existing_ue.value != "") + var state = (tf.existing_ue.value != ""); toggle_new_ue_form(state); } diff --git a/app/static/js/table_recap.js b/app/static/js/table_recap.js index 36426b508..fd5068e60 100644 --- a/app/static/js/table_recap.js +++ b/app/static/js/table_recap.js @@ -15,13 +15,23 @@ $(function () { }, { name: "toggle_partitions", - text: "Toutes les partitions", + text: "Montrer groupes", action: function (e, dt, node, config) { let visible = dt.columns(".partition_aux").visible()[0]; dt.columns(".partition_aux").visible(!visible); - dt.buttons('toggle_partitions:name').text(visible ? "Toutes les partitions" : "Cacher les partitions"); + dt.buttons('toggle_partitions:name').text(visible ? "Montrer groupes" : "Cacher les groupes"); } - }]; + }, + { + name: "toggle_partitions_rangs", + text: "Rangs groupes", + action: function (e, dt, node, config) { + let rangs_visible = dt.columns(".partition_rangs").visible()[0]; + dt.columns(".partition_rangs").visible(!rangs_visible); + dt.buttons('toggle_partitions_rangs:name').text(rangs_visible ? "Rangs groupes" : "Cacher rangs groupes"); + } + }, + ]; if (!$('table.table_recap').hasClass("jury")) { buttons.push( $('table.table_recap').hasClass("apc") ? @@ -95,7 +105,7 @@ $(function () { "columnDefs": [ { // cache les codes, le détail de l'identité, les groupes, les colonnes admission et les vides - targets: ["codes", "identite_detail", "partition_aux", "admission", "col_empty"], + targets: ["codes", "identite_detail", "partition_aux", "partition_rangs", "admission", "col_empty"], visible: false, }, { diff --git a/sco_version.py b/sco_version.py index 3222274fa..3de1255fd 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.2.22" +SCOVERSION = "9.2.24" SCONAME = "ScoDoc" |