ScoDoc/app/but/bulletin_but_court.py

158 lines
5.5 KiB
Python

##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""Génération bulletin BUT HTML synthétique en une page
On génère du HTML à partir d'un template Jinja.
## Données
Ces données sont des objets passés au template.
- `etud: Identite` : l'étudiant
- `formsemestre: FormSemestre` : le formsemestre d'où est émis ce bulletin
- `bulletins_sem: BulletinBUT` les données bulletins pour tous les étudiants
- `bul: dict` : le bulletin (dict, même structure que le json publié)
- `cursus: EtudCursusBUT`: infos sur le cursus BUT (niveaux validés etc)
- `decision_ues: dict`: `{ acronyme_ue : { 'code' : 'ADM' }}` accès aux décisions
de jury d'UE
- `ects_total` : nombre d'ECTS validées dans ce cursus
- `ue_validation_by_niveau : dict` : les validations d'UE de chaque niveau du cursus
"""
import datetime
import time
from flask import render_template
from flask import g
from app.but.bulletin_but import BulletinBUT
from app.but import bulletin_but_court_pdf, cursus_but, validations_view
from app.decorators import (
scodoc,
permission_required,
)
from app.models import FormSemestre, FormSemestreInscription, Identite
from app.scodoc.codes_cursus import UE_STANDARD
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
from app.scodoc.sco_logos import find_logo
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_pv_lettres_inviduelles import add_dut120_infos
import app.scodoc.sco_utils as scu
from app.views import notes_bp as bp
from app.views import ScoData
@bp.route(
"/bulletin_but/<int:formsemestre_id>/<int:etudid>", endpoint="bulletin_but_html"
)
@bp.route(
"/bulletin_but/<int:formsemestre_id>/<int:etudid>/pdf",
defaults={"fmt": "pdf"},
endpoint="bulletin_but_pdf",
)
@scodoc
@permission_required(Permission.ScoView)
def bulletin_but(formsemestre_id: int, etudid: int = None, fmt="html"):
"""Page HTML affichant le bulletin BUT simplifié"""
etud: Identite = Identite.query.get_or_404(etudid)
formsemestre: FormSemestre = (
FormSemestre.query.filter_by(id=formsemestre_id)
.join(FormSemestreInscription)
.filter_by(etudid=etudid)
.first_or_404()
)
if not formsemestre.formation.is_apc():
raise ScoValueError("formation non BUT")
args = _build_bulletin_but_infos(etud, formsemestre, fmt=fmt)
if fmt == "pdf":
filename = scu.bul_filename(formsemestre, etud, prefix="bul-but")
bul_pdf = bulletin_but_court_pdf.make_bulletin_but_court_pdf(args)
return scu.sendPDFFile(bul_pdf, filename + ".pdf")
return render_template(
"but/bulletin_court_page.j2",
datetime=datetime,
sco=ScoData(formsemestre=formsemestre, etud=etud),
time=time,
version="butcourt",
**args,
)
def bulletin_but_court_pdf_frag(
etud: Identite, formsemestre: FormSemestre, stand_alone=False
) -> bytes:
"""Le code PDF d'un bulletin BUT court, à intégrer dans un document
(pour les classeurs de tous les bulletins)
"""
args = _build_bulletin_but_infos(etud, formsemestre)
return bulletin_but_court_pdf.make_bulletin_but_court_pdf(
args, stand_alone=stand_alone
)
def _build_bulletin_but_infos(
etud: Identite, formsemestre: FormSemestre, fmt="pdf"
) -> dict:
"""Réuni toutes les information pour le contenu d'un bulletin BUT court.
On indique le format ("html" ou "pdf") car il y a moins d'infos en HTML.
"""
bulletins_sem = BulletinBUT(formsemestre)
if fmt == "pdf":
bul: dict = bulletins_sem.bulletin_etud_complet(etud)
filigranne = bul["filigranne"]
else: # la même chose avec un peu moins d'infos
bul: dict = bulletins_sem.bulletin_etud(etud, force_publishing=True)
filigranne = ""
decision_ues = (
{x["acronyme"]: x for x in bul["semestre"]["decision_ue"]}
if "semestre" in bul and "decision_ue" in bul["semestre"]
else {}
)
if "ues" not in bul:
raise ScoValueError("Aucune UE à afficher")
cursus = cursus_but.EtudCursusBUT(etud, formsemestre.formation)
refcomp = formsemestre.formation.referentiel_competence
if refcomp is None:
raise ScoNoReferentielCompetences(formation=formsemestre.formation)
warn_html = cursus_but.formsemestre_warning_apc_setup(
formsemestre, bulletins_sem.res
)
if warn_html:
raise ScoValueError(
"<b>Formation mal configurée pour le BUT</b>" + warn_html, safe=True
)
ue_validation_by_niveau = validations_view.get_ue_validation_by_niveau(
refcomp, etud
)
ects_total = sum((v.ects() for v in ue_validation_by_niveau.values()))
logo = find_logo(logoname="header", dept_id=g.scodoc_dept_id)
ue_acronyms = bul["ues"].keys()
args = {
"bul": bul,
"cursus": cursus,
"decision_ues": decision_ues,
"ects_total": ects_total,
"etud": etud,
"filigranne": filigranne,
"formsemestre": formsemestre,
"logo": logo,
"prefs": bulletins_sem.prefs,
"title": f"Bul. {etud.nom_disp()} BUT (court)",
"ue_validation_by_niveau": ue_validation_by_niveau,
"ues_acronyms": [
ue.acronyme
for ue in bulletins_sem.res.ues
if ue.type == UE_STANDARD and ue.acronyme in ue_acronyms
],
}
add_dut120_infos(formsemestre, etud.id, args)
return args