1
0
forked from ScoDoc/ScoDoc
ScoDoc/app/but/jury_but_pv.py

201 lines
7.3 KiB
Python

##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""Jury BUT: table synthèse résultats semestre / PV
"""
from flask import g, request, url_for
from openpyxl.styles import Font, Border, Side, Alignment, PatternFill
from app import log
from app.but import jury_but
from app.but.cursus_but import but_ects_valides
from app.models.etudiants import Identite
from app.models.formsemestre import FormSemestre
from app.scodoc.gen_tables import GenTable
from app.scodoc import sco_excel
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu
def _descr_cursus_but(etud: Identite) -> str:
"description de la liste des semestres BUT suivis"
# prend simplement tous les semestre de type APC, ce qui sera faux si
# l'étudiant change de spécialité au sein du même département
# (ce qui ne peut normalement pas se produire)
inscriptions = sorted(
[
ins
for ins in etud.formsemestre_inscriptions
if ins.formsemestre.formation.is_apc()
],
key=lambda i: i.formsemestre.date_debut,
)
indices = [
ins.formsemestre.semestre_id if ins.formsemestre.semestre_id is not None else -1
for ins in inscriptions
]
return ", ".join(f"S{indice}" for indice in indices)
def pvjury_page_but(formsemestre_id: int, fmt="html"):
"""Page récapitulant les décisions de jury BUT
formsemestre peut être pair ou impair
"""
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
assert formsemestre.formation.is_apc()
title = "Procès-verbal de jury BUT"
if fmt == "html":
line_sep = "<br>"
else:
line_sep = "\n"
rows, titles = pvjury_table_but(formsemestre, line_sep=line_sep)
if fmt.startswith("xls"):
titles.update(
{
"etudid": "etudid",
"code_nip": "nip",
"code_ine": "ine",
"ects_but": "Total ECTS BUT",
"civilite": "Civ.",
"nom": "Nom",
"prenom": "Prénom",
}
)
# Style excel... passages à la ligne sur \n
xls_style_base = sco_excel.excel_make_style()
xls_style_base["alignment"] = Alignment(wrapText=True, vertical="top")
tab = GenTable(
base_url=f"{request.base_url}?formsemestre_id={formsemestre_id}",
caption=title,
columns_ids=titles.keys(),
html_caption=title,
html_class="pvjury_table_but table_leftalign",
html_title=f"""<div style="margin-bottom: 8px;"><span
style="font-size: 120%; font-weight: bold;">{title}</span>
<span style="padding-left: 20px;">
<a href="{url_for("notes.pvjury_page_but",
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, fmt="xlsx")}"
class="stdlink">version excel</a></span></div>
""",
html_with_td_classes=True,
origin=f"Généré par {scu.sco_version.SCONAME} le {scu.timedate_human_repr()}",
page_title=title,
pdf_title=title,
preferences=sco_preferences.SemPreferences(),
rows=rows,
table_id="formation_table_recap",
titles=titles,
xls_columns_width={
"nom": 32,
"cursus": 12,
"ues": 32,
"niveaux": 32,
"decision_but": 14,
"diplome": 17,
"devenir": 8,
"observations": 12,
},
xls_style_base=xls_style_base,
)
return tab.make_page(fmt=fmt, javascripts=["js/etud_info.js"], init_qtip=True)
def pvjury_table_but(
formsemestre: FormSemestre,
etudids: list[int] = None,
line_sep: str = "\n",
only_diplome=False,
anonymous=False,
with_paragraph_nom=False,
) -> tuple[list[dict], dict]:
"""Table avec résultats jury BUT pour PV.
Si etudids est None, prend tous les étudiants inscrits.
"""
# remplace pour le BUT la fonction sco_pv_forms.pvjury_table
annee_but = (formsemestre.semestre_id + 1) // 2
referentiel_competence_id = formsemestre.formation.referentiel_competence_id
if referentiel_competence_id is None:
raise ScoValueError(
"pas de référentiel de compétences associé à la formation de ce semestre !"
)
titles = {
"nom_pv": "Code" if anonymous else "Nom",
"cursus": "Cursus",
"ects": "ECTS",
"ues": "UE validées",
"niveaux": "Niveaux de compétences validés",
"decision_but": f"Décision BUT{annee_but}",
"diplome": "Résultat au diplôme",
"devenir": "Devenir",
"observations": "Observations",
}
rows = []
formsemestre_etudids = formsemestre.etuds_inscriptions.keys()
if etudids is None:
etudids = formsemestre_etudids
for etudid in etudids:
if not etudid in formsemestre_etudids:
continue # garde fou
etud = Identite.get_etud(etudid)
try:
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
if deca.annee_but != annee_but: # wtf ?
log(
f"pvjury_table_but: inconsistent annee_but {deca.annee_but} != {annee_but}"
)
continue
except ScoValueError:
deca = None
ects_but_valides = but_ects_valides(etud, referentiel_competence_id)
row = {
"nom_pv": (
etud.code_ine or etud.code_nip or etud.id
if anonymous # Mode anonyme: affiche INE ou sinon NIP, ou id
else etud.etat_civil_pv(
line_sep=line_sep, with_paragraph=with_paragraph_nom
)
),
"_nom_pv_order": etud.sort_key,
"_nom_pv_target_attrs": f'class="etudinfo" id="{etud.id}"',
"_nom_pv_td_attrs": f'id="{etud.id}" class="etudinfo"',
"_nom_pv_target": url_for(
"scolar.fiche_etud",
scodoc_dept=g.scodoc_dept,
etudid=etud.id,
),
"cursus": _descr_cursus_but(etud),
"ects": f"""{deca.ects_annee():g}<br><br>Tot. {ects_but_valides:g}""",
"_ects_xls": deca.ects_annee(),
"ects_but": ects_but_valides,
"ues": deca.descr_ues_validation(line_sep=line_sep) if deca else "-",
"niveaux": (
deca.descr_niveaux_validation(line_sep=line_sep) if deca else "-"
),
"decision_but": deca.code_valide if deca else "",
"devenir": (
", ".join([f"S{i}" for i in deca.get_autorisations_passage()])
if deca
else ""
),
# pour exports excel seulement:
"civilite": etud.civilite_etat_civil_str,
"nom": etud.nom,
"prenom": etud.prenom_etat_civil or etud.prenom or "",
"etudid": etud.id,
"code_nip": etud.code_nip,
"code_ine": etud.code_ine,
}
if deca.valide_diplome() or not only_diplome:
rows.append(row)
rows.sort(key=lambda x: x["_nom_pv_order"])
return rows, titles