UE capitalisées sur bulletins BUT PDF + code cleaning

This commit is contained in:
Emmanuel Viennet 2023-03-18 21:56:08 +01:00
parent e482e6bd3d
commit 8d453eb42b
12 changed files with 161 additions and 104 deletions

View File

@ -286,7 +286,7 @@ def bulletin(
if pdf:
pdf_response, _ = do_formsemestre_bulletinetud(
formsemestre,
etud.id,
etud,
version=version,
format="pdf",
with_img_signatures_pdf=with_img_signatures_pdf,

View File

@ -187,6 +187,8 @@ class BulletinBUT:
)
if ue_capitalisee.formsemestre_id
else None,
"ressources": {}, # sans détail en BUT
"saes": {},
}
if self.prefs["bul_show_ects"]:
d[ue.acronyme]["ECTS"] = {
@ -473,6 +475,7 @@ class BulletinBUT:
def bulletin_etud_complet(self, etud: Identite, version="long") -> dict:
"""Bulletin dict complet avec toutes les infos pour les bulletins BUT pdf
(pas utilisé pour json/html)
Résultat compatible avec celui de sco_bulletins.formsemestre_bulletinetud_dict
"""
d = self.bulletin_etud(

View File

@ -5,6 +5,20 @@
##############################################################################
"""Génération bulletin BUT au format PDF standard
La génération du bulletin PDF suit le chemin suivant:
- vue formsemestre_bulletinetud -> sco_bulletins.formsemestre_bulletinetud
bul_dict = bulletin_but.BulletinBUT(formsemestre).bulletin_etud_complet(etud)
- sco_bulletins_generator.make_formsemestre_bulletinetud(infos)
- instance de BulletinGeneratorStandardBUT(infos)
- BulletinGeneratorStandardBUT.generate(format="pdf")
sco_bulletins_generator.BulletinGenerator.generate()
.generate_pdf()
.bul_table() (ci-dessous)
"""
from reportlab.lib.colors import blue
from reportlab.lib.units import cm, mm
@ -65,7 +79,9 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
return objects
def but_table_synthese_ues(self, title_bg=(182, 235, 255)):
def but_table_synthese_ues(
self, title_bg=(182, 235, 255), title_ue_cap_bg=(150, 207, 147)
):
"""La table de synthèse; pour chaque UE, liste des ressources et SAÉs avec leurs notes
et leurs coefs.
Renvoie: colkeys, P, pdf_style, colWidths
@ -74,6 +90,7 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
- pdf_style : commandes table Platypus
- largeurs de colonnes pour PDF
"""
# nb: self.infos a ici été donné par BulletinBUT.bulletin_etud_complet()
col_widths = {
"titre": None,
"min": 1.5 * cm,
@ -95,6 +112,7 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
col_keys += ["coef", "moyenne"]
# Couleur fond:
title_bg = tuple(x / 255.0 for x in title_bg)
title_ue_cap_bg = tuple(x / 255.0 for x in title_ue_cap_bg)
# elems pour générer table avec gen_table (liste de dicts)
rows = [
# Ligne de titres
@ -141,9 +159,13 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
blue,
),
]
ues_capitalisees = self.infos.get("ues_capitalisees", {})
for ue_acronym, ue in self.infos["ues"].items():
self.ue_rows(rows, ue_acronym, ue, title_bg)
self._ue_rows(rows, ue_acronym, ue, title_bg)
if ue_acronym in ues_capitalisees:
self._ue_rows(
rows, ue_acronym, ues_capitalisees[ue_acronym], title_ue_cap_bg
)
# Global pdf style commands:
pdf_style = [
@ -152,20 +174,18 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
]
return col_keys, rows, pdf_style, col_widths
def ue_rows(self, rows: list, ue_acronym: str, ue: dict, title_bg: tuple):
def _ue_rows(self, rows: list, ue_acronym: str, ue: dict, title_bg: tuple):
"Décrit une UE dans la table synthèse: titre, sous-titre et liste modules"
if (ue["type"] == UE_SPORT) and len(ue.get("modules", [])) == 0:
# ne mentionne l'UE que s'il y a des modules
return
# 1er ligne titre UE
moy_ue = ue.get("moyenne")
moy_ue = ue.get("moyenne", "-")
if isinstance(moy_ue, dict):
moy_ue = moy_ue.get("value", "-") if moy_ue is not None else "-"
t = {
"titre": f"{ue_acronym} - {ue['titre']}",
"moyenne": Paragraph(
f"""<para align=right><b>{moy_ue.get("value", "-")
if moy_ue is not None else "-"
}</b></para>"""
),
"moyenne": Paragraph(f"""<para align=right><b>{moy_ue}</b></para>"""),
"_css_row_class": "note_bold",
"_pdf_row_markup": ["b"],
"_pdf_style": [
@ -196,25 +216,40 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
# case Bonus/Malus/Rang "bmr"
fields_bmr = []
try:
value = float(ue["bonus"])
value = float(ue.get("bonus", 0.0))
if value != 0:
fields_bmr.append(f"Bonus: {ue['bonus']}")
except ValueError:
pass
try:
value = float(ue["malus"])
value = float(ue.get("malus", 0.0))
if value != 0:
fields_bmr.append(f"Malus: {ue['malus']}")
except ValueError:
pass
moy_ue = ue.get("moyenne", "-")
if isinstance(moy_ue, dict): # UE non capitalisées
if self.preferences["bul_show_ue_rangs"]:
fields_bmr.append(
f"Rang: {ue['moyenne']['rang']} / {ue['moyenne']['total']}"
)
ue_min, ue_max, ue_moy = (
ue["moyenne"]["min"],
ue["moyenne"]["max"],
ue["moyenne"]["moy"],
)
else: # UE capitalisée
ue_min, ue_max, ue_moy = "", "", moy_ue
date_capitalisation = ue.get("date_capitalisation")
if date_capitalisation:
fields_bmr.append(
f"""Capitalisée le {date_capitalisation.strftime("%d/%m/%Y")}"""
)
t = {
"titre": " - ".join(fields_bmr),
"coef": ects_txt,
"_coef_pdf": Paragraph(f"""<para align=left>{ects_txt}</para>"""),
"_coef_pdf": Paragraph(f"""<para align=right>{ects_txt}</para>"""),
"_coef_colspan": 2,
"_pdf_style": [
("BACKGROUND", (0, 0), (-1, 0), title_bg),
@ -222,9 +257,9 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
# ligne au dessus du bonus/malus, gris clair
("LINEABOVE", (0, 0), (-1, 0), self.PDF_LINEWIDTH, (0.7, 0.7, 0.7)),
],
"min": ue["moyenne"]["min"],
"max": ue["moyenne"]["max"],
"moy": ue["moyenne"]["moy"],
"min": ue_min,
"max": ue_max,
"moy": ue_moy,
}
rows.append(t)

View File

@ -234,7 +234,7 @@ class ResultatsSemestreBUT(NotesTableCompat):
)
# matrice de NaN: inscrits par défaut à AUCUNE UE:
ues_inscr_parcours_df = pd.DataFrame(
np.nan, index=etuds_parcour_id.keys(), columns=ue_ids, dtype=float # XXX
np.nan, index=etuds_parcour_id.keys(), columns=ue_ids, dtype=float
)
# Construit pour chaque parcours du référentiel l'ensemble de ses UE
# (considère aussi le cas des semestres sans parcours: None)

View File

@ -6,6 +6,8 @@
import datetime
from functools import cached_property
from operator import attrgetter
from flask import abort, has_request_context, url_for
from flask import g, request
import sqlalchemy
@ -155,9 +157,19 @@ class Identite(db.Model):
)
def get_first_email(self, field="email") -> str:
"Le mail associé à la première adrese de l'étudiant, ou None"
"Le mail associé à la première adresse de l'étudiant, ou None"
return getattr(self.adresses[0], field) if self.adresses.count() > 0 else None
def get_formsemestres(self) -> list:
"""Liste des formsemestres dans lesquels l'étudiant est (a été) inscrit,
triée par date_debut
"""
return sorted(
[ins.formsemestre for ins in self.formsemestre_inscriptions],
key=attrgetter("date_debut"),
reverse=True,
)
def to_dict_short(self) -> dict:
"""Les champs essentiels"""
return {

View File

@ -82,11 +82,11 @@ def get_formsemestre_bulletin_etud_json(
) -> str:
"""Le JSON du bulletin d'un étudiant, quel que soit le type de formation."""
if formsemestre.formation.is_apc():
bul = bulletin_but.BulletinBUT(formsemestre)
if not etud.id in bul.res.identdict:
bulletins_sem = bulletin_but.BulletinBUT(formsemestre)
if not etud.id in bulletins_sem.res.identdict:
return json_error(404, "get_formsemestre_bulletin_etud_json: invalid etud")
return jsonify(
bul.bulletin_etud(
bulletins_sem.bulletin_etud(
etud,
formsemestre,
force_publishing=force_publishing,
@ -746,7 +746,10 @@ def etud_descr_situation_semestre(
infos["refcomp_specialite_long"] = ""
if formsemestre.formation.is_apc():
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
parcour: ApcParcours = ApcParcours.query.get(res.etuds_parcour_id[etudid])
parcour_id = res.etuds_parcour_id[etudid]
parcour: ApcParcours = (
ApcParcours.query.get(parcour_id) if parcour_id is not None else None
)
if parcour:
infos["parcours_titre"] = parcour.libelle or ""
infos["parcours_code"] = parcour.code or ""
@ -930,13 +933,14 @@ def formsemestre_bulletinetud(
bulletin = do_formsemestre_bulletinetud(
formsemestre,
etud.id,
etud,
format=format,
version=version,
xml_with_decisions=xml_with_decisions,
force_publishing=force_publishing,
prefer_mail_perso=prefer_mail_perso,
)[0]
if format not in {"html", "pdfmail"}:
filename = scu.bul_filename(formsemestre, etud, format)
mime, suffix = scu.get_mime_suffix(format)
@ -973,7 +977,7 @@ def can_send_bulletin_by_mail(formsemestre_id):
def do_formsemestre_bulletinetud(
formsemestre: FormSemestre,
etudid: int,
etud: Identite,
version="long", # short, long, selectedevals
format=None,
xml_with_decisions: bool = False,
@ -1001,7 +1005,7 @@ def do_formsemestre_bulletinetud(
if format == "xml":
bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud(
formsemestre.id,
etudid,
etud.id,
xml_with_decisions=xml_with_decisions,
force_publishing=force_publishing,
version=version,
@ -1012,7 +1016,7 @@ def do_formsemestre_bulletinetud(
elif format == "json": # utilisé pour classic et "oldjson"
bul = sco_bulletins_json.make_json_formsemestre_bulletinetud(
formsemestre.id,
etudid,
etud.id,
xml_with_decisions=xml_with_decisions,
force_publishing=force_publishing,
version=version,
@ -1022,22 +1026,20 @@ def do_formsemestre_bulletinetud(
version = version[:-4] # enlève le "_mat"
if formsemestre.formation.is_apc():
etudiant = Identite.query.get(etudid)
r = bulletin_but.BulletinBUT(formsemestre)
infos = r.bulletin_etud_complet(etudiant, version=version)
bulletins_sem = bulletin_but.BulletinBUT(formsemestre)
bul_dict = bulletins_sem.bulletin_etud_complet(etud, version=version)
else:
infos = formsemestre_bulletinetud_dict(formsemestre.id, etudid)
etud = infos["etud"]
bul_dict = formsemestre_bulletinetud_dict(formsemestre.id, etud.id)
if format == "html":
htm, _ = sco_bulletins_generator.make_formsemestre_bulletinetud(
infos, version=version, format="html"
bul_dict, version=version, format="html"
)
return htm, infos["filigranne"]
return htm, bul_dict["filigranne"]
elif format == "pdf" or format == "pdfpart":
bul, filename = sco_bulletins_generator.make_formsemestre_bulletinetud(
infos,
bul_dict,
version=version,
format="pdf",
stand_alone=(format != "pdfpart"),
@ -1046,10 +1048,10 @@ def do_formsemestre_bulletinetud(
if format == "pdf":
return (
scu.sendPDFFile(bul, filename),
infos["filigranne"],
bul_dict["filigranne"],
) # unused ret. value
else:
return bul, infos["filigranne"]
return bul, bul_dict["filigranne"]
elif format == "pdfmail":
# format pdfmail: envoie le pdf par mail a l'etud, et affiche le html
@ -1058,24 +1060,28 @@ def do_formsemestre_bulletinetud(
raise AccessDenied("Vous n'avez pas le droit d'effectuer cette opération !")
pdfdata, filename = sco_bulletins_generator.make_formsemestre_bulletinetud(
infos, version=version, format="pdf"
bul_dict, version=version, format="pdf"
)
if prefer_mail_perso:
recipient_addr = etud.get("emailperso", "") or etud.get("email", "")
recipient_addr = (
etud.get_first_email("emailperso") or etud.get_first_email()
)
else:
recipient_addr = etud.get("email", "") or etud.get("emailperso", "")
recipient_addr = etud.get_first_email() or etud.get_first_email(
"emailperso"
)
if not recipient_addr:
flash(f"{etud['nomprenom']} n'a pas d'adresse e-mail !")
return False, infos["filigranne"]
flash(f"{etud.nomprenom} n'a pas d'adresse e-mail !")
return False, bul_dict["filigranne"]
else:
mail_bulletin(formsemestre.id, infos, pdfdata, filename, recipient_addr)
mail_bulletin(formsemestre.id, bul_dict, pdfdata, filename, recipient_addr)
flash(f"mail envoyé à {recipient_addr}")
return True, infos["filigranne"]
return True, bul_dict["filigranne"]
raise ValueError("do_formsemestre_bulletinetud: invalid format (%s)" % format)
raise ValueError(f"do_formsemestre_bulletinetud: invalid format ({format})")
def mail_bulletin(formsemestre_id, infos, pdfdata, filename, recipient_addr):

View File

@ -83,7 +83,7 @@ class BulletinGenerator:
def __init__(
self,
infos,
bul_dict,
authuser=None,
version="long",
filigranne=None,
@ -92,16 +92,18 @@ class BulletinGenerator:
):
from app.scodoc import sco_preferences
if not version in scu.BULLETINS_VERSIONS:
if version not in scu.BULLETINS_VERSIONS:
raise ValueError("invalid version code !")
self.infos = infos
self.authuser = authuser # nécessaire pour version HTML qui contient liens dépendant de l'utilisateur
self.bul_dict = bul_dict
self.infos = bul_dict # legacy code compat
# authuser nécessaire pour version HTML qui contient liens dépendants de l'utilisateur
self.authuser = authuser
self.version = version
self.filigranne = filigranne
self.server_name = server_name
self.with_img_signatures_pdf = with_img_signatures_pdf
# Store preferences for convenience:
formsemestre_id = self.infos["formsemestre_id"]
formsemestre_id = self.bul_dict["formsemestre_id"]
self.preferences = sco_preferences.SemPreferences(formsemestre_id)
self.diagnostic = None # error message if any problem
# Common PDF styles:
@ -127,13 +129,13 @@ class BulletinGenerator:
def get_filename(self):
"""Build a filename to be proposed to the web client"""
sem = sco_formsemestre.get_formsemestre(self.infos["formsemestre_id"])
return scu.bul_filename_old(sem, self.infos["etud"], "pdf")
sem = sco_formsemestre.get_formsemestre(self.bul_dict["formsemestre_id"])
return scu.bul_filename_old(sem, self.bul_dict["etud"], "pdf")
def generate(self, format="", stand_alone=True):
"""Return bulletin in specified format"""
if not format in self.supported_formats:
raise ValueError("unsupported bulletin format (%s)" % format)
raise ValueError(f"unsupported bulletin format ({format})")
try:
PDFLOCK.acquire() # this lock is necessary since reportlab is not re-entrant
if format == "html":
@ -141,7 +143,7 @@ class BulletinGenerator:
elif format == "pdf":
return self.generate_pdf(stand_alone=stand_alone)
else:
raise ValueError("invalid bulletin format (%s)" % format)
raise ValueError(f"invalid bulletin format ({format})")
finally:
PDFLOCK.release()
@ -163,11 +165,12 @@ class BulletinGenerator:
"""
from app.scodoc import sco_preferences
formsemestre_id = self.infos["formsemestre_id"]
formsemestre_id = self.bul_dict["formsemestre_id"]
nomprenom = self.bul_dict["etud"]["nomprenom"]
marque_debut_bulletin = sco_pdf.DebutBulletin(
self.infos["etud"]["nomprenom"],
filigranne=self.infos["filigranne"],
footer_content=f"""ScoDoc - Bulletin de {self.infos["etud"]["nomprenom"]} - {time.strftime("%d/%m/%Y %H:%M")}""",
nomprenom,
filigranne=self.bul_dict["filigranne"],
footer_content=f"""ScoDoc - Bulletin de {nomprenom} - {time.strftime("%d/%m/%Y %H:%M")}""",
)
story = []
# partie haute du bulletin
@ -208,8 +211,7 @@ class BulletinGenerator:
document,
author="%s %s (E. Viennet) [%s]"
% (sco_version.SCONAME, sco_version.SCOVERSION, self.description),
title="Bulletin %s de %s"
% (sem["titremois"], self.infos["etud"]["nomprenom"]),
title=f"""Bulletin {sem["titremois"]} de {nomprenom}""",
subject="Bulletin de note",
margins=self.margins,
server_name=self.server_name,
@ -247,7 +249,7 @@ class BulletinGenerator:
# ---------------------------------------------------------------------------
def make_formsemestre_bulletinetud(
infos,
bul_dict,
version=None, # short, long, selectedevals
format="pdf", # html, pdf
stand_alone=True,
@ -262,10 +264,10 @@ def make_formsemestre_bulletinetud(
from app.scodoc import sco_preferences
version = version or "long"
if not version in scu.BULLETINS_VERSIONS:
if version not in scu.BULLETINS_VERSIONS:
raise ValueError("invalid version code !")
formsemestre_id = infos["formsemestre_id"]
formsemestre_id = bul_dict["formsemestre_id"]
bul_class_name = sco_preferences.get_preference("bul_class_name", formsemestre_id)
gen_class = None
@ -274,7 +276,7 @@ def make_formsemestre_bulletinetud(
# si pas trouvé (modifs locales bizarres ,), ré-essaye avec la valeur par défaut
bulletin_default_class_name(),
):
if infos.get("type") == "BUT" and format.startswith("pdf"):
if bul_dict.get("type") == "BUT" and format.startswith("pdf"):
gen_class = bulletin_get_class(bul_class_name + "BUT")
if gen_class is None:
gen_class = bulletin_get_class(bul_class_name)
@ -285,10 +287,10 @@ def make_formsemestre_bulletinetud(
try:
PDFLOCK.acquire()
bul_generator = gen_class(
infos,
bul_dict,
authuser=current_user,
version=version,
filigranne=infos["filigranne"],
filigranne=bul_dict["filigranne"],
server_name=request.url_root,
with_img_signatures_pdf=with_img_signatures_pdf,
)
@ -301,24 +303,22 @@ def make_formsemestre_bulletinetud(
bul_class_name = bulletin_default_class_name()
gen_class = bulletin_get_class(bul_class_name)
bul_generator = gen_class(
infos,
bul_dict,
authuser=current_user,
version=version,
filigranne=infos["filigranne"],
filigranne=bul_dict["filigranne"],
server_name=request.url_root,
with_img_signatures_pdf=with_img_signatures_pdf,
)
data = bul_generator.generate(format=format, stand_alone=stand_alone)
finally:
PDFLOCK.release()
if bul_generator.diagnostic:
log("bul_error: %s" % bul_generator.diagnostic)
log(f"bul_error: {bul_generator.diagnostic}")
raise NoteProcessError(bul_generator.diagnostic)
filename = bul_generator.get_filename()
return data, filename

View File

@ -45,7 +45,7 @@ Pour définir un nouveau type de bulletin:
(s'inspirer de sco_bulletins_pdf_default);
- en fin du fichier sco_bulletins_pdf.py, ajouter la ligne
import sco_bulletins_pdf_xxxx
- votre type sera alors (après redémarrage de ScoDoc) proposé dans le formulaire de paramètrage ScoDoc.
- votre type sera alors (après redémarrage de ScoDoc) proposé dans le formulaire de paramètrage.
Chaque semestre peut si nécessaire utiliser un type de bulletin différent.
@ -60,13 +60,12 @@ import traceback
from flask import g, request
from app import log, ScoValueError
from app.models import FormSemestre
from app.models import FormSemestre, Identite
from app.scodoc import sco_cache
from app.scodoc import codes_cursus
from app.scodoc import sco_pdf
from app.scodoc import sco_preferences
from app.scodoc import sco_etud
from app.scodoc.sco_logos import find_logo
import app.scodoc.sco_utils as scu
@ -97,8 +96,8 @@ def assemble_bulletins_pdf(
document.addPageTemplates(
sco_pdf.ScoDocPageTemplate(
document,
author="%s %s (E. Viennet)" % (sco_version.SCONAME, sco_version.SCOVERSION),
title="Bulletin %s" % bul_title,
author=f"{sco_version.SCONAME} {sco_version.SCOVERSION} (E. Viennet)",
title=f"Bulletin {bul_title}",
subject="Bulletin de note",
server_name=server_name,
margins=margins,
@ -125,11 +124,13 @@ def replacement_function(match):
class WrapDict(object):
"""Wrap a dict so that getitem returns '' when values are None"""
"""Wrap a dict so that getitem returns '' when values are None
and non existent keys returns an error message as value.
"""
def __init__(self, adict, NoneValue=""):
def __init__(self, adict, none_value=""):
self.dict = adict
self.NoneValue = NoneValue
self.none_value = none_value
def __getitem__(self, key):
try:
@ -137,12 +138,11 @@ class WrapDict(object):
except KeyError:
return f"XXX {key} invalide XXX"
if value is None:
return self.NoneValue
else:
return self.none_value
return value
def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"):
def process_field(field, cdict, style, suppress_empty_pars=False, fmt="pdf"):
"""Process a field given in preferences, returns
- if format = 'pdf': a list of Platypus objects
- if format = 'html' : a string
@ -183,7 +183,7 @@ def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"):
)
# remove unhandled or dangerous tags:
text = re.sub(r"<\s*img", "", text)
if format == "html":
if fmt == "html":
# convert <para>
text = re.sub(r"<\s*para(\s*)(.*?)>", r"<p>", text)
return text
@ -219,7 +219,7 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
for etud in formsemestre.get_inscrits(include_demdef=True, order=True):
frag, _ = sco_bulletins.do_formsemestre_bulletinetud(
formsemestre,
etud.id,
etud,
format="pdfpart",
version=version,
)
@ -256,22 +256,21 @@ def get_etud_bulletins_pdf(etudid, version="selectedevals"):
"Bulletins pdf de tous les semestres de l'étudiant, et filename"
from app.scodoc import sco_bulletins
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
etud: Identite = Identite.query.get_or_404(etudid)
fragments = []
bookmarks = {}
filigrannes = {}
i = 1
for sem in etud["sems"]:
formsemestre = FormSemestre.query.get(sem["formsemestre_id"])
for formsemestre in etud.get_formsemestres():
frag, filigranne = sco_bulletins.do_formsemestre_bulletinetud(
formsemestre,
etudid,
etud,
format="pdfpart",
version=version,
)
fragments += frag
filigrannes[i] = filigranne
bookmarks[i] = sem["session_id"] # eg RT-DUT-FI-S1-2015
bookmarks[i] = formsemestre.session_id() # eg RT-DUT-FI-S1-2015
i = i + 1
infos = {"DeptName": sco_preferences.get_preference("DeptName")}
if request:
@ -283,7 +282,7 @@ def get_etud_bulletins_pdf(etudid, version="selectedevals"):
pdfdoc = assemble_bulletins_pdf(
None,
fragments,
etud["nomprenom"],
etud.nomprenom,
infos,
bookmarks,
filigranne=filigrannes,
@ -292,7 +291,7 @@ def get_etud_bulletins_pdf(etudid, version="selectedevals"):
finally:
sco_pdf.PDFLOCK.release()
#
filename = "bul-%s" % (etud["nomprenom"])
filename = f"bul-{etud.nomprenom}"
filename = (
scu.unescape_html(filename).replace(" ", "_").replace("&", "").replace(".", "")
+ ".pdf"

View File

@ -186,13 +186,13 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
self.preferences["bul_pdf_caption"],
self.infos,
self.FieldStyle,
format="pdf",
fmt="pdf",
)
field = sco_bulletins_pdf.process_field(
self.preferences["bul_pdf_caption"],
self.infos,
self.FieldStyle,
format="html",
fmt="html",
)
H.append('<div class="bul_decision">' + field + "</div>")

View File

@ -939,7 +939,7 @@ def fill_etuds_info(etuds: list[dict], add_admission=True):
def etud_inscriptions_infos(etudid: int, ne="") -> dict:
"""Dict avec les informations sur les semestres passés et courant.
{
"sems" : ,
"sems" : , # trie les semestres par date de debut, le plus recent d'abord
"ins" : ,
"cursem" : ,
"inscription" : ,

View File

@ -397,8 +397,8 @@ def gen_formsemestre_recapcomplet_json(
etudid = t[-1]
if is_apc:
etud = Identite.query.get(etudid)
r = bulletin_but.BulletinBUT(formsemestre)
bul = r.bulletin_etud(etud, formsemestre)
bulletins_sem = bulletin_but.BulletinBUT(formsemestre)
bul = bulletins_sem.bulletin_etud(etud, formsemestre)
else:
bul = sco_bulletins_json.formsemestre_bulletinetud_published_dict(
formsemestre_id,

View File

@ -335,7 +335,8 @@ def formsemestre_bulletinetud(
if format == "oldjson":
format = "json"
r = sco_bulletins.formsemestre_bulletinetud(
response = sco_bulletins.formsemestre_bulletinetud(
etud,
formsemestre_id=formsemestre_id,
format=format,
@ -344,7 +345,8 @@ def formsemestre_bulletinetud(
force_publishing=force_publishing,
prefer_mail_perso=prefer_mail_perso,
)
if format == "pdfmail":
if format == "pdfmail": # ne renvoie rien dans ce cas (mails envoyés)
return redirect(
url_for(
"notes.formsemestre_bulletinetud",
@ -353,7 +355,7 @@ def formsemestre_bulletinetud(
formsemestre_id=formsemestre_id,
)
)
return r
return response
sco_publish(
@ -2074,7 +2076,7 @@ def formsemestre_bulletins_mailetuds(
for inscription in inscriptions:
sent, _ = sco_bulletins.do_formsemestre_bulletinetud(
formsemestre,
inscription.etudid,
inscription.etud,
version=version,
prefer_mail_perso=prefer_mail_perso,
format="pdfmail",