Bulletins XML (ancienne structure) avec résultats BUT
This commit is contained in:
parent
915d4059a7
commit
aa78346a06
@ -33,6 +33,7 @@ class ResultatsSemestreBUT:
|
||||
"etud_moy_ue",
|
||||
"modimpls_evals_poids",
|
||||
"modimpls_evals_notes",
|
||||
"etud_moy_gen",
|
||||
)
|
||||
|
||||
def __init__(self, formsemestre):
|
||||
|
326
app/but/bulletin_but_xml_compat.py
Normal file
326
app/but/bulletin_but_xml_compat.py
Normal file
@ -0,0 +1,326 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gestion scolarite IUT
|
||||
#
|
||||
# Copyright (c) 1999 - 2021 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
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
"""Génération du bulletin en format XML / compatibilité ScoDoc 7
|
||||
|
||||
=> exporte quelques résultats BUT dans le format des anciens bulletins XML ScoDoc 7
|
||||
afin d'avoir un affichage acceptable sur les ENT anciens.
|
||||
|
||||
Les plate-formes modernes utilisent uniquement la version JSON (but/bulletin_but.py)
|
||||
"""
|
||||
|
||||
|
||||
import datetime
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from app import log
|
||||
from app.but import bulletin_but
|
||||
from app.models import FormSemestre, Identite
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc import sco_abs
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.scodoc import sco_edit_ue
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_photos
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_xml
|
||||
|
||||
|
||||
def bulletin_but_xml_compat(
|
||||
formsemestre_id,
|
||||
etudid,
|
||||
doc=None, # XML document
|
||||
force_publishing=False,
|
||||
xml_nodate=False,
|
||||
xml_with_decisions=False, # inclue les decisions même si non publiées
|
||||
version="long",
|
||||
) -> str:
|
||||
"""Bulletin XML au format ScoDoc 7, avec informations "BUT" """
|
||||
from app.scodoc import sco_bulletins
|
||||
|
||||
log(
|
||||
"bulletin_but_xml_compat( formsemestre_id=%s, etudid=%s )"
|
||||
% (formsemestre_id, etudid)
|
||||
)
|
||||
sem = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
etud = Identite.query.get_or_404(etudid)
|
||||
results = bulletin_but.ResultatsSemestreBUT(sem)
|
||||
nb_inscrits = len(results.etuds)
|
||||
if sem.bul_hide_xml or force_publishing:
|
||||
published = "1"
|
||||
else:
|
||||
published = "0"
|
||||
if xml_nodate:
|
||||
docdate = ""
|
||||
else:
|
||||
docdate = datetime.datetime.now().isoformat()
|
||||
el = {
|
||||
"etudid": str(etudid),
|
||||
"formsemestre_id": str(formsemestre_id),
|
||||
"date": docdate,
|
||||
"publie": published,
|
||||
}
|
||||
if sem.etapes:
|
||||
el["etape_apo"] = sem.etapes[0].etape_apo or ""
|
||||
n = 2
|
||||
for et in sem.etapes[1:]:
|
||||
el["etape_apo" + str(n)] = et.etape_apo or ""
|
||||
n += 1
|
||||
x = Element("bulletinetud", **el)
|
||||
if doc:
|
||||
is_appending = True
|
||||
doc.append(x)
|
||||
else:
|
||||
is_appending = False
|
||||
doc = x
|
||||
# Infos sur l'etudiant
|
||||
doc.append(
|
||||
Element(
|
||||
"etudiant",
|
||||
etudid=str(etudid),
|
||||
code_nip=etud.code_nip or "",
|
||||
code_ine=etud.code_ine or "",
|
||||
nom=scu.quote_xml_attr(etud.nom),
|
||||
prenom=scu.quote_xml_attr(etud.prenom),
|
||||
civilite=scu.quote_xml_attr(etud.civilite_str()),
|
||||
sexe=scu.quote_xml_attr(etud.civilite_str()), # compat
|
||||
photo_url=scu.quote_xml_attr(sco_photos.get_etud_photo_url(etud.id)),
|
||||
email=scu.quote_xml_attr(etud.get_first_email() or ""),
|
||||
emailperso=scu.quote_xml_attr(etud.get_first_email("emailperso") or ""),
|
||||
)
|
||||
)
|
||||
# Disponible pour publication ?
|
||||
if not published:
|
||||
return doc # stop !
|
||||
# Moyenne générale:
|
||||
doc.append(
|
||||
Element(
|
||||
"note",
|
||||
value=scu.fmt_note(results.etud_moy_gen[etud.id]),
|
||||
min=scu.fmt_note(results.etud_moy_gen.min()),
|
||||
max=scu.fmt_note(results.etud_moy_gen.max()),
|
||||
moy=scu.fmt_note(results.etud_moy_gen.mean()), # moyenne des moy. gen.
|
||||
)
|
||||
)
|
||||
rang = 0 # XXX TODO rang de l'étduiant selon la moy gen indicative
|
||||
bonus = 0 # XXX TODO valeur du bonus sport
|
||||
doc.append(Element("rang", value=str(rang), ninscrits=str(nb_inscrits)))
|
||||
# XXX TODO: ajouter "rang_group" : rangs dans les partitions
|
||||
doc.append(Element("note_max", value="20")) # notes toujours sur 20
|
||||
doc.append(Element("bonus_sport_culture", value=str(bonus)))
|
||||
# Liste les UE / modules /evals
|
||||
for ue in results.ues:
|
||||
rang_ue = 0 # XXX TODO rang de l'étudiant dans cette UE
|
||||
nb_inscrits_ue = (
|
||||
nb_inscrits # approx: compliqué de définir le "nb d'inscrit à une UE"
|
||||
)
|
||||
x_ue = Element(
|
||||
"ue",
|
||||
id=str(ue.id),
|
||||
numero=scu.quote_xml_attr(ue.numero),
|
||||
acronyme=scu.quote_xml_attr(ue.acronyme or ""),
|
||||
titre=scu.quote_xml_attr(ue.titre or ""),
|
||||
code_apogee=scu.quote_xml_attr(ue.code_apogee or ""),
|
||||
)
|
||||
doc.append(x_ue)
|
||||
if ue.type != sco_codes_parcours.UE_SPORT:
|
||||
v = results.etud_moy_ue[ue.id][etud.id]
|
||||
else:
|
||||
v = 0 # XXX TODO valeur bonus sport pour cet étudiant
|
||||
x_ue.append(
|
||||
Element(
|
||||
"note",
|
||||
value=scu.fmt_note(v),
|
||||
min=scu.fmt_note(results.etud_moy_ue[ue.id].min()),
|
||||
max=scu.fmt_note(results.etud_moy_ue[ue.id].max()),
|
||||
)
|
||||
)
|
||||
x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0)))
|
||||
x_ue.append(Element("rang", value=str(rang_ue)))
|
||||
x_ue.append(Element("effectif", value=str(nb_inscrits_ue)))
|
||||
# Liste les modules rattachés à cette UE
|
||||
for modimpl in results.modimpls:
|
||||
# Liste ici uniquement les modules rattachés à cette UE
|
||||
if modimpl.module.ue.id == ue.id:
|
||||
mod_moy = scu.fmt_note(results.etud_moy_ue[ue.id][etud.id])
|
||||
coef = results.modimpl_coefs_df[modimpl.id][ue.id]
|
||||
x_mod = Element(
|
||||
"module",
|
||||
id=str(modimpl.id),
|
||||
code=str(modimpl.module.code or ""),
|
||||
coefficient=str(coef),
|
||||
numero=str(modimpl.module.numero or 0),
|
||||
titre=scu.quote_xml_attr(modimpl.module.titre or ""),
|
||||
abbrev=scu.quote_xml_attr(modimpl.module.abbrev or ""),
|
||||
code_apogee=scu.quote_xml_attr(modimpl.module.code_apogee or ""),
|
||||
)
|
||||
x_ue.append(x_mod)
|
||||
x_mod.append(
|
||||
Element(
|
||||
"note",
|
||||
value=mod_moy,
|
||||
min=scu.fmt_note(results.etud_moy_ue[ue.id].min()),
|
||||
max=scu.fmt_note(results.etud_moy_ue[ue.id].max()),
|
||||
moy=scu.fmt_note(results.etud_moy_ue[ue.id].mean()),
|
||||
)
|
||||
)
|
||||
# XXX TODO rangs et effectifs
|
||||
# --- notes de chaque eval:
|
||||
if version != "short":
|
||||
for e in modimpl.evaluations:
|
||||
if e.visibulletin or version == "long":
|
||||
x_eval = Element(
|
||||
"evaluation",
|
||||
jour=e.jour.isoformat() if e.jour else "",
|
||||
heure_debut=e.heure_debut.isoformat()
|
||||
if e.heure_debut
|
||||
else "",
|
||||
heure_fin=e.heure_fin.isoformat()
|
||||
if e.heure_debut
|
||||
else "",
|
||||
coefficient=str(e.coefficient),
|
||||
# pas les poids en XML compat
|
||||
evaluation_type=str(e.evaluation_type),
|
||||
description=scu.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_eval.append(
|
||||
Element(
|
||||
"note",
|
||||
value=scu.fmt_note(
|
||||
results.modimpls_evals_notes[e.moduleimpl_id][
|
||||
e.id
|
||||
][etud.id]
|
||||
),
|
||||
)
|
||||
)
|
||||
# XXX TODO: Evaluations incomplètes ou futures: XXX
|
||||
# XXX TODO UE capitalisee (listee seulement si meilleure que l'UE courante)
|
||||
|
||||
# --- Absences
|
||||
if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
|
||||
nbabs, nbabsjust = sem.get_abs_count(etud.id)
|
||||
doc.append(Element("absences", nbabs=str(nbabs), nbabsjust=str(nbabsjust)))
|
||||
|
||||
# -------- LA SUITE EST COPIEE SANS MODIF DE sco_bulletins_xml.py ---------
|
||||
# TODO : refactoring
|
||||
|
||||
# --- Decision Jury
|
||||
if (
|
||||
sco_preferences.get_preference("bul_show_decision", formsemestre_id)
|
||||
or xml_with_decisions
|
||||
):
|
||||
infos, dpv = sco_bulletins.etud_descr_situation_semestre(
|
||||
etudid,
|
||||
formsemestre_id,
|
||||
format="xml",
|
||||
show_uevalid=sco_preferences.get_preference(
|
||||
"bul_show_uevalid", formsemestre_id
|
||||
),
|
||||
)
|
||||
x_situation = Element("situation")
|
||||
x_situation.text = scu.quote_xml_attr(infos["situation"])
|
||||
doc.append(x_situation)
|
||||
if dpv:
|
||||
decision = dpv["decisions"][0]
|
||||
etat = decision["etat"]
|
||||
if decision["decision_sem"]:
|
||||
code = decision["decision_sem"]["code"] or ""
|
||||
else:
|
||||
code = ""
|
||||
if (
|
||||
decision["decision_sem"]
|
||||
and "compense_formsemestre_id" in decision["decision_sem"]
|
||||
):
|
||||
doc.append(
|
||||
Element(
|
||||
"decision",
|
||||
code=code,
|
||||
etat=str(etat),
|
||||
compense_formsemestre_id=str(
|
||||
decision["decision_sem"]["compense_formsemestre_id"] or ""
|
||||
),
|
||||
)
|
||||
)
|
||||
else:
|
||||
doc.append(Element("decision", code=code, etat=str(etat)))
|
||||
|
||||
if decision[
|
||||
"decisions_ue"
|
||||
]: # and sco_preferences.get_preference( 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee)
|
||||
for ue_id in decision["decisions_ue"].keys():
|
||||
ue = sco_edit_ue.ue_list({"ue_id": ue_id})[0]
|
||||
doc.append(
|
||||
Element(
|
||||
"decision_ue",
|
||||
ue_id=str(ue["ue_id"]),
|
||||
numero=scu.quote_xml_attr(ue["numero"]),
|
||||
acronyme=scu.quote_xml_attr(ue["acronyme"]),
|
||||
titre=scu.quote_xml_attr(ue["titre"]),
|
||||
code=decision["decisions_ue"][ue_id]["code"],
|
||||
)
|
||||
)
|
||||
|
||||
for aut in decision["autorisations"]:
|
||||
doc.append(
|
||||
Element(
|
||||
"autorisation_inscription", semestre_id=str(aut["semestre_id"])
|
||||
)
|
||||
)
|
||||
else:
|
||||
doc.append(Element("decision", code="", etat="DEM"))
|
||||
# --- Appreciations
|
||||
cnx = ndb.GetDBConnexion()
|
||||
apprecs = sco_etud.appreciations_list(
|
||||
cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id}
|
||||
)
|
||||
for appr in apprecs:
|
||||
x_appr = Element(
|
||||
"appreciation",
|
||||
date=ndb.DateDMYtoISO(appr["date"]),
|
||||
)
|
||||
x_appr.text = scu.quote_xml_attr(appr["comment"])
|
||||
doc.append(x_appr)
|
||||
|
||||
if is_appending:
|
||||
return None
|
||||
else:
|
||||
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(scu.SCO_ENCODING)
|
||||
|
||||
|
||||
"""
|
||||
formsemestre_id=718
|
||||
etudid=12496
|
||||
from app.but.bulletin_but import *
|
||||
mapp.set_sco_dept("RT")
|
||||
sem = FormSemestre.query.get(formsemestre_id)
|
||||
r = ResultatsSemestreBUT(sem)
|
||||
"""
|
@ -66,6 +66,10 @@ class Identite(db.Model):
|
||||
else:
|
||||
return self.nom
|
||||
|
||||
def get_first_email(self, field="email") -> str:
|
||||
"le mail associé à la première adrese de l'étudiant, ou None"
|
||||
return self.adresses[0].email or None if self.adresses.count() > 0 else None
|
||||
|
||||
def to_dict_bul(self):
|
||||
"""Infos exportées dans les bulletins"""
|
||||
return {
|
||||
@ -75,12 +79,8 @@ class Identite(db.Model):
|
||||
"date_naissance": self.date_naissance.isoformat()
|
||||
if self.date_naissance
|
||||
else None,
|
||||
"email": self.adresses[0].email or None
|
||||
if self.adresses.count() > 0
|
||||
else None,
|
||||
"emailperso": self.adresses[0].emailperso or None
|
||||
if self.adresses.count() > 0
|
||||
else None,
|
||||
"email": self.get_first_email(),
|
||||
"emailperso": self.get_first_email("emailperso"),
|
||||
"etudid": self.id,
|
||||
"nom": self.nom_disp(),
|
||||
"photo_url": sco_photos.get_etud_photo_url(self.id),
|
||||
|
@ -229,6 +229,17 @@ class FormSemestre(db.Model):
|
||||
return self.titre
|
||||
return f"{self.titre} {self.formation.get_parcours().SESSION_NAME} {self.semestre_id}"
|
||||
|
||||
def get_abs_count(self, etudid):
|
||||
"""Les comptes d'absences de cet étudiant dans ce semestre:
|
||||
tuple (nb abs non justifiées, nb abs justifiées)
|
||||
Utilise un cache.
|
||||
"""
|
||||
from app.scodoc import sco_abs
|
||||
|
||||
return sco_abs.get_abs_count_in_interval(
|
||||
etudid, self.date_debut.isoformat(), self.date_fin.isoformat()
|
||||
)
|
||||
|
||||
|
||||
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
|
||||
notes_formsemestre_responsables = db.Table(
|
||||
|
@ -82,3 +82,18 @@ class UniteEns(db.Model):
|
||||
self.semestre_idx = module.semestre_id
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
||||
|
||||
def get_ressources(self):
|
||||
"Liste des modules ressources rattachés à cette UE"
|
||||
return self.modules.filter_by(module_type=scu.ModuleType.RESSOURCE).all()
|
||||
|
||||
def get_saes(self):
|
||||
"Liste des modules SAE rattachés à cette UE"
|
||||
return self.modules.filter_by(module_type=scu.ModuleType.SAE).all()
|
||||
|
||||
def get_modules_not_apc(self):
|
||||
"Listes des modules non SAE et non ressource (standards, mais aussi bonus...)"
|
||||
return self.modules.filter(
|
||||
(Module.module_type != scu.ModuleType.SAE),
|
||||
(Module.module_type != scu.ModuleType.RESSOURCE),
|
||||
).all()
|
||||
|
@ -47,6 +47,8 @@ from xml.etree.ElementTree import Element
|
||||
import app.scodoc.sco_utils as scu
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app import log
|
||||
from app.but.bulletin_but_xml_compat import bulletin_but_xml_compat
|
||||
from app.models.formsemestre import FormSemestre
|
||||
from app.scodoc import sco_abs
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.scodoc import sco_cache
|
||||
@ -78,6 +80,18 @@ def make_xml_formsemestre_bulletinetud(
|
||||
log("xml_bulletin( formsemestre_id=%s, etudid=%s )" % (formsemestre_id, etudid))
|
||||
|
||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
if formsemestre.formation.is_apc:
|
||||
return bulletin_but_xml_compat(
|
||||
formsemestre_id,
|
||||
etudid,
|
||||
doc=doc,
|
||||
force_publishing=force_publishing,
|
||||
xml_nodate=xml_nodate,
|
||||
xml_with_decisions=xml_with_decisions, # inclue les decisions même si non publiées
|
||||
version=version,
|
||||
)
|
||||
|
||||
if (not sem["bul_hide_xml"]) or force_publishing:
|
||||
published = "1"
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user