diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py
index f64769fc91..6a3f6e2392 100644
--- a/app/but/bulletin_but.py
+++ b/app/but/bulletin_but.py
@@ -177,7 +177,7 @@ class BulletinBUT:
"date": e.jour.isoformat() if e.jour else None,
"heure_debut": e.heure_debut.strftime("%H:%M") if e.heure_debut else None,
"heure_fin": e.heure_fin.strftime("%H:%M") if e.heure_debut else None,
- "coef": e.coefficient,
+ "coef": fmt_note(e.coefficient),
"poids": {p.ue.acronyme: p.poids for p in e.ue_poids},
"note": {
"value": fmt_note(
diff --git a/app/but/bulletin_but_pdf.py b/app/but/bulletin_but_pdf.py
index 5003e216e6..bd8791ccd8 100644
--- a/app/but/bulletin_but_pdf.py
+++ b/app/but/bulletin_but_pdf.py
@@ -7,19 +7,12 @@
"""Génération bulletin BUT au format PDF standard
"""
-import datetime
+from reportlab.platypus import KeepInFrame, Paragraph, Spacer
+
from app.scodoc.sco_pdf import blue, cm, mm
-from flask import url_for, g
-from app.models.formsemestre import FormSemestre
-
from app.scodoc import gen_tables
-from app.scodoc import sco_utils as scu
-from app.scodoc import sco_bulletins_json
-from app.scodoc import sco_preferences
-from app.scodoc.sco_codes_parcours import UE_SPORT
from app.scodoc.sco_utils import fmt_note
-from app.comp.res_but import ResultatsSemestreBUT
from app.scodoc.sco_bulletins_standard import BulletinGeneratorStandard
@@ -31,6 +24,7 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
"""
list_in_menu = False # spécialisation du BulletinGeneratorStandard, ne pas présenter à l'utilisateur
+ scale_table_in_page = False
def bul_table(self, format="html"):
"""Génère la table centrale du bulletin de notes
@@ -38,31 +32,35 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
- en HTML: une chaine
- en PDF: une liste d'objets PLATYPUS (eg instance de Table).
"""
- formsemestre_id = self.infos["formsemestre_id"]
- (
- synth_col_keys,
- synth_P,
- synth_pdf_style,
- synth_col_widths,
- ) = self.but_table_synthese()
- #
- table_synthese = gen_tables.GenTable(
- rows=synth_P,
- columns_ids=synth_col_keys,
- pdf_table_style=synth_pdf_style,
- pdf_col_widths=[synth_col_widths[k] for k in synth_col_keys],
- preferences=self.preferences,
- html_class="notes_bulletin",
- html_class_ignore_default=True,
- html_with_td_classes=True,
- )
- # Ici on ajoutera table des ressources, tables des UE
- # TODO
+ tables_infos = [
+ # ---- TABLE SYNTHESE UES
+ self.but_table_synthese_ues(),
+ # ---- TABLE RESSOURCES
+ self.but_table_ressources(),
+ # ---- TABLE SAE
+ self.but_table_saes(),
+ ]
+ objects = []
+ for i, (col_keys, rows, pdf_style, col_widths) in enumerate(tables_infos):
+ table = gen_tables.GenTable(
+ rows=rows,
+ columns_ids=col_keys,
+ pdf_table_style=pdf_style,
+ pdf_col_widths=[col_widths[k] for k in col_keys],
+ preferences=self.preferences,
+ html_class="notes_bulletin",
+ html_class_ignore_default=True,
+ html_with_td_classes=True,
+ )
+ table_objects = table.gen(format=format)
+ objects += table_objects
+ # objects += [KeepInFrame(0, 0, table_objects, mode="shrink")]
+ if i != 2:
+ objects.append(Spacer(1, 6 * mm))
- # XXX à modifier pour générer plusieurs tables:
- return table_synthese.gen(format=format)
+ return objects
- def but_table_synthese(self):
+ def but_table_synthese_ues(self, title_bg=(182, 235, 255)):
"""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
@@ -76,8 +74,30 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
"moyenne": 2 * cm,
"coef": 2 * cm,
}
- P = [] # elems pour générer table avec gen_table (liste de dicts)
- col_keys = ["titre", "moyenne"] # noms des colonnes à afficher
+ title_bg = tuple(x / 255.0 for x in title_bg)
+ # elems pour générer table avec gen_table (liste de dicts)
+ rows = [
+ # Ligne de titres
+ {
+ "titre": "Unités d'enseignement",
+ "moyenne": "Note/20",
+ "coef": "Coef.",
+ "_css_row_class": "note_bold",
+ "_pdf_row_markup": ["b"],
+ "_pdf_style": [
+ ("BACKGROUND", (0, 0), (-1, 0), title_bg),
+ ("BOTTOMPADDING", (0, 0), (-1, 0), 7),
+ (
+ "LINEBELOW",
+ (0, 0),
+ (-1, 0),
+ self.PDF_LINEWIDTH,
+ blue,
+ ),
+ ],
+ }
+ ]
+ col_keys = ["titre", "moyenne", "coef"] # noms des colonnes à afficher
for ue_acronym, ue in self.infos["ues"].items():
# 1er ligne titre UE
moy_ue = ue.get("moyenne")
@@ -86,31 +106,163 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard):
"moyenne": moy_ue.get("value", "-") if moy_ue is not None else "-",
"_css_row_class": "note_bold",
"_pdf_row_markup": ["b"],
- "_pdf_style": [],
+ "_pdf_style": [
+ (
+ "LINEABOVE",
+ (0, 0),
+ (-1, 0),
+ self.PDF_LINEWIDTH,
+ self.PDF_LINECOLOR,
+ ),
+ ("BACKGROUND", (0, 0), (-1, 0), title_bg),
+ ("BOTTOMPADDING", (0, 0), (-1, 0), 7),
+ ],
}
- P.append(t)
+ rows.append(t)
# 2eme ligne titre UE (bonus/malus/ects)
t = {
- "titre": "",
- "moyenne": f"""Bonus: {ue['bonus']} - Malus: {
- ue["malus"]} - ECTS: {ue["ECTS"]["acquis"]} / {ue["ECTS"]["total"]}""",
- "_css_row_class": "note_bold",
- "_pdf_row_markup": ["b"],
+ "titre": f"""Bonus: {ue['bonus']} - Malus: {
+ ue["malus"]}""",
+ "moyenne": f"""ECTS: {ue["ECTS"]["acquis"]} / {ue["ECTS"]["total"]}""",
+ "_moyenne_colspan": 2,
+ # "_css_row_class": "",
+ # "_pdf_row_markup": [""],
"_pdf_style": [
+ ("ALIGN", (0, 0), (1, 0), "RIGHT"),
+ ("TEXTCOLOR", (0, 0), (-1, 0), blue),
+ ("BACKGROUND", (0, 0), (-1, 0), title_bg),
(
"LINEBELOW",
(0, 0),
(-1, 0),
self.PDF_LINEWIDTH,
self.PDF_LINECOLOR,
- )
+ ),
],
}
- P.append(t)
-
+ rows.append(t)
+ # Liste chaque ressource
+ for mod_code, mod in ue["ressources"].items():
+ t = {
+ "titre": f"{mod_code} {self.infos['ressources'][mod_code]['titre']}",
+ "moyenne": mod["moyenne"],
+ "coef": mod["coef"],
+ "_coef_pdf": Paragraph(
+ f"{mod['coef']}"
+ ),
+ "_pdf_style": [
+ (
+ "LINEBELOW",
+ (0, 0),
+ (-1, 0),
+ self.PDF_LINEWIDTH,
+ (0.7, 0.7, 0.7), # gris clair
+ )
+ ],
+ }
+ rows.append(t)
# Global pdf style commands:
pdf_style = [
("VALIGN", (0, 0), (-1, -1), "TOP"),
("BOX", (0, 0), (-1, -1), 0.4, blue), # ajoute cadre extérieur bleu:
]
- return col_keys, P, pdf_style, col_widths
+ return col_keys, rows, pdf_style, col_widths
+
+ def but_table_ressources(self):
+ """La table de synthèse; pour chaque ressources, note et liste d'évaluations
+ Renvoie: colkeys, P, pdf_style, colWidths
+ """
+ return self.bul_table_modules(
+ mod_type="ressources", title="Ressources", title_bg=(248, 200, 68)
+ )
+
+ def but_table_saes(self):
+ "table des SAEs"
+ return self.bul_table_modules(
+ mod_type="saes",
+ title="Situations d'apprentissage et d'évaluation",
+ title_bg=(198, 255, 171),
+ )
+
+ def bul_table_modules(self, mod_type=None, title="", title_bg=(248, 200, 68)):
+ """Table ressources ou SAEs
+ - colkeys: nom des colonnes de la table (clés)
+ - P : table (liste de dicts de chaines de caracteres)
+ - pdf_style : commandes table Platypus
+ - largeurs de colonnes pour PDF
+ """
+ col_widths = {
+ "titre": None,
+ "moyenne": 2 * cm,
+ "coef": 2 * cm,
+ }
+ title_bg = tuple(x / 255.0 for x in title_bg)
+ # elems pour générer table avec gen_table (liste de dicts)
+ rows = [
+ # Ligne de titres
+ {
+ "titre": title,
+ "moyenne": "Note/20",
+ "coef": "Coef.",
+ "_css_row_class": "note_bold",
+ "_pdf_row_markup": ["b"],
+ "_pdf_style": [
+ ("BACKGROUND", (0, 0), (-1, 0), title_bg),
+ ("BOTTOMPADDING", (0, 0), (-1, 0), 7),
+ (
+ "LINEBELOW",
+ (0, 0),
+ (-1, 0),
+ self.PDF_LINEWIDTH,
+ blue,
+ ),
+ ],
+ }
+ ]
+ col_keys = ["titre", "moyenne", "coef"] # noms des colonnes à afficher
+ for mod_code, mod in self.infos[mod_type].items():
+ # 1er ligne titre module
+ t = {
+ "titre": f"{mod_code} - {mod['titre']}",
+ "moyenne": "", # pas de moyenne
+ "_css_row_class": "note_bold",
+ "_pdf_row_markup": ["b"],
+ "_pdf_style": [
+ (
+ "LINEABOVE",
+ (0, 0),
+ (-1, 0),
+ self.PDF_LINEWIDTH,
+ self.PDF_LINECOLOR,
+ ),
+ ("BACKGROUND", (0, 0), (-1, 0), title_bg),
+ ("BOTTOMPADDING", (0, 0), (-1, 0), 7),
+ ],
+ }
+ rows.append(t)
+ # Evaluations:
+ for e in mod["evaluations"]:
+ t = {
+ "titre": f"{e['description']}",
+ "moyenne": e["note"]["value"],
+ "coef": e["coef"],
+ "_coef_pdf": Paragraph(
+ f"{e['coef']}"
+ ),
+ "_pdf_style": [
+ (
+ "LINEBELOW",
+ (0, 0),
+ (-1, 0),
+ self.PDF_LINEWIDTH,
+ (0.7, 0.7, 0.7), # gris clair
+ )
+ ],
+ }
+ rows.append(t)
+ # Global pdf style commands:
+ pdf_style = [
+ ("VALIGN", (0, 0), (-1, -1), "TOP"),
+ ("BOX", (0, 0), (-1, -1), 0.4, blue), # ajoute cadre extérieur bleu:
+ ]
+ return col_keys, rows, pdf_style, col_widths
diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py
index 2aeb792fb4..5fa07aa8f6 100644
--- a/app/scodoc/sco_bulletins_generator.py
+++ b/app/scodoc/sco_bulletins_generator.py
@@ -71,6 +71,7 @@ class BulletinGenerator:
supported_formats = [] # should list supported formats, eg [ 'html', 'pdf' ]
description = "superclass for bulletins" # description for user interface
list_in_menu = True # la classe doit-elle est montrée dans le menu de config ?
+ scale_table_in_page = True # rescale la table sur 1 page
def __init__(
self,
@@ -163,8 +164,9 @@ class BulletinGenerator:
# signatures
objects += self.bul_signatures_pdf() # pylint: disable=no-member
- # Réduit sur une page
- objects = [KeepInFrame(0, 0, objects, mode="shrink")]
+ if self.scale_table_in_page:
+ # Réduit sur une page
+ objects = [KeepInFrame(0, 0, objects, mode="shrink")]
#
if not stand_alone:
objects.append(PageBreak()) # insert page break at end
@@ -219,7 +221,7 @@ class BulletinGenerator:
# ---------------------------------------------------------------------------
def make_formsemestre_bulletinetud(
infos,
- version="long", # short, long, selectedevals
+ version=None, # short, long, selectedevals
format="pdf", # html, pdf
stand_alone=True,
):
@@ -231,6 +233,7 @@ def make_formsemestre_bulletinetud(
"""
from app.scodoc import sco_preferences
+ version = version or "long"
if not version in scu.BULLETINS_VERSIONS:
raise ValueError("invalid version code !")