Edition des évaluations, nettoyage code, fix #799. Tests OK.

This commit is contained in:
Emmanuel Viennet 2024-02-26 17:20:36 +01:00
parent ee601071f5
commit bc5292b165
8 changed files with 217 additions and 239 deletions

View File

@ -91,7 +91,7 @@ class Evaluation(models.ScoDocModel):
evaluation_type=None,
numero=None,
**kw, # ceci pour absorber les éventuel arguments excedentaires
):
) -> "Evaluation":
"""Create an evaluation. Check permission and all arguments.
Ne crée pas les poids vers les UEs.
Add to session, do not commit.
@ -103,7 +103,7 @@ class Evaluation(models.ScoDocModel):
args = locals()
del args["cls"]
del args["kw"]
check_convert_evaluation_args(moduleimpl, args)
check_and_convert_evaluation_args(args, moduleimpl)
# Check numeros
Evaluation.moduleimpl_evaluation_renumber(moduleimpl, only_if_unumbered=True)
if not "numero" in args or args["numero"] is None:
@ -254,15 +254,6 @@ class Evaluation(models.ScoDocModel):
return e_dict
def convert_dict_fields(self, args: dict) -> dict:
"""Convert fields in the given dict. No other side effect.
returns: dict to store in model's db.
"""
check_convert_evaluation_args(self.moduleimpl, args)
if args.get("numero") is None:
args["numero"] = Evaluation.get_max_numero(self.moduleimpl.id) + 1
return args
@classmethod
def get_evaluation(
cls, evaluation_id: int | str, dept_id: int = None
@ -568,7 +559,7 @@ def evaluation_enrich_dict(e: Evaluation, e_dict: dict):
return e_dict
def check_convert_evaluation_args(moduleimpl: "ModuleImpl", data: dict):
def check_and_convert_evaluation_args(data: dict, moduleimpl: "ModuleImpl"):
"""Check coefficient, dates and duration, raises exception if invalid.
Convert date and time strings to date and time objects.
@ -608,7 +599,7 @@ def check_convert_evaluation_args(moduleimpl: "ModuleImpl", data: dict):
if coef < 0:
raise ScoValueError("invalid coefficient value (must be positive or null)")
data["coefficient"] = coef
# --- date de l'évaluation
# --- date de l'évaluation dans le semestre ?
formsemestre = moduleimpl.formsemestre
date_debut = data.get("date_debut", None)
if date_debut:

View File

@ -31,96 +31,15 @@
import flask
from flask import url_for, g
from flask_login import current_user
import sqlalchemy as sa
from app import db, log
from app.models import Evaluation
from app.models.evaluations import check_convert_evaluation_args
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc.sco_exceptions import AccessDenied
from app.scodoc import sco_cache
from app.scodoc import sco_moduleimpl
_evaluationEditor = ndb.EditableTable(
"notes_evaluation",
"evaluation_id",
(
"evaluation_id",
"moduleimpl_id",
"date_debut",
"date_fin",
"description",
"note_max",
"coefficient",
"visibulletin",
"publish_incomplete",
"evaluation_type",
"numero",
),
sortkey="numero, date_debut desc", # plus recente d'abord
output_formators={
"numero": ndb.int_null_is_zero,
},
input_formators={
"visibulletin": bool,
"publish_incomplete": bool,
"evaluation_type": int,
},
)
def get_evaluations_dict(args: dict) -> list[dict]:
"""Liste evaluations, triées numero (or most recent date first).
Fonction de transition pour ancien code ScoDoc7.
Ajoute les champs:
'duree' : '2h30'
'matin' : 1 (commence avant 12:00) ou 0
'apresmidi' : 1 (termine après 12:00) ou 0
'descrheure' : ' de 15h00 à 16h30'
"""
# calcule duree (chaine de car.) de chaque evaluation et ajoute jour_iso, matin, apresmidi
return [
e.to_dict()
for e in Evaluation.query.filter_by(**args).order_by(
sa.desc(Evaluation.numero), sa.desc(Evaluation.date_debut)
)
]
def do_evaluation_list_in_formsemestre(formsemestre_id):
"list evaluations in this formsemestre"
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
evals = []
for modimpl in mods:
evals += get_evaluations_dict(args={"moduleimpl_id": modimpl["moduleimpl_id"]})
return evals
def do_evaluation_edit(args):
"edit an evaluation"
evaluation_id = args["evaluation_id"]
evaluation: Evaluation = db.session.get(Evaluation, evaluation_id)
if evaluation is None:
raise ValueError("evaluation inexistante !")
if not evaluation.moduleimpl.can_edit_evaluation(current_user):
raise AccessDenied(
f"Modification évaluation impossible pour {current_user.get_nomplogin()}"
)
args["moduleimpl_id"] = evaluation.moduleimpl.id
check_convert_evaluation_args(evaluation.moduleimpl, args)
cnx = ndb.GetDBConnexion()
_evaluationEditor.edit(cnx, args)
# inval cache pour ce semestre
sco_cache.invalidate_formsemestre(
formsemestre_id=evaluation.moduleimpl.formsemestre_id
)
# ancien _notes_getall

View File

@ -31,14 +31,12 @@ import datetime
import time
import flask
from flask import url_for, render_template
from flask import g
from flask import g, render_template, request, url_for
from flask_login import current_user
from flask import request
from app import db
from app.models import Evaluation, Module, ModuleImpl
from app.models.evaluations import heure_to_time
from app.models.evaluations import heure_to_time, check_and_convert_evaluation_args
import app.scodoc.sco_utils as scu
from app.scodoc.sco_utils import ModuleType
@ -383,6 +381,8 @@ def evaluation_create_form(
raise ScoValueError("Date (j/m/a) invalide") from exc
else:
date_debut = None
args["date_debut"] = date_debut
args["date_fin"] = date_debut # même jour
args.pop("jour", None)
if date_debut and args.get("heure_debut"):
try:
@ -415,6 +415,7 @@ def evaluation_create_form(
args["blocked_until"] = None
#
if edit:
check_and_convert_evaluation_args(args, modimpl)
evaluation.from_dict(args)
else:
# création d'une evaluation

View File

@ -31,6 +31,7 @@ import flask
from flask import url_for, flash, redirect
from flask import g, request
from flask_login import current_user
import sqlalchemy as sa
from app import db
from app.auth.models import User
@ -63,8 +64,6 @@ from app.scodoc import html_sco_header
from app.scodoc import codes_cursus
from app.scodoc import sco_compute_moy
from app.scodoc import sco_edit_module
from app.scodoc import sco_edit_ue
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups_copy
from app.scodoc import sco_modalites
@ -1113,7 +1112,8 @@ def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
f"""<b>impossible de supprimer {module.code} ({module.titre or ""})
car il y a {nb_evals} évaluations définies
(<a href="{
url_for("notes.moduleimpl_status", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
url_for("notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
}" class="stdlink">supprimez-les d\'abord</a>)</b>"""
]
ok = False
@ -1233,7 +1233,11 @@ def formsemestre_clone(formsemestre_id):
return "".join(H) + msg + tf[1] + html_sco_header.sco_footer()
elif tf[0] == -1: # cancel
return flask.redirect(
"formsemestre_status?formsemestre_id=%s" % formsemestre_id
url_for(
"notes.formsemestre_status",
scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id,
)
)
else:
resp = User.get_user_from_nomplogin(tf[2]["responsable_id"])
@ -1356,9 +1360,9 @@ def do_formsemestre_clone(
return formsemestre_id
def formsemestre_delete(formsemestre_id):
def formsemestre_delete(formsemestre_id: int) -> str | flask.Response:
"""Delete a formsemestre (affiche avertissements)"""
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
formsemestre: FormSemestre = FormSemestre.get_formsemestre(formsemestre_id)
H = [
html_sco_header.html_sem_header("Suppression du semestre"),
"""<div class="ue_warning"><span>Attention !</span>
@ -1376,17 +1380,18 @@ Ceci n'est possible que si :
</ol>
</div>""",
]
evals = sco_evaluation_db.do_evaluation_list_in_formsemestre(formsemestre_id)
if evals:
evaluations = (
Evaluation.query.join(ModuleImpl)
.filter_by(formsemestre_id=formsemestre.id)
.all()
)
if evaluations:
H.append(
f"""<p class="warning">Attention: il y a {len(evals)} évaluations
f"""<p class="warning">Attention: il y a {len(evaluations)} évaluations
dans ce semestre
(sa suppression entrainera l'effacement définif des notes) !</p>"""
)
submit_label = (
f"Confirmer la suppression (du semestre et des {len(evals)} évaluations !)"
)
submit_label = f"Confirmer la suppression (du semestre et des {len(evaluations)} évaluations !)"
else:
submit_label = "Confirmer la suppression du semestre"
tf = TrivialFormulator(
@ -1413,8 +1418,10 @@ Ceci n'est possible que si :
)
else:
H.append(tf[1])
return "\n".join(H) + html_sco_header.sco_footer()
elif tf[0] == -1: # cancel
if tf[0] == -1: # cancel
return flask.redirect(
url_for(
"notes.formsemestre_status",
@ -1422,10 +1429,9 @@ Ceci n'est possible que si :
formsemestre_id=formsemestre_id,
)
)
else:
return flask.redirect(
"formsemestre_delete2?formsemestre_id=" + str(formsemestre_id)
)
return flask.redirect(
"formsemestre_delete2?formsemestre_id=" + str(formsemestre_id)
)
def formsemestre_delete2(formsemestre_id, dialog_confirmed=False):
@ -1486,106 +1492,165 @@ def formsemestre_has_decisions_or_compensations(
return False, ""
def do_formsemestre_delete(formsemestre_id):
def do_formsemestre_delete(formsemestre_id: int):
"""delete formsemestre, and all its moduleimpls.
No checks, no warnings: erase all !
"""
cnx = ndb.GetDBConnexion()
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sco_cache.EvaluationCache.invalidate_sem(formsemestre_id)
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
sco_cache.EvaluationCache.invalidate_sem(formsemestre.id)
titre_sem = formsemestre.titre_annee()
# --- Destruction des modules de ce semestre
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
for mod in mods:
for modimpl in formsemestre.modimpls:
# evaluations
evals = sco_evaluation_db.get_evaluations_dict(
args={"moduleimpl_id": mod["moduleimpl_id"]}
)
for e in evals:
ndb.SimpleQuery(
"DELETE FROM notes_notes WHERE evaluation_id=%(evaluation_id)s",
e,
for e in modimpl.evaluations:
db.session.execute(
sa.text(
"""DELETE FROM notes_notes WHERE evaluation_id=:evaluation_id"""
),
{"evaluation_id": e.id},
)
ndb.SimpleQuery(
"DELETE FROM notes_notes_log WHERE evaluation_id=%(evaluation_id)s",
e,
)
ndb.SimpleQuery(
"DELETE FROM notes_evaluation WHERE id=%(evaluation_id)s",
e,
db.session.execute(
sa.text(
"""DELETE FROM notes_notes_log WHERE evaluation_id=:evaluation_id"""
),
{"evaluation_id": e.id},
)
sco_moduleimpl.do_moduleimpl_delete(
mod["moduleimpl_id"], formsemestre_id=formsemestre_id
)
db.session.delete(e)
db.session.delete(modimpl)
# --- Desinscription des etudiants
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
req = "DELETE FROM notes_formsemestre_inscription WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM notes_formsemestre_inscription WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des evenements
req = "DELETE FROM scolar_events WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text("DELETE FROM scolar_events WHERE formsemestre_id=:formsemestre_id"),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des appreciations
req = "DELETE FROM notes_appreciations WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM notes_appreciations WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Supression des validations (!!!)
req = "DELETE FROM scolar_formsemestre_validation WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM scolar_formsemestre_validation WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Supression des references a ce semestre dans les compensations:
req = "UPDATE scolar_formsemestre_validation SET compense_formsemestre_id=NULL WHERE compense_formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"""UPDATE scolar_formsemestre_validation
SET compense_formsemestre_id=NULL
WHERE compense_formsemestre_id=:formsemestre_id"""
),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des autorisations
req = "DELETE FROM scolar_autorisation_inscription WHERE origin_formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM scolar_autorisation_inscription WHERE origin_formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des coefs d'UE capitalisées
req = "DELETE FROM notes_formsemestre_uecoef WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM notes_formsemestre_uecoef WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des item du menu custom
req = "DELETE FROM notes_formsemestre_custommenu WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM notes_formsemestre_custommenu WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des formules
req = "DELETE FROM notes_formsemestre_ue_computation_expr WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM notes_formsemestre_ue_computation_expr WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des preferences
req = "DELETE FROM sco_prefs WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text("DELETE FROM sco_prefs WHERE formsemestre_id=:formsemestre_id"),
{"formsemestre_id": formsemestre_id},
)
# --- Suppression des groupes et partitions
req = """DELETE FROM group_membership
db.session.execute(
sa.text(
"""
DELETE FROM group_membership
WHERE group_id IN
(SELECT gm.group_id FROM group_membership gm, partition p, group_descr gd
WHERE gm.group_id = gd.id AND gd.partition_id = p.id
AND p.formsemestre_id=%(formsemestre_id)s)
AND p.formsemestre_id=:formsemestre_id)
"""
cursor.execute(req, {"formsemestre_id": formsemestre_id})
req = """DELETE FROM group_descr
),
{"formsemestre_id": formsemestre_id},
)
db.session.execute(
sa.text(
"""
DELETE FROM group_descr
WHERE id IN
(SELECT gd.id FROM group_descr gd, partition p
WHERE gd.partition_id = p.id
AND p.formsemestre_id=%(formsemestre_id)s)
AND p.formsemestre_id=:formsemestre_id)
"""
cursor.execute(req, {"formsemestre_id": formsemestre_id})
req = "DELETE FROM partition WHERE formsemestre_id=%(formsemestre_id)s"
cursor.execute(req, {"formsemestre_id": formsemestre_id})
),
{"formsemestre_id": formsemestre_id},
)
db.session.execute(
sa.text("DELETE FROM partition WHERE formsemestre_id=:formsemestre_id"),
{"formsemestre_id": formsemestre_id},
)
# --- Responsables
req = """DELETE FROM notes_formsemestre_responsables
WHERE formsemestre_id=%(formsemestre_id)s"""
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM notes_formsemestre_responsables WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Etapes
req = """DELETE FROM notes_formsemestre_etapes
WHERE formsemestre_id=%(formsemestre_id)s"""
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text(
"DELETE FROM notes_formsemestre_etapes WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- SemSets
db.session.execute(
sa.text(
"DELETE FROM notes_semset_formsemestre WHERE formsemestre_id=:formsemestre_id"
),
{"formsemestre_id": formsemestre_id},
)
# --- Dispenses d'UE
req = """DELETE FROM "dispenseUE" WHERE formsemestre_id=%(formsemestre_id)s"""
cursor.execute(req, {"formsemestre_id": formsemestre_id})
db.session.execute(
sa.text("""DELETE FROM "dispenseUE" WHERE formsemestre_id=:formsemestre_id"""),
{"formsemestre_id": formsemestre_id},
)
# --- Destruction du semestre
sco_formsemestre._formsemestreEditor.delete(cnx, formsemestre_id)
db.session.delete(formsemestre)
# news
ScolarNews.add(
typ=ScolarNews.NEWS_SEM,
obj=formsemestre_id,
text="Suppression du semestre %(titre)s" % sem,
text=f"Suppression du semestre {titre_sem}",
max_frequency=0,
)

View File

@ -91,7 +91,9 @@ def do_moduleimpl_delete(oid, formsemestre_id=None):
) # > moduleimpl_delete
def moduleimpl_list(moduleimpl_id=None, formsemestre_id=None, module_id=None):
def moduleimpl_list(
moduleimpl_id=None, formsemestre_id=None, module_id=None
) -> list[dict]:
"list moduleimpls"
args = locals()
cnx = ndb.GetDBConnexion()

View File

@ -48,20 +48,17 @@ from wtforms import (
HiddenField,
SelectMultipleField,
)
from app.models import ModuleImpl
from app.models import Evaluation, ModuleImpl
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app import ScoValueError
from app.scodoc import html_sco_header, sco_preferences
from app.scodoc import sco_edit_module
from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_excel
from app.scodoc.sco_excel import ScoExcelBook, COLORS
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_permissions_check
from app.scodoc.gen_tables import GenTable
from app.scodoc import sco_etud
import sco_version
@ -138,11 +135,7 @@ class PlacementForm(FlaskForm):
def set_evaluation_infos(self, evaluation_id):
"""Initialise les données du formulaire avec les données de l'évaluation."""
eval_data = sco_evaluation_db.get_evaluations_dict(
{"evaluation_id": evaluation_id}
)
if not eval_data:
raise ScoValueError("invalid evaluation_id")
_ = Evaluation.get_evaluation(evaluation_id) # check exist ?
self.groups_tree, self.has_groups, self.nb_groups = _get_group_info(
evaluation_id
)
@ -239,14 +232,12 @@ class PlacementRunner:
self.groups_ids = [
gid if gid != TOUS else form.tous_id for gid in form["groups"].data
]
self.eval_data = sco_evaluation_db.get_evaluations_dict(
{"evaluation_id": self.evaluation_id}
)[0]
self.evaluation = Evaluation.get_evaluation(self.evaluation_id)
self.groups = sco_groups.listgroups(self.groups_ids)
self.gr_title_filename = sco_groups.listgroups_filename(self.groups)
# gr_title = sco_groups.listgroups_abbrev(d['groups'])
self.current_user = current_user
self.moduleimpl_id = self.eval_data["moduleimpl_id"]
self.moduleimpl_id = self.evaluation.moduleimpl_id
self.moduleimpl: ModuleImpl = ModuleImpl.query.get_or_404(self.moduleimpl_id)
# TODO: à revoir pour utiliser modèle ModuleImpl
self.moduleimpl_data = sco_moduleimpl.moduleimpl_list(
@ -260,20 +251,25 @@ class PlacementRunner:
)
self.evalname = "%s-%s" % (
self.module_data["code"] or "?",
ndb.DateDMYtoISO(self.eval_data["jour"]),
(
self.evaluation.date_debut.strftime("%Y-%m-%d_%Hh%M")
if self.evaluation.date_debut
else ""
),
)
if self.eval_data["description"]:
self.evaltitre = self.eval_data["description"]
if self.evaluation.description:
self.evaltitre = self.evaluation.description
else:
self.evaltitre = "évaluation du %s" % self.eval_data["jour"]
self.evaltitre = f"""évaluation{
self.evaluation.date_debut.strftime(' du %d/%m/%Y à %Hh%M')
if self.evaluation.date_debut else ''}"""
self.desceval = [ # une liste de chaines: description de l'evaluation
"%s" % self.sem["titreannee"],
self.sem["titreannee"],
"Module : %s - %s"
% (self.module_data["code"] or "?", self.module_data["abbrev"] or ""),
"Surveillants : %s" % self.surveillants,
"Batiment : %(batiment)s - Salle : %(salle)s" % self.__dict__,
"Controle : %s (coef. %g)"
% (self.evaltitre, self.eval_data["coefficient"]),
"Controle : %s (coef. %g)" % (self.evaltitre, self.evaluation.coefficient),
]
self.styles = None
self.plan = None
@ -339,10 +335,10 @@ class PlacementRunner:
def _production_pdf(self):
pdf_title = "<br>".join(self.desceval)
pdf_title += (
"\nDate : %(jour)s - Horaire : %(heure_debut)s à %(heure_fin)s"
% self.eval_data
)
pdf_title += f"""\nDate : {self.evaluation.date_debut.strftime("%d/%m/%Y")
if self.evaluation.date_debut else '-'
} - Horaire : {self.evaluation.heure_debut()} à {self.evaluation.heure_fin()
}"""
filename = "placement_%(evalname)s_%(gr_title_filename)s" % self.__dict__
titles = {
"nom": "Nom",
@ -489,8 +485,10 @@ class PlacementRunner:
worksheet.append_blank_row()
worksheet.append_single_cell_row(desceval, self.styles["titres"])
worksheet.append_single_cell_row(
"Date : %(jour)s - Horaire : %(heure_debut)s à %(heure_fin)s"
% self.eval_data,
f"""Date : {self.evaluation.date_debut.strftime("%d/%m/%Y")
if self.evaluation.date_debut else '-'
} - Horaire : {self.evaluation.heure_debut()} à {self.evaluation.heure_fin()
}""",
self.styles["titres"],
)

View File

@ -48,16 +48,15 @@ Opérations:
import datetime
from flask import request
from app.models import FormSemestre
from app.models import Evaluation, FormSemestre
from app.scodoc.intervals import intervalmap
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_preferences
from app.scodoc import sco_users
import sco_version
from app.scodoc.gen_tables import GenTable
import sco_version
# deux notes (de même uid) sont considérées comme de la même opération si
# elles sont séparées de moins de 2*tolerance:
@ -149,10 +148,8 @@ def list_operations(evaluation_id):
def evaluation_list_operations(evaluation_id):
"""Page listing operations on evaluation"""
E = sco_evaluation_db.get_evaluations_dict({"evaluation_id": evaluation_id})[0]
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
Ops = list_operations(evaluation_id)
evaluation = Evaluation.get_evaluation(evaluation_id)
operations = list_operations(evaluation_id)
columns_ids = ("datestr", "user_name", "nb_notes", "comment")
titles = {
@ -164,11 +161,14 @@ def evaluation_list_operations(evaluation_id):
tab = GenTable(
titles=titles,
columns_ids=columns_ids,
rows=Ops,
rows=operations,
html_sortable=False,
html_title="<h2>Opérations sur l'évaluation %s du %s</h2>"
% (E["description"], E["jour"]),
preferences=sco_preferences.SemPreferences(M["formsemestre_id"]),
html_title=f"""<h2>Opérations sur l'évaluation {evaluation.description} {
evaluation.date_debut.strftime("du %d/%m/%Y") if evaluation.date_debut else "(sans date)"
}</h2>""",
preferences=sco_preferences.SemPreferences(
evaluation.moduleimpl.formsemestre_id
),
)
return tab.make_page()

View File

@ -13,7 +13,7 @@ Au besoin, créer un base de test neuve:
"""
import datetime
from app.models import FormSemestreInscription, Identite
from app.models import Evaluation, FormSemestreInscription, Identite, ModuleImpl
from config import TestConfig
from tests.unit import sco_fake_gen
@ -29,7 +29,6 @@ from app.scodoc import sco_bulletins
from app.scodoc import codes_cursus
from app.scodoc import sco_assiduites as scass
from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formsemestre_validation
from app.scodoc import sco_cursus_dut
from app.scodoc import sco_saisie_notes
@ -81,7 +80,7 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
module_id=module_id,
formsemestre_id=formsemestre_id,
)
moduleimpl: ModuleImpl = db.session.get(ModuleImpl, moduleimpl_id)
# --- Inscription des étudiants
for etud in etuds:
G.inscrit_etudiant(formsemestre_id, etud)
@ -97,17 +96,18 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
assert ins.parcour is None
# --- Création évaluation
e = G.create_evaluation(
moduleimpl_id=moduleimpl_id,
e1 = Evaluation.create(
moduleimpl=moduleimpl,
date_debut=datetime.datetime(2020, 1, 1),
description="evaluation test",
coefficient=1.0,
)
db.session.commit()
# --- Saisie toutes les notes de l'évaluation
for idx, etud in enumerate(etuds):
etudids_changed, nb_suppress, existing_decisions = G.create_note(
evaluation_id=e["evaluation_id"],
evaluation_id=e1.id,
etudid=etud["etudid"],
note=NOTES_T[idx % len(NOTES_T)],
)
@ -118,7 +118,7 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
# --- Vérifie que les notes sont prises en compte:
b = sco_bulletins.formsemestre_bulletinetud_dict(formsemestre_id, etud["etudid"])
# Toute les notes sont saisies, donc eval complète
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
etat = sco_evaluations.do_evaluation_etat(e1.id)
assert etat["evalcomplete"]
assert etat["nb_inscrits"] == len(etuds)
assert etat["nb_notes"] == len(etuds)
@ -131,30 +131,32 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
)
# --- Une autre évaluation
e2 = G.create_evaluation(
moduleimpl_id=moduleimpl_id,
e2 = Evaluation.create(
moduleimpl=moduleimpl,
date_debut=datetime.datetime(2020, 1, 2),
description="evaluation test 2",
coefficient=1.0,
)
db.session.commit()
# Saisie les notes des 5 premiers étudiants:
for idx, etud in enumerate(etuds[:5]):
etudids_changed, nb_suppress, existing_decisions = G.create_note(
evaluation_id=e2["evaluation_id"],
evaluation_id=e2.id,
etudid=etud["etudid"],
note=NOTES_T[idx % len(NOTES_T)],
)
# Cette éval n'est pas complète
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
etat = sco_evaluations.do_evaluation_etat(e2.id)
assert etat["evalcomplete"] is False
# la première éval est toujours complète:
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
etat = sco_evaluations.do_evaluation_etat(e1.id)
assert etat["evalcomplete"]
# Modifie l'évaluation 2 pour "prise en compte immédiate"
e2["publish_incomplete"] = True
sco_evaluation_db.do_evaluation_edit(e2)
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
e2.publish_incomplete = True
db.session.add(e2)
db.session.flush()
etat = sco_evaluations.do_evaluation_etat(e2.id)
assert etat["evalcomplete"] is False
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)
@ -162,26 +164,26 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
# Saisie des notes qui manquent:
for idx, etud in enumerate(etuds[5:]):
etudids_changed, nb_suppress, existing_decisions = G.create_note(
evaluation_id=e2["evaluation_id"],
evaluation_id=e2.id,
etudid=etud["etudid"],
note=NOTES_T[idx % len(NOTES_T)],
)
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
etat = sco_evaluations.do_evaluation_etat(e2.id)
assert etat["evalcomplete"]
assert etat["nb_att"] == 0
assert not etat["evalattente"] # toutes les notes sont présentes
# --- Suppression des notes
sco_saisie_notes.evaluation_suppress_alln(e["evaluation_id"], dialog_confirmed=True)
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
sco_saisie_notes.evaluation_suppress_alln(e1.id, dialog_confirmed=True)
etat = sco_evaluations.do_evaluation_etat(e1.id)
assert etat["nb_notes"] == 0
assert not etat["evalcomplete"]
# --- Saisie des notes manquantes
ans = sco_saisie_notes.do_evaluation_set_missing(
e["evaluation_id"], 12.34, dialog_confirmed=True
e1.id, 12.34, dialog_confirmed=True
)
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(e1.id)
assert etat["evalcomplete"]
# -----------------------