comptes croisés: ajout nb RCUE et code annuel

This commit is contained in:
Emmanuel Viennet 2022-09-26 20:57:52 +02:00
parent 1c30d4d926
commit 692d7b5fe0
6 changed files with 85 additions and 34 deletions

View File

@ -296,6 +296,10 @@ class DecisionsProposeesAnnee(DecisionsProposees):
[rcue for rcue in rcues_avec_niveau if rcue.est_validable()]
)
"le nombre de comp. validables (éventuellement par compensation)"
self.nb_rcue_valides = len(
[rcue for rcue in rcues_avec_niveau if rcue.code_valide()]
)
"le nombre de niveaux validés (déc. jury prise)"
self.nb_rcues_under_8 = len(
[rcue for rcue in rcues_avec_niveau if not rcue.est_suffisant()]
)
@ -393,7 +397,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
<li>RCUEs: {html.escape(str(self.rcues_annee))}</li>
<li>nb_competences: {getattr(self, "nb_competences", "-")}</li>
<li>nb_nb_validables: {getattr(self, "nb_validables", "-")}</li>
<li>nb_validables: {getattr(self, "nb_validables", "-")}</li>
<li>codes: {self.codes}</li>
<li>explanation: {self.explanation}</li>
</ul>

View File

@ -299,7 +299,7 @@ class NotesTableCompat(ResultatsSemestre):
return sum([d.get("ects", 0.0) for d in decisions_ues.values()])
def get_etud_decision_sem(self, etudid: int) -> dict:
"""Decision du jury prise pour cet etudiant, ou None s'il n'y en pas eu.
"""Decision du jury semestre prise pour cet etudiant, ou None s'il n'y en pas eu.
{ 'code' : None|ATT|..., 'assidu' : 0|1, 'event_date' : , compense_formsemestre_id }
Si état défaillant, force le code a DEF
"""

View File

@ -196,8 +196,8 @@ class RegroupementCoherentUE:
)
def est_validable(self) -> bool:
"""Vrai si ce RCU satisfait les conditions pour être validé
Pour cela, il suffit que la moyenne des UE qui le constitue soit > 10
"""Vrai si ce RCUE satisfait les conditions pour être validé,
c'est à dire que la moyenne des UE qui le constituent soit > 10
"""
return (self.moy_rcue is not None) and (
self.moy_rcue > sco_codes.BUT_BARRE_RCUE

View File

@ -610,7 +610,7 @@ def log_unknown_etud():
log(f"unknown student: args={etud_args}")
def get_etud_info(etudid=False, code_nip=False, filled=False) -> list:
def get_etud_info(etudid=False, code_nip=False, filled=False) -> list[dict]:
"""infos sur un etudiant (API). If not found, returns empty list.
On peut spécifier etudid ou code_nip
ou bien cherche dans les arguments de la requête courante:

View File

@ -167,9 +167,9 @@ def _formsemestre_enrich(sem):
sem["semestre_id"],
) # eg "DUT Informatique semestre 2"
sem["dateord"] = ndb.DateDMYtoISO(sem["date_debut"])
sem["date_debut_iso"] = ndb.DateDMYtoISO(sem["date_debut"])
sem["date_fin_iso"] = ndb.DateDMYtoISO(sem["date_fin"])
sem["dateord"] = sem["date_debut_iso"] # pour les tris
try:
mois_debut, annee_debut = sem["date_debut"].split("/")[1:]
except:

View File

@ -39,12 +39,14 @@ from operator import itemgetter
from flask import url_for, g, request
import pydot
from app.but import jury_but
from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre, ScolarAutorisationInscription
from app.models import FormationModalite
from app.models.etudiants import Identite
import app.scodoc.sco_utils as scu
from app.models import FormationModalite
from app.scodoc import notesdb as ndb
from app.scodoc import html_sco_header
from app.scodoc import sco_codes_parcours
@ -52,6 +54,7 @@ from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_preferences
from app.scodoc import sco_pvjury
import sco_version
from app.scodoc.gen_tables import GenTable
from app import log
@ -59,17 +62,28 @@ from app.scodoc.sco_codes_parcours import code_semestre_validant
MAX_ETUD_IN_DESCR = 20
LEGENDES_CODES_BUT = {
"Nb_rcue_valides": "nb RCUE validés",
"decision_annee": "code jury annuel BUT",
}
def formsemestre_etuds_stats(sem, only_primo=False):
def formsemestre_etuds_stats(sem: dict, only_primo=False):
"""Récupère liste d'etudiants avec etat et decision."""
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
formsemestre: FormSemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
T = nt.get_table_moyennes_triees()
# Décisions de jury BUT pour les semestres pairs seulement
jury_but_mode = (
formsemestre.formation.is_apc() and formsemestre.semestre_id % 2 == 0
)
# Construit liste d'étudiants du semestre avec leur decision
etuds = []
for t in T:
etudid = t[-1]
etudiant: Identite = Identite.query.get(etudid)
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
decision = nt.get_etud_decision_sem(etudid)
if decision:
@ -87,6 +101,11 @@ def formsemestre_etuds_stats(sem, only_primo=False):
autorisations.sort()
autorisations_str = ", ".join(autorisations)
etud["devenir"] = autorisations_str
# Décisions de jury BUT (APC)
if jury_but_mode:
deca = jury_but.DecisionsProposeesAnnee(etudiant, formsemestre)
etud["nb_rcue_valides"] = deca.nb_rcue_valides
etud["decision_annee"] = deca.code_valide
# Ajout clé 'bac-specialite'
bs = []
if etud["bac"]:
@ -100,13 +119,22 @@ def formsemestre_etuds_stats(sem, only_primo=False):
return etuds
def is_primo_etud(etud, sem):
"""Determine si un (filled) etud a ete inscrit avant ce semestre.
Regarde la liste des semestres dans lesquels l'étudiant est inscrit
def is_primo_etud(etud: dict, sem: dict):
"""Determine si un (filled) etud a été inscrit avant ce semestre.
Regarde la liste des semestres dans lesquels l'étudiant est inscrit.
Si semestre pair, considère comme primo-entrants ceux qui étaient
primo dans le précédent (S_{2n-1}).
"""
now = sem["dateord"]
debut_cur = sem["date_debut_iso"]
# si semestre impair et sem. précédent contigu, recule date debut
if (
(len(etud["sems"]) > 1)
and (sem["semestre_id"] % 2 == 0)
and (etud["sems"][1]["semestre_id"] == (sem["semestre_id"] - 1))
):
debut_cur = etud["sems"][1]["date_debut_iso"]
for s in etud["sems"]: # le + recent d'abord
if s["dateord"] < now:
if s["date_debut_iso"] < debut_cur:
return False
return True
@ -176,21 +204,20 @@ def _results_by_category(
# ajout titre ligne:
for (cat, l) in zip(categories, C):
l["row_title"] = cat or "?"
l["row_title"] = cat if cat is not None else "?"
#
codes.append("sum")
codes.append("sumpercent")
# on veut { ADM : ADM, ... }, était peu elegant en python 2.3:
# titles = {}
# map( lambda x,titles=titles: titles.__setitem__(x[0],x[1]), zip(codes,codes) )
# Version moderne:
# on veut { ADM : ADM, ... }
titles = {x: x for x in codes}
# sauf pour
titles.update(LEGENDES_CODES_BUT)
titles["sum"] = "Total"
titles["sumpercent"] = "%"
titles["DEM"] = "Dém." # démissions
titles["row_title"] = category_name
titles["row_title"] = titles.get(category_name, category_name)
return GenTable(
titles=titles,
columns_ids=codes,
@ -234,14 +261,11 @@ def formsemestre_report(
#
tab.filename = scu.make_filename("stats " + sem["titreannee"])
tab.origin = (
"Généré par %s le " % sco_version.SCONAME + scu.timedate_human_repr() + ""
tab.origin = f"Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}"
tab.caption = (
f"Répartition des résultats par {category_name}, semestre {sem['titreannee']}"
)
tab.caption = "Répartition des résultats par %s, semestre %s" % (
category_name,
sem["titreannee"],
)
tab.html_caption = "Répartition des résultats par %s." % category_name
tab.html_caption = f"Répartition des résultats par {category_name}."
tab.base_url = "%s?formsemestre_id=%s" % (request.base_url, formsemestre_id)
if only_primo:
tab.base_url += "&only_primo=on"
@ -265,17 +289,32 @@ def formsemestre_report(
def formsemestre_report_counts(
formsemestre_id,
formsemestre_id: int,
format="html",
category="bac",
result="codedecision",
allkeys=False,
only_primo=False,
category: str = "bac",
result: str = None,
allkeys: bool = False,
only_primo: bool = False,
):
"""
Tableau comptage avec choix des categories
category: attribut en lignes
result: attribut en colonnes
only_primo: restreint aux primo-entrants (= non redoublants)
allkeys: pour le menu du choix de l'attribut en colonnes:
si vrai, toutes les valeurs présentes dans les données
sinon liste prédéfinie (voir ci-dessous)
"""
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
# Décisions de jury BUT pour les semestres pairs seulement
jury_but_mode = (
formsemestre.formation.is_apc() and formsemestre.semestre_id % 2 == 0
)
if result is None:
result = "statut" if formsemestre.formation.is_apc() else "codedecision"
category_name = category.capitalize()
title = "Comptages " + category_name
etuds = formsemestre_etuds_stats(sem, only_primo=only_primo)
@ -311,6 +350,8 @@ def formsemestre_report_counts(
"type_admission",
"boursier_prec",
]
if jury_but_mode:
keys += ["nb_rcue_valides", "decision_annee"]
keys.sort(key=scu.heterogeneous_sorting_key)
F = [
"""<form name="f" method="get" action="%s"><p>
@ -322,7 +363,10 @@ def formsemestre_report_counts(
selected = "selected"
else:
selected = ""
F.append('<option value="%s" %s>%s</option>' % (k, selected, k))
F.append(
'<option value="%s" %s>%s</option>'
% (k, selected, LEGENDES_CODES_BUT.get(k, k))
)
F.append("</select>")
F.append(' Lignes: <select name="category" onchange="document.f.submit()">')
for k in keys:
@ -330,7 +374,10 @@ def formsemestre_report_counts(
selected = "selected"
else:
selected = ""
F.append('<option value="%s" %s>%s</option>' % (k, selected, k))
F.append(
'<option value="%s" %s>%s</option>'
% (k, selected, LEGENDES_CODES_BUT.get(k, k))
)
F.append("</select>")
if only_primo:
checked = 'checked="1"'