From bee87cf58b9cf4bd944e31c25ada787bb95f41a9 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Tue, 5 Apr 2022 11:44:08 +0200 Subject: [PATCH] =?UTF-8?q?R=C3=A9glage=20pr=C3=A9cision=20des=20notes=20e?= =?UTF-8?q?xport=C3=A9es=20dans=20Apog=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/forms/main/config_apo.py | 11 +++++++++++ app/models/config.py | 27 +-------------------------- app/scodoc/sco_apogee_csv.py | 16 ++++++++++------ app/scodoc/sco_utils.py | 2 +- app/views/scodoc.py | 3 ++- sco_version.py | 2 +- 6 files changed, 26 insertions(+), 35 deletions(-) diff --git a/app/forms/main/config_apo.py b/app/forms/main/config_apo.py index facbf85fe..9a5e11989 100644 --- a/app/forms/main/config_apo.py +++ b/app/forms/main/config_apo.py @@ -70,5 +70,16 @@ class CodesDecisionsForm(FlaskForm): DEM = _build_code_field("DEM") NAR = _build_code_field("NAR") RAT = _build_code_field("RAT") + NOTES_FMT = StringField( + label="Format notes exportées", + description="""Format des notes. Par défaut %3.2f (deux chiffres après la virgule)""", + validators=[ + validators.Length( + max=SHORT_STR_LEN, + message=f"Le format ne doit pas dépasser {SHORT_STR_LEN} caractères", + ), + validators.DataRequired("format requis"), + ], + ) submit = SubmitField("Valider") cancel = SubmitField("Annuler", render_kw={"formnovalidate": True}) diff --git a/app/models/config.py b/app/models/config.py index 1271beeb9..53ac96e9b 100644 --- a/app/models/config.py +++ b/app/models/config.py @@ -36,6 +36,7 @@ CODES_SCODOC_TO_APO = { DEM: "NAR", NAR: "NAR", RAT: "ATT", + "NOTES_FMT": "%3.2f", } @@ -157,32 +158,6 @@ class ScoDocSiteConfig(db.Model): class_list.sort(key=lambda x: x[1].replace(" du ", " de ")) return [("", "")] + class_list - @classmethod - def get_bonus_sport_func(cls): - """Fonction bonus_sport ScoDoc 7 XXX - Transitoire pour les tests durant la transition #sco92 - """ - """returns bonus func with specified name. - If name not specified, return the configured function. - None if no bonus function configured. - Raises ScoValueError if func_name not found in module bonus_sport. - """ - from app.scodoc import bonus_sport - - c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first() - if c is None: - return None - func_name = c.value - if func_name == "": # pas de bonus défini - return None - try: - return getattr(bonus_sport, func_name) - except AttributeError: - raise ScoValueError( - f"""Fonction de calcul de l'UE bonus inexistante: "{func_name}". - (contacter votre administrateur local).""" - ) - @classmethod def get_code_apo(cls, code: str) -> str: """La représentation d'un code pour les exports Apogée. diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py index 3f979677c..d9c176eb3 100644 --- a/app/scodoc/sco_apogee_csv.py +++ b/app/scodoc/sco_apogee_csv.py @@ -83,6 +83,7 @@ XXX A vérifier: import collections import datetime from functools import reduce +import functools import io import os import pprint @@ -125,7 +126,7 @@ APO_SEP = "\t" APO_NEWLINE = "\r\n" -def _apo_fmt_note(note): +def _apo_fmt_note(note, fmt="%3.2f"): "Formatte une note pour Apogée (séparateur décimal: ',')" # if not note and isinstance(note, float): changé le 31/1/2022, étrange ? # return "" @@ -133,7 +134,7 @@ def _apo_fmt_note(note): val = float(note) except ValueError: return "" - return ("%3.2f" % val).replace(".", APO_DECIMAL_SEP) + return (fmt % val).replace(".", APO_DECIMAL_SEP) def guess_data_encoding(text, threshold=0.6): @@ -270,6 +271,9 @@ class ApoEtud(dict): self.export_res_modules = export_res_modules self.export_res_sdj = export_res_sdj # export meme si pas de decision de jury self.export_res_rat = export_res_rat + self.fmt_note = functools.partial( + _apo_fmt_note, fmt=ScoDocSiteConfig.get_code_apo("NOTES_FMT") or "3.2f" + ) def __repr__(self): return "ApoEtud( nom='%s', nip='%s' )" % (self["nom"], self["nip"]) @@ -423,7 +427,7 @@ class ApoEtud(dict): ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"]) code_decision_ue = decisions_ue[ue["ue_id"]]["code"] return dict( - N=_apo_fmt_note(ue_status["moy"] if ue_status else ""), + N=self.fmt_note(ue_status["moy"] if ue_status else ""), B=20, J="", R=ScoDocSiteConfig.get_code_apo(code_decision_ue), @@ -443,7 +447,7 @@ class ApoEtud(dict): ].split(","): n = nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid) if n != "NI" and self.export_res_modules: - return dict(N=_apo_fmt_note(n), B=20, J="", R="") + return dict(N=self.fmt_note(n), B=20, J="", R="") else: module_code_found = True if module_code_found: @@ -465,7 +469,7 @@ class ApoEtud(dict): if decision_apo == "DEF" or decision["code"] == DEM or decision["code"] == DEF: note_str = "0,01" # note non nulle pour les démissionnaires else: - note_str = _apo_fmt_note(note) + note_str = self.fmt_note(note) return dict(N=note_str, B=20, J="", R=decision_apo, M="") def comp_elt_annuel(self, etudid, cur_sem, autre_sem): @@ -531,7 +535,7 @@ class ApoEtud(dict): moy_annuelle = (note + autre_note) / 2 except TypeError: moy_annuelle = "" - note_str = _apo_fmt_note(moy_annuelle) + note_str = self.fmt_note(moy_annuelle) if code_semestre_validant(autre_decision["code"]): decision_apo_annuelle = decision_apo diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index a332037f6..0a4da781a 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -191,7 +191,7 @@ def fmt_note(val, note_max=None, keep_numeric=False): if isinstance(val, float) or isinstance(val, int): if np.isnan(val): return "~" - if note_max != None and note_max > 0: + if (note_max is not None) and note_max > 0: val = val * 20.0 / note_max if keep_numeric: return val diff --git a/app/views/scodoc.py b/app/views/scodoc.py index 70c58cede..494cf3b9c 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -144,11 +144,12 @@ def config_codes_decisions(): if form.validate_on_submit(): for code in models.config.CODES_SCODOC_TO_APO: ScoDocSiteConfig.set_code_apo(code, getattr(form, code).data) - flash(f"Codes décisions enregistrés.") + flash("Codes décisions enregistrés.") return redirect(url_for("scodoc.index")) elif request.method == "GET": for code in models.config.CODES_SCODOC_TO_APO: getattr(form, code).data = ScoDocSiteConfig.get_code_apo(code) + return render_template( "config_codes_decisions.html", form=form, diff --git a/sco_version.py b/sco_version.py index bcca3ab1b..aced26cfe 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.1.90" +SCOVERSION = "9.1.91" SCONAME = "ScoDoc"