############################################################################## # 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 import app.scodoc.sco_utils as scu from app.views import notes_bp as bp from app.views import ScoData @bp.route( "/bulletin_but//", endpoint="bulletin_but_html" ) @bp.route( "/bulletin_but///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("Formation mal configurée pour le BUT" + warn_html) 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 ], } return args