forked from ScoDoc/DocScoDoc
Réglage précision des notes exportées dans Apogée
This commit is contained in:
parent
6b49c8472d
commit
bee87cf58b
@ -70,5 +70,16 @@ class CodesDecisionsForm(FlaskForm):
|
|||||||
DEM = _build_code_field("DEM")
|
DEM = _build_code_field("DEM")
|
||||||
NAR = _build_code_field("NAR")
|
NAR = _build_code_field("NAR")
|
||||||
RAT = _build_code_field("RAT")
|
RAT = _build_code_field("RAT")
|
||||||
|
NOTES_FMT = StringField(
|
||||||
|
label="Format notes exportées",
|
||||||
|
description="""Format des notes. Par défaut <tt style="font-family: monotype;">%3.2f</tt> (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")
|
submit = SubmitField("Valider")
|
||||||
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})
|
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})
|
||||||
|
@ -36,6 +36,7 @@ CODES_SCODOC_TO_APO = {
|
|||||||
DEM: "NAR",
|
DEM: "NAR",
|
||||||
NAR: "NAR",
|
NAR: "NAR",
|
||||||
RAT: "ATT",
|
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 "))
|
class_list.sort(key=lambda x: x[1].replace(" du ", " de "))
|
||||||
return [("", "")] + class_list
|
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
|
@classmethod
|
||||||
def get_code_apo(cls, code: str) -> str:
|
def get_code_apo(cls, code: str) -> str:
|
||||||
"""La représentation d'un code pour les exports Apogée.
|
"""La représentation d'un code pour les exports Apogée.
|
||||||
|
@ -83,6 +83,7 @@ XXX A vérifier:
|
|||||||
import collections
|
import collections
|
||||||
import datetime
|
import datetime
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
import functools
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import pprint
|
import pprint
|
||||||
@ -125,7 +126,7 @@ APO_SEP = "\t"
|
|||||||
APO_NEWLINE = "\r\n"
|
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: ',')"
|
"Formatte une note pour Apogée (séparateur décimal: ',')"
|
||||||
# if not note and isinstance(note, float): changé le 31/1/2022, étrange ?
|
# if not note and isinstance(note, float): changé le 31/1/2022, étrange ?
|
||||||
# return ""
|
# return ""
|
||||||
@ -133,7 +134,7 @@ def _apo_fmt_note(note):
|
|||||||
val = float(note)
|
val = float(note)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return ""
|
return ""
|
||||||
return ("%3.2f" % val).replace(".", APO_DECIMAL_SEP)
|
return (fmt % val).replace(".", APO_DECIMAL_SEP)
|
||||||
|
|
||||||
|
|
||||||
def guess_data_encoding(text, threshold=0.6):
|
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_modules = export_res_modules
|
||||||
self.export_res_sdj = export_res_sdj # export meme si pas de decision de jury
|
self.export_res_sdj = export_res_sdj # export meme si pas de decision de jury
|
||||||
self.export_res_rat = export_res_rat
|
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):
|
def __repr__(self):
|
||||||
return "ApoEtud( nom='%s', nip='%s' )" % (self["nom"], self["nip"])
|
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"])
|
ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"])
|
||||||
code_decision_ue = decisions_ue[ue["ue_id"]]["code"]
|
code_decision_ue = decisions_ue[ue["ue_id"]]["code"]
|
||||||
return dict(
|
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,
|
B=20,
|
||||||
J="",
|
J="",
|
||||||
R=ScoDocSiteConfig.get_code_apo(code_decision_ue),
|
R=ScoDocSiteConfig.get_code_apo(code_decision_ue),
|
||||||
@ -443,7 +447,7 @@ class ApoEtud(dict):
|
|||||||
].split(","):
|
].split(","):
|
||||||
n = nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
n = nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
||||||
if n != "NI" and self.export_res_modules:
|
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:
|
else:
|
||||||
module_code_found = True
|
module_code_found = True
|
||||||
if module_code_found:
|
if module_code_found:
|
||||||
@ -465,7 +469,7 @@ class ApoEtud(dict):
|
|||||||
if decision_apo == "DEF" or decision["code"] == DEM or decision["code"] == DEF:
|
if decision_apo == "DEF" or decision["code"] == DEM or decision["code"] == DEF:
|
||||||
note_str = "0,01" # note non nulle pour les démissionnaires
|
note_str = "0,01" # note non nulle pour les démissionnaires
|
||||||
else:
|
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="")
|
return dict(N=note_str, B=20, J="", R=decision_apo, M="")
|
||||||
|
|
||||||
def comp_elt_annuel(self, etudid, cur_sem, autre_sem):
|
def comp_elt_annuel(self, etudid, cur_sem, autre_sem):
|
||||||
@ -531,7 +535,7 @@ class ApoEtud(dict):
|
|||||||
moy_annuelle = (note + autre_note) / 2
|
moy_annuelle = (note + autre_note) / 2
|
||||||
except TypeError:
|
except TypeError:
|
||||||
moy_annuelle = ""
|
moy_annuelle = ""
|
||||||
note_str = _apo_fmt_note(moy_annuelle)
|
note_str = self.fmt_note(moy_annuelle)
|
||||||
|
|
||||||
if code_semestre_validant(autre_decision["code"]):
|
if code_semestre_validant(autre_decision["code"]):
|
||||||
decision_apo_annuelle = decision_apo
|
decision_apo_annuelle = decision_apo
|
||||||
|
@ -191,7 +191,7 @@ def fmt_note(val, note_max=None, keep_numeric=False):
|
|||||||
if isinstance(val, float) or isinstance(val, int):
|
if isinstance(val, float) or isinstance(val, int):
|
||||||
if np.isnan(val):
|
if np.isnan(val):
|
||||||
return "~"
|
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
|
val = val * 20.0 / note_max
|
||||||
if keep_numeric:
|
if keep_numeric:
|
||||||
return val
|
return val
|
||||||
|
@ -144,11 +144,12 @@ def config_codes_decisions():
|
|||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
for code in models.config.CODES_SCODOC_TO_APO:
|
for code in models.config.CODES_SCODOC_TO_APO:
|
||||||
ScoDocSiteConfig.set_code_apo(code, getattr(form, code).data)
|
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"))
|
return redirect(url_for("scodoc.index"))
|
||||||
elif request.method == "GET":
|
elif request.method == "GET":
|
||||||
for code in models.config.CODES_SCODOC_TO_APO:
|
for code in models.config.CODES_SCODOC_TO_APO:
|
||||||
getattr(form, code).data = ScoDocSiteConfig.get_code_apo(code)
|
getattr(form, code).data = ScoDocSiteConfig.get_code_apo(code)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"config_codes_decisions.html",
|
"config_codes_decisions.html",
|
||||||
form=form,
|
form=form,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.1.90"
|
SCOVERSION = "9.1.91"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user