WIP: Bulletins BUT courts pdf

This commit is contained in:
Emmanuel Viennet 2023-08-30 15:59:11 +02:00
parent 740235ef01
commit f14b6a4f2b
3 changed files with 148 additions and 14 deletions

View File

@ -31,7 +31,7 @@ from flask import render_template, url_for
from flask import g, request from flask import g, request
from app.but.bulletin_but import BulletinBUT from app.but.bulletin_but import BulletinBUT
from app.but import cursus_but, validations_view from app.but import bulletin_but_court_pdf, cursus_but, validations_view
from app.decorators import ( from app.decorators import (
scodoc, scodoc,
permission_required, permission_required,
@ -40,14 +40,18 @@ from app.models import FormSemestre, FormSemestreInscription, Identite
from app.scodoc.sco_exceptions import ScoNoReferentielCompetences from app.scodoc.sco_exceptions import ScoNoReferentielCompetences
from app.scodoc.sco_logos import find_logo from app.scodoc.sco_logos import find_logo
from app.scodoc.sco_permissions import Permission 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 notes_bp as bp
from app.views import ScoData from app.views import ScoData
@bp.route("/bulletin_but/<int:formsemestre_id>/<int:etudid>") @bp.route("/bulletin_but/<int:formsemestre_id>/<int:etudid>")
@bp.route(
"/bulletin_but/<int:formsemestre_id>/<int:etudid>/pdf", defaults={"fmt": "pdf"}
)
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
def bulletin_but(formsemestre_id: int, etudid: int = None): def bulletin_but(formsemestre_id: int, etudid: int = None, fmt="html"):
"""Page HTML affichant le bulletin BUT simplifié""" """Page HTML affichant le bulletin BUT simplifié"""
etud: Identite = Identite.query.get_or_404(etudid) etud: Identite = Identite.query.get_or_404(etudid)
formsemestre: FormSemestre = ( formsemestre: FormSemestre = (
@ -70,19 +74,27 @@ def bulletin_but(formsemestre_id: int, etudid: int = None):
logo = find_logo(logoname="header", dept_id=g.scodoc_dept_id) logo = find_logo(logoname="header", dept_id=g.scodoc_dept_id)
args = {
"bul": bul,
"cursus": cursus,
"decision_ues": decision_ues,
"ects_total": ects_total,
"etud": etud,
"formsemestre": formsemestre,
"logo": logo,
"title": f"Bul. {etud.nom_disp()} BUT (court)",
"ue_validation_by_niveau": ue_validation_by_niveau,
}
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)
return render_template( return render_template(
"but/bulletin_court_page.j2", "but/bulletin_court_page.j2",
bul=bul,
bulletins_sem=bulletins_sem,
cursus=cursus,
datetime=datetime, datetime=datetime,
decision_ues=decision_ues,
ects_total=ects_total,
etud=etud,
formsemestre=formsemestre,
logo=logo,
sco=ScoData(formsemestre=formsemestre, etud=etud), sco=ScoData(formsemestre=formsemestre, etud=etud),
time=time, time=time,
title=f"Bul. {etud.nom_disp()} BUT (court)", **args,
ue_validation_by_niveau=ue_validation_by_niveau,
) )

View File

@ -0,0 +1,122 @@
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""Génération bulletin BUT PDF synthétique en une page
On génère du PDF avec reportLab en utilisant les classes
ScoDoc BulletinGenerator et GenTable.
"""
from flask_login import current_user
from reportlab.lib.colors import blue
from reportlab.lib.units import cm, mm
from reportlab.platypus import Paragraph, Spacer
from app.but import cursus_but
from app.models import FormSemestre, Identite, ScolarFormSemestreValidation
from app.scodoc.sco_bulletins_standard import BulletinGeneratorStandard
from app.scodoc.sco_logos import Logo
from app.scodoc import gen_tables, sco_pdf, sco_preferences
from app.scodoc.sco_pdf import PDFLOCK
def make_bulletin_but_court_pdf(
bul: dict = None,
cursus: cursus_but.EtudCursusBUT = None,
decision_ues: dict = None,
ects_total: float = 0.0,
etud: Identite = None,
formsemestre: FormSemestre = None,
logo: Logo = None,
title: str = "",
ue_validation_by_niveau: dict[tuple[int, str], ScolarFormSemestreValidation] = None,
) -> bytes:
# A priori ce verrou n'est plus nécessaire avec Flask (multi-process)
# mais...
try:
PDFLOCK.acquire()
bul_generator = BulletinGeneratorBUTCourt(**locals())
bul_pdf = bul_generator.generate(format="pdf")
finally:
PDFLOCK.release()
return bul_pdf
class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
"""Ce générateur de bulletin BUT court est assez différent des autres bulletins.
Ne génére que du PDF.
Il reprend la mise en page et certains éléments (pied de page, signature).
"""
# spécialisation du BulletinGeneratorStandard, ne pas présenter à l'utilisateur:
list_in_menu = False
scale_table_in_page = True # pas de mise à l'échelle pleine page auto
multi_pages = False # une page par bulletin
small_fontsize = "8"
def __init__(
self,
bul: dict = None,
cursus: cursus_but.EtudCursusBUT = None,
decision_ues: dict = None,
ects_total: float = 0.0,
etud: Identite = None,
formsemestre: FormSemestre = None,
logo: Logo = None,
title: str = "",
ue_validation_by_niveau: dict[
tuple[int, str], ScolarFormSemestreValidation
] = None,
):
# données pour anciens codes bulletins... à moderniser
infos = {
"etud": etud.to_dict_bul(),
"filigranne": None,
"formsemestre_id": formsemestre.id,
"nbabs": 0,
"nbabsjust": 0,
}
super().__init__(infos, authuser=current_user)
self.bul = bul
self.cursus = cursus
self.decision_ues = decision_ues
self.ects_total = ects_total
self.etud = etud
self.formsemestre = formsemestre
self.logo = logo
self.title = title
self.ue_validation_by_niveau = ue_validation_by_niveau
def bul_table(self, fmt=None):
"""Génère la table centrale du bulletin de notes
Renvoie: une liste d'objets PLATYPUS (eg instance de Table).
L'argument fmt est ici ignoré (toujours en PDF)
"""
ue_table = self.build_ue_table()
return ue_table.gen(format="pdf")
def build_ue_table(self) -> gen_tables.GenTable:
"""Table avec les résultats d'UE du semestre courant"""
columns_ids = ("titre", "UE1", "UE2")
rows = [
{"titre": "ligne 1", "UE1": "12.", "UE2": "13"},
{"titre": "ligne 2", "UE1": "14.", "UE2": "15"},
]
pdf_style = [
("VALIGN", (0, 0), (-1, -1), "TOP"),
("BOX", (0, 0), (-1, -1), 0.4, blue), # ajoute cadre extérieur bleu
]
col_widths = {"titre": 3 * cm, "UE1": 1 * cm, "UE2": 1 * cm}
return gen_tables.GenTable(
rows=rows,
columns_ids=columns_ids,
pdf_table_style=pdf_style,
pdf_col_widths=[col_widths[k] for k in columns_ids],
preferences=sco_preferences.SemPreferences(self.formsemestre.id),
)

View File

@ -887,10 +887,10 @@ def bul_filename_old(sem: dict, etud: dict, format):
return filename return filename
def bul_filename(formsemestre, etud): def bul_filename(formsemestre, etud, prefix="bul"):
"""Build a filename for this bulletin (without suffix)""" """Build a filename for this bulletin (without suffix)"""
dt = time.strftime("%Y-%m-%d") dt = time.strftime("%Y-%m-%d")
filename = f"bul-{formsemestre.titre_num()}-{dt}-{etud.nom}" filename = f"{prefix}-{formsemestre.titre_num()}-{dt}-{etud.nom}"
filename = make_filename(filename) filename = make_filename(filename)
return filename return filename