forked from ScoDoc/ScoDoc
353 lines
12 KiB
Python
353 lines
12 KiB
Python
# -*- mode: python -*-
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
|
#
|
|
# Gestion scolarite IUT
|
|
#
|
|
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
|
#
|
|
##############################################################################
|
|
|
|
"""Export d'une table avec les résultats de tous les étudiants"""
|
|
|
|
from flask import url_for, g, request
|
|
|
|
from app.comp import res_sem
|
|
from app.comp.res_compat import NotesTableCompat
|
|
from app.models import FormSemestre
|
|
import app.scodoc.notesdb as ndb
|
|
import app.scodoc.sco_utils as scu
|
|
from app import log
|
|
from app.models import Formation
|
|
from app.scodoc import html_sco_header
|
|
from app.scodoc import sco_bac
|
|
from app.scodoc import codes_cursus
|
|
from app.scodoc import sco_preferences
|
|
from app.scodoc import sco_pv_dict
|
|
from app.scodoc import sco_etud
|
|
import sco_version
|
|
from app.scodoc.gen_tables import GenTable
|
|
from app.scodoc.codes_cursus import NO_SEMESTRE_ID
|
|
|
|
|
|
def _build_results_table(start_date=None, end_date=None, types_parcours=[]):
|
|
"""Construit une table avec les résultats de jury de TOUS les étudiants
|
|
de TOUS les semestres ScoDoc de ce département entre les dates indiquées
|
|
(c'est à dire commençant APRES ou à start_date et terminant avant ou à end_date)
|
|
Les dates sont des chaines iso.
|
|
"""
|
|
formsemestre_ids = get_set_formsemestre_id_dates(start_date, end_date)
|
|
# Décisions de jury de tous les semestres:
|
|
dpv_by_sem = {}
|
|
for formsemestre_id in formsemestre_ids:
|
|
dpv_by_sem[formsemestre_id] = sco_pv_dict.dict_pvjury(
|
|
formsemestre_id, with_parcours_decisions=True
|
|
)
|
|
|
|
semlist = [dpv["formsemestre"] for dpv in dpv_by_sem.values() if dpv]
|
|
semlist_parcours = []
|
|
for sem in semlist:
|
|
sem["formation"] = Formation.query.get_or_404(sem["formation_id"]).to_dict()
|
|
sem["parcours"] = codes_cursus.get_cursus_from_code(
|
|
sem["formation"]["type_parcours"]
|
|
)
|
|
if sem["parcours"].TYPE_CURSUS in types_parcours:
|
|
semlist_parcours.append(sem)
|
|
formsemestre_ids_parcours = [sem["formsemestre_id"] for sem in semlist_parcours]
|
|
|
|
# Ensemble des étudiants
|
|
etuds_infos = {} # etudid : { formsemestre_id d'inscription le plus recent dans les dates considérées, etud }
|
|
for formsemestre_id in formsemestre_ids_parcours:
|
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
|
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
|
etudids = nt.get_etudids()
|
|
for etudid in etudids:
|
|
if etudid not in etuds_infos: # pas encore traité ?
|
|
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
|
for sem in etud["sems"]: # le plus récent d'abord
|
|
if sem["formsemestre_id"] in formsemestre_ids_parcours:
|
|
etuds_infos[etudid] = {
|
|
"recent_formsemestre_id": sem["formsemestre_id"],
|
|
"etud": etud,
|
|
}
|
|
break
|
|
# sanity check
|
|
assert etudid in etuds_infos
|
|
# Construit la table (semblable à pvjury_table)
|
|
rows, titles, columns_ids = _build_results_list(dpv_by_sem, etuds_infos)
|
|
tab = GenTable(
|
|
rows=rows,
|
|
titles=titles,
|
|
columns_ids=columns_ids,
|
|
filename=scu.make_filename("scodoc-results-%s-%s" % (start_date, end_date)),
|
|
caption="Résultats ScoDoc de %s à %s" % (start_date, end_date),
|
|
origin="Généré par %s le " % sco_version.SCONAME
|
|
+ scu.timedate_human_repr()
|
|
+ "",
|
|
html_class="table_leftalign",
|
|
html_sortable=True,
|
|
preferences=sco_preferences.SemPreferences(),
|
|
table_id="export_result_table",
|
|
)
|
|
return tab, semlist
|
|
|
|
|
|
def _build_results_list(dpv_by_sem, etuds_infos):
|
|
"""Construit la table (semblable à pvjury_table)
|
|
Returns:
|
|
rows, titles, columns_ids
|
|
"""
|
|
titles = {
|
|
"anneescolaire": "Année",
|
|
"periode": "Période",
|
|
"sid": "Semestre",
|
|
"etudid": "etudid",
|
|
"code_nip": "NIP",
|
|
"nom": "Nom",
|
|
"prenom": "Prénom",
|
|
"civilite_str": "Civ.",
|
|
"nom_usuel": "Nom usuel",
|
|
"bac": "Bac",
|
|
"parcours": "Parcours",
|
|
"devenir": "Devenir",
|
|
}
|
|
columns_ids = [
|
|
"anneescolaire",
|
|
"periode",
|
|
"sid",
|
|
"code_nip",
|
|
"civilite_str",
|
|
"nom",
|
|
# 'nom_usuel', # inutile ?
|
|
"prenom",
|
|
"bac",
|
|
"parcours",
|
|
]
|
|
|
|
# Recherche la liste des indices de semestres à considérer
|
|
all_idx = set()
|
|
for etudid in etuds_infos:
|
|
# la décision de jury à considérer pour cet étudiant:
|
|
e = dpv_by_sem[etuds_infos[etudid]["recent_formsemestre_id"]]["decisions_dict"][
|
|
etudid
|
|
]
|
|
all_idx |= set(e["parcours_decisions"].keys())
|
|
sem_ids = sorted(all_idx)
|
|
# ajoute les titres des colonnes résultats de semestres
|
|
for i in sem_ids:
|
|
if i != NO_SEMESTRE_ID:
|
|
titles[i] = "S%d" % i
|
|
else:
|
|
titles[i] = "S" # pas très parlant ?
|
|
columns_ids += [i]
|
|
columns_ids += ["devenir"]
|
|
# Construit la liste:
|
|
rows = []
|
|
for etudid in etuds_infos:
|
|
etud = etuds_infos[etudid]["etud"]
|
|
bac = sco_bac.Baccalaureat(etud["bac"], etud["specialite"])
|
|
dpv = dpv_by_sem[etuds_infos[etudid]["recent_formsemestre_id"]]
|
|
dec = dpv["decisions_dict"][etudid]
|
|
l = {
|
|
"etudid": etudid,
|
|
"code_nip": etud["code_nip"],
|
|
"nom": etud["nom"],
|
|
"nom_usuel": etud["nom_usuel"],
|
|
"prenom": etud["prenom"],
|
|
"civilite_str": etud["civilite_str"],
|
|
"_nom_target": url_for(
|
|
"scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid
|
|
),
|
|
"_nom_td_attrs": f'id="{etudid}" class="etudinfo"',
|
|
"bac": bac.abbrev(),
|
|
"parcours": dec["parcours"],
|
|
}
|
|
for sem in reversed(etud["sems"]):
|
|
r = l.copy()
|
|
dpv = dpv_by_sem.get(sem["formsemestre_id"], None)
|
|
if dpv: # semestre à inclure dans ce rapport
|
|
dec = dpv["decisions_dict"].get(etudid, None)
|
|
if dec and dec["decision_sem"]:
|
|
code = dec["decision_sem"]["code"]
|
|
if dec["validation_parcours"]:
|
|
r["devenir"] = "Diplôme obtenu"
|
|
else:
|
|
r["devenir"] = dec["autorisations_descr"]
|
|
else:
|
|
code = "-"
|
|
r[sem["semestre_id"]] = code
|
|
r["periode"] = sem["periode"]
|
|
r["anneescolaire"] = scu.annee_scolaire_debut(
|
|
int(sem["annee_debut"]), sem["mois_debut_ord"]
|
|
)
|
|
r["sid"] = "{} {} {}".format(
|
|
sem["sem_id_txt"], g.scodoc_dept, sem["modalite"]
|
|
)
|
|
rows.append(r)
|
|
|
|
return rows, titles, columns_ids
|
|
|
|
|
|
def get_set_formsemestre_id_dates(start_date, end_date) -> set:
|
|
"""Ensemble des formsemestre_id entre ces dates"""
|
|
s = ndb.SimpleDictFetch(
|
|
"""SELECT id
|
|
FROM notes_formsemestre
|
|
WHERE date_debut >= %(start_date)s
|
|
AND date_fin <= %(end_date)s
|
|
AND dept_id = %(dept_id)s
|
|
""",
|
|
{"start_date": start_date, "end_date": end_date, "dept_id": g.scodoc_dept_id},
|
|
)
|
|
return {x["id"] for x in s}
|
|
|
|
|
|
def scodoc_table_results(
|
|
start_date="", end_date="", types_parcours: list = None, fmt="html"
|
|
):
|
|
"""Page affichant la table des résultats
|
|
Les dates sont en dd/mm/yyyy (datepicker javascript)
|
|
types_parcours est la liste des types de parcours à afficher
|
|
(liste de chaines, eg ['100', '210'] )
|
|
"""
|
|
log(f"scodoc_table_results: start_date={start_date!r}")
|
|
if not types_parcours:
|
|
types_parcours = []
|
|
if not isinstance(types_parcours, list):
|
|
types_parcours = [types_parcours]
|
|
if start_date:
|
|
start_date_iso = ndb.DateDMYtoISO(start_date)
|
|
if end_date:
|
|
end_date_iso = ndb.DateDMYtoISO(end_date)
|
|
types_parcours = [int(x) for x in types_parcours if x]
|
|
|
|
if start_date and end_date:
|
|
tab, semlist = _build_results_table(
|
|
start_date_iso, end_date_iso, types_parcours
|
|
)
|
|
tab.base_url = "%s?start_date=%s&end_date=%s&types_parcours=%s" % (
|
|
request.base_url,
|
|
start_date,
|
|
end_date,
|
|
"&types_parcours=".join([str(x) for x in types_parcours]),
|
|
)
|
|
if fmt != "html":
|
|
return tab.make_page(fmt=fmt, with_html_headers=False)
|
|
tab_html = tab.html()
|
|
nb_rows = tab.get_nb_rows()
|
|
else:
|
|
tab = None
|
|
nb_rows = 0
|
|
tab_html = ""
|
|
semlist = []
|
|
|
|
# affiche la liste des semestres utilisés:
|
|
info_sems = ["<ul>"]
|
|
menu_options = []
|
|
type_parcours_set = set()
|
|
for sem in sorted(semlist, key=lambda x: x["dateord"]):
|
|
if sem["parcours"].TYPE_CURSUS in types_parcours:
|
|
selected = "selected"
|
|
else:
|
|
selected = ""
|
|
if sem["parcours"].TYPE_CURSUS not in type_parcours_set:
|
|
type_parcours_set.add(sem["parcours"].TYPE_CURSUS)
|
|
menu_options.append(
|
|
'<option value="%s" %s>%s</option>'
|
|
% (sem["parcours"].TYPE_CURSUS, selected, sem["parcours"].__doc__)
|
|
)
|
|
|
|
if sem["parcours"].TYPE_CURSUS in types_parcours:
|
|
info_sems.append(
|
|
'<li><a class="stdlink" href="formsemestre_status?formsemestre_id=%(formsemestre_id)s">%(titremois)s</a></li>'
|
|
% sem
|
|
)
|
|
|
|
info_sems.append("</ul>")
|
|
|
|
H = [
|
|
html_sco_header.sco_header(
|
|
page_title="Export résultats",
|
|
javascripts=["js/export_results.js"],
|
|
),
|
|
# XXX
|
|
"""
|
|
<h2>Table des résultats de tous les semestres</h2>
|
|
<p class="warning">Développement en cours / attention !</p>
|
|
""",
|
|
_DATE_FORM.format(
|
|
start_date=start_date,
|
|
end_date=end_date,
|
|
menu_options="\n".join(menu_options),
|
|
),
|
|
"""<div>
|
|
<h4>%d étudiants dans les %d semestres de cette période</h4>
|
|
</div>
|
|
"""
|
|
% (nb_rows, len(semlist)),
|
|
tab_html,
|
|
"""<div><h4>Semestres pris en compte:</h4>
|
|
""",
|
|
"\n".join(info_sems),
|
|
"""</div>""",
|
|
html_sco_header.sco_footer(),
|
|
]
|
|
return "\n".join(H)
|
|
|
|
|
|
# Formulaire pour saisie dates et sélection parcours
|
|
_DATE_FORM = """
|
|
<form method="get">
|
|
<div><b>Choisir les dates :</b>
|
|
<div>Début: <input type="text" name="start_date" size="10" value="{start_date}" class="datepicker"/> </div>
|
|
<div>Fin: <input type="text" name="end_date" size="10" value="{end_date}" class="datepicker"/></div>
|
|
<input type="submit" name="" value=" OK " width=100/>
|
|
</div>
|
|
<div>
|
|
<b>Types de parcours :</b>
|
|
<multi-select name="types_parcours" id="parcours_sel" label="Choisir le(s) parcours...">
|
|
{menu_options}
|
|
</multi-select>
|
|
|
|
<input type="submit" name="" value=" charger " width=100/>
|
|
</form>
|
|
"""
|
|
|
|
# ------- debug
|
|
"""
|
|
# /opt/scodoc/bin/zopectl debug
|
|
from debug import *
|
|
from app.scodoc.sco_export_results import *
|
|
_ = go_dept(app, 'RT').Notes
|
|
etudid = 'EID27764'
|
|
etud = sco_etud.get_etud_info( etudid=etudid, filled=True)[0]
|
|
|
|
start_date='2015-08-15'
|
|
end_date='2017-08-31'
|
|
|
|
formsemestre_ids = get_set_formsemestre_id_dates( start_date, end_date)
|
|
dpv_by_sem = {}
|
|
for formsemestre_id in formsemestre_ids:
|
|
dpv_by_sem[formsemestre_id] = sco_pv_dict.dict_pvjury( formsemestre_id, with_parcours_decisions=True)
|
|
|
|
semlist = [ dpv['formsemestre'] for dpv in dpv_by_sem.values() ]
|
|
|
|
"""
|