forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -44,9 +44,13 @@ from app.views import notes_bp as bp
|
||||
from app.views import ScoData
|
||||
|
||||
|
||||
@bp.route("/bulletin_but/<int:formsemestre_id>/<int:etudid>")
|
||||
@bp.route(
|
||||
"/bulletin_but/<int:formsemestre_id>/<int:etudid>/pdf", defaults={"fmt": "pdf"}
|
||||
"/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)
|
||||
|
@ -20,12 +20,15 @@ from reportlab.lib.units import cm, mm
|
||||
from reportlab.platypus import Paragraph, Spacer, Table
|
||||
|
||||
from app.but import cursus_but
|
||||
from app.models import FormSemestre, Identite, ScolarFormSemestreValidation
|
||||
from app.models import (
|
||||
BulAppreciations,
|
||||
FormSemestre,
|
||||
Identite,
|
||||
ScolarFormSemestreValidation,
|
||||
)
|
||||
|
||||
from app.scodoc.sco_bulletins_standard import BulletinGeneratorStandard
|
||||
from app.scodoc import sco_bulletins
|
||||
from app.scodoc.sco_logos import Logo
|
||||
from app.scodoc import sco_pdf, sco_preferences
|
||||
from app.scodoc.sco_pdf import PDFLOCK, SU
|
||||
|
||||
|
||||
@ -41,6 +44,7 @@ def make_bulletin_but_court_pdf(
|
||||
ue_validation_by_niveau: dict[tuple[int, str], ScolarFormSemestreValidation] = None,
|
||||
ues_acronyms: list[str] = None,
|
||||
) -> bytes:
|
||||
"génère le bulletin court BUT en pdf"
|
||||
# A priori ce verrou n'est plus nécessaire avec Flask (multi-process)
|
||||
# mais...
|
||||
try:
|
||||
@ -64,6 +68,7 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
multi_pages = False # une page par bulletin
|
||||
small_fontsize = "8"
|
||||
color_blue_bg = Color(0, 153 / 255, 204 / 255)
|
||||
color_gray_bg = Color(0.86, 0.86, 0.86)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -94,13 +99,23 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
|
||||
self.nb_ues = len(self.ues_acronyms)
|
||||
# Styles PDF
|
||||
self.style_cell = styles.ParagraphStyle("style_cell")
|
||||
self.style_cell.fontName = "Helvetica"
|
||||
self.style_base = styles.ParagraphStyle("style_base")
|
||||
self.style_base.fontName = "Helvetica"
|
||||
self.style_base.fontSize = 9
|
||||
|
||||
self.style_nom = styles.ParagraphStyle("style_nom", self.style_base)
|
||||
self.style_nom.fontSize = 11
|
||||
self.style_nom.fontName = "Helvetica-Bold"
|
||||
|
||||
self.style_field = self.style_base # écrase style defaut buleltins
|
||||
|
||||
self.style_cell = styles.ParagraphStyle("style_cell", self.style_base)
|
||||
self.style_cell.fontSize = 7
|
||||
self.style_cell.leading = 7
|
||||
self.style_bold = styles.ParagraphStyle("style_bold", self.style_cell)
|
||||
self.style_bold.fontName = "Helvetica-Bold"
|
||||
self.style_head = styles.ParagraphStyle("style_head", self.style_bold)
|
||||
self.style_cell_bold = styles.ParagraphStyle("style_cell_bold", self.style_cell)
|
||||
self.style_cell_bold.fontName = "Helvetica-Bold"
|
||||
|
||||
self.style_head = styles.ParagraphStyle("style_head", self.style_cell_bold)
|
||||
self.style_head.fontSize = 9
|
||||
|
||||
self.style_niveaux = styles.ParagraphStyle("style_niveaux", self.style_cell)
|
||||
@ -128,6 +143,25 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
"style_niveaux_code", self.style_niveaux
|
||||
)
|
||||
self.style_niveaux_code.borderColor = black
|
||||
#
|
||||
self.style_jury = styles.ParagraphStyle("style_jury", self.style_base)
|
||||
self.style_jury.fontSize = 9
|
||||
self.style_jury.leading = self.style_jury.fontSize * 1.4 # espace les lignes
|
||||
self.style_jury.backColor = self.color_gray_bg
|
||||
self.style_jury.borderColor = black
|
||||
self.style_jury.borderWidth = 1
|
||||
self.style_jury.borderPadding = 2
|
||||
self.style_jury.borderRadius = 2
|
||||
|
||||
self.style_appreciations = styles.ParagraphStyle(
|
||||
"style_appreciations", self.style_base
|
||||
)
|
||||
self.style_appreciations.fontSize = 9
|
||||
self.style_appreciations.leading = (
|
||||
self.style_jury.fontSize * 1.4
|
||||
) # espace les lignes
|
||||
|
||||
self.style_assiduite = self.style_cell
|
||||
|
||||
# Géométrie page
|
||||
self.width_page_avail = 185 * mm # largeur utilisable
|
||||
@ -138,7 +172,27 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
self.width_col_code = self.width_col_ue
|
||||
# Niveaux
|
||||
self.width_col_niveaux_titre = 24 * mm
|
||||
self.width_col_niveaux_code = 12 * mm
|
||||
self.width_col_niveaux_code = 14 * mm
|
||||
|
||||
def bul_title_pdf(self, preference_field="bul_but_pdf_title") -> list:
|
||||
"""Génère la partie "titre" du bulletin de notes.
|
||||
Renvoie une liste d'objets platypus
|
||||
"""
|
||||
# comme les bulletins standard, mais avec notre préférence
|
||||
return super().bul_title_pdf(preference_field=preference_field)
|
||||
|
||||
def bul_part_below(self, fmt="pdf") -> list:
|
||||
"""Génère les informations placées sous la table
|
||||
Dans le cas du bul. court BUT pdf, seulement les appréciations.
|
||||
fmt est ignoré ici.
|
||||
"""
|
||||
appreciations = BulAppreciations.get_appreciations_list(
|
||||
self.formsemestre.id, self.etud.id
|
||||
)
|
||||
return [
|
||||
Spacer(1, 3 * mm),
|
||||
self.bul_appreciations_pdf(appreciations, style=self.style_appreciations),
|
||||
]
|
||||
|
||||
def bul_table(self, fmt=None) -> list:
|
||||
"""Génère la table centrale du bulletin de notes
|
||||
@ -148,7 +202,7 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
style_table_2cols = [
|
||||
("ALIGN", (0, -1), (0, -1), "LEFT"),
|
||||
("ALIGN", (-1, -1), (-1, -1), "RIGHT"),
|
||||
("VALIGN", (0, 0), (-1, 1), "TOP"),
|
||||
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||
("LEFTPADDING", (0, 0), (-1, -1), 0),
|
||||
("TOPPADDING", (0, 0), (-1, -1), 0),
|
||||
("RIGHTPADDING", (0, 0), (-1, -1), 0),
|
||||
@ -156,15 +210,24 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
]
|
||||
# Ligne avec boite assiduité et table UEs
|
||||
table_abs_ues = Table(
|
||||
[[self.box_assiduite(), self.table_ues()]],
|
||||
colWidths=(3 * cm, self.width_page_avail - 3 * cm),
|
||||
[
|
||||
[
|
||||
self.boite_identite() + [Spacer(1, 3 * mm), self.boite_assiduite()],
|
||||
self.table_ues(),
|
||||
],
|
||||
],
|
||||
style=style_table_2cols,
|
||||
)
|
||||
table_abs_ues.hAlign = "RIGHT"
|
||||
# Ligne (en bas) avec table cursus et boite jury
|
||||
table_cursus_jury = Table(
|
||||
[[self.table_cursus_but(), self.boite_decisions_jury()]],
|
||||
colWidths=(self.width_page_avail - 45 * mm, 45 * mm),
|
||||
[
|
||||
[
|
||||
self.table_cursus_but(),
|
||||
[Spacer(1, 8 * mm), self.boite_decisions_jury()],
|
||||
]
|
||||
],
|
||||
colWidths=(self.width_page_avail - 84 * mm, 84 * mm),
|
||||
style=style_table_2cols,
|
||||
)
|
||||
return [
|
||||
@ -223,13 +286,15 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
col_widths = [self.width_col_ue_titres] + [self.width_col_ue] * self.nb_ues
|
||||
|
||||
rows_styled = [[Paragraph(SU(str(cell)), self.style_head) for cell in rows[0]]]
|
||||
rows_styled += [[Paragraph(SU(str(cell)), self.style_bold) for cell in rows[1]]]
|
||||
rows_styled += [
|
||||
[Paragraph(SU(str(cell)), self.style_cell_bold) for cell in rows[1]]
|
||||
]
|
||||
rows_styled += [
|
||||
[Paragraph(SU(str(cell)), self.style_cell) for cell in row]
|
||||
for row in rows[2:-1]
|
||||
]
|
||||
rows_styled += [
|
||||
[Paragraph(SU(str(cell)), self.style_bold) for cell in rows[-1]]
|
||||
[Paragraph(SU(str(cell)), self.style_cell_bold) for cell in rows[-1]]
|
||||
]
|
||||
table = Table(
|
||||
rows_styled,
|
||||
@ -285,7 +350,7 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
] * self.nb_ues
|
||||
|
||||
rows_styled = [
|
||||
[Paragraph(SU(str(cell)), self.style_bold) for cell in row]
|
||||
[Paragraph(SU(str(cell)), self.style_cell_bold) for cell in row]
|
||||
for row in rows[:2]
|
||||
]
|
||||
rows_styled += [
|
||||
@ -310,7 +375,26 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
"saes", "Situations d'Apprentissage et d'Évaluation (SAÉ)"
|
||||
)
|
||||
|
||||
def box_assiduite(self) -> Table:
|
||||
def boite_identite(self) -> list:
|
||||
"Les informations sur l'identité et l'inscription de l'étudiant"
|
||||
return [
|
||||
Paragraph(
|
||||
SU(f"""{self.etud.nomprenom}"""),
|
||||
style=self.style_nom,
|
||||
),
|
||||
Paragraph(
|
||||
SU(
|
||||
f"""
|
||||
<b>{self.bul["demission"]}</b><br/>
|
||||
Formation: {self.formsemestre.titre_num()}<br/>
|
||||
Année scolaire: {self.formsemestre.annee_scolaire_str()}<br/>
|
||||
"""
|
||||
),
|
||||
style=self.style_base,
|
||||
),
|
||||
]
|
||||
|
||||
def boite_assiduite(self) -> Table:
|
||||
"Les informations sur l'assiduité"
|
||||
if not self.bul["options"]["show_abs"]:
|
||||
return Paragraph("") # empty
|
||||
@ -326,7 +410,7 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
for row in rows[:1]
|
||||
]
|
||||
rows_styled += [
|
||||
[Paragraph(SU(str(cell)), self.style_cell) for cell in row]
|
||||
[Paragraph(SU(str(cell)), self.style_assiduite) for cell in row]
|
||||
for row in rows[1:]
|
||||
]
|
||||
table = Table(
|
||||
@ -339,6 +423,7 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
("SPAN", (0, 1), (1, 1)),
|
||||
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||
],
|
||||
colWidths=(25 * mm, 10 * mm),
|
||||
)
|
||||
table.hAlign = "LEFT"
|
||||
return table
|
||||
@ -387,12 +472,14 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
style=[
|
||||
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
||||
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
||||
("LEFTPADDING", (0, 0), (-1, -1), 2),
|
||||
("LEFTPADDING", (0, 0), (-1, -1), 5),
|
||||
("TOPPADDING", (0, 0), (-1, -1), 4),
|
||||
("RIGHTPADDING", (0, 0), (-1, -1), 2),
|
||||
("RIGHTPADDING", (0, 0), (-1, -1), 5),
|
||||
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
|
||||
# sert de séparateur entre les lignes:
|
||||
("LINEABOVE", (0, 1), (-1, -1), 3, white),
|
||||
# séparateur colonne
|
||||
("LINEBEFORE", (1, 1), (-1, -1), 5, white),
|
||||
],
|
||||
)
|
||||
table.hAlign = "LEFT"
|
||||
@ -400,24 +487,24 @@ class BulletinGeneratorBUTCourt(BulletinGeneratorStandard):
|
||||
|
||||
def boite_decisions_jury(self):
|
||||
"""La boite en bas à droite avec jury"""
|
||||
txt = f"""ECTS acquis : {self.ects_total}<br/>"""
|
||||
txt = f"""ECTS acquis : {self.ects_total:g}<br/>"""
|
||||
if self.bul["semestre"]["decision_annee"]:
|
||||
txt += f"""
|
||||
Jury tenu le {
|
||||
datetime.datetime.fromisoformat(self.bul["semestre"]["decision_annee"]["date"]).strftime("%d/%m/%Y à %H:%M")
|
||||
}, année BUT {self.bul["semestre"]["decision_annee"]["code"]}.
|
||||
}, année BUT <b>{self.bul["semestre"]["decision_annee"]["code"]}</b>.
|
||||
<br/>
|
||||
"""
|
||||
if self.bul["semestre"]["autorisation_inscription"]:
|
||||
txt += (
|
||||
"Autorisé à s'inscrire en "
|
||||
"Autorisé à s'inscrire en <b>"
|
||||
+ ", ".join(
|
||||
[
|
||||
f"S{aut['semestre_id']}"
|
||||
for aut in self.bul["semestre"]["autorisation_inscription"]
|
||||
]
|
||||
)
|
||||
+ "."
|
||||
+ "</b>."
|
||||
)
|
||||
|
||||
return Paragraph(txt)
|
||||
return Paragraph(txt, style=self.style_jury)
|
||||
|
@ -113,10 +113,10 @@ class BulletinGenerator:
|
||||
self.diagnostic = None # error message if any problem
|
||||
# Common PDF styles:
|
||||
# - Pour tous les champs du bulletin sauf les cellules de table:
|
||||
self.FieldStyle = reportlab.lib.styles.ParagraphStyle({})
|
||||
self.FieldStyle.fontName = self.preferences["SCOLAR_FONT_BUL_FIELDS"]
|
||||
self.FieldStyle.fontSize = self.preferences["SCOLAR_FONT_SIZE"]
|
||||
self.FieldStyle.firstLineIndent = 0
|
||||
self.style_field = reportlab.lib.styles.ParagraphStyle({})
|
||||
self.style_field.fontName = self.preferences["SCOLAR_FONT_BUL_FIELDS"]
|
||||
self.style_field.fontSize = self.preferences["SCOLAR_FONT_SIZE"]
|
||||
self.style_field.firstLineIndent = 0
|
||||
# - Pour les cellules de table:
|
||||
self.CellStyle = reportlab.lib.styles.ParagraphStyle({})
|
||||
self.CellStyle.fontSize = self.preferences["SCOLAR_FONT_SIZE"]
|
||||
|
@ -62,7 +62,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
Renvoie une liste d'objets platypus
|
||||
"""
|
||||
objects = sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_title"], self.infos, self.FieldStyle
|
||||
self.preferences["bul_pdf_title"], self.infos, self.style_field
|
||||
)
|
||||
objects.append(
|
||||
Spacer(1, 5 * mm)
|
||||
@ -301,7 +301,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
objects += sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_caption"],
|
||||
self.infos,
|
||||
self.FieldStyle,
|
||||
self.style_field,
|
||||
)
|
||||
|
||||
return objects
|
||||
@ -387,7 +387,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_sig_left"],
|
||||
self.infos,
|
||||
self.FieldStyle,
|
||||
self.style_field,
|
||||
)
|
||||
]
|
||||
]
|
||||
@ -398,7 +398,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
|
||||
sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_sig_right"],
|
||||
self.infos,
|
||||
self.FieldStyle,
|
||||
self.style_field,
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
@ -142,7 +142,9 @@ class WrapDict(object):
|
||||
return value
|
||||
|
||||
|
||||
def process_field(field, cdict, style, suppress_empty_pars=False, fmt="pdf"):
|
||||
def process_field(
|
||||
field, cdict, style, suppress_empty_pars=False, fmt="pdf", field_name=None
|
||||
):
|
||||
"""Process a field given in preferences, returns
|
||||
- if format = 'pdf': a list of Platypus objects
|
||||
- if format = 'html' : a string
|
||||
@ -178,7 +180,7 @@ def process_field(field, cdict, style, suppress_empty_pars=False, fmt="pdf"):
|
||||
# ne sera pas visible si lien vers pdf:
|
||||
scu.flash_once(f"Attention: format PDF invalide (champs {field})")
|
||||
text = (
|
||||
"<para><i>format invalide !</i></para><para>"
|
||||
"<para><i>format invalide ! (1)</i></para><para>"
|
||||
+ traceback.format_exc()
|
||||
+ "</para>"
|
||||
)
|
||||
@ -204,7 +206,9 @@ def process_field(field, cdict, style, suppress_empty_pars=False, fmt="pdf"):
|
||||
# secure_filename dans la classe Logo
|
||||
|
||||
# log('field: %s' % (text))
|
||||
return sco_pdf.make_paras(text, style, suppress_empty=suppress_empty_pars)
|
||||
return sco_pdf.make_paras(
|
||||
text, style, suppress_empty=suppress_empty_pars, field_name=field_name
|
||||
)
|
||||
|
||||
|
||||
def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
|
||||
|
@ -81,12 +81,15 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
||||
description = "standard ScoDoc (version 2011)"
|
||||
supported_formats = ["html", "pdf"]
|
||||
|
||||
def bul_title_pdf(self) -> list:
|
||||
def bul_title_pdf(self, preference_field="bul_pdf_title") -> list:
|
||||
"""Génère la partie "titre" du bulletin de notes.
|
||||
Renvoie une liste d'objets platypus
|
||||
"""
|
||||
objects = sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_title"], self.infos, self.FieldStyle
|
||||
self.preferences[preference_field],
|
||||
self.infos,
|
||||
self.style_field,
|
||||
field_name=preference_field,
|
||||
)
|
||||
objects.append(
|
||||
Spacer(1, 5 * mm)
|
||||
@ -195,37 +198,26 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
||||
% self.infos
|
||||
)
|
||||
H.append("</div>")
|
||||
# Appréciations sur PDF:
|
||||
# ------ Appréciations sur PDF
|
||||
if appreciations:
|
||||
story.append(Spacer(1, 3 * mm))
|
||||
try:
|
||||
story.append(
|
||||
Paragraph(
|
||||
SU(
|
||||
"Appréciation : "
|
||||
+ "\n".join(BulAppreciations.summarize(appreciations))
|
||||
),
|
||||
self.CellStyle,
|
||||
)
|
||||
)
|
||||
except AttributeError as exc:
|
||||
raise ScoPDFFormatError(
|
||||
"Appréciation invalide bloquant la génération du pdf"
|
||||
) from exc
|
||||
story.append(self.bul_appreciations_pdf(appreciations))
|
||||
|
||||
# ----- DECISION JURY
|
||||
if self.preferences["bul_show_decision"]:
|
||||
story += sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_caption"],
|
||||
self.infos,
|
||||
self.FieldStyle,
|
||||
self.style_field,
|
||||
fmt="pdf",
|
||||
field_name="bul_pdf_caption",
|
||||
)
|
||||
field = sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_caption"],
|
||||
self.infos,
|
||||
self.FieldStyle,
|
||||
self.style_field,
|
||||
fmt="html",
|
||||
field_name="bul_pdf_caption",
|
||||
)
|
||||
H.append('<div class="bul_decision">' + field + "</div>")
|
||||
|
||||
@ -240,6 +232,24 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
||||
elif fmt == "html":
|
||||
return "\n".join(H)
|
||||
|
||||
def bul_appreciations_pdf(
|
||||
self, appreciations: list[BulAppreciations], style=None
|
||||
) -> Paragraph:
|
||||
"Liste d'objets platypus pour les appréciations sous le bulletin"
|
||||
style = style or self.CellStyle
|
||||
try:
|
||||
return Paragraph(
|
||||
SU(
|
||||
"Appréciation du "
|
||||
+ "\n".join(BulAppreciations.summarize(appreciations))
|
||||
),
|
||||
style,
|
||||
)
|
||||
except AttributeError as exc:
|
||||
raise ScoPDFFormatError(
|
||||
"Appréciation invalide bloquant la génération du pdf"
|
||||
) from exc
|
||||
|
||||
def bul_signatures_pdf(self):
|
||||
"""Génère les signatures placées en bas du bulletin PDF
|
||||
Renvoie une liste d'objets platypus
|
||||
@ -253,7 +263,8 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
||||
sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_sig_left"],
|
||||
self.infos,
|
||||
self.FieldStyle,
|
||||
self.style_field,
|
||||
field_name="bul_pdf_sig_left",
|
||||
)
|
||||
]
|
||||
]
|
||||
@ -264,7 +275,8 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
||||
sco_bulletins_pdf.process_field(
|
||||
self.preferences["bul_pdf_sig_right"],
|
||||
self.infos,
|
||||
self.FieldStyle,
|
||||
self.style_field,
|
||||
field_name="bul_pdf_sig_right",
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
@ -45,7 +45,7 @@ CONFIG.LOGO_HEADER_HEIGHT = 28
|
||||
# server_url: URL du serveur ScoDoc
|
||||
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir sco_version.py)
|
||||
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = (
|
||||
"Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s"
|
||||
"Édité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s"
|
||||
)
|
||||
|
||||
|
||||
|
@ -57,6 +57,7 @@ from flask import g
|
||||
|
||||
from app import log
|
||||
from app.scodoc.sco_exceptions import ScoGenError, ScoPDFFormatError, ScoValueError
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.sco_utils import CONFIG
|
||||
import sco_version
|
||||
@ -119,7 +120,9 @@ def _splitPara(txt):
|
||||
return L
|
||||
|
||||
|
||||
def make_paras(txt: str, style, suppress_empty=False) -> list[Paragraph]:
|
||||
def make_paras(
|
||||
txt: str, style, suppress_empty=False, field_name=None
|
||||
) -> list[Paragraph]:
|
||||
"""Returns a list of Paragraph instances from a text
|
||||
with one or more <para> ... </para>
|
||||
"""
|
||||
@ -157,9 +160,17 @@ def make_paras(txt: str, style, suppress_empty=False) -> list[Paragraph]:
|
||||
log(traceback.format_exc())
|
||||
log(f"Invalid pdf para format: {txt}")
|
||||
try:
|
||||
# récupère le nom de la préférence
|
||||
if field_name:
|
||||
p = sco_preferences.BasePreferences(g.scodoc_dept_id)
|
||||
pref = p.prefs_dict.get(field_name)
|
||||
if pref:
|
||||
field_name = pref["title"]
|
||||
result = [
|
||||
Paragraph(
|
||||
SU('<font color="red"><i>Erreur: format invalide</i></font>'),
|
||||
SU(
|
||||
f"""<font color="red"><i>Erreur: format invalide (voir préférence {field_name or ""})</i></font>"""
|
||||
),
|
||||
style,
|
||||
)
|
||||
]
|
||||
|
@ -229,6 +229,16 @@ PREF_CATEGORIES = (
|
||||
"related": ("abs", "bul_margins", "bul_mail"),
|
||||
},
|
||||
),
|
||||
(
|
||||
"bul_but_pdf",
|
||||
{
|
||||
"title": "Réglages des bulletins BUT (pdf)",
|
||||
"related": (
|
||||
"bul",
|
||||
"bul_margins",
|
||||
),
|
||||
},
|
||||
),
|
||||
# sur page "Mise en page des bulletins"
|
||||
(
|
||||
"bul_margins",
|
||||
@ -257,7 +267,7 @@ PREF_CATEGORIES = (
|
||||
)
|
||||
|
||||
|
||||
class BasePreferences(object):
|
||||
class BasePreferences:
|
||||
"""Global preferences"""
|
||||
|
||||
_editor = ndb.EditableTable(
|
||||
@ -1681,6 +1691,30 @@ class BasePreferences(object):
|
||||
"category": "bul",
|
||||
},
|
||||
),
|
||||
# Bulletin court BUT
|
||||
# avec peu de réglages afin conserver la mise en page compacte...
|
||||
(
|
||||
"bul_but_pdf_title",
|
||||
{
|
||||
"initvalue": """
|
||||
<para fontSize="14" align="center">
|
||||
<b>%(UnivName)s</b>
|
||||
</para>
|
||||
<para fontSize="14" align="center" spaceBefore="2mm">
|
||||
<b>%(InstituteName)s</b>
|
||||
</para>
|
||||
<para fontSize="14" align="center" spaceBefore="4mm">
|
||||
<b>Bachelor Universitaire de Technologie</b>
|
||||
</para>
|
||||
""",
|
||||
"title": "Bulletins PDF BUT: paragraphe de titre",
|
||||
"explanation": "(balises interprétées, voir documentation)",
|
||||
"input_type": "textarea",
|
||||
"rows": 10,
|
||||
"cols": 64,
|
||||
"category": "bul_but_pdf",
|
||||
},
|
||||
),
|
||||
# XXX A COMPLETER, voir sco_formsemestre_edit.py XXX
|
||||
# bul_mail
|
||||
(
|
||||
|
@ -42,6 +42,13 @@
|
||||
format='pdf',
|
||||
version=version,
|
||||
)}}">{{scu.ICON_PDF|safe}}</a>
|
||||
<a style="margin-left: 20px;"
|
||||
href="{{url_for(
|
||||
'notes.bulletin_but_html',
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre.id,
|
||||
etudid=etud.id
|
||||
)}}">version courte spéciale BUT</a>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -39,6 +39,11 @@
|
||||
{%- endmacro %}
|
||||
|
||||
{% block app_content %}
|
||||
<p><a href="{{url_for(
|
||||
'notes.bulletin_but_pdf', scodoc_dept=g.scodoc_dept, etudid=etud.id,
|
||||
formsemestre_id=formsemestre.id
|
||||
)}}" class="stdlink">version pdf {{scu.ICON_PDF|safe}}</a>
|
||||
</p>
|
||||
|
||||
<div class="but_bul_court">
|
||||
<div id="infos_etudiant">
|
||||
|
@ -11,6 +11,7 @@ SCONEWS = """
|
||||
|
||||
<li>ScoDoc 9.6 (juillet 2023)</li>
|
||||
<ul>
|
||||
<li>Nouveaux bulletins BUT compacts</li>
|
||||
<li>Nouvelle gestion des absences et assiduité</li>
|
||||
<li>Mise à jour logiciels: Debian 12, Python 3.11, ...</li>
|
||||
</ul>
|
||||
|
@ -64,7 +64,7 @@ CONFIG.LOGO_HEADER_HEIGHT = 28 # taille verticale dans le document en millimetr
|
||||
# scodoc_name: le nom du logiciel (ScoDoc actuellement, voir sco_version.py)
|
||||
|
||||
CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = (
|
||||
"Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s"
|
||||
"Édité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s"
|
||||
)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user