forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -297,7 +297,7 @@ class BulletinBUT:
|
|||||||
)
|
)
|
||||||
if has_request_context()
|
if has_request_context()
|
||||||
else "na",
|
else "na",
|
||||||
# deprecated
|
# deprecated (supprimer avant #sco9.7)
|
||||||
"date": e.date_debut.isoformat() if e.date_debut else None,
|
"date": e.date_debut.isoformat() if e.date_debut else None,
|
||||||
"heure_debut": e.date_debut.time().isoformat("minutes")
|
"heure_debut": e.date_debut.time().isoformat("minutes")
|
||||||
if e.date_debut
|
if e.date_debut
|
||||||
|
@ -218,12 +218,8 @@ def bulletin_but_xml_compat(
|
|||||||
jour=e.date_debut.isoformat()
|
jour=e.date_debut.isoformat()
|
||||||
if e.date_debut
|
if e.date_debut
|
||||||
else "",
|
else "",
|
||||||
heure_debut=e.date_debut.time().isoformat("minutes")
|
heure_debut=e.heure_debut(),
|
||||||
if e.date_debut
|
heure_fin=e.heure_fin(),
|
||||||
else "",
|
|
||||||
heure_fin=e.date_fin.time().isoformat("minutes")
|
|
||||||
if e.date_fin
|
|
||||||
else "",
|
|
||||||
)
|
)
|
||||||
x_mod.append(x_eval)
|
x_mod.append(x_eval)
|
||||||
try:
|
try:
|
||||||
|
@ -250,7 +250,7 @@ class ModuleImplResults:
|
|||||||
).reshape(-1, 1)
|
).reshape(-1, 1)
|
||||||
|
|
||||||
# was _list_notes_evals_titles
|
# was _list_notes_evals_titles
|
||||||
def get_evaluations_completes(self, moduleimpl: ModuleImpl) -> list:
|
def get_evaluations_completes(self, moduleimpl: ModuleImpl) -> list[Evaluation]:
|
||||||
"Liste des évaluations complètes"
|
"Liste des évaluations complètes"
|
||||||
return [
|
return [
|
||||||
e for e in moduleimpl.evaluations if self.evaluations_completes_dict[e.id]
|
e for e in moduleimpl.evaluations if self.evaluations_completes_dict[e.id]
|
||||||
|
@ -80,8 +80,8 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
self.moy_gen_rangs_by_group = None # virtual
|
self.moy_gen_rangs_by_group = None # virtual
|
||||||
self.modimpl_inscr_df: pd.DataFrame = None
|
self.modimpl_inscr_df: pd.DataFrame = None
|
||||||
"Inscriptions: row etudid, col modimlpl_id"
|
"Inscriptions: row etudid, col modimlpl_id"
|
||||||
self.modimpls_results: ModuleImplResults = None
|
self.modimpls_results: dict[int, ModuleImplResults] = None
|
||||||
"Résultats de chaque modimpl: dict { modimpl.id : ModuleImplResults(Classique ou BUT) }"
|
"Résultats de chaque modimpl (classique ou BUT)"
|
||||||
self.etud_coef_ue_df = None
|
self.etud_coef_ue_df = None
|
||||||
"""coefs d'UE effectifs pour chaque étudiant (pour form. classiques)"""
|
"""coefs d'UE effectifs pour chaque étudiant (pour form. classiques)"""
|
||||||
self.modimpl_coefs_df: pd.DataFrame = None
|
self.modimpl_coefs_df: pd.DataFrame = None
|
||||||
@ -192,6 +192,17 @@ class ResultatsSemestre(ResultatsCache):
|
|||||||
*[mr.etudids_attente for mr in self.modimpls_results.values()]
|
*[mr.etudids_attente for mr in self.modimpls_results.values()]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# # Etat des évaluations
|
||||||
|
# # (se substitue à do_evaluation_etat, sans les moyennes par groupes)
|
||||||
|
# def get_evaluations_etats(evaluation_id: int) -> dict:
|
||||||
|
# """Renvoie dict avec les clés:
|
||||||
|
# last_modif
|
||||||
|
# nb_evals_completes
|
||||||
|
# nb_evals_en_cours
|
||||||
|
# nb_evals_vides
|
||||||
|
# attente
|
||||||
|
# """
|
||||||
|
|
||||||
# --- JURY...
|
# --- JURY...
|
||||||
def get_formsemestre_validations(self) -> ValidationsSemestre:
|
def get_formsemestre_validations(self) -> ValidationsSemestre:
|
||||||
"""Load validations if not already stored, set attribute and return value"""
|
"""Load validations if not already stored, set attribute and return value"""
|
||||||
|
@ -16,7 +16,13 @@ from app import db, log
|
|||||||
from app.comp import moy_sem
|
from app.comp import moy_sem
|
||||||
from app.comp.aux_stats import StatsMoyenne
|
from app.comp.aux_stats import StatsMoyenne
|
||||||
from app.comp.res_common import ResultatsSemestre
|
from app.comp.res_common import ResultatsSemestre
|
||||||
from app.models import Identite, FormSemestre, ModuleImpl, ScolarAutorisationInscription
|
from app.models import (
|
||||||
|
Evaluation,
|
||||||
|
Identite,
|
||||||
|
FormSemestre,
|
||||||
|
ModuleImpl,
|
||||||
|
ScolarAutorisationInscription,
|
||||||
|
)
|
||||||
from app.scodoc.codes_cursus import UE_SPORT, DEF
|
from app.scodoc.codes_cursus import UE_SPORT, DEF
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
@ -389,7 +395,7 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
"ects_total": ects_total,
|
"ects_total": ects_total,
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_evals_in_mod(self, moduleimpl_id: int) -> list[dict]:
|
def get_modimpl_evaluations_completes(self, moduleimpl_id: int) -> list[Evaluation]:
|
||||||
"""Liste d'informations (compat NotesTable) sur évaluations completes
|
"""Liste d'informations (compat NotesTable) sur évaluations completes
|
||||||
de ce module.
|
de ce module.
|
||||||
Évaluation "complete" ssi toutes notes saisies ou en attente.
|
Évaluation "complete" ssi toutes notes saisies ou en attente.
|
||||||
@ -398,34 +404,24 @@ class NotesTableCompat(ResultatsSemestre):
|
|||||||
modimpl_results = self.modimpls_results.get(moduleimpl_id)
|
modimpl_results = self.modimpls_results.get(moduleimpl_id)
|
||||||
if not modimpl_results:
|
if not modimpl_results:
|
||||||
return [] # safeguard
|
return [] # safeguard
|
||||||
evals_results = []
|
evaluations = []
|
||||||
for e in modimpl.evaluations:
|
for e in modimpl.evaluations:
|
||||||
if modimpl_results.evaluations_completes_dict.get(e.id, False):
|
if modimpl_results.evaluations_completes_dict.get(e.id, False):
|
||||||
d = e.to_dict()
|
evaluations.append(e)
|
||||||
d["heure_debut"] = e.heure_debut # datetime.time
|
|
||||||
d["heure_fin"] = e.heure_fin
|
|
||||||
d["jour"] = e.jour # datetime
|
|
||||||
d["notes"] = {
|
|
||||||
etud.id: {
|
|
||||||
"etudid": etud.id,
|
|
||||||
"value": modimpl_results.evals_notes[e.id][etud.id],
|
|
||||||
}
|
|
||||||
for etud in self.etuds
|
|
||||||
}
|
|
||||||
d["etat"] = {
|
|
||||||
"evalattente": modimpl_results.evaluations_etat[e.id].nb_attente,
|
|
||||||
}
|
|
||||||
evals_results.append(d)
|
|
||||||
elif e.id not in modimpl_results.evaluations_completes_dict:
|
elif e.id not in modimpl_results.evaluations_completes_dict:
|
||||||
# ne devrait pas arriver ? XXX
|
# ne devrait pas arriver ? XXX
|
||||||
log(
|
log(
|
||||||
f"Warning: 220213 get_evals_in_mod {e.id} not in mod {moduleimpl_id} ?"
|
f"Warning: 220213 get_modimpl_evaluations_completes {e.id} not in mod {moduleimpl_id} ?"
|
||||||
)
|
)
|
||||||
return evals_results
|
return evaluations
|
||||||
|
|
||||||
|
def get_evaluations_etats(self) -> list[dict]:
|
||||||
|
"""Liste de toutes les évaluations du semestre
|
||||||
|
[ {...evaluation et son etat...} ]"""
|
||||||
|
# TODO: à moderniser (voir dans ResultatsSemestre)
|
||||||
|
# utilisé par
|
||||||
|
# do_evaluation_etat_in_sem
|
||||||
|
|
||||||
def get_evaluations_etats(self):
|
|
||||||
"""[ {...evaluation et son etat...} ]"""
|
|
||||||
# TODO: à moderniser
|
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
|
|
||||||
if not hasattr(self, "_evaluations_etats"):
|
if not hasattr(self, "_evaluations_etats"):
|
||||||
|
@ -18,8 +18,8 @@ from app.models.ues import UniteEns
|
|||||||
|
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
import app.scodoc.notesdb as ndb
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_xml import quote_xml_attr
|
||||||
|
|
||||||
MAX_EVALUATION_DURATION = datetime.timedelta(days=365)
|
MAX_EVALUATION_DURATION = datetime.timedelta(days=365)
|
||||||
NOON = datetime.time(12, 00)
|
NOON = datetime.time(12, 00)
|
||||||
@ -46,6 +46,7 @@ class Evaluation(db.Model):
|
|||||||
visibulletin = db.Column(
|
visibulletin = db.Column(
|
||||||
db.Boolean, nullable=False, default=True, server_default="true"
|
db.Boolean, nullable=False, default=True, server_default="true"
|
||||||
)
|
)
|
||||||
|
"visible sur les bulletins version intermédiaire"
|
||||||
publish_incomplete = db.Column(
|
publish_incomplete = db.Column(
|
||||||
db.Boolean, nullable=False, default=False, server_default="false"
|
db.Boolean, nullable=False, default=False, server_default="false"
|
||||||
)
|
)
|
||||||
@ -67,9 +68,8 @@ class Evaluation(db.Model):
|
|||||||
def create(
|
def create(
|
||||||
cls,
|
cls,
|
||||||
moduleimpl: ModuleImpl = None,
|
moduleimpl: ModuleImpl = None,
|
||||||
jour=None,
|
date_debut: datetime.datetime = None,
|
||||||
heure_debut=None,
|
date_fin: datetime.datetime = None,
|
||||||
heure_fin=None,
|
|
||||||
description=None,
|
description=None,
|
||||||
note_max=None,
|
note_max=None,
|
||||||
coefficient=None,
|
coefficient=None,
|
||||||
@ -124,7 +124,7 @@ class Evaluation(db.Model):
|
|||||||
next_eval = None
|
next_eval = None
|
||||||
t = date_debut
|
t = date_debut
|
||||||
for e in evaluations:
|
for e in evaluations:
|
||||||
if e.date_debut > t:
|
if e.date_debut and e.date_debut > t:
|
||||||
next_eval = e
|
next_eval = e
|
||||||
break
|
break
|
||||||
if next_eval:
|
if next_eval:
|
||||||
@ -140,26 +140,26 @@ class Evaluation(db.Model):
|
|||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
"Représentation dict (riche, compat ScoDoc 7)"
|
"Représentation dict (riche, compat ScoDoc 7)"
|
||||||
e = dict(self.__dict__)
|
e_dict = dict(self.__dict__)
|
||||||
e.pop("_sa_instance_state", None)
|
e_dict.pop("_sa_instance_state", None)
|
||||||
# ScoDoc7 output_formators
|
# ScoDoc7 output_formators
|
||||||
e["evaluation_id"] = self.id
|
e_dict["evaluation_id"] = self.id
|
||||||
e["date_debut"] = e.date_debut.isoformat() if e.date_debut else None
|
e_dict["date_debut"] = self.date_debut.isoformat() if self.date_debut else None
|
||||||
e["date_fin"] = e.date_debut.isoformat() if e.date_fin else None
|
e_dict["date_fin"] = self.date_debut.isoformat() if self.date_fin else None
|
||||||
e["numero"] = ndb.int_null_is_zero(e["numero"])
|
e_dict["numero"] = self.numero or 0
|
||||||
e["poids"] = self.get_ue_poids_dict() # { ue_id : poids }
|
e_dict["poids"] = self.get_ue_poids_dict() # { ue_id : poids }
|
||||||
|
|
||||||
# Deprecated
|
# Deprecated
|
||||||
e["jour"] = e.date_debut.strftime("%d/%m/%Y") if e.date_debut else ""
|
e_dict["jour"] = self.date_debut.strftime("%d/%m/%Y") if self.date_debut else ""
|
||||||
|
|
||||||
return evaluation_enrich_dict(e)
|
return evaluation_enrich_dict(self, e_dict)
|
||||||
|
|
||||||
def to_dict_api(self) -> dict:
|
def to_dict_api(self) -> dict:
|
||||||
"Représentation dict pour API JSON"
|
"Représentation dict pour API JSON"
|
||||||
return {
|
return {
|
||||||
"coefficient": self.coefficient,
|
"coefficient": self.coefficient,
|
||||||
"date_debut": self.date_debut.isoformat(),
|
"date_debut": self.date_debut.isoformat() if self.date_debut else "",
|
||||||
"date_fin": self.date_fin.isoformat(),
|
"date_fin": self.date_fin.isoformat() if self.date_fin else "",
|
||||||
"description": self.description,
|
"description": self.description,
|
||||||
"evaluation_type": self.evaluation_type,
|
"evaluation_type": self.evaluation_type,
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
@ -168,14 +168,36 @@ class Evaluation(db.Model):
|
|||||||
"numero": self.numero,
|
"numero": self.numero,
|
||||||
"poids": self.get_ue_poids_dict(),
|
"poids": self.get_ue_poids_dict(),
|
||||||
"publish_incomplete": self.publish_incomplete,
|
"publish_incomplete": self.publish_incomplete,
|
||||||
"visi_bulletin": self.visibulletin,
|
"visibulletin": self.visibulletin,
|
||||||
|
# Deprecated (supprimer avant #sco9.7)
|
||||||
|
"date": self.date_debut.date().isoformat() if self.date_debut else "",
|
||||||
|
"heure_debut": self.date_debut.time().isoformat()
|
||||||
|
if self.date_debut
|
||||||
|
else "",
|
||||||
|
"heure_fin": self.date_fin.time().isoformat() if self.date_fin else "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def to_dict_bul(self) -> dict:
|
||||||
|
"dict pour les bulletins json"
|
||||||
|
# c'est la version API avec quelques champs legacy en plus
|
||||||
|
e_dict = self.to_dict_api()
|
||||||
|
# Pour les bulletins (json ou xml), quote toujours la description
|
||||||
|
e_dict["description"] = quote_xml_attr(self.description or "")
|
||||||
|
# deprecated fields:
|
||||||
|
e_dict["evaluation_id"] = self.id
|
||||||
|
e_dict["jour"] = e_dict["date_debut"] # chaine iso
|
||||||
|
e_dict["heure_debut"] = (
|
||||||
|
self.date_debut.time().isoformat() if self.date_debut else ""
|
||||||
|
)
|
||||||
|
e_dict["heure_fin"] = self.date_fin.time().isoformat() if self.date_fin else ""
|
||||||
|
|
||||||
|
return e_dict
|
||||||
|
|
||||||
def from_dict(self, data):
|
def from_dict(self, data):
|
||||||
"""Set evaluation attributes from given dict values."""
|
"""Set evaluation attributes from given dict values."""
|
||||||
check_convert_evaluation_args(self.moduleimpl, data)
|
check_convert_evaluation_args(self.moduleimpl, data)
|
||||||
if data.get("numero") is None:
|
if data.get("numero") is None:
|
||||||
data["numero"] = Evaluation.get_max_numero() + 1
|
data["numero"] = Evaluation.get_max_numero(self.moduleimpl.id) + 1
|
||||||
for k in self.__dict__.keys():
|
for k in self.__dict__.keys():
|
||||||
if k != "_sa_instance_state" and k != "id" and k in data:
|
if k != "_sa_instance_state" and k != "id" and k in data:
|
||||||
setattr(self, k, data[k])
|
setattr(self, k, data[k])
|
||||||
@ -217,28 +239,64 @@ class Evaluation(db.Model):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def descr_heure(self) -> str:
|
def descr_heure(self) -> str:
|
||||||
"Description de la plage horaire pour affichages"
|
"Description de la plage horaire pour affichages ('de 13h00 à 14h00')"
|
||||||
if self.heure_debut and (
|
if self.date_debut and (not self.date_fin or self.date_fin == self.date_debut):
|
||||||
not self.heure_fin or self.heure_fin == self.heure_debut
|
return f"""à {self.date_debut.strftime("%Hh%M")}"""
|
||||||
):
|
elif self.date_debut and self.date_fin:
|
||||||
return f"""à {self.heure_debut.strftime("%Hh%M")}"""
|
return f"""de {self.date_debut.strftime("%Hh%M")
|
||||||
elif self.heure_debut and self.heure_fin:
|
} à {self.date_fin.strftime("%Hh%M")}"""
|
||||||
return f"""de {self.heure_debut.strftime("%Hh%M")} à {self.heure_fin.strftime("%Hh%M")}"""
|
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def descr_duree(self) -> str:
|
def descr_duree(self) -> str:
|
||||||
"Description de la durée pour affichages"
|
"Description de la durée pour affichages ('3h' ou '2h30')"
|
||||||
if self.heure_debut is None and self.heure_fin is None:
|
if self.date_debut is None or self.date_fin is None:
|
||||||
return ""
|
return ""
|
||||||
debut = self.heure_debut or DEFAULT_EVALUATION_TIME
|
minutes = (self.date_fin - self.date_debut).seconds // 60
|
||||||
fin = self.heure_fin or DEFAULT_EVALUATION_TIME
|
duree = f"{minutes // 60}h"
|
||||||
d = (fin.hour * 60 + fin.minute) - (debut.hour * 60 + debut.minute)
|
minutes = minutes % 60
|
||||||
duree = f"{d//60}h"
|
if minutes != 0:
|
||||||
if d % 60:
|
duree += f"{minutes:02d}"
|
||||||
duree += f"{d%60:02d}"
|
|
||||||
return duree
|
return duree
|
||||||
|
|
||||||
|
def descr_date(self) -> str:
|
||||||
|
"""Description de la date pour affichages
|
||||||
|
'sans date'
|
||||||
|
'le 21/9/2021 à 13h'
|
||||||
|
'le 21/9/2021 de 13h à 14h30'
|
||||||
|
'du 21/9/2021 à 13h30 au 23/9/2021 à 15h'
|
||||||
|
"""
|
||||||
|
if self.date_debut is None:
|
||||||
|
return "sans date"
|
||||||
|
|
||||||
|
def _h(dt: datetime.datetime) -> str:
|
||||||
|
if dt.minute:
|
||||||
|
return dt.strftime("%Hh%M")
|
||||||
|
return f"{dt.hour}h"
|
||||||
|
|
||||||
|
if self.date_fin is None:
|
||||||
|
return (
|
||||||
|
f"le {self.date_debut.strftime('%d/%m/%Y')} à {_h(self.date_debut())}"
|
||||||
|
)
|
||||||
|
if self.date_debut.date() == self.date_fin.date(): # même jour
|
||||||
|
if self.date_debut.time() == self.date_fin.time():
|
||||||
|
return f"le {self.date_debut.strftime('%d/%m/%Y')} à {_h(self.date_debut())}"
|
||||||
|
return f"""le {self.date_debut.strftime('%d/%m/%Y')} de {
|
||||||
|
_h(self.date_debut())} à {_h(self.date_fin())}"""
|
||||||
|
# évaluation sur plus d'une journée
|
||||||
|
return f"""du {self.date_debut.strftime('%d/%m/%Y')} à {
|
||||||
|
_h(self.date_debut())} au {self.date_fin.strftime('%d/%m/%Y')} à {_h(self.date_fin())}"""
|
||||||
|
|
||||||
|
def heure_debut(self) -> str:
|
||||||
|
"""L'heure de début (sans la date), en ISO.
|
||||||
|
Chaine vide si non renseignée."""
|
||||||
|
return self.date_debut.time().isoformat("minutes") if self.date_debut else ""
|
||||||
|
|
||||||
|
def heure_fin(self) -> str:
|
||||||
|
"""L'heure de fin (sans la date), en ISO.
|
||||||
|
Chaine vide si non renseignée."""
|
||||||
|
return self.date_fin.time().isoformat("minutes") if self.date_fin else ""
|
||||||
|
|
||||||
def clone(self, not_copying=()):
|
def clone(self, not_copying=()):
|
||||||
"""Clone, not copying the given attrs
|
"""Clone, not copying the given attrs
|
||||||
Attention: la copie n'a pas d'id avant le prochain commit
|
Attention: la copie n'a pas d'id avant le prochain commit
|
||||||
@ -381,41 +439,28 @@ class EvaluationUEPoids(db.Model):
|
|||||||
return f"<EvaluationUEPoids {self.evaluation} {self.ue} poids={self.poids}>"
|
return f"<EvaluationUEPoids {self.evaluation} {self.ue} poids={self.poids}>"
|
||||||
|
|
||||||
|
|
||||||
# Fonction héritée de ScoDoc7 à refactorer
|
# Fonction héritée de ScoDoc7
|
||||||
def evaluation_enrich_dict(e: dict):
|
def evaluation_enrich_dict(e: Evaluation, e_dict: dict):
|
||||||
"""add or convert some fields in an evaluation dict"""
|
"""add or convert some fields in an evaluation dict"""
|
||||||
# For ScoDoc7 compat
|
# For ScoDoc7 compat
|
||||||
heure_debut_dt = e["date_debut"].time()
|
e_dict["heure_debut"] = e.date_debut.strftime("%Hh%M") if e.date_debut else ""
|
||||||
heure_fin_dt = e["date_fin"].time()
|
e_dict["heure_fin"] = e.date_fin.strftime("%Hh%M") if e.date_fin else ""
|
||||||
e["heure_debut"] = heure_debut_dt.strftime("%Hh%M")
|
e_dict["jour_iso"] = e.date_debut.isoformat() if e.date_debut else ""
|
||||||
e["heure_fin"] = heure_fin_dt.strftime("%Hh%M")
|
# Calcule durée en minutes
|
||||||
e["jour_iso"] = e["date_debut"].isoformat() # XXX
|
e_dict["descrheure"] = e.descr_heure()
|
||||||
heure_debut, heure_fin = e["heure_debut"], e["heure_fin"]
|
e_dict["descrduree"] = e.descr_duree()
|
||||||
d = _time_duration_HhM(heure_debut, heure_fin)
|
|
||||||
if d is not None:
|
|
||||||
m = d % 60
|
|
||||||
e["duree"] = "%dh" % (d / 60)
|
|
||||||
if m != 0:
|
|
||||||
e["duree"] += "%02d" % m
|
|
||||||
else:
|
|
||||||
e["duree"] = ""
|
|
||||||
if heure_debut and (not heure_fin or heure_fin == heure_debut):
|
|
||||||
e["descrheure"] = " à " + heure_debut
|
|
||||||
elif heure_debut and heure_fin:
|
|
||||||
e["descrheure"] = " de %s à %s" % (heure_debut, heure_fin)
|
|
||||||
else:
|
|
||||||
e["descrheure"] = ""
|
|
||||||
# matin, apresmidi: utile pour se referer aux absences:
|
# matin, apresmidi: utile pour se referer aux absences:
|
||||||
|
# note août 2023: si l'évaluation s'étend sur plusieurs jours,
|
||||||
if e["jour"] and heure_debut_dt < datetime.time(12, 00):
|
# cet indicateur n'a pas grand sens
|
||||||
e["matin"] = 1
|
if e.date_debut and e.date_debut.time() < datetime.time(12, 00):
|
||||||
|
e_dict["matin"] = 1
|
||||||
else:
|
else:
|
||||||
e["matin"] = 0
|
e_dict["matin"] = 0
|
||||||
if e["jour"] and heure_fin_dt > datetime.time(12, 00):
|
if e.date_fin and e.date_fin.time() > datetime.time(12, 00):
|
||||||
e["apresmidi"] = 1
|
e_dict["apresmidi"] = 1
|
||||||
else:
|
else:
|
||||||
e["apresmidi"] = 0
|
e_dict["apresmidi"] = 0
|
||||||
return e
|
return e_dict
|
||||||
|
|
||||||
|
|
||||||
def check_convert_evaluation_args(moduleimpl: ModuleImpl, data: dict):
|
def check_convert_evaluation_args(moduleimpl: ModuleImpl, data: dict):
|
||||||
@ -426,71 +471,87 @@ def check_convert_evaluation_args(moduleimpl: ModuleImpl, data: dict):
|
|||||||
May raise ScoValueError.
|
May raise ScoValueError.
|
||||||
"""
|
"""
|
||||||
# --- description
|
# --- description
|
||||||
description = data.get("description", "")
|
data["description"] = data.get("description", "") or ""
|
||||||
if len(description) > scu.MAX_TEXT_LEN:
|
if len(data["description"]) > scu.MAX_TEXT_LEN:
|
||||||
raise ScoValueError("description too large")
|
raise ScoValueError("description too large")
|
||||||
|
|
||||||
# --- evaluation_type
|
# --- evaluation_type
|
||||||
try:
|
try:
|
||||||
data["evaluation_type"] = int(data.get("evaluation_type", 0) or 0)
|
data["evaluation_type"] = int(data.get("evaluation_type", 0) or 0)
|
||||||
if not data["evaluation_type"] in VALID_EVALUATION_TYPES:
|
if not data["evaluation_type"] in VALID_EVALUATION_TYPES:
|
||||||
raise ScoValueError("Invalid evaluation_type value")
|
raise ScoValueError("invalid evaluation_type value")
|
||||||
except ValueError:
|
except ValueError as exc:
|
||||||
raise ScoValueError("Invalid evaluation_type value")
|
raise ScoValueError("invalid evaluation_type value") from exc
|
||||||
|
|
||||||
# --- note_max (bareme)
|
# --- note_max (bareme)
|
||||||
note_max = data.get("note_max", 20.0) or 20.0
|
note_max = data.get("note_max", 20.0) or 20.0
|
||||||
try:
|
try:
|
||||||
note_max = float(note_max)
|
note_max = float(note_max)
|
||||||
except ValueError:
|
except ValueError as exc:
|
||||||
raise ScoValueError("Invalid note_max value")
|
raise ScoValueError("invalid note_max value") from exc
|
||||||
if note_max < 0:
|
if note_max < 0:
|
||||||
raise ScoValueError("Invalid note_max value (must be positive or null)")
|
raise ScoValueError("invalid note_max value (must be positive or null)")
|
||||||
data["note_max"] = note_max
|
data["note_max"] = note_max
|
||||||
# --- coefficient
|
# --- coefficient
|
||||||
coef = data.get("coefficient", 1.0) or 1.0
|
coef = data.get("coefficient", 1.0) or 1.0
|
||||||
try:
|
try:
|
||||||
coef = float(coef)
|
coef = float(coef)
|
||||||
except ValueError:
|
except ValueError as exc:
|
||||||
raise ScoValueError("Invalid coefficient value")
|
raise ScoValueError("invalid coefficient value") from exc
|
||||||
if coef < 0:
|
if coef < 0:
|
||||||
raise ScoValueError("Invalid coefficient value (must be positive or null)")
|
raise ScoValueError("invalid coefficient value (must be positive or null)")
|
||||||
data["coefficient"] = coef
|
data["coefficient"] = coef
|
||||||
# --- jour (date de l'évaluation)
|
# --- date de l'évaluation
|
||||||
jour = data.get("jour", None)
|
formsemestre = moduleimpl.formsemestre
|
||||||
if jour and not isinstance(jour, datetime.date):
|
date_debut = data.get("date_debut", None)
|
||||||
if date_format == "dmy":
|
if date_debut:
|
||||||
y, m, d = [int(x) for x in ndb.DateDMYtoISO(jour).split("-")]
|
if isinstance(date_debut, str):
|
||||||
jour = datetime.date(y, m, d)
|
data["date_debut"] = datetime.datetime.fromisoformat(date_debut)
|
||||||
else: # ISO
|
if data["date_debut"].tzinfo is None:
|
||||||
jour = datetime.date.fromisoformat(jour)
|
data["date_debut"] = scu.TIME_ZONE.localize(data["date_debut"])
|
||||||
formsemestre = moduleimpl.formsemestre
|
if not (
|
||||||
if (jour > formsemestre.date_fin) or (jour < formsemestre.date_debut):
|
formsemestre.date_debut
|
||||||
|
<= data["date_debut"].date()
|
||||||
|
<= formsemestre.date_fin
|
||||||
|
):
|
||||||
raise ScoValueError(
|
raise ScoValueError(
|
||||||
f"""La date de l'évaluation ({jour.strftime("%d/%m/%Y")}) n'est pas dans le semestre !""",
|
f"""La date de début de l'évaluation ({
|
||||||
|
data["date_debut"].strftime("%d/%m/%Y")
|
||||||
|
}) n'est pas dans le semestre !""",
|
||||||
dest_url="javascript:history.back();",
|
dest_url="javascript:history.back();",
|
||||||
)
|
)
|
||||||
data["jour"] = jour
|
date_fin = data.get("date_fin", None)
|
||||||
# --- heures
|
if date_fin:
|
||||||
heure_debut = data.get("heure_debut", None)
|
if isinstance(date_fin, str):
|
||||||
if heure_debut and not isinstance(heure_debut, datetime.time):
|
data["date_fin"] = datetime.datetime.fromisoformat(date_fin)
|
||||||
if date_format == "dmy":
|
if data["date_fin"].tzinfo is None:
|
||||||
data["heure_debut"] = heure_to_time(heure_debut)
|
data["date_fin"] = scu.TIME_ZONE.localize(data["date_fin"])
|
||||||
else: # ISO
|
if not (
|
||||||
data["heure_debut"] = datetime.time.fromisoformat(heure_debut)
|
formsemestre.date_debut <= data["date_fin"].date() <= formsemestre.date_fin
|
||||||
heure_fin = data.get("heure_fin", None)
|
):
|
||||||
if heure_fin and not isinstance(heure_fin, datetime.time):
|
raise ScoValueError(
|
||||||
if date_format == "dmy":
|
f"""La date de fin de l'évaluation ({
|
||||||
data["heure_fin"] = heure_to_time(heure_fin)
|
data["date_fin"].strftime("%d/%m/%Y")
|
||||||
else: # ISO
|
}) n'est pas dans le semestre !""",
|
||||||
data["heure_fin"] = datetime.time.fromisoformat(heure_fin)
|
dest_url="javascript:history.back();",
|
||||||
if jour and ((not heure_debut) or (not heure_fin)):
|
)
|
||||||
raise ScoValueError("Les heures doivent être précisées")
|
if date_debut and date_fin:
|
||||||
if heure_debut and heure_fin:
|
duration = data["date_fin"] - data["date_debut"]
|
||||||
duration = ((data["heure_fin"].hour * 60) + data["heure_fin"].minute) - (
|
if duration.total_seconds() < 0 or duration > MAX_EVALUATION_DURATION:
|
||||||
(data["heure_debut"].hour * 60) + data["heure_debut"].minute
|
|
||||||
)
|
|
||||||
if duration < 0 or duration > 60 * 12:
|
|
||||||
raise ScoValueError("Heures de l'évaluation incohérentes !")
|
raise ScoValueError("Heures de l'évaluation incohérentes !")
|
||||||
|
# # --- heures
|
||||||
|
# heure_debut = data.get("heure_debut", None)
|
||||||
|
# if heure_debut and not isinstance(heure_debut, datetime.time):
|
||||||
|
# if date_format == "dmy":
|
||||||
|
# data["heure_debut"] = heure_to_time(heure_debut)
|
||||||
|
# else: # ISO
|
||||||
|
# data["heure_debut"] = datetime.time.fromisoformat(heure_debut)
|
||||||
|
# heure_fin = data.get("heure_fin", None)
|
||||||
|
# if heure_fin and not isinstance(heure_fin, datetime.time):
|
||||||
|
# if date_format == "dmy":
|
||||||
|
# data["heure_fin"] = heure_to_time(heure_fin)
|
||||||
|
# else: # ISO
|
||||||
|
# data["heure_fin"] = datetime.time.fromisoformat(heure_fin)
|
||||||
|
|
||||||
|
|
||||||
def heure_to_time(heure: str) -> datetime.time:
|
def heure_to_time(heure: str) -> datetime.time:
|
||||||
|
@ -30,6 +30,7 @@ from app.models.but_refcomp import (
|
|||||||
)
|
)
|
||||||
from app.models.config import ScoDocSiteConfig
|
from app.models.config import ScoDocSiteConfig
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
|
from app.models.evaluations import Evaluation
|
||||||
from app.models.formations import Formation
|
from app.models.formations import Formation
|
||||||
from app.models.groups import GroupDescr, Partition
|
from app.models.groups import GroupDescr, Partition
|
||||||
from app.models.moduleimpls import ModuleImpl, ModuleImplInscription
|
from app.models.moduleimpls import ModuleImpl, ModuleImplInscription
|
||||||
@ -350,6 +351,21 @@ class FormSemestre(db.Model):
|
|||||||
_cache[key] = ues
|
_cache[key] = ues
|
||||||
return ues
|
return ues
|
||||||
|
|
||||||
|
def get_evaluations(self) -> list[Evaluation]:
|
||||||
|
"Liste de toutes les évaluations du semestre, triées par module/numero"
|
||||||
|
return (
|
||||||
|
Evaluation.query.join(ModuleImpl)
|
||||||
|
.filter_by(formsemestre_id=self.id)
|
||||||
|
.join(Module)
|
||||||
|
.order_by(
|
||||||
|
Module.numero,
|
||||||
|
Module.code,
|
||||||
|
Evaluation.numero,
|
||||||
|
Evaluation.date_debut.desc(),
|
||||||
|
)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def modimpls_sorted(self) -> list[ModuleImpl]:
|
def modimpls_sorted(self) -> list[ModuleImpl]:
|
||||||
"""Liste des modimpls du semestre (y compris bonus)
|
"""Liste des modimpls du semestre (y compris bonus)
|
||||||
|
@ -509,7 +509,7 @@ def _get_abs_description(a, cursor=None):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def list_abs_jour(date, am=True, pm=True, is_abs=True, is_just=None):
|
def list_abs_jour(date, am=True, pm=True, is_abs=True, is_just=None) -> list[dict]:
|
||||||
"""Liste des absences et/ou justificatifs ce jour.
|
"""Liste des absences et/ou justificatifs ce jour.
|
||||||
is_abs: None (peu importe), True, False
|
is_abs: None (peu importe), True, False
|
||||||
is_just: idem
|
is_just: idem
|
||||||
@ -535,7 +535,7 @@ WHERE A.jour = %(date)s
|
|||||||
return A
|
return A
|
||||||
|
|
||||||
|
|
||||||
def list_abs_non_just_jour(date, am=True, pm=True):
|
def list_abs_non_just_jour(date, am=True, pm=True) -> list[dict]:
|
||||||
"Liste des absences non justifiees ce jour"
|
"Liste des absences non justifiees ce jour"
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
|
@ -972,12 +972,12 @@ def _tables_abs_etud(
|
|||||||
FROM notes_evaluation eval,
|
FROM notes_evaluation eval,
|
||||||
notes_moduleimpl_inscription mi,
|
notes_moduleimpl_inscription mi,
|
||||||
notes_moduleimpl m
|
notes_moduleimpl m
|
||||||
WHERE eval.jour = %(jour)s
|
WHERE DATE(eval.date_debut) = %(date_debut)s
|
||||||
and eval.moduleimpl_id = m.id
|
and eval.moduleimpl_id = m.id
|
||||||
and mi.moduleimpl_id = m.id
|
and mi.moduleimpl_id = m.id
|
||||||
and mi.etudid = %(etudid)s
|
and mi.etudid = %(etudid)s
|
||||||
""",
|
""",
|
||||||
{"jour": a["jour"].strftime("%Y-%m-%d"), "etudid": etudid},
|
{"date_debut": a["jour"], "etudid": etudid},
|
||||||
)
|
)
|
||||||
a["evals"] = cursor.dictfetchall()
|
a["evals"] = cursor.dictfetchall()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
|
@ -47,6 +47,7 @@ from app.comp.res_but import ResultatsSemestreBUT
|
|||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
from app.models import (
|
from app.models import (
|
||||||
ApcParcours,
|
ApcParcours,
|
||||||
|
Evaluation,
|
||||||
Formation,
|
Formation,
|
||||||
FormSemestre,
|
FormSemestre,
|
||||||
Identite,
|
Identite,
|
||||||
@ -482,6 +483,7 @@ def _ue_mod_bulletin(
|
|||||||
mods = [] # result
|
mods = [] # result
|
||||||
ue_attente = False # true si une eval en attente dans cette UE
|
ue_attente = False # true si une eval en attente dans cette UE
|
||||||
for modimpl in ue_modimpls:
|
for modimpl in ue_modimpls:
|
||||||
|
modimpl_results = nt.modimpls_results.get(modimpl["moduleimpl_id"])
|
||||||
mod_attente = False
|
mod_attente = False
|
||||||
mod = modimpl.copy()
|
mod = modimpl.copy()
|
||||||
mod_moy = nt.get_etud_mod_moy(
|
mod_moy = nt.get_etud_mod_moy(
|
||||||
@ -531,10 +533,13 @@ def _ue_mod_bulletin(
|
|||||||
scu.fmt_coef(modimpl["module"]["coefficient"]),
|
scu.fmt_coef(modimpl["module"]["coefficient"]),
|
||||||
sco_users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
sco_users.user_info(modimpl["responsable_id"])["nomcomplet"],
|
||||||
)
|
)
|
||||||
link_mod = (
|
link_mod = f"""<a class="bull_link" href="{
|
||||||
'<a class="bull_link" href="moduleimpl_status?moduleimpl_id=%s" title="%s">'
|
url_for("notes.moduleimpl_status",
|
||||||
% (modimpl["moduleimpl_id"], mod["mod_descr_txt"])
|
scodoc_dept=g.scodoc_dept,
|
||||||
)
|
moduleimpl_id=modimpl["moduleimpl_id"]
|
||||||
|
)
|
||||||
|
}" title="{mod["mod_descr_txt"]}">"""
|
||||||
|
|
||||||
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
if sco_preferences.get_preference("bul_show_codemodules", formsemestre_id):
|
||||||
mod["code"] = modimpl["module"]["code"]
|
mod["code"] = modimpl["module"]["code"]
|
||||||
mod["code_html"] = link_mod + (mod["code"] or "") + "</a>"
|
mod["code_html"] = link_mod + (mod["code"] or "") + "</a>"
|
||||||
@ -561,91 +566,88 @@ def _ue_mod_bulletin(
|
|||||||
mod["code_txt"] = ""
|
mod["code_txt"] = ""
|
||||||
mod["code_html"] = ""
|
mod["code_html"] = ""
|
||||||
# Evaluations: notes de chaque eval
|
# Evaluations: notes de chaque eval
|
||||||
evals = nt.get_evals_in_mod(modimpl["moduleimpl_id"])
|
evaluations_completes = nt.get_modimpl_evaluations_completes(
|
||||||
|
modimpl["moduleimpl_id"]
|
||||||
|
)
|
||||||
|
# On liste séparément les éval. complètes ou non
|
||||||
mod["evaluations"] = []
|
mod["evaluations"] = []
|
||||||
for e in evals:
|
mod["evaluations_incompletes"] = []
|
||||||
e = e.copy()
|
complete_eval_ids = {e.id for e in evaluations_completes}
|
||||||
if e["visibulletin"] or version == "long":
|
all_evals: list[Evaluation] = Evaluation.query.filter_by(
|
||||||
# affiche "bonus" quand les points de malus sont négatifs
|
moduleimpl_id=modimpl["moduleimpl_id"]
|
||||||
if is_malus:
|
).order_by(Evaluation.numero, Evaluation.date_debut)
|
||||||
val = e["notes"].get(etudid, {"value": "NP"})[
|
# (plus ancienne d'abord)
|
||||||
"value"
|
for e in all_evals:
|
||||||
] # NA si etud demissionnaire
|
if not e.visibulletin and version != "long":
|
||||||
if val == "NP" or val > 0:
|
continue
|
||||||
e["name"] = "Points de malus sur cette UE"
|
is_complete = e.id in complete_eval_ids
|
||||||
else:
|
e_dict = e.to_dict_bul()
|
||||||
e["name"] = "Points de bonus sur cette UE"
|
# Note à l'évaluation:
|
||||||
|
val = modimpl_results.evals_notes[e.id].get(etudid, "NP")
|
||||||
|
# Affiche "bonus" quand les points de malus sont négatifs
|
||||||
|
if is_malus:
|
||||||
|
if val == "NP":
|
||||||
|
e_dict["name"] = "Points de bonus/malus sur cette UE"
|
||||||
|
elif val > 0:
|
||||||
|
e_dict["name"] = "Points de malus sur cette UE"
|
||||||
else:
|
else:
|
||||||
e["name"] = e["description"] or f"le {e['jour']}"
|
e_dict["name"] = "Points de bonus sur cette UE"
|
||||||
e["target_html"] = url_for(
|
else:
|
||||||
|
e_dict[
|
||||||
|
"name"
|
||||||
|
] = f"""{e.description or ""} {
|
||||||
|
e.descr_date()
|
||||||
|
if e.date_debut and not is_complete
|
||||||
|
else ""}"""
|
||||||
|
e_dict["target_html"] = url_for(
|
||||||
"notes.evaluation_listenotes",
|
"notes.evaluation_listenotes",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
evaluation_id=e["evaluation_id"],
|
evaluation_id=e.id,
|
||||||
format="html",
|
format="html",
|
||||||
tf_submitted=1,
|
tf_submitted=1,
|
||||||
)
|
)
|
||||||
e[
|
e_dict[
|
||||||
"name_html"
|
"name_html"
|
||||||
] = f"""<a class="bull_link" href="{
|
] = f"""<a class="bull_link" href="{
|
||||||
e['target_html']}">{e['name']}</a>"""
|
e_dict['target_html']}">{e_dict['name']}</a>"""
|
||||||
val = e["notes"].get(etudid, {"value": "NP"})["value"]
|
if is_complete: # évaluation complète
|
||||||
# val est NP si etud demissionnaire
|
# val est NP si etud demissionnaire
|
||||||
if val == "NP":
|
if val == "NP":
|
||||||
e["note_txt"] = "nd"
|
e_dict["note_txt"] = "nd"
|
||||||
e["note_html"] = '<span class="note_nd">nd</span>'
|
e_dict["note_html"] = '<span class="note_nd">nd</span>'
|
||||||
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
e_dict["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
||||||
else:
|
|
||||||
# (-0.15) s'affiche "bonus de 0.15"
|
|
||||||
if is_malus:
|
|
||||||
val = abs(val)
|
|
||||||
e["note_txt"] = scu.fmt_note(val, note_max=e["note_max"])
|
|
||||||
e["note_html"] = e["note_txt"]
|
|
||||||
if is_malus:
|
|
||||||
e["coef_txt"] = ""
|
|
||||||
else:
|
else:
|
||||||
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
# (-0.15) s'affiche "bonus de 0.15"
|
||||||
if e["evaluation_type"] == scu.EVALUATION_RATTRAPAGE:
|
if is_malus:
|
||||||
e["coef_txt"] = "rat."
|
val = abs(val)
|
||||||
elif e["evaluation_type"] == scu.EVALUATION_SESSION2:
|
e_dict["note_txt"] = e_dict["note_html"] = scu.fmt_note(
|
||||||
e["coef_txt"] = "Ses. 2"
|
val, note_max=e.note_max
|
||||||
if e["etat"]["evalattente"]:
|
)
|
||||||
|
else: # évaluation incomplète: pas de note
|
||||||
|
e_dict["note_txt"] = e_dict["note_html"] = ""
|
||||||
|
|
||||||
|
if is_malus:
|
||||||
|
e_dict["coef_txt"] = ""
|
||||||
|
else:
|
||||||
|
e_dict["coef_txt"] = scu.fmt_coef(e.coefficient)
|
||||||
|
if e.evaluation_type == scu.EVALUATION_RATTRAPAGE:
|
||||||
|
e_dict["coef_txt"] = "rat."
|
||||||
|
elif e.evaluation_type == scu.EVALUATION_SESSION2:
|
||||||
|
e_dict["coef_txt"] = "Ses. 2"
|
||||||
|
|
||||||
|
if modimpl_results.evaluations_etat[e.id].nb_attente:
|
||||||
mod_attente = True # une eval en attente dans ce module
|
mod_attente = True # une eval en attente dans ce module
|
||||||
|
|
||||||
if ((not is_malus) or (val != "NP")) and (
|
if ((not is_malus) or (val != "NP")) and (
|
||||||
(
|
(e.evaluation_type == scu.EVALUATION_NORMALE or not np.isnan(val))
|
||||||
e["evaluation_type"] == scu.EVALUATION_NORMALE
|
|
||||||
or not np.isnan(val)
|
|
||||||
)
|
|
||||||
):
|
):
|
||||||
# ne liste pas les eval malus sans notes
|
# ne liste pas les eval malus sans notes
|
||||||
# ni les rattrapages et sessions 2 si pas de note
|
# ni les rattrapages et sessions 2 si pas de note
|
||||||
mod["evaluations"].append(e)
|
if e.id in complete_eval_ids:
|
||||||
|
mod["evaluations"].append(e_dict)
|
||||||
|
else:
|
||||||
|
mod["evaluations_incompletes"].append(e_dict)
|
||||||
|
|
||||||
# Evaluations incomplètes ou futures:
|
|
||||||
mod["evaluations_incompletes"] = []
|
|
||||||
if sco_preferences.get_preference("bul_show_all_evals", formsemestre_id):
|
|
||||||
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
|
||||||
all_evals = sco_evaluation_db.do_evaluation_list(
|
|
||||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
|
||||||
)
|
|
||||||
all_evals.reverse() # plus ancienne d'abord
|
|
||||||
for e in all_evals:
|
|
||||||
if e["evaluation_id"] not in complete_eval_ids:
|
|
||||||
e = e.copy()
|
|
||||||
mod["evaluations_incompletes"].append(e)
|
|
||||||
e["name"] = (e["description"] or "") + " (%s)" % e["jour"]
|
|
||||||
e["target_html"] = url_for(
|
|
||||||
"notes.evaluation_listenotes",
|
|
||||||
scodoc_dept=g.scodoc_dept,
|
|
||||||
evaluation_id=e["evaluation_id"],
|
|
||||||
tf_submitted=1,
|
|
||||||
format="html",
|
|
||||||
)
|
|
||||||
e["name_html"] = '<a class="bull_link" href="%s">%s</a>' % (
|
|
||||||
e["target_html"],
|
|
||||||
e["name"],
|
|
||||||
)
|
|
||||||
e["note_txt"] = e["note_html"] = ""
|
|
||||||
e["coef_txt"] = scu.fmt_coef(e["coefficient"])
|
|
||||||
# Classement
|
# Classement
|
||||||
if (
|
if (
|
||||||
bul_show_mod_rangs
|
bul_show_mod_rangs
|
||||||
|
@ -37,7 +37,7 @@ from app import db, ScoDocJSONEncoder
|
|||||||
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 but_validations
|
from app.models import but_validations
|
||||||
from app.models import Evaluation, Matiere, ModuleImpl, UniteEns
|
from app.models import Evaluation, Matiere, UniteEns
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
from app.models.formsemestre import FormSemestre
|
from app.models.formsemestre import FormSemestre
|
||||||
|
|
||||||
@ -46,7 +46,6 @@ import app.scodoc.notesdb as ndb
|
|||||||
from app.scodoc import sco_assiduites
|
from app.scodoc import sco_assiduites
|
||||||
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_evaluations
|
||||||
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
|
||||||
from app.scodoc import sco_photos
|
from app.scodoc import sco_photos
|
||||||
@ -333,6 +332,7 @@ def _list_modimpls(
|
|||||||
mod_moy = scu.fmt_note(nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid))
|
mod_moy = scu.fmt_note(nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid))
|
||||||
if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit
|
if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit
|
||||||
continue
|
continue
|
||||||
|
modimpl_results = nt.modimpls_results.get(modimpl["moduleimpl_id"])
|
||||||
mod = modimpl["module"]
|
mod = modimpl["module"]
|
||||||
# if mod['ects'] is None:
|
# if mod['ects'] is None:
|
||||||
# ects = ''
|
# ects = ''
|
||||||
@ -363,66 +363,42 @@ def _list_modimpls(
|
|||||||
mod_dict["effectif"] = dict(value=nt.mod_rangs[modimpl["moduleimpl_id"]][1])
|
mod_dict["effectif"] = dict(value=nt.mod_rangs[modimpl["moduleimpl_id"]][1])
|
||||||
|
|
||||||
# --- notes de chaque eval:
|
# --- notes de chaque eval:
|
||||||
evals = nt.get_evals_in_mod(modimpl["moduleimpl_id"])
|
evaluations_completes = nt.get_modimpl_evaluations_completes(
|
||||||
|
modimpl["moduleimpl_id"]
|
||||||
|
)
|
||||||
mod_dict["evaluation"] = []
|
mod_dict["evaluation"] = []
|
||||||
if version != "short":
|
if version != "short":
|
||||||
for e in evals:
|
for e in evaluations_completes:
|
||||||
if e["visibulletin"] or version == "long":
|
if e.visibulletin or version == "long":
|
||||||
val = e["notes"].get(etudid, {"value": "NP"})["value"]
|
# Note à l'évaluation:
|
||||||
|
val = modimpl_results.evals_notes[e.id].get(etudid, "NP")
|
||||||
# nb: val est NA si etud démissionnaire
|
# nb: val est NA si etud démissionnaire
|
||||||
val = scu.fmt_note(val, note_max=e["note_max"])
|
e_dict = e.to_dict_bul()
|
||||||
eval_dict = dict(
|
e_dict["note"] = scu.fmt_note(val, note_max=e.note_max)
|
||||||
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
|
||||||
heure_debut=ndb.TimetoISO8601(
|
|
||||||
e["heure_debut"], null_is_empty=True
|
|
||||||
),
|
|
||||||
heure_fin=ndb.TimetoISO8601(e["heure_fin"], null_is_empty=True),
|
|
||||||
coefficient=e["coefficient"],
|
|
||||||
evaluation_type=e["evaluation_type"],
|
|
||||||
# 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"]),
|
|
||||||
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"] = etat["mini"] # chaine, sur 20
|
|
||||||
eval_dict["max"] = etat["maxi"]
|
|
||||||
if prefs["bul_show_moypromo"]:
|
|
||||||
eval_dict["moy"] = etat["moy"]
|
|
||||||
|
|
||||||
mod_dict["evaluation"].append(eval_dict)
|
if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]:
|
||||||
|
# XXX à revoir pour utiliser modimplresult
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(e.id)
|
||||||
|
if prefs["bul_show_minmax_eval"]:
|
||||||
|
e_dict["min"] = etat["mini"] # chaine, sur 20
|
||||||
|
e_dict["max"] = etat["maxi"]
|
||||||
|
if prefs["bul_show_moypromo"]:
|
||||||
|
e_dict["moy"] = etat["moy"]
|
||||||
|
|
||||||
|
mod_dict["evaluation"].append(e_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 = {e.id for e in evaluations_completes}
|
||||||
if prefs["bul_show_all_evals"]:
|
if prefs["bul_show_all_evals"]:
|
||||||
evaluations = Evaluation.query.filter_by(
|
evaluations: list[Evaluation] = Evaluation.query.filter_by(
|
||||||
moduleimpl_id=modimpl["moduleimpl_id"]
|
moduleimpl_id=modimpl["moduleimpl_id"]
|
||||||
).order_by(Evaluation.date_debut)
|
).order_by(Evaluation.date_debut)
|
||||||
# plus ancienne d'abord
|
# plus ancienne d'abord
|
||||||
for e in evaluations:
|
for e in evaluations:
|
||||||
if e.id not in complete_eval_ids:
|
if e.id not in complete_eval_ids:
|
||||||
mod_dict["evaluation"].append(
|
e_dict = e.to_dict_bul()
|
||||||
dict(
|
e_dict["incomplete"] = 1
|
||||||
date_debut=e.date_debut.isoformat()
|
mod_dict["evaluation"].append(e_dict)
|
||||||
if e.date_debut
|
|
||||||
else None,
|
|
||||||
date_fin=e.date_fin.isoformat() if e.date_fin else None,
|
|
||||||
coefficient=e.coefficient,
|
|
||||||
description=quote_xml_attr(e.description or ""),
|
|
||||||
incomplete="1",
|
|
||||||
# Deprecated:
|
|
||||||
jour=e.date_debut.isoformat() if e.date_debut else "",
|
|
||||||
heure_debut=ndb.TimetoISO8601(
|
|
||||||
e["heure_debut"], null_is_empty=True
|
|
||||||
),
|
|
||||||
heure_fin=ndb.TimetoISO8601(
|
|
||||||
e["heure_fin"], null_is_empty=True
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
modules_dict.append(mod_dict)
|
modules_dict.append(mod_dict)
|
||||||
return modules_dict
|
return modules_dict
|
||||||
|
|
||||||
|
@ -242,6 +242,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
# Liste les modules de l'UE
|
# Liste les modules de l'UE
|
||||||
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
|
||||||
for modimpl in ue_modimpls:
|
for modimpl in ue_modimpls:
|
||||||
|
modimpl_results = nt.modimpls_results.get(modimpl["moduleimpl_id"])
|
||||||
mod_moy = scu.fmt_note(
|
mod_moy = scu.fmt_note(
|
||||||
nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)
|
||||||
)
|
)
|
||||||
@ -290,33 +291,24 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
# --- notes de chaque eval:
|
# --- notes de chaque eval:
|
||||||
evals = nt.get_evals_in_mod(modimpl["moduleimpl_id"])
|
evaluations_completes = nt.get_modimpl_evaluations_completes(
|
||||||
|
modimpl["moduleimpl_id"]
|
||||||
|
)
|
||||||
if version != "short":
|
if version != "short":
|
||||||
for e in evals:
|
for e in evaluations_completes:
|
||||||
if e["visibulletin"] or version == "long":
|
if e.visibulletin or version == "long":
|
||||||
x_eval = Element(
|
# pour xml, tout convertir en chaines
|
||||||
"evaluation",
|
e_dict = {k: str(v) for k, v in e.to_dict_bul().items()}
|
||||||
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
# notes envoyées sur 20, ceci juste pour garder trace:
|
||||||
heure_debut=ndb.TimetoISO8601(
|
e_dict["note_max_origin"] = str(e.note_max)
|
||||||
e["heure_debut"], null_is_empty=True
|
x_eval = Element("evaluation", **e_dict)
|
||||||
),
|
|
||||||
heure_fin=ndb.TimetoISO8601(
|
|
||||||
e["heure_fin"], null_is_empty=True
|
|
||||||
),
|
|
||||||
coefficient=str(e["coefficient"]),
|
|
||||||
evaluation_type=str(e["evaluation_type"]),
|
|
||||||
description=quote_xml_attr(e["description"]),
|
|
||||||
# notes envoyées sur 20, ceci juste pour garder trace:
|
|
||||||
note_max_origin=str(e["note_max"]),
|
|
||||||
)
|
|
||||||
x_mod.append(x_eval)
|
x_mod.append(x_eval)
|
||||||
val = e["notes"].get(etudid, {"value": "NP"})[
|
# Note à l'évaluation:
|
||||||
"value"
|
val = modimpl_results.evals_notes[e.id].get(etudid, "NP")
|
||||||
] # NA si etud demissionnaire
|
val = scu.fmt_note(val, note_max=e.note_max)
|
||||||
val = scu.fmt_note(val, note_max=e["note_max"])
|
|
||||||
x_eval.append(Element("note", value=val))
|
x_eval.append(Element("note", value=val))
|
||||||
# Evaluations incomplètes ou futures:
|
# Evaluations incomplètes ou futures:
|
||||||
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
complete_eval_ids = {e.id for e in evaluations_completes}
|
||||||
if sco_preferences.get_preference(
|
if sco_preferences.get_preference(
|
||||||
"bul_show_all_evals", formsemestre_id
|
"bul_show_all_evals", formsemestre_id
|
||||||
):
|
):
|
||||||
@ -325,21 +317,8 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
).order_by(Evaluation.date_debut)
|
).order_by(Evaluation.date_debut)
|
||||||
for e in evaluations:
|
for e in evaluations:
|
||||||
if e.id not in complete_eval_ids:
|
if e.id not in complete_eval_ids:
|
||||||
x_eval = Element(
|
e_dict = e.to_dict_bul()
|
||||||
"evaluation",
|
x_eval = Element("evaluation", **e_dict)
|
||||||
jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
|
||||||
heure_debut=ndb.TimetoISO8601(
|
|
||||||
e["heure_debut"], null_is_empty=True
|
|
||||||
),
|
|
||||||
heure_fin=ndb.TimetoISO8601(
|
|
||||||
e["heure_fin"], null_is_empty=True
|
|
||||||
),
|
|
||||||
coefficient=str(e["coefficient"]),
|
|
||||||
description=quote_xml_attr(e["description"]),
|
|
||||||
incomplete="1",
|
|
||||||
# notes envoyées sur 20, ceci juste pour garder trace:
|
|
||||||
note_max_origin=str(e["note_max"] or ""),
|
|
||||||
)
|
|
||||||
x_mod.append(x_eval)
|
x_mod.append(x_eval)
|
||||||
# UE capitalisee (listee seulement si meilleure que l'UE courante)
|
# UE capitalisee (listee seulement si meilleure que l'UE courante)
|
||||||
if ue_status["is_capitalized"]:
|
if ue_status["is_capitalized"]:
|
||||||
|
@ -29,8 +29,9 @@
|
|||||||
"""
|
"""
|
||||||
from flask import url_for, g
|
from flask import url_for, g
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app.models import Evaluation, Identite
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
@ -40,25 +41,8 @@ from app.scodoc import sco_formsemestre
|
|||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
|
|
||||||
# matin et/ou après-midi ?
|
|
||||||
def _eval_demijournee(E):
|
|
||||||
"1 si matin, 0 si apres midi, 2 si toute la journee"
|
|
||||||
am, pm = False, False
|
|
||||||
if E["heure_debut"] < "13:00":
|
|
||||||
am = True
|
|
||||||
if E["heure_fin"] > "13:00":
|
|
||||||
pm = True
|
|
||||||
if am and pm:
|
|
||||||
demijournee = 2
|
|
||||||
elif am:
|
|
||||||
demijournee = 1
|
|
||||||
else:
|
|
||||||
demijournee = 0
|
|
||||||
pm = True
|
|
||||||
return am, pm, demijournee
|
|
||||||
|
|
||||||
|
def evaluation_check_absences(evaluation: Evaluation):
|
||||||
def evaluation_check_absences(evaluation_id):
|
|
||||||
"""Vérifie les absences au moment de cette évaluation.
|
"""Vérifie les absences au moment de cette évaluation.
|
||||||
Cas incohérents que l'on peut rencontrer pour chaque étudiant:
|
Cas incohérents que l'on peut rencontrer pour chaque étudiant:
|
||||||
note et absent
|
note et absent
|
||||||
@ -66,51 +50,58 @@ def evaluation_check_absences(evaluation_id):
|
|||||||
ABS et absent justifié
|
ABS et absent justifié
|
||||||
EXC et pas noté absent
|
EXC et pas noté absent
|
||||||
EXC et pas justifie
|
EXC et pas justifie
|
||||||
Ramene 3 listes d'etudid
|
Ramene 5 listes d'etudid
|
||||||
"""
|
"""
|
||||||
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
if not evaluation.date_debut:
|
||||||
if not E["jour"]:
|
|
||||||
return [], [], [], [], [] # evaluation sans date
|
return [], [], [], [], [] # evaluation sans date
|
||||||
|
|
||||||
am, pm, demijournee = _eval_demijournee(E)
|
am, pm = evaluation.is_matin(), evaluation.is_apresmidi()
|
||||||
|
|
||||||
# Liste les absences à ce moment:
|
# Liste les absences à ce moment:
|
||||||
A = sco_abs.list_abs_jour(ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm)
|
absences = sco_abs.list_abs_jour(evaluation.date_debut, am=am, pm=pm)
|
||||||
As = set([x["etudid"] for x in A]) # ensemble des etudiants absents
|
abs_etudids = set([x["etudid"] for x in absences]) # ensemble des etudiants absents
|
||||||
NJ = sco_abs.list_abs_non_just_jour(ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm)
|
abs_non_just = sco_abs.list_abs_non_just_jour(
|
||||||
NJs = set([x["etudid"] for x in NJ]) # ensemble des etudiants absents non justifies
|
evaluation.date_debut.date(), am=am, pm=pm
|
||||||
Just = sco_abs.list_abs_jour(
|
|
||||||
ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm, is_abs=None, is_just=True
|
|
||||||
)
|
)
|
||||||
Justs = set([x["etudid"] for x in Just]) # ensemble des etudiants avec justif
|
abs_nj_etudids = set(
|
||||||
|
[x["etudid"] for x in abs_non_just]
|
||||||
|
) # ensemble des etudiants absents non justifies
|
||||||
|
justifs = sco_abs.list_abs_jour(
|
||||||
|
evaluation.date_debut.date(), am=am, pm=pm, is_abs=None, is_just=True
|
||||||
|
)
|
||||||
|
just_etudids = set(
|
||||||
|
[x["etudid"] for x in justifs]
|
||||||
|
) # ensemble des etudiants avec justif
|
||||||
|
|
||||||
# Les notes:
|
# Les notes:
|
||||||
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation.id)
|
||||||
ValButAbs = [] # une note mais noté absent
|
ValButAbs = [] # une note mais noté absent
|
||||||
AbsNonSignalee = [] # note ABS mais pas noté absent
|
AbsNonSignalee = [] # note ABS mais pas noté absent
|
||||||
ExcNonSignalee = [] # note EXC mais pas noté absent
|
ExcNonSignalee = [] # note EXC mais pas noté absent
|
||||||
ExcNonJust = [] # note EXC mais absent non justifie
|
ExcNonJust = [] # note EXC mais absent non justifie
|
||||||
AbsButExc = [] # note ABS mais justifié
|
AbsButExc = [] # note ABS mais justifié
|
||||||
for etudid, _ in sco_groups.do_evaluation_listeetuds_groups(
|
for etudid, _ in sco_groups.do_evaluation_listeetuds_groups(
|
||||||
evaluation_id, getallstudents=True
|
evaluation.id, getallstudents=True
|
||||||
):
|
):
|
||||||
if etudid in notes_db:
|
if etudid in notes_db:
|
||||||
val = notes_db[etudid]["value"]
|
val = notes_db[etudid]["value"]
|
||||||
if (
|
if (
|
||||||
val != None and val != scu.NOTES_NEUTRALISE and val != scu.NOTES_ATTENTE
|
val is not None
|
||||||
) and etudid in As:
|
and val != scu.NOTES_NEUTRALISE
|
||||||
|
and val != scu.NOTES_ATTENTE
|
||||||
|
) and etudid in abs_etudids:
|
||||||
# note valide et absent
|
# note valide et absent
|
||||||
ValButAbs.append(etudid)
|
ValButAbs.append(etudid)
|
||||||
if val is None and not etudid in As:
|
if val is None and not etudid in abs_etudids:
|
||||||
# absent mais pas signale comme tel
|
# absent mais pas signale comme tel
|
||||||
AbsNonSignalee.append(etudid)
|
AbsNonSignalee.append(etudid)
|
||||||
if val == scu.NOTES_NEUTRALISE and not etudid in As:
|
if val == scu.NOTES_NEUTRALISE and not etudid in abs_etudids:
|
||||||
# Neutralisé mais pas signale absent
|
# Neutralisé mais pas signale absent
|
||||||
ExcNonSignalee.append(etudid)
|
ExcNonSignalee.append(etudid)
|
||||||
if val == scu.NOTES_NEUTRALISE and etudid in NJs:
|
if val == scu.NOTES_NEUTRALISE and etudid in abs_nj_etudids:
|
||||||
# EXC mais pas justifié
|
# EXC mais pas justifié
|
||||||
ExcNonJust.append(etudid)
|
ExcNonJust.append(etudid)
|
||||||
if val is None and etudid in Justs:
|
if val is None and etudid in just_etudids:
|
||||||
# ABS mais justificatif
|
# ABS mais justificatif
|
||||||
AbsButExc.append(etudid)
|
AbsButExc.append(etudid)
|
||||||
|
|
||||||
@ -119,9 +110,16 @@ def evaluation_check_absences(evaluation_id):
|
|||||||
|
|
||||||
def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True):
|
def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True):
|
||||||
"""Affiche état vérification absences d'une évaluation"""
|
"""Affiche état vérification absences d'une évaluation"""
|
||||||
|
evaluation: Evaluation = db.session.get(Evaluation, evaluation_id)
|
||||||
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
am, pm = evaluation.is_matin(), evaluation.is_apresmidi()
|
||||||
am, pm, demijournee = _eval_demijournee(E)
|
# 1 si matin, 0 si apres midi, 2 si toute la journee:
|
||||||
|
match am, pm:
|
||||||
|
case False, True:
|
||||||
|
demijournee = 0
|
||||||
|
case True, False:
|
||||||
|
demijournee = 1
|
||||||
|
case _:
|
||||||
|
demijournee = 2
|
||||||
|
|
||||||
(
|
(
|
||||||
ValButAbs,
|
ValButAbs,
|
||||||
@ -129,19 +127,23 @@ def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True
|
|||||||
ExcNonSignalee,
|
ExcNonSignalee,
|
||||||
ExcNonJust,
|
ExcNonJust,
|
||||||
AbsButExc,
|
AbsButExc,
|
||||||
) = evaluation_check_absences(evaluation_id)
|
) = evaluation_check_absences(evaluation)
|
||||||
|
|
||||||
if with_header:
|
if with_header:
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.html_sem_header("Vérification absences à l'évaluation"),
|
html_sco_header.html_sem_header("Vérification absences à l'évaluation"),
|
||||||
sco_evaluations.evaluation_describe(evaluation_id=evaluation_id),
|
sco_evaluations.evaluation_describe(evaluation_id=evaluation.id),
|
||||||
"""<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées.</p>""",
|
"""<p class="help">Vérification de la cohérence entre les notes saisies
|
||||||
|
et les absences signalées.</p>""",
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
# pas de header, mais un titre
|
# pas de header, mais un titre
|
||||||
H = [
|
H = [
|
||||||
"""<h2 class="eval_check_absences">%s du %s """
|
f"""<h2 class="eval_check_absences">{
|
||||||
% (E["description"], E["jour"])
|
evaluation.description or "évaluation"
|
||||||
|
} du {
|
||||||
|
evaluation.date_debut.strftime("%d/%m/%Y") if evaluation.date_debut else ""
|
||||||
|
} """
|
||||||
]
|
]
|
||||||
if (
|
if (
|
||||||
not ValButAbs
|
not ValButAbs
|
||||||
@ -157,26 +159,27 @@ def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True
|
|||||||
if not etudids and show_ok:
|
if not etudids and show_ok:
|
||||||
H.append("<li>aucun</li>")
|
H.append("<li>aucun</li>")
|
||||||
for etudid in etudids:
|
for etudid in etudids:
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
etud: Identite = db.session.get(Identite, etudid)
|
||||||
H.append(
|
H.append(
|
||||||
'<li><a class="discretelink" href="%s">'
|
f"""<li><a class="discretelink" href="{
|
||||||
% url_for(
|
url_for(
|
||||||
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"]
|
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid
|
||||||
)
|
)
|
||||||
+ "%(nomprenom)s</a>" % etud
|
}">{etud.nomprenom}</a>"""
|
||||||
)
|
)
|
||||||
if linkabs:
|
if linkabs:
|
||||||
H.append(
|
url = url_for(
|
||||||
f"""<a class="stdlink" href="{url_for(
|
"absences.doSignaleAbsence",
|
||||||
'absences.doSignaleAbsence',
|
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
etudid=etud["etudid"],
|
etudid=etudid,
|
||||||
datedebut=E["jour"],
|
# par defaut signale le jour du début de l'éval
|
||||||
datefin=E["jour"],
|
datedebut=evaluation.date_debut.strftime("%d/%m/%Y"),
|
||||||
|
datefin=evaluation.date_debut.strftime("%d/%m/%Y"),
|
||||||
demijournee=demijournee,
|
demijournee=demijournee,
|
||||||
moduleimpl_id=E["moduleimpl_id"],
|
moduleimpl_id=evaluation.moduleimpl_id,
|
||||||
)
|
)
|
||||||
}">signaler cette absence</a>"""
|
H.append(
|
||||||
|
f"""<a class="stdlink" href="{url}">signaler cette absence</a>"""
|
||||||
)
|
)
|
||||||
H.append("</li>")
|
H.append("</li>")
|
||||||
H.append("</ul>")
|
H.append("</ul>")
|
||||||
@ -231,7 +234,7 @@ def formsemestre_check_absences_html(formsemestre_id):
|
|||||||
# Modules, dans l'ordre
|
# Modules, dans l'ordre
|
||||||
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
for M in Mlist:
|
for M in Mlist:
|
||||||
evals = sco_evaluation_db.do_evaluation_list(
|
evals = sco_evaluation_db.get_evaluation_dict(
|
||||||
{"moduleimpl_id": M["moduleimpl_id"]}
|
{"moduleimpl_id": M["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
if evals:
|
if evals:
|
||||||
|
@ -37,14 +37,13 @@ from flask_login import current_user
|
|||||||
from app import db, log
|
from app import db, log
|
||||||
|
|
||||||
from app.models import Evaluation, ModuleImpl, ScolarNews
|
from app.models import Evaluation, ModuleImpl, ScolarNews
|
||||||
from app.models.evaluations import evaluation_enrich_dict, check_convert_evaluation_args
|
from app.models.evaluations import check_convert_evaluation_args
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
|
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_permissions_check
|
|
||||||
|
|
||||||
|
|
||||||
_evaluationEditor = ndb.EditableTable(
|
_evaluationEditor = ndb.EditableTable(
|
||||||
@ -53,9 +52,8 @@ _evaluationEditor = ndb.EditableTable(
|
|||||||
(
|
(
|
||||||
"evaluation_id",
|
"evaluation_id",
|
||||||
"moduleimpl_id",
|
"moduleimpl_id",
|
||||||
"jour",
|
"date_debut",
|
||||||
"heure_debut",
|
"date_fin",
|
||||||
"heure_fin",
|
|
||||||
"description",
|
"description",
|
||||||
"note_max",
|
"note_max",
|
||||||
"coefficient",
|
"coefficient",
|
||||||
@ -64,15 +62,11 @@ _evaluationEditor = ndb.EditableTable(
|
|||||||
"evaluation_type",
|
"evaluation_type",
|
||||||
"numero",
|
"numero",
|
||||||
),
|
),
|
||||||
sortkey="numero desc, jour desc, heure_debut desc", # plus recente d'abord
|
sortkey="numero, date_debut desc", # plus recente d'abord
|
||||||
output_formators={
|
output_formators={
|
||||||
"jour": ndb.DateISOtoDMY,
|
|
||||||
"numero": ndb.int_null_is_zero,
|
"numero": ndb.int_null_is_zero,
|
||||||
},
|
},
|
||||||
input_formators={
|
input_formators={
|
||||||
"jour": ndb.DateDMYtoISO,
|
|
||||||
"heure_debut": ndb.TimetoISO8601, # converti par evaluation_enrich_dict
|
|
||||||
"heure_fin": ndb.TimetoISO8601, # converti par evaluation_enrich_dict
|
|
||||||
"visibulletin": bool,
|
"visibulletin": bool,
|
||||||
"publish_incomplete": bool,
|
"publish_incomplete": bool,
|
||||||
"evaluation_type": int,
|
"evaluation_type": int,
|
||||||
@ -80,8 +74,9 @@ _evaluationEditor = ndb.EditableTable(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_list(args, sortkey=None):
|
def get_evaluation_dict(args: dict) -> list[dict]:
|
||||||
"""List evaluations, sorted by numero (or most recent date first).
|
"""Liste evaluations, triées numero (or most recent date first).
|
||||||
|
Fonction de transition pour ancien code ScoDoc7.
|
||||||
|
|
||||||
Ajoute les champs:
|
Ajoute les champs:
|
||||||
'duree' : '2h30'
|
'duree' : '2h30'
|
||||||
@ -89,13 +84,8 @@ def do_evaluation_list(args, sortkey=None):
|
|||||||
'apresmidi' : 1 (termine après 12:00) ou 0
|
'apresmidi' : 1 (termine après 12:00) ou 0
|
||||||
'descrheure' : ' de 15h00 à 16h30'
|
'descrheure' : ' de 15h00 à 16h30'
|
||||||
"""
|
"""
|
||||||
cnx = ndb.GetDBConnexion()
|
|
||||||
evals = _evaluationEditor.list(cnx, args, sortkey=sortkey)
|
|
||||||
# calcule duree (chaine de car.) de chaque evaluation et ajoute jour_iso, matin, apresmidi
|
# calcule duree (chaine de car.) de chaque evaluation et ajoute jour_iso, matin, apresmidi
|
||||||
for e in evals:
|
return [e.to_dict() for e in Evaluation.query.filter_by(**args)]
|
||||||
evaluation_enrich_dict(e)
|
|
||||||
|
|
||||||
return evals
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_list_in_formsemestre(formsemestre_id):
|
def do_evaluation_list_in_formsemestre(formsemestre_id):
|
||||||
@ -103,7 +93,7 @@ def do_evaluation_list_in_formsemestre(formsemestre_id):
|
|||||||
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
evals = []
|
evals = []
|
||||||
for modimpl in mods:
|
for modimpl in mods:
|
||||||
evals += do_evaluation_list(args={"moduleimpl_id": modimpl["moduleimpl_id"]})
|
evals += get_evaluation_dict(args={"moduleimpl_id": modimpl["moduleimpl_id"]})
|
||||||
return evals
|
return evals
|
||||||
|
|
||||||
|
|
||||||
@ -219,12 +209,12 @@ def moduleimpl_evaluation_move(evaluation_id: int, after=0, redirect=1):
|
|||||||
Evaluation.moduleimpl_evaluation_renumber(
|
Evaluation.moduleimpl_evaluation_renumber(
|
||||||
evaluation.moduleimpl, only_if_unumbered=True
|
evaluation.moduleimpl, only_if_unumbered=True
|
||||||
)
|
)
|
||||||
e = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
e = get_evaluation_dict(args={"evaluation_id": evaluation_id})[0]
|
||||||
|
|
||||||
after = int(after) # 0: deplace avant, 1 deplace apres
|
after = int(after) # 0: deplace avant, 1 deplace apres
|
||||||
if after not in (0, 1):
|
if after not in (0, 1):
|
||||||
raise ValueError('invalid value for "after"')
|
raise ValueError('invalid value for "after"')
|
||||||
mod_evals = do_evaluation_list({"moduleimpl_id": e["moduleimpl_id"]})
|
mod_evals = get_evaluation_dict({"moduleimpl_id": e["moduleimpl_id"]})
|
||||||
if len(mod_evals) > 1:
|
if len(mod_evals) > 1:
|
||||||
idx = [p["evaluation_id"] for p in mod_evals].index(evaluation_id)
|
idx = [p["evaluation_id"] for p in mod_evals].index(evaluation_id)
|
||||||
neigh = None # object to swap with
|
neigh = None # object to swap with
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
"""Formulaire ajout/édition d'une évaluation
|
"""Formulaire ajout/édition d'une évaluation
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
@ -38,6 +38,7 @@ from flask import request
|
|||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import Evaluation, FormSemestre, ModuleImpl
|
from app.models import Evaluation, FormSemestre, ModuleImpl
|
||||||
|
from app.models.evaluations import heure_to_time
|
||||||
|
|
||||||
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
|
||||||
@ -47,7 +48,6 @@ from app.scodoc import html_sco_header
|
|||||||
from app.scodoc import sco_evaluations
|
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_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_permissions_check
|
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
|
|
||||||
|
|
||||||
@ -139,15 +139,8 @@ def evaluation_create_form(
|
|||||||
|
|
||||||
heures = [f"{h:02d}h{m:02d}" for h in range(8, 19) for m in (0, 30)]
|
heures = [f"{h:02d}h{m:02d}" for h in range(8, 19) for m in (0, 30)]
|
||||||
#
|
#
|
||||||
initvalues["visibulletin"] = initvalues.get("visibulletin", True)
|
|
||||||
if initvalues["visibulletin"]:
|
|
||||||
initvalues["visibulletinlist"] = ["X"]
|
|
||||||
else:
|
|
||||||
initvalues["visibulletinlist"] = []
|
|
||||||
initvalues["coefficient"] = initvalues.get("coefficient", 1.0)
|
initvalues["coefficient"] = initvalues.get("coefficient", 1.0)
|
||||||
vals = scu.get_request_args()
|
vals = scu.get_request_args()
|
||||||
if vals.get("tf_submitted", False) and "visibulletinlist" not in vals:
|
|
||||||
vals["visibulletinlist"] = []
|
|
||||||
#
|
#
|
||||||
ue_coef_dict = modimpl.module.get_ue_coef_dict()
|
ue_coef_dict = modimpl.module.get_ue_coef_dict()
|
||||||
if is_apc: # BUT: poids vers les UE
|
if is_apc: # BUT: poids vers les UE
|
||||||
@ -236,11 +229,9 @@ def evaluation_create_form(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"visibulletinlist",
|
"visibulletin",
|
||||||
{
|
{
|
||||||
"input_type": "checkbox",
|
"input_type": "boolcheckbox",
|
||||||
"allowed_values": ["X"],
|
|
||||||
"labels": [""],
|
|
||||||
"title": "Visible sur bulletins",
|
"title": "Visible sur bulletins",
|
||||||
"explanation": "(pour les bulletins en version intermédiaire)",
|
"explanation": "(pour les bulletins en version intermédiaire)",
|
||||||
},
|
},
|
||||||
@ -349,15 +340,37 @@ def evaluation_create_form(
|
|||||||
return flask.redirect(dest_url)
|
return flask.redirect(dest_url)
|
||||||
else:
|
else:
|
||||||
# form submission
|
# form submission
|
||||||
if tf[2]["visibulletinlist"]:
|
args = tf[2]
|
||||||
tf[2]["visibulletin"] = True
|
# modifie le codage des dates
|
||||||
|
# (nb: ce formulaire ne permet de créer que des évaluation sur la même journée)
|
||||||
|
if args.get("jour"):
|
||||||
|
try:
|
||||||
|
date_debut = datetime.datetime.strptime(args["jour"], "%d/%m/%Y")
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ScoValueError("Date (j/m/a) invalide") from exc
|
||||||
else:
|
else:
|
||||||
tf[2]["visibulletin"] = False
|
date_debut = None
|
||||||
|
args.pop("jour", None)
|
||||||
|
if args.get("heure_debut"):
|
||||||
|
try:
|
||||||
|
heure_debut = heure_to_time(args["heure_debut"])
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ScoValueError("Heure début invalide") from exc
|
||||||
|
args["date_debut"] = datetime.datetime.combine(date_debut, heure_debut)
|
||||||
|
args.pop("heure_debut", None)
|
||||||
|
if args.get("heure_fin"):
|
||||||
|
try:
|
||||||
|
heure_fin = heure_to_time(args["heure_fin"])
|
||||||
|
except ValueError as exc:
|
||||||
|
raise ScoValueError("Heure fin invalide") from exc
|
||||||
|
args["date_fin"] = datetime.datetime.combine(date_debut, heure_fin)
|
||||||
|
args.pop("heure_fin", None)
|
||||||
|
#
|
||||||
if edit:
|
if edit:
|
||||||
sco_evaluation_db.do_evaluation_edit(tf[2])
|
evaluation.from_dict(args)
|
||||||
else:
|
else:
|
||||||
# création d'une evaluation
|
# création d'une evaluation
|
||||||
evaluation = Evaluation.create(moduleimpl=modimpl, **tf[2])
|
evaluation = Evaluation.create(moduleimpl=modimpl, **args)
|
||||||
db.session.add(evaluation)
|
db.session.add(evaluation)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
evaluation_id = evaluation.id
|
evaluation_id = evaluation.id
|
||||||
@ -366,6 +379,6 @@ def evaluation_create_form(
|
|||||||
evaluation = db.session.get(Evaluation, evaluation_id)
|
evaluation = db.session.get(Evaluation, evaluation_id)
|
||||||
for ue in sem_ues:
|
for ue in sem_ues:
|
||||||
evaluation.set_ue_poids(ue, tf[2][f"poids_{ue.id}"])
|
evaluation.set_ue_poids(ue, tf[2][f"poids_{ue.id}"])
|
||||||
db.session.add(evaluation)
|
db.session.add(evaluation)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return flask.redirect(dest_url)
|
return flask.redirect(dest_url)
|
||||||
|
@ -126,8 +126,8 @@ def evaluations_recap_table(formsemestre: FormSemestre) -> list[dict]:
|
|||||||
evaluation_id=evaluation_id,
|
evaluation_id=evaluation_id,
|
||||||
),
|
),
|
||||||
"_titre_target_attrs": 'class="discretelink"',
|
"_titre_target_attrs": 'class="discretelink"',
|
||||||
"date": e.jour.strftime("%d/%m/%Y") if e.jour else "",
|
"date": e.date_debut.strftime("%d/%m/%Y") if e.date_debut else "",
|
||||||
"_date_order": e.jour.isoformat() if e.jour else "",
|
"_date_order": e.date_debut.isoformat() if e.date_debut else "",
|
||||||
"complete": "oui" if eval_etat.is_complete else "non",
|
"complete": "oui" if eval_etat.is_complete else "non",
|
||||||
"_complete_target": "#",
|
"_complete_target": "#",
|
||||||
"_complete_target_attrs": 'class="bull_link" title="prise en compte dans les moyennes"'
|
"_complete_target_attrs": 'class="bull_link" title="prise en compte dans les moyennes"'
|
||||||
|
@ -101,6 +101,14 @@ def do_evaluation_etat(
|
|||||||
) -> dict:
|
) -> dict:
|
||||||
"""Donne infos sur l'état de l'évaluation.
|
"""Donne infos sur l'état de l'évaluation.
|
||||||
Ancienne fonction, lente: préférer ModuleImplResults pour tout calcul.
|
Ancienne fonction, lente: préférer ModuleImplResults pour tout calcul.
|
||||||
|
XXX utilisée par de très nombreuses fonctions, dont
|
||||||
|
- _eval_etat<do_evaluation_etat_in_sem (en cours de remplacement)
|
||||||
|
|
||||||
|
- _eval_etat<do_evaluation_etat_in_mod<formsemestre_tableau_modules
|
||||||
|
qui a seulement besoin de
|
||||||
|
nb_evals_completes, nb_evals_en_cours, nb_evals_vides, attente
|
||||||
|
|
||||||
|
renvoie:
|
||||||
{
|
{
|
||||||
nb_inscrits : inscrits au module
|
nb_inscrits : inscrits au module
|
||||||
nb_notes
|
nb_notes
|
||||||
@ -124,7 +132,7 @@ def do_evaluation_etat(
|
|||||||
) # { etudid : note }
|
) # { etudid : note }
|
||||||
|
|
||||||
# ---- Liste des groupes complets et incomplets
|
# ---- Liste des groupes complets et incomplets
|
||||||
E = sco_evaluation_db.do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.get_evaluation_dict(args={"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
is_malus = Mod["module_type"] == ModuleType.MALUS # True si module de malus
|
is_malus = Mod["module_type"] == ModuleType.MALUS # True si module de malus
|
||||||
@ -275,7 +283,8 @@ def do_evaluation_etat(
|
|||||||
|
|
||||||
|
|
||||||
def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
||||||
"""Liste les evaluations de tous les modules de ce semestre.
|
"""Liste les évaluations de tous les modules de ce semestre.
|
||||||
|
Triée par module, numero desc, date_debut desc
|
||||||
Donne pour chaque eval son état (voir do_evaluation_etat)
|
Donne pour chaque eval son état (voir do_evaluation_etat)
|
||||||
{ evaluation_id,nb_inscrits, nb_notes, nb_abs, nb_neutre, moy, median, last_modif ... }
|
{ evaluation_id,nb_inscrits, nb_notes, nb_abs, nb_neutre, moy, median, last_modif ... }
|
||||||
|
|
||||||
@ -315,7 +324,7 @@ def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
|||||||
'evaluation_type': 0,
|
'evaluation_type': 0,
|
||||||
'heure_debut': datetime.time(8, 0),
|
'heure_debut': datetime.time(8, 0),
|
||||||
'heure_fin': datetime.time(9, 30),
|
'heure_fin': datetime.time(9, 30),
|
||||||
'jour': datetime.date(2015, 11, 3), // vide => 1/1/1
|
'jour': datetime.date(2015, 11, 3), // vide => 1/1/1900
|
||||||
'moduleimpl_id': 'GEAMIP80490',
|
'moduleimpl_id': 'GEAMIP80490',
|
||||||
'note_max': 20.0,
|
'note_max': 20.0,
|
||||||
'numero': 0,
|
'numero': 0,
|
||||||
@ -323,11 +332,11 @@ def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
|||||||
'visibulletin': 1} ]
|
'visibulletin': 1} ]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
req = """SELECT E.id AS evaluation_id, E.*
|
req = """SELECT E.id AS evaluation_id, E.*
|
||||||
FROM notes_evaluation E, notes_moduleimpl MI
|
FROM notes_evaluation E, notes_moduleimpl MI
|
||||||
WHERE MI.formsemestre_id = %(formsemestre_id)s
|
WHERE MI.formsemestre_id = %(formsemestre_id)s
|
||||||
and MI.id = E.moduleimpl_id
|
and MI.id = E.moduleimpl_id
|
||||||
ORDER BY MI.id, numero desc, jour desc, heure_debut DESC
|
ORDER BY MI.id, numero desc, date_debut desc
|
||||||
"""
|
"""
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
@ -335,9 +344,9 @@ def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
|||||||
res = cursor.dictfetchall()
|
res = cursor.dictfetchall()
|
||||||
# etat de chaque evaluation:
|
# etat de chaque evaluation:
|
||||||
for r in res:
|
for r in res:
|
||||||
r["jour"] = r["jour"] or datetime.date(1900, 1, 1) # pour les comparaisons
|
|
||||||
if with_etat:
|
if with_etat:
|
||||||
r["etat"] = do_evaluation_etat(r["evaluation_id"])
|
r["etat"] = do_evaluation_etat(r["evaluation_id"])
|
||||||
|
r["jour"] = r["date_debut"] or datetime.date(1900, 1, 1)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -379,7 +388,20 @@ def _eval_etat(evals):
|
|||||||
|
|
||||||
def do_evaluation_etat_in_sem(formsemestre_id):
|
def do_evaluation_etat_in_sem(formsemestre_id):
|
||||||
"""-> nb_eval_completes, nb_evals_en_cours, nb_evals_vides,
|
"""-> nb_eval_completes, nb_evals_en_cours, nb_evals_vides,
|
||||||
date derniere modif, attente"""
|
date derniere modif, attente
|
||||||
|
|
||||||
|
XXX utilisé par
|
||||||
|
- formsemestre_status_head
|
||||||
|
- gen_formsemestre_recapcomplet_xml
|
||||||
|
- gen_formsemestre_recapcomplet_json
|
||||||
|
|
||||||
|
"nb_evals_completes"
|
||||||
|
"nb_evals_en_cours"
|
||||||
|
"nb_evals_vides"
|
||||||
|
"date_derniere_note"
|
||||||
|
"last_modif"
|
||||||
|
"attente"
|
||||||
|
"""
|
||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
evals = nt.get_evaluations_etats()
|
evals = nt.get_evaluations_etats()
|
||||||
@ -403,88 +425,97 @@ def formsemestre_evaluations_cal(formsemestre_id):
|
|||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
|
|
||||||
evals = nt.get_evaluations_etats()
|
evaluations = formsemestre.get_evaluations() # TODO
|
||||||
nb_evals = len(evals)
|
nb_evals = len(evaluations)
|
||||||
|
|
||||||
color_incomplete = "#FF6060"
|
color_incomplete = "#FF6060"
|
||||||
color_complete = "#A0FFA0"
|
color_complete = "#A0FFA0"
|
||||||
color_futur = "#70E0FF"
|
color_futur = "#70E0FF"
|
||||||
|
|
||||||
today = time.strftime("%Y-%m-%d")
|
year = formsemestre.annee_scolaire()
|
||||||
|
|
||||||
year = formsemestre.date_debut.year
|
|
||||||
if formsemestre.date_debut.month < 8:
|
|
||||||
year -= 1 # calendrier septembre a septembre
|
|
||||||
events = {} # (day, halfday) : event
|
events = {} # (day, halfday) : event
|
||||||
for e in evals:
|
for e in evaluations:
|
||||||
etat = e["etat"]
|
if e.date_debut is None:
|
||||||
if not e["jour"]:
|
continue # éval. sans date
|
||||||
continue
|
txt = e.moduleimpl.module.code or e.moduleimpl.module.abbrev or "éval."
|
||||||
day = e["jour"].strftime("%Y-%m-%d")
|
if e.date_debut == e.date_fin:
|
||||||
mod = sco_moduleimpl.moduleimpl_withmodule_list(
|
heure_debut_txt, heure_fin_txt = "?", "?"
|
||||||
moduleimpl_id=e["moduleimpl_id"]
|
|
||||||
)[0]
|
|
||||||
txt = mod["module"]["code"] or mod["module"]["abbrev"] or "eval"
|
|
||||||
if e["heure_debut"]:
|
|
||||||
debut = e["heure_debut"].strftime("%Hh%M")
|
|
||||||
else:
|
else:
|
||||||
debut = "?"
|
heure_debut_txt = e.date_debut.strftime("%Hh%M") if e.date_debut else "?"
|
||||||
if e["heure_fin"]:
|
heure_fin_txt = e.date_fin.strftime("%Hh%M") if e.date_fin else "?"
|
||||||
fin = e["heure_fin"].strftime("%Hh%M")
|
|
||||||
else:
|
description = f"""{
|
||||||
fin = "?"
|
e.moduleimpl.module.titre
|
||||||
description = "%s, de %s à %s" % (mod["module"]["titre"], debut, fin)
|
}, de {heure_debut_txt} à {heure_fin_txt}"""
|
||||||
if etat["evalcomplete"]:
|
|
||||||
|
# Etat (notes completes) de l'évaluation:
|
||||||
|
modimpl_result = nt.modimpls_results[e.moduleimpl.id]
|
||||||
|
if modimpl_result.evaluations_etat[e.id].is_complete:
|
||||||
color = color_complete
|
color = color_complete
|
||||||
else:
|
else:
|
||||||
color = color_incomplete
|
color = color_incomplete
|
||||||
if day > today:
|
if e.date_debut > datetime.datetime.now(scu.TIME_ZONE):
|
||||||
color = color_futur
|
color = color_futur
|
||||||
href = "moduleimpl_status?moduleimpl_id=%s" % e["moduleimpl_id"]
|
href = url_for(
|
||||||
# if e['heure_debut'].hour < 12:
|
"notes.moduleimpl_status",
|
||||||
# halfday = True
|
scodoc_dept=g.scodoc_dept,
|
||||||
# else:
|
moduleimpl_id=e.moduleimpl_id,
|
||||||
# halfday = False
|
)
|
||||||
if not day in events:
|
day = e.date_debut.date().isoformat() # yyyy-mm-dd
|
||||||
# events[(day,halfday)] = [day, txt, color, href, halfday, description, mod]
|
event = events.get(day)
|
||||||
events[day] = [day, txt, color, href, description, mod]
|
if not event:
|
||||||
|
events[day] = [day, txt, color, href, description, e.moduleimpl]
|
||||||
else:
|
else:
|
||||||
e = events[day]
|
if event[-1].id != e.moduleimpl.id:
|
||||||
if e[-1]["moduleimpl_id"] != mod["moduleimpl_id"]:
|
|
||||||
# plusieurs evals de modules differents a la meme date
|
# plusieurs evals de modules differents a la meme date
|
||||||
e[1] += ", " + txt
|
event[1] += ", " + txt
|
||||||
e[4] += ", " + description
|
event[4] += ", " + description
|
||||||
if not etat["evalcomplete"]:
|
if color == color_incomplete:
|
||||||
e[2] = color_incomplete
|
event[2] = color_incomplete
|
||||||
if day > today:
|
if color == color_futur:
|
||||||
e[2] = color_futur
|
event[2] = color_futur
|
||||||
|
|
||||||
CalHTML = sco_abs.YearTable(
|
cal_html = sco_abs.YearTable(
|
||||||
year, events=list(events.values()), halfday=False, pad_width=None
|
year, events=list(events.values()), halfday=False, pad_width=None
|
||||||
)
|
)
|
||||||
|
|
||||||
H = [
|
return f"""
|
||||||
|
{
|
||||||
html_sco_header.html_sem_header(
|
html_sco_header.html_sem_header(
|
||||||
"Evaluations du semestre",
|
"Evaluations du semestre",
|
||||||
cssstyles=["css/calabs.css"],
|
cssstyles=["css/calabs.css"],
|
||||||
),
|
)
|
||||||
'<div class="cal_evaluations">',
|
}
|
||||||
CalHTML,
|
<div class="cal_evaluations">
|
||||||
"</div>",
|
{ cal_html }
|
||||||
"<p>soit %s évaluations planifiées;" % nb_evals,
|
</div>
|
||||||
"""<ul><li>en <span style="background-color: %s">rouge</span> les évaluations passées auxquelles il manque des notes</li>
|
<p>soit {nb_evals} évaluations planifiées;
|
||||||
<li>en <span style="background-color: %s">vert</span> les évaluations déjà notées</li>
|
</p>
|
||||||
<li>en <span style="background-color: %s">bleu</span> les évaluations futures</li></ul></p>"""
|
<ul>
|
||||||
% (color_incomplete, color_complete, color_futur),
|
<li>en <span style=
|
||||||
"""<p><a href="formsemestre_evaluations_delai_correction?formsemestre_id=%s" class="stdlink">voir les délais de correction</a></p>
|
"background-color: {color_incomplete}">rouge</span>
|
||||||
"""
|
les évaluations passées auxquelles il manque des notes
|
||||||
% (formsemestre_id,),
|
</li>
|
||||||
html_sco_header.sco_footer(),
|
<li>en <span style=
|
||||||
]
|
"background-color: {color_complete}">vert</span>
|
||||||
return "\n".join(H)
|
les évaluations déjà notées
|
||||||
|
</li>
|
||||||
|
<li>en <span style=
|
||||||
|
"background-color: {color_futur}">bleu</span>
|
||||||
|
les évaluations futures
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p><a href="{
|
||||||
|
url_for("notes.formsemestre_evaluations_delai_correction",
|
||||||
|
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id
|
||||||
|
)
|
||||||
|
}" class="stdlink">voir les délais de correction</a>
|
||||||
|
</p>
|
||||||
|
{ html_sco_header.sco_footer() }
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def evaluation_date_first_completion(evaluation_id):
|
def evaluation_date_first_completion(evaluation_id) -> datetime.datetime:
|
||||||
"""Première date à laquelle l'évaluation a été complète
|
"""Première date à laquelle l'évaluation a été complète
|
||||||
ou None si actuellement incomplète
|
ou None si actuellement incomplète
|
||||||
"""
|
"""
|
||||||
@ -496,7 +527,7 @@ def evaluation_date_first_completion(evaluation_id):
|
|||||||
# Il faut considerer les inscriptions au semestre
|
# Il faut considerer les inscriptions au semestre
|
||||||
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
# (pour avoir l'etat et le groupe) et aussi les inscriptions
|
||||||
# au module (pour gerer les modules optionnels correctement)
|
# au module (pour gerer les modules optionnels correctement)
|
||||||
# E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
# E = get_evaluation_dict({"id":evaluation_id})[0]
|
||||||
# M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
# M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
# formsemestre_id = M["formsemestre_id"]
|
# formsemestre_id = M["formsemestre_id"]
|
||||||
# insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits( formsemestre_id)
|
# insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits( formsemestre_id)
|
||||||
@ -536,40 +567,44 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
N'indique pas les évaluations de rattrapage ni celles des modules de bonus/malus.
|
N'indique pas les évaluations de rattrapage ni celles des modules de bonus/malus.
|
||||||
"""
|
"""
|
||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
evaluations = formsemestre.get_evaluations()
|
||||||
|
rows = []
|
||||||
evals = nt.get_evaluations_etats()
|
for e in evaluations:
|
||||||
T = []
|
if (e.evaluation_type != scu.EVALUATION_NORMALE) or (
|
||||||
for e in evals:
|
e.moduleimpl.module.module_type == ModuleType.MALUS
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
|
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
|
||||||
if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
|
|
||||||
Mod["module_type"] == ModuleType.MALUS
|
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
e["date_first_complete"] = evaluation_date_first_completion(e["evaluation_id"])
|
date_first_complete = evaluation_date_first_completion(e.id)
|
||||||
if e["date_first_complete"]:
|
if date_first_complete and e.date_fin:
|
||||||
e["delai_correction"] = (e["date_first_complete"].date() - e["jour"]).days
|
delai_correction = (date_first_complete.date() - e.date_fin).days
|
||||||
else:
|
else:
|
||||||
e["delai_correction"] = None
|
delai_correction = None
|
||||||
|
|
||||||
e["module_code"] = Mod["code"]
|
rows.append(
|
||||||
e["_module_code_target"] = url_for(
|
{
|
||||||
"notes.moduleimpl_status",
|
"date_first_complete": date_first_complete,
|
||||||
scodoc_dept=g.scodoc_dept,
|
"delai_correction": delai_correction,
|
||||||
moduleimpl_id=M["moduleimpl_id"],
|
"jour": e.date_debut.strftime("%d/%m/%Y")
|
||||||
|
if e.date_debut
|
||||||
|
else "sans date",
|
||||||
|
"_jour_target": url_for(
|
||||||
|
"notes.evaluation_listenotes",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
evaluation_id=e["evaluation_id"],
|
||||||
|
),
|
||||||
|
"module_code": e.moduleimpl.module.code,
|
||||||
|
"_module_code_target": url_for(
|
||||||
|
"notes.moduleimpl_status",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
moduleimpl_id=e.moduleimpl.id,
|
||||||
|
),
|
||||||
|
"module_titre": e.moduleimpl.module.abbrev or e.moduleimpl.module.titre,
|
||||||
|
"responsable_id": e.moduleimpl.responsable_id,
|
||||||
|
"responsable_nomplogin": sco_users.user_info(
|
||||||
|
e.moduleimpl.responsable_id
|
||||||
|
)["nomplogin"],
|
||||||
|
}
|
||||||
)
|
)
|
||||||
e["module_titre"] = Mod["titre"]
|
|
||||||
e["responsable_id"] = M["responsable_id"]
|
|
||||||
e["responsable_nomplogin"] = sco_users.user_info(M["responsable_id"])[
|
|
||||||
"nomplogin"
|
|
||||||
]
|
|
||||||
e["_jour_target"] = url_for(
|
|
||||||
"notes.evaluation_listenotes",
|
|
||||||
scodoc_dept=g.scodoc_dept,
|
|
||||||
evaluation_id=e["evaluation_id"],
|
|
||||||
)
|
|
||||||
T.append(e)
|
|
||||||
|
|
||||||
columns_ids = (
|
columns_ids = (
|
||||||
"module_code",
|
"module_code",
|
||||||
@ -592,16 +627,14 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
tab = GenTable(
|
tab = GenTable(
|
||||||
titles=titles,
|
titles=titles,
|
||||||
columns_ids=columns_ids,
|
columns_ids=columns_ids,
|
||||||
rows=T,
|
rows=rows,
|
||||||
html_class="table_leftalign table_coldate",
|
html_class="table_leftalign table_coldate",
|
||||||
html_sortable=True,
|
html_sortable=True,
|
||||||
html_title="<h2>Correction des évaluations du semestre</h2>",
|
html_title="<h2>Correction des évaluations du semestre</h2>",
|
||||||
caption="Correction des évaluations du semestre",
|
caption="Correction des évaluations du semestre",
|
||||||
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
preferences=sco_preferences.SemPreferences(formsemestre_id),
|
||||||
base_url="%s?formsemestre_id=%s" % (request.base_url, formsemestre_id),
|
base_url="%s?formsemestre_id=%s" % (request.base_url, formsemestre_id),
|
||||||
origin="Généré par %s le " % sco_version.SCONAME
|
origin=f"""Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}""",
|
||||||
+ scu.timedate_human_repr()
|
|
||||||
+ "",
|
|
||||||
filename=scu.make_filename("evaluations_delais_" + formsemestre.titre_annee()),
|
filename=scu.make_filename("evaluations_delais_" + formsemestre.titre_annee()),
|
||||||
)
|
)
|
||||||
return tab.make_page(format=format)
|
return tab.make_page(format=format)
|
||||||
@ -612,7 +645,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True, link_saisie=True):
|
|||||||
"""HTML description of evaluation, for page headers
|
"""HTML description of evaluation, for page headers
|
||||||
edit_in_place: allow in-place editing when permitted (not implemented)
|
edit_in_place: allow in-place editing when permitted (not implemented)
|
||||||
"""
|
"""
|
||||||
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.get_evaluation_dict({"evaluation_id": evaluation_id})[0]
|
||||||
moduleimpl_id = E["moduleimpl_id"]
|
moduleimpl_id = E["moduleimpl_id"]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
|
@ -512,8 +512,7 @@ def excel_feuille_saisie(evaluation: "Evaluation", titreannee, description, line
|
|||||||
# description evaluation
|
# description evaluation
|
||||||
ws.append_single_cell_row(scu.unescape_html(description), style_titres)
|
ws.append_single_cell_row(scu.unescape_html(description), style_titres)
|
||||||
ws.append_single_cell_row(
|
ws.append_single_cell_row(
|
||||||
"Evaluation du %s (coef. %g)"
|
f"Evaluation {evaluation.descr_date()} (coef. {(evaluation.coefficient or 0.0):g})",
|
||||||
% (evaluation.jour or "sans date", evaluation.coefficient or 0.0),
|
|
||||||
style,
|
style,
|
||||||
)
|
)
|
||||||
# ligne blanche
|
# ligne blanche
|
||||||
|
@ -1245,7 +1245,9 @@ def do_formsemestre_clone(
|
|||||||
moduleimpl_id=mod_orig["moduleimpl_id"]
|
moduleimpl_id=mod_orig["moduleimpl_id"]
|
||||||
):
|
):
|
||||||
# copie en enlevant la date
|
# copie en enlevant la date
|
||||||
new_eval = e.clone(not_copying=("jour", "moduleimpl_id"))
|
new_eval = e.clone(
|
||||||
|
not_copying=("date_debut", "date_fin", "moduleimpl_id")
|
||||||
|
)
|
||||||
new_eval.moduleimpl_id = mid
|
new_eval.moduleimpl_id = mid
|
||||||
# Copie les poids APC de l'évaluation
|
# Copie les poids APC de l'évaluation
|
||||||
new_eval.set_ue_poids_dict(e.get_ue_poids_dict())
|
new_eval.set_ue_poids_dict(e.get_ue_poids_dict())
|
||||||
@ -1443,7 +1445,7 @@ def do_formsemestre_delete(formsemestre_id):
|
|||||||
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
# evaluations
|
# evaluations
|
||||||
evals = sco_evaluation_db.do_evaluation_list(
|
evals = sco_evaluation_db.get_evaluation_dict(
|
||||||
args={"moduleimpl_id": mod["moduleimpl_id"]}
|
args={"moduleimpl_id": mod["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
for e in evals:
|
for e in evals:
|
||||||
|
@ -498,7 +498,7 @@ def retreive_formsemestre_from_request() -> int:
|
|||||||
modimpl = modimpl[0]
|
modimpl = modimpl[0]
|
||||||
formsemestre_id = modimpl["formsemestre_id"]
|
formsemestre_id = modimpl["formsemestre_id"]
|
||||||
elif "evaluation_id" in args:
|
elif "evaluation_id" in args:
|
||||||
E = sco_evaluation_db.do_evaluation_list(
|
E = sco_evaluation_db.get_evaluation_dict(
|
||||||
{"evaluation_id": args["evaluation_id"]}
|
{"evaluation_id": args["evaluation_id"]}
|
||||||
)
|
)
|
||||||
if not E:
|
if not E:
|
||||||
@ -620,7 +620,7 @@ def formsemestre_description_table(
|
|||||||
columns_ids += ["Inscrits", "Responsable", "Enseignants"]
|
columns_ids += ["Inscrits", "Responsable", "Enseignants"]
|
||||||
if with_evals:
|
if with_evals:
|
||||||
columns_ids += [
|
columns_ids += [
|
||||||
"jour",
|
"date_evaluation",
|
||||||
"description",
|
"description",
|
||||||
"coefficient",
|
"coefficient",
|
||||||
"evalcomplete_str",
|
"evalcomplete_str",
|
||||||
@ -630,7 +630,7 @@ def formsemestre_description_table(
|
|||||||
titles = {title: title for title in columns_ids}
|
titles = {title: title for title in columns_ids}
|
||||||
titles.update({f"ue_{ue.id}": ue.acronyme for ue in ues})
|
titles.update({f"ue_{ue.id}": ue.acronyme for ue in ues})
|
||||||
titles["ects"] = "ECTS"
|
titles["ects"] = "ECTS"
|
||||||
titles["jour"] = "Évaluation"
|
titles["date_evaluation"] = "Évaluation"
|
||||||
titles["description"] = ""
|
titles["description"] = ""
|
||||||
titles["coefficient"] = "Coef. éval."
|
titles["coefficient"] = "Coef. éval."
|
||||||
titles["evalcomplete_str"] = "Complète"
|
titles["evalcomplete_str"] = "Complète"
|
||||||
@ -738,8 +738,10 @@ def formsemestre_description_table(
|
|||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
evaluation_id=e["evaluation_id"],
|
evaluation_id=e["evaluation_id"],
|
||||||
)
|
)
|
||||||
e["_jour_order"] = e["jour"].isoformat()
|
e["_date_evaluation_order"] = e["jour"].isoformat()
|
||||||
e["jour"] = e["jour"].strftime("%d/%m/%Y") if e["jour"] else ""
|
e["date_evaluation"] = (
|
||||||
|
e["jour"].strftime("%d/%m/%Y") if e["jour"] else ""
|
||||||
|
)
|
||||||
e["UE"] = row["UE"]
|
e["UE"] = row["UE"]
|
||||||
e["_UE_td_attrs"] = row["_UE_td_attrs"]
|
e["_UE_td_attrs"] = row["_UE_td_attrs"]
|
||||||
e["Code"] = row["Code"]
|
e["Code"] = row["Code"]
|
||||||
|
@ -69,38 +69,44 @@ def do_evaluation_listenotes(
|
|||||||
mode = None
|
mode = None
|
||||||
if moduleimpl_id:
|
if moduleimpl_id:
|
||||||
mode = "module"
|
mode = "module"
|
||||||
evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
evals = sco_evaluation_db.get_evaluation_dict({"moduleimpl_id": moduleimpl_id})
|
||||||
elif evaluation_id:
|
elif evaluation_id:
|
||||||
mode = "eval"
|
mode = "eval"
|
||||||
evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluation_db.get_evaluation_dict({"evaluation_id": evaluation_id})
|
||||||
else:
|
else:
|
||||||
raise ValueError("missing argument: evaluation or module")
|
raise ValueError("missing argument: evaluation or module")
|
||||||
if not evals:
|
if not evals:
|
||||||
return "<p>Aucune évaluation !</p>", "ScoDoc"
|
return "<p>Aucune évaluation !</p>", "ScoDoc"
|
||||||
|
|
||||||
E = evals[0] # il y a au moins une evaluation
|
eval_dict = evals[0] # il y a au moins une evaluation
|
||||||
modimpl = db.session.get(ModuleImpl, E["moduleimpl_id"])
|
modimpl = db.session.get(ModuleImpl, eval_dict["moduleimpl_id"])
|
||||||
# description de l'evaluation
|
# description de l'evaluation
|
||||||
if mode == "eval":
|
if mode == "eval":
|
||||||
H = [sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)]
|
H = [sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)]
|
||||||
page_title = f"Notes {E['description'] or modimpl.module.code}"
|
page_title = f"Notes {eval_dict['description'] or modimpl.module.code}"
|
||||||
else:
|
else:
|
||||||
H = []
|
H = []
|
||||||
page_title = f"Notes {modimpl.module.code}"
|
page_title = f"Notes {modimpl.module.code}"
|
||||||
# groupes
|
# groupes
|
||||||
groups = sco_groups.do_evaluation_listegroupes(
|
groups = sco_groups.do_evaluation_listegroupes(
|
||||||
E["evaluation_id"], include_default=True
|
eval_dict["evaluation_id"], include_default=True
|
||||||
)
|
)
|
||||||
grlabs = [g["group_name"] or "tous" for g in groups] # legendes des boutons
|
grlabs = [g["group_name"] or "tous" for g in groups] # legendes des boutons
|
||||||
grnams = [str(g["group_id"]) for g in groups] # noms des checkbox
|
grnams = [str(g["group_id"]) for g in groups] # noms des checkbox
|
||||||
|
|
||||||
if len(evals) > 1:
|
if len(evals) > 1:
|
||||||
descr = [
|
descr = [
|
||||||
("moduleimpl_id", {"default": E["moduleimpl_id"], "input_type": "hidden"})
|
(
|
||||||
|
"moduleimpl_id",
|
||||||
|
{"default": eval_dict["moduleimpl_id"], "input_type": "hidden"},
|
||||||
|
)
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
descr = [
|
descr = [
|
||||||
("evaluation_id", {"default": E["evaluation_id"], "input_type": "hidden"})
|
(
|
||||||
|
"evaluation_id",
|
||||||
|
{"default": eval_dict["evaluation_id"], "input_type": "hidden"},
|
||||||
|
)
|
||||||
]
|
]
|
||||||
if len(grnams) > 1:
|
if len(grnams) > 1:
|
||||||
descr += [
|
descr += [
|
||||||
@ -199,7 +205,7 @@ def do_evaluation_listenotes(
|
|||||||
url_for(
|
url_for(
|
||||||
"notes.moduleimpl_status",
|
"notes.moduleimpl_status",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
moduleimpl_id=E["moduleimpl_id"],
|
moduleimpl_id=eval_dict["moduleimpl_id"],
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
"",
|
"",
|
||||||
|
@ -61,7 +61,7 @@ from app.tables import list_etuds
|
|||||||
# menu evaluation dans moduleimpl
|
# menu evaluation dans moduleimpl
|
||||||
def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
||||||
"Menu avec actions sur une evaluation"
|
"Menu avec actions sur une evaluation"
|
||||||
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.get_evaluation_dict({"evaluation_id": evaluation_id})[0]
|
||||||
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
|
|
||||||
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
||||||
@ -203,11 +203,10 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||||
# Evaluations, la plus RECENTE en tête
|
# Evaluations, par numéros ou la plus RECENTE en tête
|
||||||
evaluations = modimpl.evaluations.order_by(
|
evaluations = modimpl.evaluations.order_by(
|
||||||
Evaluation.numero.desc(),
|
Evaluation.numero.desc(),
|
||||||
Evaluation.jour.desc(),
|
Evaluation.date_debut.desc(),
|
||||||
Evaluation.heure_debut.desc(),
|
|
||||||
).all()
|
).all()
|
||||||
nb_evaluations = len(evaluations)
|
nb_evaluations = len(evaluations)
|
||||||
max_poids = max(
|
max_poids = max(
|
||||||
@ -571,10 +570,8 @@ def _ligne_evaluation(
|
|||||||
# visualisation des poids (Hinton map)
|
# visualisation des poids (Hinton map)
|
||||||
H.append(_evaluation_poids_html(evaluation, max_poids))
|
H.append(_evaluation_poids_html(evaluation, max_poids))
|
||||||
H.append("""<div class="evaluation_titre">""")
|
H.append("""<div class="evaluation_titre">""")
|
||||||
if evaluation.jour:
|
if evaluation.date_debut:
|
||||||
H.append(
|
H.append(evaluation.descr_date())
|
||||||
f"""Le {evaluation.jour.strftime("%d/%m/%Y")} {evaluation.descr_heure()}"""
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
H.append(
|
H.append(
|
||||||
f"""<a href="{url_for("notes.evaluation_edit",
|
f"""<a href="{url_for("notes.evaluation_edit",
|
||||||
|
@ -138,7 +138,7 @@ class PlacementForm(FlaskForm):
|
|||||||
|
|
||||||
def set_evaluation_infos(self, evaluation_id):
|
def set_evaluation_infos(self, evaluation_id):
|
||||||
"""Initialise les données du formulaire avec les données de l'évaluation."""
|
"""Initialise les données du formulaire avec les données de l'évaluation."""
|
||||||
eval_data = sco_evaluation_db.do_evaluation_list(
|
eval_data = sco_evaluation_db.get_evaluation_dict(
|
||||||
{"evaluation_id": evaluation_id}
|
{"evaluation_id": evaluation_id}
|
||||||
)
|
)
|
||||||
if not eval_data:
|
if not eval_data:
|
||||||
@ -239,7 +239,7 @@ class PlacementRunner:
|
|||||||
self.groups_ids = [
|
self.groups_ids = [
|
||||||
gid if gid != TOUS else form.tous_id for gid in form["groups"].data
|
gid if gid != TOUS else form.tous_id for gid in form["groups"].data
|
||||||
]
|
]
|
||||||
self.eval_data = sco_evaluation_db.do_evaluation_list(
|
self.eval_data = sco_evaluation_db.get_evaluation_dict(
|
||||||
{"evaluation_id": self.evaluation_id}
|
{"evaluation_id": self.evaluation_id}
|
||||||
)[0]
|
)[0]
|
||||||
self.groups = sco_groups.listgroups(self.groups_ids)
|
self.groups = sco_groups.listgroups(self.groups_ids)
|
||||||
|
@ -884,15 +884,15 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]):
|
|||||||
modimpl = evaluation.moduleimpl
|
modimpl = evaluation.moduleimpl
|
||||||
formsemestre = modimpl.formsemestre
|
formsemestre = modimpl.formsemestre
|
||||||
mod_responsable = sco_users.user_info(modimpl.responsable_id)
|
mod_responsable = sco_users.user_info(modimpl.responsable_id)
|
||||||
if evaluation.jour:
|
if evaluation.date_debut:
|
||||||
indication_date = evaluation.jour.isoformat()
|
indication_date = evaluation.date_debut.date().isoformat()
|
||||||
else:
|
else:
|
||||||
indication_date = scu.sanitize_filename(evaluation.description or "")[:12]
|
indication_date = scu.sanitize_filename(evaluation.description or "")[:12]
|
||||||
eval_name = f"{evaluation.moduleimpl.module.code}-{indication_date}"
|
eval_name = f"{evaluation.moduleimpl.module.code}-{indication_date}"
|
||||||
|
|
||||||
date_str = (
|
date_str = (
|
||||||
f"""du {evaluation.jour.strftime("%d/%m/%Y")}"""
|
f"""du {evaluation.date_debut.strftime("%d/%m/%Y")}"""
|
||||||
if evaluation.jour
|
if evaluation.date_debut
|
||||||
else "(sans date)"
|
else "(sans date)"
|
||||||
)
|
)
|
||||||
eval_titre = f"""{evaluation.description if evaluation.description else "évaluation"} {date_str}"""
|
eval_titre = f"""{evaluation.description if evaluation.description else "évaluation"} {date_str}"""
|
||||||
@ -1107,7 +1107,9 @@ def _get_sorted_etuds(evaluation: Evaluation, etudids: list, formsemestre_id: in
|
|||||||
e["groups"] = sco_groups.get_etud_groups(etudid, formsemestre_id)
|
e["groups"] = sco_groups.get_etud_groups(etudid, formsemestre_id)
|
||||||
|
|
||||||
# Information sur absence (tenant compte de la demi-journée)
|
# Information sur absence (tenant compte de la demi-journée)
|
||||||
jour_iso = evaluation.jour.isoformat() if evaluation.jour else ""
|
jour_iso = (
|
||||||
|
evaluation.date_debut.date().isoformat() if evaluation.date_debut else ""
|
||||||
|
)
|
||||||
warn_abs_lst = []
|
warn_abs_lst = []
|
||||||
if evaluation.is_matin():
|
if evaluation.is_matin():
|
||||||
nbabs = sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=True)
|
nbabs = sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=True)
|
||||||
|
@ -149,7 +149,7 @@ def list_operations(evaluation_id):
|
|||||||
|
|
||||||
def evaluation_list_operations(evaluation_id):
|
def evaluation_list_operations(evaluation_id):
|
||||||
"""Page listing operations on evaluation"""
|
"""Page listing operations on evaluation"""
|
||||||
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.get_evaluation_dict({"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
|
|
||||||
Ops = list_operations(evaluation_id)
|
Ops = list_operations(evaluation_id)
|
||||||
@ -179,7 +179,7 @@ def formsemestre_list_saisies_notes(formsemestre_id, format="html"):
|
|||||||
"""
|
"""
|
||||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||||
rows = ndb.SimpleDictFetch(
|
rows = ndb.SimpleDictFetch(
|
||||||
"""SELECT i.nom, i.prenom, code_nip, n.*, mod.titre, e.description, e.jour,
|
"""SELECT i.nom, i.prenom, code_nip, n.*, mod.titre, e.description, e.date_debut,
|
||||||
u.user_name, e.id as evaluation_id
|
u.user_name, e.id as evaluation_id
|
||||||
FROM notes_notes n, notes_evaluation e, notes_moduleimpl mi,
|
FROM notes_notes n, notes_evaluation e, notes_moduleimpl mi,
|
||||||
notes_modules mod, identite i, "user" u
|
notes_modules mod, identite i, "user" u
|
||||||
@ -197,6 +197,12 @@ def formsemestre_list_saisies_notes(formsemestre_id, format="html"):
|
|||||||
keep_numeric = format in scu.FORMATS_NUMERIQUES
|
keep_numeric = format in scu.FORMATS_NUMERIQUES
|
||||||
for row in rows:
|
for row in rows:
|
||||||
row["value"] = scu.fmt_note(row["value"], keep_numeric=keep_numeric)
|
row["value"] = scu.fmt_note(row["value"], keep_numeric=keep_numeric)
|
||||||
|
row["date_evaluation"] = (
|
||||||
|
row["date_debut"].strftime("%d/%m/%Y %H:%M") if row["date_debut"] else ""
|
||||||
|
)
|
||||||
|
row["_date_evaluation_order"] = (
|
||||||
|
row["date_debut"].isoformat() if row["date_debut"] else ""
|
||||||
|
)
|
||||||
columns_ids = (
|
columns_ids = (
|
||||||
"date",
|
"date",
|
||||||
"code_nip",
|
"code_nip",
|
||||||
@ -207,7 +213,7 @@ def formsemestre_list_saisies_notes(formsemestre_id, format="html"):
|
|||||||
"titre",
|
"titre",
|
||||||
"evaluation_id",
|
"evaluation_id",
|
||||||
"description",
|
"description",
|
||||||
"jour",
|
"date_evaluation",
|
||||||
"comment",
|
"comment",
|
||||||
)
|
)
|
||||||
titles = {
|
titles = {
|
||||||
@ -221,7 +227,7 @@ def formsemestre_list_saisies_notes(formsemestre_id, format="html"):
|
|||||||
"evaluation_id": "evaluation_id",
|
"evaluation_id": "evaluation_id",
|
||||||
"titre": "Module",
|
"titre": "Module",
|
||||||
"description": "Evaluation",
|
"description": "Evaluation",
|
||||||
"jour": "Date éval.",
|
"date_evaluation": "Date éval.",
|
||||||
}
|
}
|
||||||
tab = GenTable(
|
tab = GenTable(
|
||||||
titles=titles,
|
titles=titles,
|
||||||
|
@ -75,6 +75,8 @@ MAX_TEXT_LEN = 64 * 1024
|
|||||||
STATIC_DIR = (
|
STATIC_DIR = (
|
||||||
os.environ.get("SCRIPT_NAME", "") + "/ScoDoc/static/links/" + sco_version.SCOVERSION
|
os.environ.get("SCRIPT_NAME", "") + "/ScoDoc/static/links/" + sco_version.SCOVERSION
|
||||||
)
|
)
|
||||||
|
# La time zone du serveur:
|
||||||
|
TIME_ZONE = timezone("/".join(os.path.realpath("/etc/localtime").split("/")[-2:]))
|
||||||
|
|
||||||
# ----- CALCUL ET PRESENTATION DES NOTES
|
# ----- CALCUL ET PRESENTATION DES NOTES
|
||||||
NOTES_PRECISION = 1e-4 # evite eventuelles erreurs d'arrondis
|
NOTES_PRECISION = 1e-4 # evite eventuelles erreurs d'arrondis
|
||||||
|
@ -385,7 +385,9 @@ class TableRecap(tb.Table):
|
|||||||
first_eval_of_mod = True
|
first_eval_of_mod = True
|
||||||
for e in evals:
|
for e in evals:
|
||||||
col_id = f"eval_{e.id}"
|
col_id = f"eval_{e.id}"
|
||||||
title = f'{modimpl.module.code} {eval_index} {e.jour.isoformat() if e.jour else ""}'
|
title = f"""{modimpl.module.code} {eval_index} {
|
||||||
|
e.date_debut.strftime("%d/%m/%Y") if e.date_debut else ""
|
||||||
|
}"""
|
||||||
col_classes = []
|
col_classes = []
|
||||||
if first_eval:
|
if first_eval:
|
||||||
col_classes.append("first")
|
col_classes.append("first")
|
||||||
|
@ -1765,7 +1765,7 @@ sco_publish(
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def evaluation_delete(evaluation_id):
|
def evaluation_delete(evaluation_id):
|
||||||
"""Form delete evaluation"""
|
"""Form delete evaluation"""
|
||||||
El = sco_evaluation_db.do_evaluation_list(args={"evaluation_id": evaluation_id})
|
El = sco_evaluation_db.get_evaluation_dict(args={"evaluation_id": evaluation_id})
|
||||||
if not El:
|
if not El:
|
||||||
raise ScoValueError("Evaluation inexistante ! (%s)" % evaluation_id)
|
raise ScoValueError("Evaluation inexistante ! (%s)" % evaluation_id)
|
||||||
E = El[0]
|
E = El[0]
|
||||||
|
@ -116,3 +116,75 @@ def POST_JSON(path: str, data: dict = {}, headers: dict = None, errmsg=None, dep
|
|||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
raise APIError(errmsg or f"erreur status={r.status_code} !", r.json())
|
raise APIError(errmsg or f"erreur status={r.status_code} !", r.json())
|
||||||
return r.json() # decode la reponse JSON
|
return r.json() # decode la reponse JSON
|
||||||
|
|
||||||
|
|
||||||
|
def check_fields(data: dict, fields: dict = None):
|
||||||
|
"""
|
||||||
|
Vérifie que le dictionnaire data contient les bonnes clés
|
||||||
|
et les bons types de valeurs.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (dict): un dictionnaire (json de retour de l'api)
|
||||||
|
fields (dict, optional): Un dictionnaire représentant les clés et les types d'une réponse.
|
||||||
|
"""
|
||||||
|
if fields is None:
|
||||||
|
fields = ASSIDUITES_FIELDS
|
||||||
|
assert set(data.keys()) == set(fields.keys())
|
||||||
|
for key in data:
|
||||||
|
if key in ("moduleimpl_id", "desc", "user_id", "external_data"):
|
||||||
|
assert (
|
||||||
|
isinstance(data[key], fields[key]) or data[key] is None
|
||||||
|
), f"error [{key}:{type(data[key])}, {data[key]}, {fields[key]}]"
|
||||||
|
else:
|
||||||
|
assert isinstance(
|
||||||
|
data[key], fields[key]
|
||||||
|
), f"error [{key}:{type(data[key])}, {data[key]}, {fields[key]}]"
|
||||||
|
|
||||||
|
|
||||||
|
def check_failure_get(path: str, headers: dict, err: str = None):
|
||||||
|
"""
|
||||||
|
Vérifie que la requête GET renvoie bien un 404
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): la route de l'api
|
||||||
|
headers (dict): le token d'auth de l'api
|
||||||
|
err (str, optional): L'erreur qui est sensée être fournie par l'api.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
APIError: Une erreur car la requête a fonctionné (mauvais comportement)
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
GET(path=path, headers=headers)
|
||||||
|
# ^ Renvoi un 404
|
||||||
|
except APIError as api_err:
|
||||||
|
if err is not None:
|
||||||
|
assert api_err.payload["message"] == err
|
||||||
|
else:
|
||||||
|
raise APIError("Le GET n'aurait pas du fonctionner")
|
||||||
|
|
||||||
|
|
||||||
|
def check_failure_post(path: str, headers: dict, data: dict, err: str = None):
|
||||||
|
"""
|
||||||
|
Vérifie que la requête POST renvoie bien un 404
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): la route de l'api
|
||||||
|
headers (dict): le token d'auth
|
||||||
|
data (dict): un dictionnaire (json) à envoyer
|
||||||
|
err (str, optional): L'erreur qui est sensée être fournie par l'api.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
APIError: Une erreur car la requête a fonctionné (mauvais comportement)
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = POST_JSON(path=path, headers=headers, data=data)
|
||||||
|
# ^ Renvoie un 404
|
||||||
|
except APIError as api_err:
|
||||||
|
if err is not None:
|
||||||
|
assert (
|
||||||
|
api_err.payload["message"] == err
|
||||||
|
), f"received: {api_err.payload['message']}"
|
||||||
|
else:
|
||||||
|
raise APIError("Le GET n'aurait pas du fonctionner")
|
||||||
|
@ -18,6 +18,7 @@ Utilisation :
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from types import NoneType
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@ -513,13 +514,16 @@ def test_etudiant_bulletin_semestre(api_headers):
|
|||||||
assert evaluation["description"] is None or isinstance(
|
assert evaluation["description"] is None or isinstance(
|
||||||
evaluation["description"], str
|
evaluation["description"], str
|
||||||
)
|
)
|
||||||
assert evaluation["date"] is None or isinstance(evaluation["date"], str)
|
|
||||||
assert isinstance(evaluation["heure_debut"], str)
|
|
||||||
assert isinstance(evaluation["heure_fin"], str)
|
|
||||||
assert isinstance(evaluation["coef"], str)
|
assert isinstance(evaluation["coef"], str)
|
||||||
assert isinstance(evaluation["poids"], dict)
|
assert isinstance(evaluation["poids"], dict)
|
||||||
assert isinstance(evaluation["note"], dict)
|
assert isinstance(evaluation["note"], dict)
|
||||||
assert isinstance(evaluation["url"], str)
|
assert isinstance(evaluation["url"], str)
|
||||||
|
assert isinstance(evaluation["date_debut"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["date_fin"], (str, NoneType))
|
||||||
|
# Deprecated (supprimer avant #sco9.7):
|
||||||
|
assert isinstance(evaluation["date"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_debut"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_fin"], (str, NoneType))
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
verify_fields(
|
verify_fields(
|
||||||
@ -567,13 +571,16 @@ def test_etudiant_bulletin_semestre(api_headers):
|
|||||||
assert evaluation["description"] is None or isinstance(
|
assert evaluation["description"] is None or isinstance(
|
||||||
evaluation["description"], str
|
evaluation["description"], str
|
||||||
)
|
)
|
||||||
assert evaluation["date"] is None or isinstance(evaluation["date"], str)
|
|
||||||
assert isinstance(evaluation["heure_debut"], str)
|
|
||||||
assert isinstance(evaluation["heure_fin"], str)
|
|
||||||
assert isinstance(evaluation["coef"], str)
|
assert isinstance(evaluation["coef"], str)
|
||||||
assert isinstance(evaluation["poids"], dict)
|
assert isinstance(evaluation["poids"], dict)
|
||||||
assert isinstance(evaluation["note"], dict)
|
assert isinstance(evaluation["note"], dict)
|
||||||
assert isinstance(evaluation["url"], str)
|
assert isinstance(evaluation["url"], str)
|
||||||
|
assert isinstance(evaluation["date_fin"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["date_debut"], (str, NoneType))
|
||||||
|
# Deprecated fields (supprimer avant #sco9.7)
|
||||||
|
assert isinstance(evaluation["date"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_debut"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_fin"], (str, NoneType))
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
verify_fields(
|
verify_fields(
|
||||||
|
@ -18,6 +18,7 @@ Utilisation :
|
|||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
from types import NoneType
|
||||||
|
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
@ -301,14 +302,18 @@ def test_bulletins(api_headers):
|
|||||||
assert evaluation["description"] is None or isinstance(
|
assert evaluation["description"] is None or isinstance(
|
||||||
evaluation["description"], str
|
evaluation["description"], str
|
||||||
)
|
)
|
||||||
assert evaluation["date"] is None or isinstance(evaluation["date"], str)
|
assert isinstance(evaluation["date_debut"], (str, NoneType))
|
||||||
assert isinstance(evaluation["heure_debut"], str)
|
assert isinstance(evaluation["date_fin"], (str, NoneType))
|
||||||
assert isinstance(evaluation["heure_fin"], str)
|
|
||||||
assert isinstance(evaluation["coef"], str)
|
assert isinstance(evaluation["coef"], str)
|
||||||
assert isinstance(evaluation["poids"], dict)
|
assert isinstance(evaluation["poids"], dict)
|
||||||
assert isinstance(evaluation["note"], dict)
|
assert isinstance(evaluation["note"], dict)
|
||||||
assert isinstance(evaluation["url"], str)
|
assert isinstance(evaluation["url"], str)
|
||||||
|
|
||||||
|
# Deprecated (supprimer avant #sco9.7):
|
||||||
|
assert isinstance(evaluation["date"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_debut"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_fin"], (str, NoneType))
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
verify_fields(
|
verify_fields(
|
||||||
evaluation["poids"],
|
evaluation["poids"],
|
||||||
@ -354,14 +359,18 @@ def test_bulletins(api_headers):
|
|||||||
assert evaluation["description"] is None or isinstance(
|
assert evaluation["description"] is None or isinstance(
|
||||||
evaluation["description"], str
|
evaluation["description"], str
|
||||||
)
|
)
|
||||||
assert evaluation["date"] is None or isinstance(evaluation["date"], str)
|
assert isinstance(evaluation["date_debut"], (str, NoneType))
|
||||||
assert isinstance(evaluation["heure_debut"], str)
|
assert isinstance(evaluation["date_fin"], (str, NoneType))
|
||||||
assert isinstance(evaluation["heure_fin"], str)
|
|
||||||
assert isinstance(evaluation["coef"], str)
|
assert isinstance(evaluation["coef"], str)
|
||||||
assert isinstance(evaluation["poids"], dict)
|
assert isinstance(evaluation["poids"], dict)
|
||||||
assert isinstance(evaluation["note"], dict)
|
assert isinstance(evaluation["note"], dict)
|
||||||
assert isinstance(evaluation["url"], str)
|
assert isinstance(evaluation["url"], str)
|
||||||
|
|
||||||
|
# Deprecated (supprimer avant #sco9.7):
|
||||||
|
assert isinstance(evaluation["date"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_debut"], (str, NoneType))
|
||||||
|
assert isinstance(evaluation["heure_fin"], (str, NoneType))
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
verify_fields(
|
verify_fields(
|
||||||
evaluation["poids"],
|
evaluation["poids"],
|
||||||
|
@ -491,7 +491,7 @@ EVAL_FIELDS = {
|
|||||||
"numero",
|
"numero",
|
||||||
"poids",
|
"poids",
|
||||||
"publish_incomplete",
|
"publish_incomplete",
|
||||||
"visi_bulletin",
|
"visibulletin",
|
||||||
"etat",
|
"etat",
|
||||||
"nb_inscrits",
|
"nb_inscrits",
|
||||||
"nb_notes_manquantes",
|
"nb_notes_manquantes",
|
||||||
@ -565,7 +565,7 @@ EVALUATIONS_FIELDS = {
|
|||||||
"numero",
|
"numero",
|
||||||
"poids",
|
"poids",
|
||||||
"publish_incomplete",
|
"publish_incomplete",
|
||||||
"visi_bulletin",
|
"visibulletin",
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTES_FIELDS = {
|
NOTES_FIELDS = {
|
||||||
|
@ -7,7 +7,7 @@ A utiliser avec debug.py (côté serveur).
|
|||||||
La classe ScoFake offre un ensemble de raccourcis permettant d'écrire
|
La classe ScoFake offre un ensemble de raccourcis permettant d'écrire
|
||||||
facilement des tests ou de reproduire des bugs.
|
facilement des tests ou de reproduire des bugs.
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
@ -304,9 +304,8 @@ class ScoFake(object):
|
|||||||
def create_evaluation(
|
def create_evaluation(
|
||||||
self,
|
self,
|
||||||
moduleimpl_id=None,
|
moduleimpl_id=None,
|
||||||
jour=None,
|
date_debut: datetime.datetime = None,
|
||||||
heure_debut="8h00",
|
date_fin: datetime.datetime = None,
|
||||||
heure_fin="9h00",
|
|
||||||
description=None,
|
description=None,
|
||||||
note_max=20,
|
note_max=20,
|
||||||
coefficient=None,
|
coefficient=None,
|
||||||
@ -314,7 +313,7 @@ class ScoFake(object):
|
|||||||
publish_incomplete=None,
|
publish_incomplete=None,
|
||||||
evaluation_type=None,
|
evaluation_type=None,
|
||||||
numero=None,
|
numero=None,
|
||||||
) -> int:
|
) -> dict:
|
||||||
args = locals()
|
args = locals()
|
||||||
del args["self"]
|
del args["self"]
|
||||||
moduleimpl: ModuleImpl = db.session.get(ModuleImpl, moduleimpl_id)
|
moduleimpl: ModuleImpl = db.session.get(ModuleImpl, moduleimpl_id)
|
||||||
@ -322,7 +321,9 @@ class ScoFake(object):
|
|||||||
evaluation: Evaluation = Evaluation.create(moduleimpl=moduleimpl, **args)
|
evaluation: Evaluation = Evaluation.create(moduleimpl=moduleimpl, **args)
|
||||||
db.session.add(evaluation)
|
db.session.add(evaluation)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return evaluation.id
|
eval_dict = evaluation.to_dict()
|
||||||
|
eval_dict["id"] = evaluation.id
|
||||||
|
return eval_dict
|
||||||
|
|
||||||
@logging_meth
|
@logging_meth
|
||||||
def create_note(
|
def create_note(
|
||||||
@ -414,7 +415,7 @@ class ScoFake(object):
|
|||||||
for e_idx in range(1, nb_evaluations_per_module + 1):
|
for e_idx in range(1, nb_evaluations_per_module + 1):
|
||||||
e = self.create_evaluation(
|
e = self.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour=date_debut,
|
date_debut=datetime.datetime.strptime(date_debut, "%d/%m/%Y"),
|
||||||
description="evaluation test %s" % e_idx,
|
description="evaluation test %s" % e_idx,
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
@ -435,7 +436,7 @@ class ScoFake(object):
|
|||||||
for e in eval_list:
|
for e in eval_list:
|
||||||
for idx, etud in enumerate(etuds):
|
for idx, etud in enumerate(etuds):
|
||||||
self.create_note(
|
self.create_note(
|
||||||
evaluation_id=e["id"],
|
evaluation_id=e["evaluation_id"],
|
||||||
etudid=etud["etudid"],
|
etudid=etud["etudid"],
|
||||||
note=notes[idx % len(notes)],
|
note=notes[idx % len(notes)],
|
||||||
)
|
)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
Quelques fonctions d'initialisation pour tests unitaires
|
Quelques fonctions d'initialisation pour tests unitaires
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
from app import db, models
|
from app import db, models
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ def build_modules_with_evaluations(
|
|||||||
for _ in range(nb_evals_per_modimpl):
|
for _ in range(nb_evals_per_modimpl):
|
||||||
e = G.create_evaluation(
|
e = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2021",
|
date_debut=datetime.datetime(2021, 1, 1),
|
||||||
description="evaluation 1",
|
description="evaluation 1",
|
||||||
coefficient=0,
|
coefficient=0,
|
||||||
)
|
)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
Créer et justifier des absences en utilisant le parametre demijournee
|
Créer et justifier des absences en utilisant le parametre demijournee
|
||||||
"""
|
"""
|
||||||
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
@ -163,7 +163,7 @@ def test_abs_basic(test_client):
|
|||||||
# --- Création d'une évaluation
|
# --- Création d'une évaluation
|
||||||
e = G.create_evaluation(
|
e = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="22/01/2021",
|
date_debut=datetime.datetime(2021, 1, 22),
|
||||||
description="evaluation test",
|
description="evaluation test",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
|
@ -22,7 +22,7 @@ from tests.unit import test_sco_basic
|
|||||||
DEPT = TestConfig.DEPT_TEST
|
DEPT = TestConfig.DEPT_TEST
|
||||||
|
|
||||||
|
|
||||||
def test_bulletin(test_client):
|
def test_bulletin_data_classic(test_client):
|
||||||
"""Vérifications sur les bulletins de notes"""
|
"""Vérifications sur les bulletins de notes"""
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
app.set_sco_dept(DEPT)
|
app.set_sco_dept(DEPT)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
Test modèles évaluations avec poids BUT
|
Test modèles évaluations avec poids BUT
|
||||||
et calcul moyennes modules
|
et calcul moyennes modules
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ def test_evaluation_poids(test_client):
|
|||||||
)
|
)
|
||||||
_e1 = G.create_evaluation(
|
_e1 = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2021",
|
date_debut=datetime.datetime(2021, 1, 1),
|
||||||
description="evaluation 1",
|
description="evaluation 1",
|
||||||
coefficient=0,
|
coefficient=0,
|
||||||
)
|
)
|
||||||
@ -218,7 +219,7 @@ def test_module_moy(test_client):
|
|||||||
# Crée une deuxième évaluation dans le même moduleimpl:
|
# Crée une deuxième évaluation dans le même moduleimpl:
|
||||||
evaluation2_id = G.create_evaluation(
|
evaluation2_id = G.create_evaluation(
|
||||||
moduleimpl_id=evaluation1.moduleimpl_id,
|
moduleimpl_id=evaluation1.moduleimpl_id,
|
||||||
jour="02/01/2021",
|
date_debut=datetime.datetime(2021, 1, 2),
|
||||||
description="evaluation 2",
|
description="evaluation 2",
|
||||||
coefficient=coef_e2,
|
coefficient=coef_e2,
|
||||||
)["evaluation_id"]
|
)["evaluation_id"]
|
||||||
|
@ -15,12 +15,11 @@ import app
|
|||||||
from app import db
|
from app import db
|
||||||
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 FormSemestre
|
from app.models import Evaluation, FormSemestre, ModuleImpl
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_evaluations
|
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 notesdb as ndb
|
|
||||||
from config import TestConfig
|
from config import TestConfig
|
||||||
from tests.unit.test_sco_basic import run_sco_basic
|
from tests.unit.test_sco_basic import run_sco_basic
|
||||||
|
|
||||||
@ -58,23 +57,24 @@ def test_cache_evaluations(test_client):
|
|||||||
# prépare le département avec quelques semestres:
|
# prépare le département avec quelques semestres:
|
||||||
run_sco_basic()
|
run_sco_basic()
|
||||||
#
|
#
|
||||||
sems = sco_formsemestre.do_formsemestre_list()
|
formsemestres = FormSemestre.query
|
||||||
assert len(sems)
|
assert formsemestres.count()
|
||||||
sem_evals = []
|
evaluation = None
|
||||||
for sem in sems:
|
for formsemestre in formsemestres:
|
||||||
sem_evals = sco_evaluations.do_evaluation_list_in_sem(
|
evaluation: Evaluation = (
|
||||||
sem["formsemestre_id"], with_etat=False
|
Evaluation.query.join(ModuleImpl)
|
||||||
|
.filter_by(formsemestre_id=formsemestre.id)
|
||||||
|
.first()
|
||||||
)
|
)
|
||||||
if sem_evals:
|
if evaluation is not None:
|
||||||
break
|
break
|
||||||
if not sem_evals:
|
if evaluation is None:
|
||||||
raise Exception("no evaluations")
|
raise Exception("no evaluations")
|
||||||
#
|
#
|
||||||
evaluation_id = sem_evals[0]["evaluation_id"]
|
eval_notes = sco_evaluation_db.do_evaluation_get_all_notes(evaluation.id)
|
||||||
eval_notes = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
|
||||||
# should have been be cached, except if empty
|
# should have been be cached, except if empty
|
||||||
if eval_notes:
|
if eval_notes:
|
||||||
assert sco_cache.EvaluationCache.get(evaluation_id)
|
assert sco_cache.EvaluationCache.get(evaluation.id)
|
||||||
sco_cache.invalidate_formsemestre(sem["formsemestre_id"])
|
sco_cache.invalidate_formsemestre(evaluation.moduleimpl.formsemestre.id)
|
||||||
# should have been erased from cache:
|
# should have been erased from cache:
|
||||||
assert not sco_cache.EvaluationCache.get(evaluation_id)
|
assert not sco_cache.EvaluationCache.get(evaluation.id)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
Vérif moyennes de modules des bulletins
|
Vérif moyennes de modules des bulletins
|
||||||
et aussi moyennes modules et UE internes (via nt)
|
et aussi moyennes modules et UE internes (via nt)
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from flask import g
|
from flask import g
|
||||||
from config import TestConfig
|
from config import TestConfig
|
||||||
@ -93,13 +94,13 @@ def test_notes_modules(test_client):
|
|||||||
coef_2 = 2.0
|
coef_2 = 2.0
|
||||||
e1 = G.create_evaluation(
|
e1 = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2020",
|
date_debut=datetime.datetime(2020, 1, 1),
|
||||||
description="evaluation 1",
|
description="evaluation 1",
|
||||||
coefficient=coef_1,
|
coefficient=coef_1,
|
||||||
)
|
)
|
||||||
e2 = G.create_evaluation(
|
e2 = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2020",
|
date_debut=datetime.datetime(2020, 1, 1),
|
||||||
description="evaluation 2",
|
description="evaluation 2",
|
||||||
coefficient=coef_2,
|
coefficient=coef_2,
|
||||||
)
|
)
|
||||||
@ -107,16 +108,16 @@ def test_notes_modules(test_client):
|
|||||||
note_1 = 12.0
|
note_1 = 12.0
|
||||||
note_2 = 13.0
|
note_2 = 13.0
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etuds[0]["etudid"], note=note_1
|
evaluation_id=e1["evaluation_id"], etudid=etuds[0]["etudid"], note=note_1
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etuds[0]["etudid"], note=note_2
|
evaluation_id=e2["evaluation_id"], etudid=etuds[0]["etudid"], note=note_2
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etuds[1]["etudid"], note=note_1 / 2
|
evaluation_id=e1["evaluation_id"], etudid=etuds[1]["etudid"], note=note_1 / 2
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etuds[1]["etudid"], note=note_2 / 3
|
evaluation_id=e2["evaluation_id"], etudid=etuds[1]["etudid"], 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"]
|
||||||
@ -138,16 +139,24 @@ def test_notes_modules(test_client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Absence à une évaluation
|
# Absence à une évaluation
|
||||||
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etudid, note=None) # abs
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation_id=e2["id"], etudid=etudid, note=note_2)
|
evaluation_id=e1["evaluation_id"], etudid=etudid, note=None
|
||||||
|
) # abs
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["evaluation_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_id=e1["id"], etudid=etudid, note=None) # abs
|
_, _, _ = G.create_note(
|
||||||
_, _, _ = G.create_note(evaluation_id=e2["id"], etudid=etudid, note=None) # abs
|
evaluation_id=e1["evaluation_id"], etudid=etudid, note=None
|
||||||
|
) # abs
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["evaluation_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"]
|
||||||
)
|
)
|
||||||
@ -162,9 +171,11 @@ def test_notes_modules(test_client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Note excusée EXC <-> scu.NOTES_NEUTRALISE
|
# Note excusée EXC <-> scu.NOTES_NEUTRALISE
|
||||||
_, _, _ = G.create_note(evaluation_id=e1["id"], etudid=etudid, note=note_1)
|
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
evaluation_id=e1["evaluation_id"], etudid=etudid, note=note_1
|
||||||
|
)
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
) # EXC
|
) # EXC
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
@ -179,9 +190,11 @@ 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_id=e1["id"], etudid=etudid, note=note_1)
|
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
evaluation_id=e1["evaluation_id"], etudid=etudid, note=note_1
|
||||||
|
)
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
||||||
) # ATT
|
) # ATT
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
@ -197,10 +210,10 @@ def test_notes_modules(test_client):
|
|||||||
)
|
)
|
||||||
# Neutralisation (EXC) des 2 évals
|
# Neutralisation (EXC) des 2 évals
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
evaluation_id=e1["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
) # EXC
|
) # EXC
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
) # EXC
|
) # EXC
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
@ -216,10 +229,10 @@ def test_notes_modules(test_client):
|
|||||||
)
|
)
|
||||||
# Attente (ATT) sur les 2 evals
|
# Attente (ATT) sur les 2 evals
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
evaluation_id=e1["evaluation_id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
||||||
) # ATT
|
) # ATT
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_ATTENTE
|
||||||
) # ATT
|
) # ATT
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
sem["formsemestre_id"], etud["etudid"]
|
sem["formsemestre_id"], etud["etudid"]
|
||||||
@ -277,7 +290,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_id=e1["id"], etudid=etudid, note=12.5)
|
_, _, _ = G.create_note(evaluation_id=e1["evaluation_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)
|
||||||
@ -301,11 +314,13 @@ def test_notes_modules(test_client):
|
|||||||
# Note dans module 2:
|
# Note dans module 2:
|
||||||
e_m2 = G.create_evaluation(
|
e_m2 = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id2,
|
moduleimpl_id=moduleimpl_id2,
|
||||||
jour="01/01/2020",
|
date_debut=datetime.datetime(2020, 1, 1),
|
||||||
description="evaluation mod 2",
|
description="evaluation mod 2",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(evaluation_id=e_m2["id"], etudid=etudid, note=19.5)
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e_m2["evaluation_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)
|
||||||
@ -314,20 +329,22 @@ def test_notes_modules(test_client):
|
|||||||
# 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(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
evaluation_id=e1["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
) # EXC
|
) # EXC
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
|
||||||
) # EXC
|
) # EXC
|
||||||
_, _, _ = G.create_note(evaluation_id=e_m2["id"], etudid=etudid, note=12.5)
|
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etuds[1]["etudid"], note=11.0
|
evaluation_id=e_m2["evaluation_id"], etudid=etudid, note=12.5
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e2["id"], etudid=etuds[1]["etudid"], note=11.0
|
evaluation_id=e1["evaluation_id"], etudid=etuds[1]["etudid"], note=11.0
|
||||||
)
|
)
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e_m2["id"], etudid=etuds[1]["etudid"], note=11.0
|
evaluation_id=e2["evaluation_id"], etudid=etuds[1]["etudid"], note=11.0
|
||||||
|
)
|
||||||
|
_, _, _ = G.create_note(
|
||||||
|
evaluation_id=e_m2["evaluation_id"], etudid=etuds[1]["etudid"], note=11.0
|
||||||
)
|
)
|
||||||
|
|
||||||
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
b = sco_bulletins.formsemestre_bulletinetud_dict(
|
||||||
@ -385,16 +402,20 @@ def test_notes_modules_att_dem(test_client):
|
|||||||
coef_1 = 1.0
|
coef_1 = 1.0
|
||||||
e1 = G.create_evaluation(
|
e1 = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2020",
|
date_debut=datetime.datetime(2020, 1, 1),
|
||||||
description="evaluation 1",
|
description="evaluation 1",
|
||||||
coefficient=coef_1,
|
coefficient=coef_1,
|
||||||
)
|
)
|
||||||
# Attente (ATT) sur les 2 evals
|
# Attente (ATT) sur les 2 evals
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etuds[0]["etudid"], note=scu.NOTES_ATTENTE
|
evaluation_id=e1["evaluation_id"],
|
||||||
|
etudid=etuds[0]["etudid"],
|
||||||
|
note=scu.NOTES_ATTENTE,
|
||||||
) # ATT
|
) # ATT
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etuds[1]["etudid"], note=scu.NOTES_ATTENTE
|
evaluation_id=e1["evaluation_id"],
|
||||||
|
etudid=etuds[1]["etudid"],
|
||||||
|
note=scu.NOTES_ATTENTE,
|
||||||
) # ATT
|
) # ATT
|
||||||
# Démission du premier étudiant
|
# Démission du premier étudiant
|
||||||
sco_formsemestre_inscriptions.do_formsemestre_demission(
|
sco_formsemestre_inscriptions.do_formsemestre_demission(
|
||||||
@ -435,7 +456,7 @@ def test_notes_modules_att_dem(test_client):
|
|||||||
|
|
||||||
# Saisie note ABS pour le deuxième etud
|
# Saisie note ABS pour le deuxième etud
|
||||||
_, _, _ = G.create_note(
|
_, _, _ = G.create_note(
|
||||||
evaluation_id=e1["id"], etudid=etuds[1]["etudid"], note=None
|
evaluation_id=e1["evaluation_id"], etudid=etuds[1]["etudid"], note=None
|
||||||
)
|
)
|
||||||
nt = check_nt(
|
nt = check_nt(
|
||||||
etuds[1]["etudid"],
|
etuds[1]["etudid"],
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""Test calculs rattrapages
|
"""Test calculs rattrapages
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
import app
|
import app
|
||||||
from app import db
|
from app import db
|
||||||
@ -58,14 +59,14 @@ def test_notes_rattrapage(test_client):
|
|||||||
# --- Creation évaluation
|
# --- Creation évaluation
|
||||||
e = G.create_evaluation(
|
e = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2020",
|
date_debut=datetime.datetime(2020, 1, 1),
|
||||||
description="evaluation test",
|
description="evaluation test",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
# --- Création d'une évaluation "de rattrapage"
|
# --- Création d'une évaluation "de rattrapage"
|
||||||
e_rat = G.create_evaluation(
|
e_rat = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="02/01/2020",
|
date_debut=datetime.datetime(2020, 1, 2),
|
||||||
description="evaluation rattrapage",
|
description="evaluation rattrapage",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
evaluation_type=scu.EVALUATION_RATTRAPAGE,
|
evaluation_type=scu.EVALUATION_RATTRAPAGE,
|
||||||
@ -139,7 +140,7 @@ def test_notes_rattrapage(test_client):
|
|||||||
# Création évaluation session 2:
|
# Création évaluation session 2:
|
||||||
e_session2 = G.create_evaluation(
|
e_session2 = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="02/01/2020",
|
date_debut=datetime.datetime(2020, 1, 2),
|
||||||
description="evaluation session 2",
|
description="evaluation session 2",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
evaluation_type=scu.EVALUATION_SESSION2,
|
evaluation_type=scu.EVALUATION_SESSION2,
|
||||||
|
@ -11,6 +11,8 @@ Au besoin, créer un base de test neuve:
|
|||||||
./tools/create_database.sh SCODOC_TEST
|
./tools/create_database.sh SCODOC_TEST
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
from app.models import FormSemestreInscription, Identite
|
from app.models import FormSemestreInscription, Identite
|
||||||
|
|
||||||
from config import TestConfig
|
from config import TestConfig
|
||||||
@ -96,7 +98,7 @@ def run_sco_basic(verbose=False) -> FormSemestre:
|
|||||||
# --- Création évaluation
|
# --- Création évaluation
|
||||||
e = G.create_evaluation(
|
e = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="01/01/2020",
|
date_debut=datetime.datetime(2020, 1, 1),
|
||||||
description="evaluation test",
|
description="evaluation test",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
@ -104,7 +106,7 @@ def run_sco_basic(verbose=False) -> FormSemestre:
|
|||||||
# --- Saisie toutes les notes de l'évaluation
|
# --- Saisie toutes les notes de l'évaluation
|
||||||
for idx, etud in enumerate(etuds):
|
for idx, etud in enumerate(etuds):
|
||||||
etudids_changed, nb_suppress, existing_decisions = G.create_note(
|
etudids_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
evaluation_id=e["id"],
|
evaluation_id=e["evaluation_id"],
|
||||||
etudid=etud["etudid"],
|
etudid=etud["etudid"],
|
||||||
note=NOTES_T[idx % len(NOTES_T)],
|
note=NOTES_T[idx % len(NOTES_T)],
|
||||||
)
|
)
|
||||||
@ -130,14 +132,14 @@ def run_sco_basic(verbose=False) -> FormSemestre:
|
|||||||
# --- Une autre évaluation
|
# --- Une autre évaluation
|
||||||
e2 = G.create_evaluation(
|
e2 = G.create_evaluation(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
jour="02/01/2020",
|
date_debut=datetime.datetime(2020, 1, 2),
|
||||||
description="evaluation test 2",
|
description="evaluation test 2",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
)
|
)
|
||||||
# Saisie les notes des 5 premiers étudiants:
|
# Saisie les notes des 5 premiers étudiants:
|
||||||
for idx, etud in enumerate(etuds[:5]):
|
for idx, etud in enumerate(etuds[:5]):
|
||||||
etudids_changed, nb_suppress, existing_decisions = G.create_note(
|
etudids_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
evaluation_id=e2["id"],
|
evaluation_id=e2["evaluation_id"],
|
||||||
etudid=etud["etudid"],
|
etudid=etud["etudid"],
|
||||||
note=NOTES_T[idx % len(NOTES_T)],
|
note=NOTES_T[idx % len(NOTES_T)],
|
||||||
)
|
)
|
||||||
@ -159,7 +161,7 @@ def run_sco_basic(verbose=False) -> FormSemestre:
|
|||||||
# Saisie des notes qui manquent:
|
# Saisie des notes qui manquent:
|
||||||
for idx, etud in enumerate(etuds[5:]):
|
for idx, etud in enumerate(etuds[5:]):
|
||||||
etudids_changed, nb_suppress, existing_decisions = G.create_note(
|
etudids_changed, nb_suppress, existing_decisions = G.create_note(
|
||||||
evaluation_id=e2["id"],
|
evaluation_id=e2["evaluation_id"],
|
||||||
etudid=etud["etudid"],
|
etudid=etud["etudid"],
|
||||||
note=NOTES_T[idx % len(NOTES_T)],
|
note=NOTES_T[idx % len(NOTES_T)],
|
||||||
)
|
)
|
||||||
|
@ -158,7 +158,7 @@ def create_evaluations(formsemestre: FormSemestre, publish_incomplete=True):
|
|||||||
for modimpl in formsemestre.modimpls:
|
for modimpl in formsemestre.modimpls:
|
||||||
evaluation = Evaluation(
|
evaluation = Evaluation(
|
||||||
moduleimpl=modimpl,
|
moduleimpl=modimpl,
|
||||||
jour=formsemestre.date_debut,
|
date_debut=formsemestre.date_debut,
|
||||||
description=f"Exam {modimpl.module.titre}",
|
description=f"Exam {modimpl.module.titre}",
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
note_max=20.0,
|
note_max=20.0,
|
||||||
|
@ -238,7 +238,8 @@ def create_evaluations(formsemestre: FormSemestre):
|
|||||||
"Création d'une evaluation dans chaque modimpl du semestre"
|
"Création d'une evaluation dans chaque modimpl du semestre"
|
||||||
for moduleimpl in formsemestre.modimpls:
|
for moduleimpl in formsemestre.modimpls:
|
||||||
args = {
|
args = {
|
||||||
"jour": datetime.date(2022, 3, 1) + datetime.timedelta(days=moduleimpl.id),
|
"jour": datetime.date(2022, 3, 1)
|
||||||
|
+ datetime.timedelta(days=moduleimpl.id), # TODO à changer
|
||||||
"heure_debut": "8h00",
|
"heure_debut": "8h00",
|
||||||
"heure_fin": "9h00",
|
"heure_fin": "9h00",
|
||||||
"description": f"Evaluation-{moduleimpl.module.code}",
|
"description": f"Evaluation-{moduleimpl.module.code}",
|
||||||
|
Loading…
Reference in New Issue
Block a user