Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
6 changed files with 71 additions and 54 deletions
Showing only changes of commit dece9a82d1 - Show all commits

View File

@ -148,6 +148,7 @@ class ModuleImplResults:
evals_notes = pd.DataFrame(index=self.etudids, dtype=float) evals_notes = pd.DataFrame(index=self.etudids, dtype=float)
self.evaluations_completes = [] self.evaluations_completes = []
self.evaluations_completes_dict = {} self.evaluations_completes_dict = {}
self.etudids_attente = set() # empty
for evaluation in moduleimpl.evaluations: for evaluation in moduleimpl.evaluations:
eval_df = self._load_evaluation_notes(evaluation) eval_df = self._load_evaluation_notes(evaluation)
# is_complete ssi # is_complete ssi
@ -155,13 +156,13 @@ class ModuleImplResults:
# ou évaluation déclarée "à prise en compte immédiate" # ou évaluation déclarée "à prise en compte immédiate"
# ou rattrapage, 2eme session, bonus # ou rattrapage, 2eme session, bonus
# ET pas bloquée par date (is_blocked) # ET pas bloquée par date (is_blocked)
is_blocked = evaluation.is_blocked()
etudids_sans_note = inscrits_module - set(eval_df.index) # sans les dem. etudids_sans_note = inscrits_module - set(eval_df.index) # sans les dem.
is_complete = ( is_complete = (
(evaluation.evaluation_type != Evaluation.EVALUATION_NORMALE) (evaluation.evaluation_type != Evaluation.EVALUATION_NORMALE)
or (evaluation.publish_incomplete) or (evaluation.publish_incomplete)
or (not etudids_sans_note) or (not etudids_sans_note)
) and not evaluation.is_blocked() ) and not is_blocked
self.evaluations_completes.append(is_complete) self.evaluations_completes.append(is_complete)
self.evaluations_completes_dict[evaluation.id] = is_complete self.evaluations_completes_dict[evaluation.id] = is_complete
self.evals_etudids_sans_note[evaluation.id] = etudids_sans_note self.evals_etudids_sans_note[evaluation.id] = etudids_sans_note
@ -178,16 +179,21 @@ class ModuleImplResults:
eval_notes_inscr = evals_notes[str(evaluation.id)][list(inscrits_module)] eval_notes_inscr = evals_notes[str(evaluation.id)][list(inscrits_module)]
# Nombre de notes (non vides, incluant ATT etc) des inscrits: # Nombre de notes (non vides, incluant ATT etc) des inscrits:
nb_notes = eval_notes_inscr.notna().sum() nb_notes = eval_notes_inscr.notna().sum()
# Etudiants avec notes en attente:
# = ceux avec note ATT if is_blocked:
eval_etudids_attente = set( eval_etudids_attente = set()
eval_notes_inscr.iloc[ else:
(eval_notes_inscr == scu.NOTES_ATTENTE).to_numpy() # Etudiants avec notes en attente:
].index # = ceux avec note ATT
) eval_etudids_attente = set(
if evaluation.publish_incomplete: eval_notes_inscr.iloc[
# et en "immédiat", tous ceux sans note (eval_notes_inscr == scu.NOTES_ATTENTE).to_numpy()
eval_etudids_attente |= etudids_sans_note ].index
)
if evaluation.publish_incomplete:
# et en "immédiat", tous ceux sans note
eval_etudids_attente |= etudids_sans_note
# Synthèse pour état du module: # Synthèse pour état du module:
self.etudids_attente |= eval_etudids_attente self.etudids_attente |= eval_etudids_attente
self.evaluations_etat[evaluation.id] = EvaluationEtat( self.evaluations_etat[evaluation.id] = EvaluationEtat(

View File

@ -209,6 +209,7 @@ class ResultatsSemestre(ResultatsCache):
"evalcomplete" : bool, "evalcomplete" : bool,
"last_modif" : datetime.datetime | None, # saisie de note la plus récente "last_modif" : datetime.datetime | None, # saisie de note la plus récente
"nb_notes" : int, # nb notes d'étudiants inscrits "nb_notes" : int, # nb notes d'étudiants inscrits
"nb_attente" : int, # nb de notes en ATTente (même si bloquée)
}, },
"evaluation_id" : int, "evaluation_id" : int,
"jour" : datetime.datetime, # e.date_debut or datetime.datetime(1900, 1, 1) "jour" : datetime.datetime, # e.date_debut or datetime.datetime(1900, 1, 1)
@ -236,6 +237,7 @@ class ResultatsSemestre(ResultatsCache):
"etat": { "etat": {
"blocked": evaluation.is_blocked(), "blocked": evaluation.is_blocked(),
"evalcomplete": etat.is_complete, "evalcomplete": etat.is_complete,
"nb_attente": etat.nb_attente,
"nb_notes": etat.nb_notes, "nb_notes": etat.nb_notes,
"last_modif": last_modif, "last_modif": last_modif,
}, },

View File

@ -873,7 +873,7 @@ class FormSemestre(db.Model):
descr_sem += " " + self.modalite descr_sem += " " + self.modalite
return descr_sem return descr_sem
def get_abs_count(self, etudid): def get_abs_count(self, etudid) -> tuple[int, int, int]:
"""Les comptes d'absences de cet étudiant dans ce semestre: """Les comptes d'absences de cet étudiant dans ce semestre:
tuple (nb abs non just, nb abs justifiées, nb abs total) tuple (nb abs non just, nb abs justifiées, nb abs total)
Utilise un cache. Utilise un cache.

View File

@ -30,17 +30,18 @@
(coût théorique en heures équivalent TD) (coût théorique en heures équivalent TD)
""" """
from flask import request from flask import request, Response
from app.models import FormSemestre from app.models import FormSemestre
from app.scodoc.gen_tables import GenTable
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_exceptions import ScoValueError
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import sco_version import sco_version
def formsemestre_table_estim_cost( def formsemestre_table_estim_cost(
formsemestre_id, formsemestre: FormSemestre,
n_group_td=1, n_group_td=1,
n_group_tp=1, n_group_tp=1,
coef_tp=1, coef_tp=1,
@ -55,8 +56,6 @@ def formsemestre_table_estim_cost(
peut conduire à une sur-estimation du coût s'il y a des modules optionnels peut conduire à une sur-estimation du coût s'il y a des modules optionnels
(dans ce cas, retoucher le tableau excel exporté). (dans ce cas, retoucher le tableau excel exporté).
""" """
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
rows = [] rows = []
for modimpl in formsemestre.modimpls: for modimpl in formsemestre.modimpls:
rows.append( rows.append(
@ -76,14 +75,14 @@ def formsemestre_table_estim_cost(
+ coef_cours * row["heures_cours"] + coef_cours * row["heures_cours"]
+ coef_tp * row["heures_tp"] + coef_tp * row["heures_tp"]
) )
sum_cours = sum([t["heures_cours"] for t in rows]) sum_cours = sum(t["heures_cours"] for t in rows)
sum_td = sum([t["heures_td"] for t in rows]) sum_td = sum(t["heures_td"] for t in rows)
sum_tp = sum([t["heures_tp"] for t in rows]) sum_tp = sum(t["heures_tp"] for t in rows)
sum_heqtd = sum_td + coef_cours * sum_cours + coef_tp * sum_tp sum_heqtd = sum_td + coef_cours * sum_cours + coef_tp * sum_tp
assert abs(sum([t["HeqTD"] for t in rows]) - sum_heqtd) < 0.01, "%s != %s" % ( # assert abs(sum(t["HeqTD"] for t in rows) - sum_heqtd) < 0.01, "%s != %s" % (
sum([t["HeqTD"] for t in rows]), # sum(t["HeqTD"] for t in rows),
sum_heqtd, # sum_heqtd,
) # )
rows.append( rows.append(
{ {
@ -117,7 +116,7 @@ def formsemestre_table_estim_cost(
), ),
rows=rows, rows=rows,
html_sortable=True, html_sortable=True,
preferences=sco_preferences.SemPreferences(formsemestre_id), preferences=sco_preferences.SemPreferences(formsemestre.id),
html_class="table_leftalign table_listegroupe", html_class="table_leftalign table_listegroupe",
xls_before_table=[ xls_before_table=[
[formsemestre.titre_annee()], [formsemestre.titre_annee()],
@ -146,47 +145,45 @@ def formsemestre_table_estim_cost(
return tab return tab
# view
def formsemestre_estim_cost( def formsemestre_estim_cost(
formsemestre_id, formsemestre_id: int,
n_group_td=1, n_group_td: int | str = 1,
n_group_tp=1, n_group_tp: int | str = 1,
coef_tp=1, coef_tp: float | str = 1.0,
coef_cours=1.5, coef_cours: float | str = 1.5,
fmt="html", fmt="html",
): ) -> str | Response:
"""Page (formulaire) estimation coûts""" """Page (formulaire) estimation coûts"""
try:
n_group_td = int(n_group_td)
n_group_tp = int(n_group_tp)
coef_tp = float(coef_tp)
coef_cours = float(coef_cours)
except ValueError as exc:
raise ScoValueError("paramètre invalide: utiliser des nombres") from exc
n_group_td = int(n_group_td) formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
n_group_tp = int(n_group_tp)
coef_tp = float(coef_tp)
coef_cours = float(coef_cours)
tab = formsemestre_table_estim_cost( tab = formsemestre_table_estim_cost(
formsemestre_id, formsemestre,
n_group_td=n_group_td, n_group_td=n_group_td,
n_group_tp=n_group_tp, n_group_tp=n_group_tp,
coef_tp=coef_tp, coef_tp=coef_tp,
coef_cours=coef_cours, coef_cours=coef_cours,
) )
h = """ tab.html_before_table = f"""
<form name="f" method="get" action="%s"> <form name="f" method="get" action="{request.base_url}">
<input type="hidden" name="formsemestre_id" value="%s"></input> <input type="hidden" name="formsemestre_id" value="{formsemestre.id}"></input>
Nombre de groupes de TD: <input type="text" name="n_group_td" value="%s" onchange="document.f.submit()"/><br> Nombre de groupes de TD: <input type="text" name="n_group_td" value="{n_group_td}" onchange="document.f.submit()"/><br>
Nombre de groupes de TP: <input type="text" name="n_group_tp" value="%s" onchange="document.f.submit()"/> Nombre de groupes de TP: <input type="text" name="n_group_tp" value="{n_group_tp}" onchange="document.f.submit()"/>
&nbsp;Coefficient heures TP: <input type="text" name="coef_tp" value="%s" onchange="document.f.submit()"/> &nbsp;Coefficient heures TP: <input type="text" name="coef_tp" value="{coef_tp}" onchange="document.f.submit()"/>
<br> <br>
</form> </form>
""" % ( """
request.base_url,
formsemestre_id,
n_group_td,
n_group_tp,
coef_tp,
)
tab.html_before_table = h
tab.base_url = "%s?formsemestre_id=%s&n_group_td=%s&n_group_tp=%s&coef_tp=%s" % ( tab.base_url = "%s?formsemestre_id=%s&n_group_td=%s&n_group_tp=%s&coef_tp=%s" % (
request.base_url, request.base_url,
formsemestre_id, formsemestre.id,
n_group_td, n_group_td,
n_group_tp, n_group_tp,
coef_tp, coef_tp,

View File

@ -279,11 +279,18 @@ def _summarize_evals_etats(etat_evals: list[dict]) -> dict:
nb_eval_completes (= prises en compte) nb_eval_completes (= prises en compte)
nb_evals_en_cours (= avec des notes, mais pas complete) nb_evals_en_cours (= avec des notes, mais pas complete)
nb_evals_vides (= sans aucune note) nb_evals_vides (= sans aucune note)
nb_evals_attente (= avec des notes en ATTente et pas bloquée)
date derniere modif date derniere modif
Une eval est "complete" ssi tous les etudiants *inscrits* ont une note. Une eval est "complete" ssi tous les etudiants *inscrits* ont une note.
""" """
nb_evals_completes, nb_evals_en_cours, nb_evals_vides, nb_evals_blocked = 0, 0, 0, 0 (
nb_evals_completes,
nb_evals_en_cours,
nb_evals_vides,
nb_evals_blocked,
nb_evals_attente,
) = (0, 0, 0, 0, 0)
dates = [] dates = []
for e in etat_evals: for e in etat_evals:
if e["etat"]["blocked"]: if e["etat"]["blocked"]:
@ -294,6 +301,8 @@ def _summarize_evals_etats(etat_evals: list[dict]) -> dict:
nb_evals_vides += 1 nb_evals_vides += 1
elif not e["etat"]["blocked"]: elif not e["etat"]["blocked"]:
nb_evals_en_cours += 1 nb_evals_en_cours += 1
if e["etat"]["nb_attente"] and not e["etat"]["blocked"]:
nb_evals_attente += 1
last_modif = e["etat"]["last_modif"] last_modif = e["etat"]["last_modif"]
if last_modif is not None: if last_modif is not None:
dates.append(e["etat"]["last_modif"]) dates.append(e["etat"]["last_modif"])
@ -303,6 +312,7 @@ def _summarize_evals_etats(etat_evals: list[dict]) -> dict:
return { return {
"nb_evals": len(etat_evals), "nb_evals": len(etat_evals),
"nb_evals_attente": nb_evals_attente,
"nb_evals_blocked": nb_evals_blocked, "nb_evals_blocked": nb_evals_blocked,
"nb_evals_completes": nb_evals_completes, "nb_evals_completes": nb_evals_completes,
"nb_evals_en_cours": nb_evals_en_cours, "nb_evals_en_cours": nb_evals_en_cours,

View File

@ -1312,7 +1312,9 @@ def formsemestre_tableau_modules(
if etat["attente"]: if etat["attente"]:
H.append( H.append(
f""" <span><a class="redlink" href="{moduleimpl_status_url}" f""" <span><a class="redlink" href="{moduleimpl_status_url}"
title="Il y a des notes en attente"><span class="evals_attente">en attente</span></a></span>""" title="Il y a des notes en attente"><span class="evals_attente">{
etat["nb_evals_attente"]
} en attente</span></a></span>"""
) )
if not mod_is_conforme: if not mod_is_conforme:
H.append( H.append(