forked from ScoDoc/ScoDoc
min/max evals sur bul. json classic. + Tests unitaires bulletin.
This commit is contained in:
parent
5018298d12
commit
ee86fba3d3
@ -101,7 +101,7 @@ Certains tests ont besoin d'un département déjà créé, qui n'est pas créé
|
|||||||
scripts de tests:
|
scripts de tests:
|
||||||
Lancer au préalable:
|
Lancer au préalable:
|
||||||
|
|
||||||
flask delete-dept TEST00 && flask create-dept TEST00
|
flask delete-dept -fy TEST00 && flask create-dept TEST00
|
||||||
|
|
||||||
Puis dérouler les tests unitaires:
|
Puis dérouler les tests unitaires:
|
||||||
|
|
||||||
|
@ -435,8 +435,6 @@ def initialize_scodoc_database(erase=False, create_all=False):
|
|||||||
SQL tables and functions.
|
SQL tables and functions.
|
||||||
If erase is True, _erase_ all database content.
|
If erase is True, _erase_ all database content.
|
||||||
"""
|
"""
|
||||||
from app import models
|
|
||||||
|
|
||||||
# - ERASE (the truncation sql function has been defined above)
|
# - ERASE (the truncation sql function has been defined above)
|
||||||
if erase:
|
if erase:
|
||||||
truncate_database()
|
truncate_database()
|
||||||
|
@ -43,6 +43,7 @@ import app.scodoc.sco_utils as scu
|
|||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_edit_ue
|
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_evaluation_db
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
@ -84,13 +85,14 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
xml_nodate=False,
|
xml_nodate=False,
|
||||||
xml_with_decisions=False, # inclue les decisions même si non publiées
|
xml_with_decisions=False, # inclue les decisions même si non publiées
|
||||||
version="long",
|
version="long",
|
||||||
):
|
) -> dict:
|
||||||
"""Dictionnaire representant les informations _publiees_ du bulletin de notes
|
"""Dictionnaire representant les informations _publiees_ du bulletin de notes
|
||||||
Utilisé pour JSON, devrait l'être aussi pour XML. (todo)
|
Utilisé pour JSON, devrait l'être aussi pour XML. (todo)
|
||||||
"""
|
"""
|
||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
|
|
||||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
|
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
||||||
etud = Identite.query.get(etudid)
|
etud = Identite.query.get(etudid)
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
@ -158,11 +160,8 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
ues = nt.get_ues_stat_dict()
|
ues = nt.get_ues_stat_dict()
|
||||||
modimpls = nt.get_modimpls_dict()
|
modimpls = nt.get_modimpls_dict()
|
||||||
nbetuds = len(nt.etud_moy_gen_ranks)
|
nbetuds = len(nt.etud_moy_gen_ranks)
|
||||||
mg = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
moy_gen = scu.fmt_note(nt.get_etud_moy_gen(etudid))
|
||||||
if (
|
if nt.get_moduleimpls_attente() or not prefs["bul_show_rangs"]:
|
||||||
nt.get_moduleimpls_attente()
|
|
||||||
or sco_preferences.get_preference("bul_show_rangs", formsemestre_id) == 0
|
|
||||||
):
|
|
||||||
# n'affiche pas le rang sur le bulletin s'il y a des
|
# n'affiche pas le rang sur le bulletin s'il y a des
|
||||||
# notes en attente dans ce semestre
|
# notes en attente dans ce semestre
|
||||||
rang = ""
|
rang = ""
|
||||||
@ -175,7 +174,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
)
|
)
|
||||||
|
|
||||||
d["note"] = dict(
|
d["note"] = dict(
|
||||||
value=mg,
|
value=moy_gen,
|
||||||
min=scu.fmt_note(nt.moy_min),
|
min=scu.fmt_note(nt.moy_min),
|
||||||
max=scu.fmt_note(nt.moy_max),
|
max=scu.fmt_note(nt.moy_max),
|
||||||
moy=scu.fmt_note(nt.moy_moy),
|
moy=scu.fmt_note(nt.moy_moy),
|
||||||
@ -217,9 +216,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
value=scu.fmt_note(ue_status["cur_moy_ue"] if ue_status else ""),
|
value=scu.fmt_note(ue_status["cur_moy_ue"] if ue_status else ""),
|
||||||
min=scu.fmt_note(ue["min"]),
|
min=scu.fmt_note(ue["min"]),
|
||||||
max=scu.fmt_note(ue["max"]),
|
max=scu.fmt_note(ue["max"]),
|
||||||
moy=scu.fmt_note(
|
moy=scu.fmt_note(ue["moy"]),
|
||||||
ue["moy"]
|
|
||||||
), # CM : ajout pour faire apparaitre la moyenne des UE
|
|
||||||
),
|
),
|
||||||
rang=rang,
|
rang=rang,
|
||||||
effectif=effectif,
|
effectif=effectif,
|
||||||
@ -259,10 +256,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
m["note"][k] = scu.fmt_note(m["note"][k])
|
m["note"][k] = scu.fmt_note(m["note"][k])
|
||||||
|
|
||||||
u["module"].append(m)
|
u["module"].append(m)
|
||||||
if (
|
if prefs["bul_show_mod_rangs"] and nt.mod_rangs is not None:
|
||||||
sco_preferences.get_preference("bul_show_mod_rangs", formsemestre_id)
|
|
||||||
and nt.mod_rangs is not None
|
|
||||||
):
|
|
||||||
m["rang"] = dict(
|
m["rang"] = dict(
|
||||||
value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid]
|
value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid]
|
||||||
)
|
)
|
||||||
@ -274,12 +268,10 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
if version != "short":
|
if version != "short":
|
||||||
for e in evals:
|
for e in evals:
|
||||||
if e["visibulletin"] or version == "long":
|
if e["visibulletin"] or version == "long":
|
||||||
val = e["notes"].get(etudid, {"value": "NP"})[
|
val = e["notes"].get(etudid, {"value": "NP"})["value"]
|
||||||
"value"
|
# nb: val est NA si etud démissionnaire
|
||||||
] # NA si etud demissionnaire
|
|
||||||
val = scu.fmt_note(val, note_max=e["note_max"])
|
val = scu.fmt_note(val, note_max=e["note_max"])
|
||||||
m["evaluation"].append(
|
eval_dict = dict(
|
||||||
dict(
|
|
||||||
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||||
heure_debut=ndb.TimetoISO8601(
|
heure_debut=ndb.TimetoISO8601(
|
||||||
e["heure_debut"], null_is_empty=True
|
e["heure_debut"], null_is_empty=True
|
||||||
@ -289,18 +281,27 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
),
|
),
|
||||||
coefficient=e["coefficient"],
|
coefficient=e["coefficient"],
|
||||||
evaluation_type=e["evaluation_type"],
|
evaluation_type=e["evaluation_type"],
|
||||||
evaluation_id=e[
|
# CM : ajout pour permettre de faire le lien sur
|
||||||
"evaluation_id"
|
# les bulletins en ligne avec l'évaluation:
|
||||||
], # CM : ajout pour permettre de faire le lien sur les bulletins en ligne avec l'évaluation
|
evaluation_id=e["evaluation_id"],
|
||||||
description=quote_xml_attr(e["description"]),
|
description=quote_xml_attr(e["description"]),
|
||||||
note=val,
|
note=val,
|
||||||
)
|
)
|
||||||
|
if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]:
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(
|
||||||
|
e["evaluation_id"]
|
||||||
)
|
)
|
||||||
|
if prefs["bul_show_minmax_eval"]:
|
||||||
|
eval_dict["min"] = scu.fmt_note(etat["mini"])
|
||||||
|
eval_dict["max"] = scu.fmt_note(etat["maxi"])
|
||||||
|
if prefs["bul_show_moypromo"]:
|
||||||
|
eval_dict["moy"] = scu.fmt_note(etat["moy"])
|
||||||
|
|
||||||
|
m["evaluation"].append(eval_dict)
|
||||||
|
|
||||||
# Evaluations incomplètes ou futures:
|
# Evaluations incomplètes ou futures:
|
||||||
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
||||||
if sco_preferences.get_preference(
|
if prefs["bul_show_all_evals"]:
|
||||||
"bul_show_all_evals", formsemestre_id
|
|
||||||
):
|
|
||||||
all_evals = sco_evaluation_db.do_evaluation_list(
|
all_evals = sco_evaluation_db.do_evaluation_list(
|
||||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
@ -344,7 +345,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# --- Absences
|
# --- Absences
|
||||||
if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
|
if prefs["bul_show_abs"]:
|
||||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||||
d["absences"] = dict(nbabs=nbabs, nbabsjust=nbabsjust)
|
d["absences"] = dict(nbabs=nbabs, nbabsjust=nbabsjust)
|
||||||
|
|
||||||
@ -403,17 +404,14 @@ def dict_decision_jury(
|
|||||||
"""
|
"""
|
||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
|
|
||||||
|
prefs = sco_preferences.SemPreferences(formsemestre.id)
|
||||||
|
|
||||||
d = {}
|
d = {}
|
||||||
if (
|
if prefs["bul_show_decision"] or with_decisions:
|
||||||
sco_preferences.get_preference("bul_show_decision", formsemestre.id)
|
|
||||||
or with_decisions
|
|
||||||
):
|
|
||||||
infos, dpv = sco_bulletins.etud_descr_situation_semestre(
|
infos, dpv = sco_bulletins.etud_descr_situation_semestre(
|
||||||
etud.id,
|
etud.id,
|
||||||
formsemestre.id,
|
formsemestre.id,
|
||||||
show_uevalid=sco_preferences.get_preference(
|
show_uevalid=prefs["bul_show_uevalid"],
|
||||||
"bul_show_uevalid", formsemestre.id
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
d["situation"] = infos["situation"]
|
d["situation"] = infos["situation"]
|
||||||
if dpv:
|
if dpv:
|
||||||
|
@ -46,11 +46,12 @@ de la forme %(XXX)s sont remplacées par la valeur de XXX, pour XXX dans:
|
|||||||
Balises img: actuellement interdites.
|
Balises img: actuellement interdites.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from flask import url_for, g
|
||||||
|
|
||||||
from reportlab.platypus import KeepTogether, Paragraph, Spacer, Table
|
from reportlab.platypus import KeepTogether, Paragraph, Spacer, Table
|
||||||
from reportlab.lib.units import cm, mm
|
from reportlab.lib.units import cm, mm
|
||||||
from reportlab.lib.colors import Color, blue
|
from reportlab.lib.colors import Color, blue
|
||||||
|
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.sco_pdf import SU, make_paras
|
from app.scodoc.sco_pdf import SU, make_paras
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
@ -434,7 +435,7 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
plusminus = pluslink
|
plusminus = pluslink
|
||||||
try:
|
try:
|
||||||
ects_txt = str(int(ue["ects"]))
|
ects_txt = str(int(ue["ects"]))
|
||||||
except:
|
except (ValueError, KeyError):
|
||||||
ects_txt = "-"
|
ects_txt = "-"
|
||||||
|
|
||||||
t = {
|
t = {
|
||||||
@ -602,12 +603,14 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|||||||
"rang": mod["mod_rang_txt"], # vide si pas option rang
|
"rang": mod["mod_rang_txt"], # vide si pas option rang
|
||||||
"note": mod["mod_moy_txt"],
|
"note": mod["mod_moy_txt"],
|
||||||
"coef": mod["mod_coef_txt"] if prefs["bul_show_coef"] else "",
|
"coef": mod["mod_coef_txt"] if prefs["bul_show_coef"] else "",
|
||||||
"abs": mod.get(
|
# vide si pas option show abs module:
|
||||||
"mod_abs_txt", ""
|
"abs": mod.get("mod_abs_txt", ""),
|
||||||
), # absent si pas option show abs module
|
"_css_row_class": f"notes_bulletin_row_mod{rowstyle}",
|
||||||
"_css_row_class": "notes_bulletin_row_mod%s" % rowstyle,
|
"_titre_target": url_for(
|
||||||
"_titre_target": "moduleimpl_status?moduleimpl_id=%s"
|
"notes.moduleimpl_status",
|
||||||
% mod["moduleimpl_id"],
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
moduleimpl_id=mod["moduleimpl_id"],
|
||||||
|
),
|
||||||
"_titre_help": mod["mod_descr_txt"],
|
"_titre_help": mod["mod_descr_txt"],
|
||||||
"_hidden": hidden,
|
"_hidden": hidden,
|
||||||
"_pdf_style": pdf_style,
|
"_pdf_style": pdf_style,
|
||||||
|
@ -2034,7 +2034,10 @@ class BasePreferences(object):
|
|||||||
if modif:
|
if modif:
|
||||||
sco_cache.invalidate_formsemestre()
|
sco_cache.invalidate_formsemestre()
|
||||||
|
|
||||||
def set(self, formsemestre_id, name, value):
|
def set(self, formsemestre_id: int, name: str, value: str):
|
||||||
|
"""Set and save a preference value.
|
||||||
|
If formsemestre_id is None, global pref.
|
||||||
|
"""
|
||||||
if not name or name[0] == "_" or name not in self.prefs_name:
|
if not name or name[0] == "_" or name not in self.prefs_name:
|
||||||
raise ValueError(f"invalid preference name: {name}")
|
raise ValueError(f"invalid preference name: {name}")
|
||||||
if formsemestre_id and name in self.prefs_only_global:
|
if formsemestre_id and name in self.prefs_only_global:
|
||||||
|
@ -39,7 +39,7 @@ from flask_login import current_user
|
|||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
from app.models import Evaluation, FormSemestre
|
from app.models import Evaluation, FormSemestre
|
||||||
from app.models import ScolarNews
|
from app.models import ModuleImpl, ScolarNews
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.sco_utils import ModuleType
|
from app.scodoc.sco_utils import ModuleType
|
||||||
@ -216,7 +216,8 @@ def do_evaluation_upload_xls():
|
|||||||
eval_id = None
|
eval_id = None
|
||||||
if eval_id != evaluation_id:
|
if eval_id != evaluation_id:
|
||||||
diag.append(
|
diag.append(
|
||||||
f"Erreur: fichier invalide: le code d'évaluation de correspond pas ! ('{eval_id_str}' != '{evaluation_id}')"
|
f"""Erreur: fichier invalide: le code d'évaluation de correspond pas ! ('{
|
||||||
|
eval_id_str}' != '{evaluation_id}')"""
|
||||||
)
|
)
|
||||||
raise InvalidNoteValue()
|
raise InvalidNoteValue()
|
||||||
# --- get notes -> list (etudid, value)
|
# --- get notes -> list (etudid, value)
|
||||||
@ -238,15 +239,14 @@ def do_evaluation_upload_xls():
|
|||||||
ni += 1
|
ni += 1
|
||||||
except:
|
except:
|
||||||
diag.append(
|
diag.append(
|
||||||
'Erreur: Ligne invalide ! (erreur ligne %d)<br>"%s"'
|
f"""Erreur: Ligne invalide ! (erreur ligne {ni})<br>{lines[ni]}"""
|
||||||
% (ni, str(lines[ni]))
|
|
||||||
)
|
)
|
||||||
raise InvalidNoteValue()
|
raise InvalidNoteValue()
|
||||||
# -- check values
|
# -- check values
|
||||||
L, invalids, withoutnotes, absents, _ = _check_notes(notes, E, M["module"])
|
L, invalids, withoutnotes, absents, _ = _check_notes(notes, E, M["module"])
|
||||||
if len(invalids):
|
if len(invalids):
|
||||||
diag.append(
|
diag.append(
|
||||||
"Erreur: la feuille contient %d notes invalides</p>" % len(invalids)
|
f"Erreur: la feuille contient {len(invalids)} notes invalides</p>"
|
||||||
)
|
)
|
||||||
if len(invalids) < 25:
|
if len(invalids) < 25:
|
||||||
etudsnames = [
|
etudsnames = [
|
||||||
@ -424,25 +424,34 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
|
|||||||
evaluation_id, by_uid=current_user.id
|
evaluation_id, by_uid=current_user.id
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise AccessDenied("Modification des notes impossible pour %s" % current_user)
|
raise AccessDenied(f"Modification des notes impossible pour {current_user}")
|
||||||
|
|
||||||
notes = [(etudid, scu.NOTES_SUPPRESS) for etudid in notes_db.keys()]
|
notes = [(etudid, scu.NOTES_SUPPRESS) for etudid in notes_db.keys()]
|
||||||
|
|
||||||
|
status_url = url_for(
|
||||||
|
"notes.moduleimpl_status",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
moduleimpl_id=E["moduleimpl_id"],
|
||||||
|
)
|
||||||
|
|
||||||
if not dialog_confirmed:
|
if not dialog_confirmed:
|
||||||
nb_changed, nb_suppress, existing_decisions = notes_add(
|
nb_changed, nb_suppress, existing_decisions = notes_add(
|
||||||
current_user, evaluation_id, notes, do_it=False, check_inscription=False
|
current_user, evaluation_id, notes, do_it=False, check_inscription=False
|
||||||
)
|
)
|
||||||
msg = (
|
msg = f"""<p>Confirmer la suppression des {nb_suppress} notes ?
|
||||||
"<p>Confirmer la suppression des %d notes ? <em>(peut affecter plusieurs groupes)</em></p>"
|
<em>(peut affecter plusieurs groupes)</em>
|
||||||
% nb_suppress
|
</p>
|
||||||
)
|
"""
|
||||||
|
|
||||||
if existing_decisions:
|
if existing_decisions:
|
||||||
msg += """<p class="warning">Important: il y a déjà des décisions de jury enregistrées, qui seront potentiellement à revoir suite à cette modification !</p>"""
|
msg += """<p class="warning">Important: il y a déjà des décisions de
|
||||||
|
jury enregistrées, qui seront potentiellement à revoir suite à
|
||||||
|
cette modification !</p>"""
|
||||||
return scu.confirm_dialog(
|
return scu.confirm_dialog(
|
||||||
msg,
|
msg,
|
||||||
dest_url="",
|
dest_url="",
|
||||||
OK="Supprimer les notes",
|
OK="Supprimer les notes",
|
||||||
cancel_url="moduleimpl_status?moduleimpl_id=%s" % E["moduleimpl_id"],
|
cancel_url=status_url,
|
||||||
parameters={"evaluation_id": evaluation_id},
|
parameters={"evaluation_id": evaluation_id},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -455,26 +464,28 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
|
|||||||
check_inscription=False,
|
check_inscription=False,
|
||||||
)
|
)
|
||||||
assert nb_changed == nb_suppress
|
assert nb_changed == nb_suppress
|
||||||
H = ["<p>%s notes supprimées</p>" % nb_suppress]
|
H = [f"""<p>{nb_suppress} notes supprimées</p>"""]
|
||||||
if existing_decisions:
|
if existing_decisions:
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="warning">Important: il y avait déjà des décisions de jury enregistrées, qui sont potentiellement à revoir suite à cette modification !</p>"""
|
"""<p class="warning">Important: il y avait déjà des décisions
|
||||||
|
de jury enregistrées, qui sont potentiellement à revoir suite
|
||||||
|
à cette modification !
|
||||||
|
</p>"""
|
||||||
)
|
)
|
||||||
H += [
|
H += [
|
||||||
'<p><a class="stdlink" href="moduleimpl_status?moduleimpl_id=%s">continuer</a>'
|
f"""<p><a class="stdlink" href="{status_url}">continuer</a>
|
||||||
% E["moduleimpl_id"]
|
"""
|
||||||
]
|
]
|
||||||
# news
|
# news
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
modimpl = ModuleImpl.query.get(E["moduleimpl_id"])
|
||||||
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
|
||||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
|
||||||
ScolarNews.add(
|
ScolarNews.add(
|
||||||
typ=ScolarNews.NEWS_NOTE,
|
typ=ScolarNews.NEWS_NOTE,
|
||||||
obj=M["moduleimpl_id"],
|
obj=modimpl.id,
|
||||||
text='Suppression des notes d\'une évaluation dans <a href="%(url)s">%(titre)s</a>'
|
text=f"""Suppression des notes d'une évaluation dans
|
||||||
% mod,
|
<a class="stdlink" href="{status_url}"
|
||||||
url=mod["url"],
|
>{modimpl.module.titre or 'module sans titre'}</a>
|
||||||
|
""",
|
||||||
|
url=status_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
return html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
|
return html_sco_header.sco_header() + "\n".join(H) + html_sco_header.sco_footer()
|
||||||
@ -555,7 +566,7 @@ def notes_add(
|
|||||||
oldval = notes_db[etudid]["value"]
|
oldval = notes_db[etudid]["value"]
|
||||||
if type(value) != type(oldval):
|
if type(value) != type(oldval):
|
||||||
changed = True
|
changed = True
|
||||||
elif type(value) == type(1.0) and (
|
elif type(value) == float and (
|
||||||
abs(value - oldval) > scu.NOTES_PRECISION
|
abs(value - oldval) > scu.NOTES_PRECISION
|
||||||
):
|
):
|
||||||
changed = True
|
changed = True
|
||||||
|
@ -651,7 +651,9 @@ def index_html():
|
|||||||
</ul>
|
</ul>
|
||||||
<h3>Référentiels de compétences</h3>
|
<h3>Référentiels de compétences</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a class="stdlink" href="{url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept)}">Liste des référentiels chargés</a>
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.refcomp_table', scodoc_dept=g.scodoc_dept)
|
||||||
|
}">Liste des référentiels chargés</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -349,6 +349,7 @@ def abort_if_false(ctx, param, value):
|
|||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
@click.option(
|
@click.option(
|
||||||
|
"-y",
|
||||||
"--yes",
|
"--yes",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
callback=abort_if_false,
|
callback=abort_if_false,
|
||||||
|
@ -38,7 +38,7 @@ def test_client():
|
|||||||
u.add_role(admin_role, TestConfig.DEPT_TEST)
|
u.add_role(admin_role, TestConfig.DEPT_TEST)
|
||||||
db.session.add(u)
|
db.session.add(u)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
# Creation département de Test
|
# Création département de Test
|
||||||
d = models.Departement(acronym=TestConfig.DEPT_TEST)
|
d = models.Departement(acronym=TestConfig.DEPT_TEST)
|
||||||
db.session.add(d)
|
db.session.add(d)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -38,14 +38,28 @@ from app.scodoc import sco_utils as scu
|
|||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
|
|
||||||
|
from tests.unit.setup import NOTES_T
|
||||||
|
|
||||||
random.seed(12345) # tests reproductibles
|
random.seed(12345) # tests reproductibles
|
||||||
|
|
||||||
|
|
||||||
NOMS_DIR = Config.SCODOC_DIR + "/tools/fakeportal/nomsprenoms"
|
NOMS_DIR = Config.SCODOC_DIR + "/tools/fakeportal/nomsprenoms"
|
||||||
NOMS = [x.strip() for x in open(NOMS_DIR + "/noms.txt").readlines()]
|
NOMS = [
|
||||||
PRENOMS_H = [x.strip() for x in open(NOMS_DIR + "/prenoms-h.txt").readlines()]
|
x.strip()
|
||||||
PRENOMS_F = [x.strip() for x in open(NOMS_DIR + "/prenoms-f.txt").readlines()]
|
for x in open(NOMS_DIR + "/noms.txt", encoding=scu.SCO_ENCODING).readlines()
|
||||||
PRENOMS_X = [x.strip() for x in open(NOMS_DIR + "/prenoms-x.txt").readlines()]
|
]
|
||||||
|
PRENOMS_H = [
|
||||||
|
x.strip()
|
||||||
|
for x in open(NOMS_DIR + "/prenoms-h.txt", encoding=scu.SCO_ENCODING).readlines()
|
||||||
|
]
|
||||||
|
PRENOMS_F = [
|
||||||
|
x.strip()
|
||||||
|
for x in open(NOMS_DIR + "/prenoms-f.txt", encoding=scu.SCO_ENCODING).readlines()
|
||||||
|
]
|
||||||
|
PRENOMS_X = [
|
||||||
|
x.strip()
|
||||||
|
for x in open(NOMS_DIR + "/prenoms-x.txt", encoding=scu.SCO_ENCODING).readlines()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
||||||
@ -297,18 +311,18 @@ class ScoFake(object):
|
|||||||
@logging_meth
|
@logging_meth
|
||||||
def create_note(
|
def create_note(
|
||||||
self,
|
self,
|
||||||
evaluation=None,
|
evaluation_id: int = None,
|
||||||
etud=None,
|
etudid: int = None,
|
||||||
note=None,
|
note=None,
|
||||||
comment=None,
|
comment: str = None,
|
||||||
user=None, # User instance
|
user: User = None, # User instance
|
||||||
):
|
):
|
||||||
if user is None:
|
if user is None:
|
||||||
user = self.default_user
|
user = self.default_user
|
||||||
return sco_saisie_notes.notes_add(
|
return sco_saisie_notes.notes_add(
|
||||||
user,
|
user,
|
||||||
evaluation["evaluation_id"],
|
evaluation_id,
|
||||||
[(etud["etudid"], note)],
|
[(etudid, note)],
|
||||||
comment=comment,
|
comment=comment,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -393,24 +407,24 @@ class ScoFake(object):
|
|||||||
eval_list.append(e)
|
eval_list.append(e)
|
||||||
return formsemestre_id, eval_list
|
return formsemestre_id, eval_list
|
||||||
|
|
||||||
def set_etud_notes_sem(
|
def set_etud_notes_evals(
|
||||||
self, sem, eval_list, etuds, notes=None, random_min=0, random_max=20
|
self, eval_list: list[dict], etuds: list[dict], notes=None
|
||||||
):
|
):
|
||||||
"""Met des notes aux étudiants indiqués des evals indiquées.
|
"""Met des notes aux étudiants indiqués des evals indiquées.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
sem: dict
|
|
||||||
eval_list: list of dicts
|
|
||||||
etuds: list of dicts
|
|
||||||
notes: liste des notes (float).
|
notes: liste des notes (float).
|
||||||
Si non spécifié, tire au hasard dans `[random_min, random_max]`
|
Si non spécifié, utilise la liste NOTES_T
|
||||||
"""
|
"""
|
||||||
set_random = notes is None
|
if notes is None:
|
||||||
|
notes = NOTES_T
|
||||||
for e in eval_list:
|
for e in eval_list:
|
||||||
if set_random:
|
for idx, etud in enumerate(etuds):
|
||||||
notes = [float(random.randint(random_min, random_max)) for _ in etuds]
|
self.create_note(
|
||||||
for etud, note in zip(etuds, notes):
|
evaluation_id=e["id"],
|
||||||
self.create_note(evaluation=e, etud=etud, note=note)
|
etudid=etud["id"],
|
||||||
|
note=notes[idx % len(notes)],
|
||||||
|
)
|
||||||
|
|
||||||
def set_code_jury(
|
def set_code_jury(
|
||||||
self,
|
self,
|
||||||
|
@ -3,12 +3,16 @@ Quelques fonctions d'initialisation pour tests unitaires
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
from app import db
|
|
||||||
from app import models
|
from app import models
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
|
|
||||||
|
# Valeurs des notes saisies par les tests:
|
||||||
|
NOTES_T = [
|
||||||
|
float(x) for x in (20, 0, 10, 13 / 7.0, 12.5, 24.0 / 11) + tuple(range(1, 19))
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def build_formation_test(
|
def build_formation_test(
|
||||||
nb_mods=1, parcours=sco_codes_parcours.ParcoursBUT, with_ue_sport=False
|
nb_mods=1, parcours=sco_codes_parcours.ParcoursBUT, with_ue_sport=False
|
||||||
|
95
tests/unit/test_bulletin.py
Normal file
95
tests/unit/test_bulletin.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
"""Tests unitaires : bulletins de notes
|
||||||
|
|
||||||
|
Utiliser comme:
|
||||||
|
pytest tests/unit/test_sco_basic.py
|
||||||
|
|
||||||
|
Au besoin, créer un base de test neuve:
|
||||||
|
./tools/create_database.sh SCODOC_TEST
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from app.models import FormSemestre, Identite
|
||||||
|
|
||||||
|
from config import TestConfig
|
||||||
|
|
||||||
|
import app
|
||||||
|
from app.scodoc import sco_bulletins_json
|
||||||
|
from app.scodoc import sco_preferences
|
||||||
|
from tests.unit import sco_fake_gen
|
||||||
|
from tests.unit import test_sco_basic
|
||||||
|
|
||||||
|
|
||||||
|
DEPT = TestConfig.DEPT_TEST
|
||||||
|
|
||||||
|
|
||||||
|
def test_bulletin(test_client):
|
||||||
|
"""Vérifications sur les bulletins de notes"""
|
||||||
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
|
app.set_sco_dept(DEPT)
|
||||||
|
formsemestre = test_sco_basic.run_sco_basic()
|
||||||
|
modimpl = formsemestre.modimpls.first()
|
||||||
|
evaluation = modimpl.evaluations.first()
|
||||||
|
# S'assure qu'on a bien une formation classique:
|
||||||
|
assert formsemestre.formation.is_apc() is False
|
||||||
|
etud: Identite = formsemestre.etuds.first()
|
||||||
|
assert etud
|
||||||
|
# Ici on a un modimpl avec 9 inscrits, 2 evals ayant toutes leurs notes
|
||||||
|
# Vérification des min/max évaluation sur le bulletin
|
||||||
|
bul = sco_bulletins_json.formsemestre_bulletinetud_published_dict(
|
||||||
|
formsemestre.id,
|
||||||
|
etud.id,
|
||||||
|
force_publishing=True,
|
||||||
|
xml_with_decisions=True,
|
||||||
|
)
|
||||||
|
assert isinstance(bul, dict)
|
||||||
|
assert bul["type"] == "classic"
|
||||||
|
modules_res = bul["ue"][0]["module"]
|
||||||
|
assert len(modules_res) == 1 # 1 seul module complet
|
||||||
|
module_res = modules_res[0]
|
||||||
|
assert modimpl.module.code == module_res["code"]
|
||||||
|
assert len(module_res["evaluation"]) == 2
|
||||||
|
note_eval_1 = module_res["evaluation"][0]
|
||||||
|
assert "note" in note_eval_1
|
||||||
|
assert "min" not in note_eval_1
|
||||||
|
assert not sco_preferences.get_preference("bul_show_minmax_eval")
|
||||||
|
# Change préférence pour avoir min/max évaluation
|
||||||
|
prefs = sco_preferences.get_base_preferences()
|
||||||
|
prefs.set(None, "bul_show_minmax_eval", True)
|
||||||
|
assert sco_preferences.get_preference("bul_show_minmax_eval")
|
||||||
|
# Redemande le bulletin
|
||||||
|
bul = sco_bulletins_json.formsemestre_bulletinetud_published_dict(
|
||||||
|
formsemestre.id,
|
||||||
|
etud.id,
|
||||||
|
force_publishing=True,
|
||||||
|
xml_with_decisions=True,
|
||||||
|
)
|
||||||
|
note_eval_1 = bul["ue"][0]["module"][0]["evaluation"][0]
|
||||||
|
assert "min" in note_eval_1
|
||||||
|
assert "max" in note_eval_1
|
||||||
|
min_eval_1 = float(note_eval_1["min"])
|
||||||
|
max_eval_1 = float(note_eval_1["max"])
|
||||||
|
# la valeur actuelle est 12.34, on s'assure qu'elle n'est pas extrême:
|
||||||
|
assert min_eval_1 > 0
|
||||||
|
assert max_eval_1 < 20
|
||||||
|
|
||||||
|
# Saisie note pour changer min/max:
|
||||||
|
# Met le max à 20:
|
||||||
|
G.create_note(evaluation_id=evaluation.id, etudid=etud.id, note=20.0)
|
||||||
|
bul = sco_bulletins_json.formsemestre_bulletinetud_published_dict(
|
||||||
|
formsemestre.id,
|
||||||
|
etud.id,
|
||||||
|
force_publishing=True,
|
||||||
|
xml_with_decisions=True,
|
||||||
|
)
|
||||||
|
note_eval_1 = bul["ue"][0]["module"][0]["evaluation"][0]
|
||||||
|
assert note_eval_1["max"] == "20.00"
|
||||||
|
# Met le min à zero:
|
||||||
|
G.create_note(evaluation_id=evaluation.id, etudid=etud.id, note=0.0)
|
||||||
|
bul = sco_bulletins_json.formsemestre_bulletinetud_published_dict(
|
||||||
|
formsemestre.id,
|
||||||
|
etud.id,
|
||||||
|
force_publishing=True,
|
||||||
|
xml_with_decisions=True,
|
||||||
|
)
|
||||||
|
note_eval_1 = bul["ue"][0]["module"][0]["evaluation"][0]
|
||||||
|
assert note_eval_1["min"] == "00.00"
|
@ -11,7 +11,6 @@ from flask import g
|
|||||||
import app
|
import app
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import Departement, ScoPreference, FormSemestre, formsemestre
|
from app.models import Departement, ScoPreference, FormSemestre, formsemestre
|
||||||
from app.scodoc import notesdb as ndb
|
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from tests.unit import test_sco_basic
|
from tests.unit import test_sco_basic
|
||||||
|
@ -108,10 +108,14 @@ def test_notes_modules(test_client):
|
|||||||
# --- Notes ordinaires
|
# --- Notes ordinaires
|
||||||
note_1 = 12.0
|
note_1 = 12.0
|
||||||
note_2 = 13.0
|
note_2 = 13.0
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etuds[0], note=note_1)
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etuds[0]["id"], note=note_1)
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etuds[0], note=note_2)
|
_, _, _ = G.create_note(evaluation_id=e2["id"], etudid=etuds[0]["id"], note=note_2)
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etuds[1], note=note_1 / 2)
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etuds[1], note=note_2 / 3)
|
evaluation_id=e1["id"], etudid=etuds[1]["id"], note=note_1 / 2
|
||||||
|
)
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["id"], etudid=etuds[1]["id"], note=note_2 / 3
|
||||||
|
)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
@ -132,16 +136,16 @@ def test_notes_modules(test_client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Absence à une évaluation
|
# Absence à une évaluation
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=None) # abs
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etudid, note=None) # abs
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etud, note=note_2)
|
_, _, _ = G.create_note(evaluation_id=e2["id"], etudid=etudid, note=note_2)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
note_th = (coef_1 * 0.0 + coef_2 * note_2) / (coef_1 + coef_2)
|
note_th = (coef_1 * 0.0 + coef_2 * note_2) / (coef_1 + coef_2)
|
||||||
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(note_th)
|
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(note_th)
|
||||||
# Absences aux deux évaluations
|
# Absences aux deux évaluations
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=None) # abs
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etudid, note=None) # abs
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etud, note=None) # abs
|
_, _, _ = G.create_note(evaluation_id=e2["id"], etudid=etudid, note=None) # abs
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
@ -156,8 +160,10 @@ def test_notes_modules(test_client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Note excusée EXC <-> scu.NOTES_NEUTRALISE
|
# Note excusée EXC <-> scu.NOTES_NEUTRALISE
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=note_1)
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etudid, note=note_1)
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etud, note=scu.NOTES_NEUTRALISE) # EXC
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
|
) # EXC
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
@ -171,8 +177,10 @@ def test_notes_modules(test_client):
|
|||||||
expected_moy_ue=note_1,
|
expected_moy_ue=note_1,
|
||||||
)
|
)
|
||||||
# Note en attente ATT <-> scu.NOTES_ATTENTE
|
# Note en attente ATT <-> scu.NOTES_ATTENTE
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=note_1)
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etudid, note=note_1)
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etud, note=scu.NOTES_ATTENTE) # ATT
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
||||||
|
) # ATT
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
@ -186,8 +194,12 @@ def test_notes_modules(test_client):
|
|||||||
expected_moy_ue=note_1,
|
expected_moy_ue=note_1,
|
||||||
)
|
)
|
||||||
# Neutralisation (EXC) des 2 évals
|
# Neutralisation (EXC) des 2 évals
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=scu.NOTES_NEUTRALISE) # EXC
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etud, note=scu.NOTES_NEUTRALISE) # EXC
|
evaluation_id=e1["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
|
) # EXC
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
|
) # EXC
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
@ -201,8 +213,12 @@ def test_notes_modules(test_client):
|
|||||||
expected_moy_ue=np.nan,
|
expected_moy_ue=np.nan,
|
||||||
)
|
)
|
||||||
# Attente (ATT) sur les 2 evals
|
# Attente (ATT) sur les 2 evals
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=scu.NOTES_ATTENTE) # ATT
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etud, note=scu.NOTES_ATTENTE) # ATT
|
evaluation_id=e1["id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
||||||
|
) # ATT
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
||||||
|
) # ATT
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
@ -261,7 +277,7 @@ def test_notes_modules(test_client):
|
|||||||
{"etudid": etudid, "moduleimpl_id": moduleimpl_id},
|
{"etudid": etudid, "moduleimpl_id": moduleimpl_id},
|
||||||
formsemestre_id=formsemestre_id,
|
formsemestre_id=formsemestre_id,
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=12.5)
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etudid, note=12.5)
|
||||||
|
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
mod_stats = nt.get_mod_stats(moduleimpl_id)
|
mod_stats = nt.get_mod_stats(moduleimpl_id)
|
||||||
@ -289,7 +305,7 @@ def test_notes_modules(test_client):
|
|||||||
description="evaluation mod 2",
|
description="evaluation mod 2",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(evaluation=e_m2, etud=etud, note=19.5)
|
_, _, _ = G.create_note(evaluation_id=e_m2["id"], etudid=etudid, note=19.5)
|
||||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
ue_status = nt.get_etud_ue_status(etudid, ue_id)
|
||||||
@ -297,12 +313,16 @@ def test_notes_modules(test_client):
|
|||||||
# Moyenne d'UE si l'un des modules est EXC ("NA")
|
# Moyenne d'UE si l'un des modules est EXC ("NA")
|
||||||
# 2 modules, notes EXC dans le premier, note valide n dans le second
|
# 2 modules, notes EXC dans le premier, note valide n dans le second
|
||||||
# la moyenne de l'UE doit être n
|
# la moyenne de l'UE doit être n
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etud, note=scu.NOTES_NEUTRALISE) # EXC
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etud, note=scu.NOTES_NEUTRALISE) # EXC
|
evaluation_id=e1["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
_, _, _ = G.create_note(evaluation=e_m2, etud=etud, note=12.5)
|
) # EXC
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etuds[1], note=11.0)
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation=e2, etud=etuds[1], note=11.0)
|
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
_, _, _ = G.create_note(evaluation=e_m2, etud=etuds[1], note=11.0)
|
) # EXC
|
||||||
|
_, _, _ = G.create_note(evaluation_id=e_m2["id"], etudid=etudid, note=12.5)
|
||||||
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etuds[1]["id"], note=11.0)
|
||||||
|
_, _, _ = G.create_note(evaluation_id=e2["id"], etudid=etuds[1]["id"], note=11.0)
|
||||||
|
_, _, _ = G.create_note(evaluation_id=e_m2["id"], etudid=etuds[1]["id"], note=11.0)
|
||||||
|
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
@ -366,8 +386,12 @@ def test_notes_modules_att_dem(test_client):
|
|||||||
coefficient=coef_1,
|
coefficient=coef_1,
|
||||||
)
|
)
|
||||||
# Attente (ATT) sur les 2 evals
|
# Attente (ATT) sur les 2 evals
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etuds[0], note=scu.NOTES_ATTENTE) # ATT
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etuds[1], note=scu.NOTES_ATTENTE) # ATT
|
evaluation_id=e1["id"], etudid=etuds[0]["id"], note=scu.NOTES_ATTENTE
|
||||||
|
) # ATT
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e1["id"], etudid=etuds[1]["id"], note=scu.NOTES_ATTENTE
|
||||||
|
) # ATT
|
||||||
# Démission du premier étudiant
|
# Démission du premier étudiant
|
||||||
sco_formsemestre_inscriptions.do_formsemestre_demission(
|
sco_formsemestre_inscriptions.do_formsemestre_demission(
|
||||||
etuds[0]["etudid"],
|
etuds[0]["etudid"],
|
||||||
@ -406,7 +430,7 @@ def test_notes_modules_att_dem(test_client):
|
|||||||
assert note_e1 == scu.NOTES_ATTENTE # XXXX un peu contestable
|
assert note_e1 == scu.NOTES_ATTENTE # XXXX un peu contestable
|
||||||
|
|
||||||
# Saisie note ABS pour le deuxième etud
|
# Saisie note ABS pour le deuxième etud
|
||||||
_, _, _ = G.create_note(evaluation=e1, etud=etuds[1], note=None) # ABS
|
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etuds[1]["id"], note=None)
|
||||||
nt = check_nt(
|
nt = check_nt(
|
||||||
etuds[1]["etudid"],
|
etuds[1]["etudid"],
|
||||||
sem["formsemestre_id"],
|
sem["formsemestre_id"],
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
"""Test calculs rattrapages
|
"""Test calculs rattrapages
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import g
|
|
||||||
|
|
||||||
import app
|
import app
|
||||||
from app.but.bulletin_but import *
|
|
||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_but import ResultatsSemestreBUT
|
from app.comp.res_but import ResultatsSemestreBUT
|
||||||
from app.models import ModuleImpl
|
from app.models import FormSemestre, ModuleImpl
|
||||||
from app.scodoc import (
|
from app.scodoc import (
|
||||||
sco_bulletins,
|
sco_bulletins,
|
||||||
sco_evaluation_db,
|
sco_evaluation_db,
|
||||||
@ -75,8 +73,8 @@ def test_notes_rattrapage(test_client):
|
|||||||
evaluation_type=scu.EVALUATION_RATTRAPAGE,
|
evaluation_type=scu.EVALUATION_RATTRAPAGE,
|
||||||
)
|
)
|
||||||
etud = etuds[0]
|
etud = etuds[0]
|
||||||
_, _, _ = G.create_note(evaluation=e, etud=etud, note=12.0)
|
_, _, _ = G.create_note(evaluation_id=e["id"], etudid=etud["id"], note=12.0)
|
||||||
_, _, _ = G.create_note(evaluation=e_rat, etud=etud, note=11.0)
|
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["id"], note=11.0)
|
||||||
|
|
||||||
# --- Vérifications internes structures ScoDoc
|
# --- Vérifications internes structures ScoDoc
|
||||||
formsemestre = FormSemestre.query.get(formsemestre_id)
|
formsemestre = FormSemestre.query.get(formsemestre_id)
|
||||||
@ -100,21 +98,21 @@ def test_notes_rattrapage(test_client):
|
|||||||
# Note moyenne: ici le ratrapage est inférieur à la note:
|
# Note moyenne: ici le ratrapage est inférieur à la note:
|
||||||
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(12.0)
|
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(12.0)
|
||||||
# rattrapage > moyenne:
|
# rattrapage > moyenne:
|
||||||
_, _, _ = G.create_note(evaluation=e_rat, etud=etud, note=18.0)
|
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["id"], note=18.0)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(18.0)
|
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(18.0)
|
||||||
# rattrapage vs absences
|
# rattrapage vs absences
|
||||||
_, _, _ = G.create_note(evaluation=e, etud=etud, note=None) # abs
|
_, _, _ = G.create_note(evaluation_id=e["id"], etudid=etud["id"], note=None) # abs
|
||||||
_, _, _ = G.create_note(evaluation=e_rat, etud=etud, note=17.0)
|
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["id"], note=17.0)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(17.0)
|
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(17.0)
|
||||||
# et sans note de rattrapage
|
# et sans note de rattrapage
|
||||||
_, _, _ = G.create_note(evaluation=e, etud=etud, note=10.0) # abs
|
_, _, _ = G.create_note(evaluation_id=e["id"], etudid=etud["id"], note=10.0)
|
||||||
_, _, _ = G.create_note(evaluation=e_rat, etud=etud, note=None)
|
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["id"], note=None)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
@ -156,21 +154,25 @@ def test_notes_rattrapage(test_client):
|
|||||||
assert len(mod_res.get_evaluations_completes(moduleimpl)) == 2
|
assert len(mod_res.get_evaluations_completes(moduleimpl)) == 2
|
||||||
|
|
||||||
# Saisie note session 2:
|
# Saisie note session 2:
|
||||||
_, _, _ = G.create_note(evaluation=e_session2, etud=etud, note=5.0)
|
_, _, _ = G.create_note(evaluation_id=e_session2["id"], etudid=etud["id"], note=5.0)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
# Note moyenne: utilise session 2 même si inférieure
|
# Note moyenne: utilise session 2 même si inférieure
|
||||||
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(5.0)
|
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(5.0)
|
||||||
|
|
||||||
_, _, _ = G.create_note(evaluation=e_session2, etud=etud, note=20.0)
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e_session2["id"], etudid=etud["id"], note=20.0
|
||||||
|
)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
# Note moyenne: utilise session 2 même si inférieure
|
# Note moyenne: utilise session 2 même si inférieure
|
||||||
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(20.0)
|
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(20.0)
|
||||||
|
|
||||||
_, _, _ = G.create_note(evaluation=e_session2, etud=etud, note=None)
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e_session2["id"], etudid=etud["id"], note=None
|
||||||
|
)
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
)
|
)
|
||||||
|
@ -11,12 +11,11 @@ Au besoin, créer un base de test neuve:
|
|||||||
./tools/create_database.sh SCODOC_TEST
|
./tools/create_database.sh SCODOC_TEST
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import random
|
|
||||||
|
|
||||||
from app.models import FormSemestreInscription, Identite
|
from app.models import FormSemestreInscription, Identite
|
||||||
|
|
||||||
from config import TestConfig
|
from config import TestConfig
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
|
from tests.unit.setup import NOTES_T
|
||||||
|
|
||||||
import app
|
import app
|
||||||
from app import db
|
from app import db
|
||||||
@ -33,7 +32,6 @@ from app.scodoc import sco_evaluation_db
|
|||||||
from app.scodoc import sco_formsemestre_validation
|
from app.scodoc import sco_formsemestre_validation
|
||||||
from app.scodoc import sco_cursus_dut
|
from app.scodoc import sco_cursus_dut
|
||||||
from app.scodoc import sco_saisie_notes
|
from app.scodoc import sco_saisie_notes
|
||||||
from app.scodoc import sco_utils as scu
|
|
||||||
|
|
||||||
DEPT = TestConfig.DEPT_TEST
|
DEPT = TestConfig.DEPT_TEST
|
||||||
|
|
||||||
@ -47,9 +45,10 @@ def test_sco_basic(test_client):
|
|||||||
run_sco_basic()
|
run_sco_basic()
|
||||||
|
|
||||||
|
|
||||||
def run_sco_basic(verbose=False):
|
def run_sco_basic(verbose=False) -> FormSemestre:
|
||||||
"""Scénario de base: création formation, semestre, étudiants, notes,
|
"""Scénario de base: création formation, semestre, étudiants, notes,
|
||||||
décisions jury
|
décisions jury
|
||||||
|
Renvoie le formsemestre créé.
|
||||||
"""
|
"""
|
||||||
G = sco_fake_gen.ScoFake(verbose=verbose)
|
G = sco_fake_gen.ScoFake(verbose=verbose)
|
||||||
|
|
||||||
@ -91,11 +90,11 @@ def run_sco_basic(verbose=False):
|
|||||||
)
|
)
|
||||||
assert q.count() == 1
|
assert q.count() == 1
|
||||||
ins = q.first()
|
ins = q.first()
|
||||||
assert ins.etape == None
|
assert ins.etape is None
|
||||||
assert ins.etat == "I"
|
assert ins.etat == "I"
|
||||||
assert ins.parcour == None
|
assert ins.parcour is None
|
||||||
|
|
||||||
# --- Creation évaluation
|
# --- Création évaluation
|
||||||
e = G.create_evaluation(
|
e = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2020",
|
jour="01/01/2020",
|
||||||
@ -104,10 +103,13 @@ def run_sco_basic(verbose=False):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# --- Saisie toutes les notes de l'évaluation
|
# --- Saisie toutes les notes de l'évaluation
|
||||||
for etud in etuds:
|
for idx, etud in enumerate(etuds):
|
||||||
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
evaluation=e, etud=etud, note=float(random.randint(0, 20))
|
evaluation_id=e["id"], etudid=etud["id"], note=NOTES_T[idx % len(NOTES_T)]
|
||||||
)
|
)
|
||||||
|
assert not existing_decisions
|
||||||
|
assert nb_suppress == 0
|
||||||
|
assert nb_changed == 1
|
||||||
|
|
||||||
# --- Vérifie que les notes sont prises en compte:
|
# --- Vérifie que les notes sont prises en compte:
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(formsemestre_id, etud["etudid"])
|
b = sco_bulletins.formsemestre_bulletinetud_dict(formsemestre_id, etud["etudid"])
|
||||||
@ -132,13 +134,13 @@ def run_sco_basic(verbose=False):
|
|||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
# Saisie les notes des 5 premiers étudiants:
|
# Saisie les notes des 5 premiers étudiants:
|
||||||
for etud in etuds[:5]:
|
for idx, etud in enumerate(etuds[:5]):
|
||||||
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
evaluation=e2, etud=etud, note=float(random.randint(0, 20))
|
evaluation_id=e2["id"], etudid=etud["id"], note=NOTES_T[idx % len(NOTES_T)]
|
||||||
)
|
)
|
||||||
# Cette éval n'est pas complète
|
# Cette éval n'est pas complète
|
||||||
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
||||||
assert etat["evalcomplete"] == False
|
assert etat["evalcomplete"] is False
|
||||||
# la première éval est toujours complète:
|
# la première éval est toujours complète:
|
||||||
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
||||||
assert etat["evalcomplete"]
|
assert etat["evalcomplete"]
|
||||||
@ -147,14 +149,14 @@ def run_sco_basic(verbose=False):
|
|||||||
e2["publish_incomplete"] = True
|
e2["publish_incomplete"] = True
|
||||||
sco_evaluation_db.do_evaluation_edit(e2)
|
sco_evaluation_db.do_evaluation_edit(e2)
|
||||||
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
||||||
assert etat["evalcomplete"] == False
|
assert etat["evalcomplete"] is False
|
||||||
assert etat["nb_att"] == 0 # il n'y a pas de notes (explicitement) en attente
|
assert etat["nb_att"] == 0 # il n'y a pas de notes (explicitement) en attente
|
||||||
assert etat["evalattente"] # mais l'eval est en attente (prise en compte immédiate)
|
assert etat["evalattente"] # mais l'eval est en attente (prise en compte immédiate)
|
||||||
|
|
||||||
# Saisie des notes qui manquent:
|
# Saisie des notes qui manquent:
|
||||||
for etud in etuds[5:]:
|
for idx, etud in enumerate(etuds[5:]):
|
||||||
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
nb_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
evaluation=e2, etud=etud, note=float(random.randint(0, 20))
|
evaluation_id=e2["id"], etudid=etud["id"], note=NOTES_T[idx % len(NOTES_T)]
|
||||||
)
|
)
|
||||||
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
||||||
assert etat["evalcomplete"]
|
assert etat["evalcomplete"]
|
||||||
@ -173,7 +175,10 @@ def run_sco_basic(verbose=False):
|
|||||||
assert f'{etat["nb_inscrits"]} notes changées' in ans
|
assert f'{etat["nb_inscrits"]} notes changées' in ans
|
||||||
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
||||||
assert etat["evalcomplete"]
|
assert etat["evalcomplete"]
|
||||||
# --- Saisie absences
|
|
||||||
|
# -----------------------
|
||||||
|
# --- Saisie absences ---
|
||||||
|
# -----------------------
|
||||||
etudid = etuds[0]["etudid"]
|
etudid = etuds[0]["etudid"]
|
||||||
|
|
||||||
_ = sco_abs_views.doSignaleAbsence(
|
_ = sco_abs_views.doSignaleAbsence(
|
||||||
@ -188,8 +193,8 @@ def run_sco_basic(verbose=False):
|
|||||||
)
|
)
|
||||||
|
|
||||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||||
assert nbabs == 6, "incorrect nbabs (%d)" % nbabs
|
assert nbabs == 6, f"incorrect nbabs ({nbabs})"
|
||||||
assert nbabsjust == 2, "incorrect nbabsjust (%s)" % nbabsjust
|
assert nbabsjust == 2, f"incorrect nbabsjust ({nbabsjust})"
|
||||||
|
|
||||||
# --- Permission saisie notes et décisions de jury, avec ou sans démission ou défaillance
|
# --- Permission saisie notes et décisions de jury, avec ou sans démission ou défaillance
|
||||||
# on n'a pas encore saisi de décisions
|
# on n'a pas encore saisi de décisions
|
||||||
@ -227,7 +232,7 @@ def run_sco_basic(verbose=False):
|
|||||||
for ue_id in dec_ues:
|
for ue_id in dec_ues:
|
||||||
assert dec_ues[ue_id]["code"] in {"ADM", "CMP"}
|
assert dec_ues[ue_id]["code"] in {"ADM", "CMP"}
|
||||||
|
|
||||||
# ---- Suppression étudiant, vérification inscription
|
# ---- Suppression d'un étudiant, vérification inscription
|
||||||
# (permet de tester les cascades)
|
# (permet de tester les cascades)
|
||||||
etud = Identite.query.get(etuds[0]["id"])
|
etud = Identite.query.get(etuds[0]["id"])
|
||||||
assert etud is not None
|
assert etud is not None
|
||||||
@ -239,3 +244,4 @@ def run_sco_basic(verbose=False):
|
|||||||
etudid=etudid, formsemestre_id=formsemestre_id
|
etudid=etudid, formsemestre_id=formsemestre_id
|
||||||
)
|
)
|
||||||
assert q.count() == 0
|
assert q.count() == 0
|
||||||
|
return formsemestre
|
||||||
|
Loading…
Reference in New Issue
Block a user