ScoDoc/app/scodoc/sco_bulletins_standard.py

752 lines
28 KiB
Python
Raw Permalink Normal View History

2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2023-12-31 23:04:06 +01:00
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@gmail.com
#
##############################################################################
"""Generation du bulletin note au format standard
Nouvelle version juillet 2011: changement de la présentation de la table.
Note sur le PDF:
Les templates utilisent les XML markup tags de ReportLab
(voir ReportLab user guide, page 70 et suivantes), dans lesquels les balises
de la forme %(XXX)s sont remplacées par la valeur de XXX, pour XXX dans:
- preferences du semestre (ou globales) (voir sco_preferences.py)
- champs de formsemestre: titre, date_debut, date_fin, responsable, anneesem
- champs de l'etudiant s(etud, décoré par getEtudInfo)
- demission ("DEMISSION" ou vide)
- situation ("Inscrit le XXX")
Balises img: actuellement interdites.
"""
from flask import g, url_for
from reportlab.lib.colors import Color, blue
from reportlab.lib.units import cm, mm
from reportlab.platypus import KeepTogether, Paragraph, Spacer, Table
2022-11-20 23:03:26 +01:00
from app.models import BulAppreciations, Evaluation
import app.scodoc.sco_utils as scu
from app.scodoc import (
gen_tables,
sco_bulletins_generator,
sco_bulletins_pdf,
sco_evaluations,
sco_groups,
sco_preferences,
)
from app.scodoc.codes_cursus import (
2020-12-28 14:43:12 +01:00
UE_COLORS,
UE_DEFAULT_COLOR,
UE_ELECTIVE,
UE_SPORT,
UE_STANDARD,
)
from app.scodoc.sco_exceptions import ScoPDFFormatError
from app.scodoc.sco_pdf import SU, make_paras
from app.scodoc.sco_permissions import Permission
2020-09-26 16:19:37 +02:00
2022-02-21 19:25:38 +01:00
# Important: Le nom de la classe ne doit pas changer (bien le choisir),
# car il sera stocké en base de données (dans les préférences)
2020-09-26 16:19:37 +02:00
class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
"Les bulletins standards"
# la description doit être courte: elle apparait dans le menu de paramètrage ScoDoc
description = "standard ScoDoc (version 2011)"
2020-09-26 16:19:37 +02:00
supported_formats = ["html", "pdf"]
def bul_title_pdf(self, preference_field="bul_pdf_title") -> list:
2020-09-26 16:19:37 +02:00
"""Génère la partie "titre" du bulletin de notes.
Renvoie une liste d'objets platypus
"""
objects = sco_bulletins_pdf.process_field(
self.preferences[preference_field],
self.infos,
self.style_field,
field_name=preference_field,
2020-09-26 16:19:37 +02:00
)
objects.append(
Spacer(1, 5 * mm)
) # impose un espace vertical entre le titre et la table qui suit
return objects
def bul_table(self, fmt="html"):
2020-09-26 16:19:37 +02:00
"""Génère la table centrale du bulletin de notes
Renvoie:
- en HTML: une chaine
- en PDF: une liste d'objets PLATYPUS (eg instance de Table).
"""
formsemestre_id = self.infos["formsemestre_id"]
colkeys, P, pdf_style, colWidths = self.build_bulletin_table()
T = gen_tables.GenTable(
rows=P,
columns_ids=colkeys,
pdf_table_style=pdf_style,
pdf_col_widths=[colWidths[k] for k in colkeys],
preferences=sco_preferences.SemPreferences(formsemestre_id),
2020-09-26 16:19:37 +02:00
html_class="notes_bulletin",
html_class_ignore_default=True,
html_with_td_classes=True,
table_id="std_bul_table",
2020-09-26 16:19:37 +02:00
)
return T.gen(fmt=fmt)
2020-09-26 16:19:37 +02:00
def bul_part_below(self, fmt="html"):
2020-09-26 16:19:37 +02:00
"""Génère les informations placées sous la table de notes
(absences, appréciations, décisions de jury...)
Renvoie:
- en HTML: une chaine
- en PDF: une liste d'objets platypus
"""
H = [] # html
story = [] # objets platypus
2020-09-26 16:19:37 +02:00
# ----- ABSENCES
if self.preferences["bul_show_abs"]:
nbabs = self.infos["nbabs"]
story.append(Spacer(1, 2 * mm))
2020-09-26 16:19:37 +02:00
if nbabs:
H.append(
2023-09-04 09:24:08 +02:00
f"""<p class="bul_abs">
2023-12-12 03:05:31 +01:00
<a href="{ url_for('assiduites.calendrier_assi_etud',
scodoc_dept=g.scodoc_dept,
etudid=self.infos["etudid"]) }" class="bull_link">
<b>Absences :</b> {self.infos['nbabs']} demi-journées, dont {
self.infos['nbabsjust']} justifiées
2020-09-26 16:19:37 +02:00
(pendant ce semestre).
</a></p>
"""
)
2023-12-12 15:32:47 +01:00
metrique = scu.AssiduitesMetrics.short_to_str(
self.preferences["assi_metrique"], lower_plural=True
)
story.append(
2020-09-26 16:19:37 +02:00
Paragraph(
SU(
2023-12-12 15:32:47 +01:00
f"""{self.infos['nbabs']:g} {metrique} d'absences, dont {
self.infos['nbabsjust']:g} justifiées."""
2020-09-26 16:19:37 +02:00
),
self.CellStyle,
)
)
else:
H.append("""<p class="bul_abs">Pas d'absences signalées.</p>""")
2022-11-20 23:03:26 +01:00
story += make_paras("Pas d'absences signalées.", self.CellStyle)
2020-09-26 16:19:37 +02:00
# ---- APPRECIATIONS
# le dir. des etud peut ajouter des appreciations,
# mais aussi le chef (perm. EtudInscrit)
can_edit_app = (self.formsemestre.est_responsable(self.authuser)) or (
self.authuser.has_permission(Permission.EtudInscrit)
2020-09-26 16:19:37 +02:00
)
H.append('<div class="bull_appreciations">')
appreciations = BulAppreciations.get_appreciations_list(
self.formsemestre.id, self.etud.id
)
for appreciation in appreciations:
2020-09-26 16:19:37 +02:00
if can_edit_app:
mlink = f"""<a class="stdlink" href="{
url_for('notes.appreciation_add_form', scodoc_dept=g.scodoc_dept, appreciation_id=appreciation.id)
}">modifier</a>
<a class="stdlink" href="{
url_for('notes.appreciation_add_form', scodoc_dept=g.scodoc_dept, appreciation_id=appreciation.id, suppress=1)
}">supprimer</a>"""
2020-09-26 16:19:37 +02:00
else:
mlink = ""
H.append(
f"""<p>
<span class="bull_appreciations_date">{
appreciation.date.strftime(scu.DATE_FMT)
if appreciation.date else ""}</span>
{appreciation.comment_safe()}
<span class="bull_appreciations_link">{mlink}</span>
</p>
"""
2020-09-26 16:19:37 +02:00
)
if can_edit_app:
H.append(
f"""<p><a class="stdlink" href="{
2023-12-12 03:05:31 +01:00
url_for('notes.appreciation_add_form', scodoc_dept=g.scodoc_dept,
etudid=self.etud.etudid,
formsemestre_id=self.formsemestre.id
)
}">Ajouter une appréciation</a></p>"""
2020-09-26 16:19:37 +02:00
% self.infos
)
H.append("</div>")
# ------ Appréciations sur PDF
if appreciations:
story.append(Spacer(1, 3 * mm))
story.append(self.bul_appreciations_pdf(appreciations))
2020-09-26 16:19:37 +02:00
# ----- DECISION JURY
if self.preferences["bul_show_decision"]:
story += sco_bulletins_pdf.process_field(
2020-09-26 16:19:37 +02:00
self.preferences["bul_pdf_caption"],
self.infos,
self.style_field,
fmt="pdf",
field_name="bul_pdf_caption",
2020-09-26 16:19:37 +02:00
)
field = sco_bulletins_pdf.process_field(
self.preferences["bul_pdf_caption"],
self.infos,
self.style_field,
fmt="html",
field_name="bul_pdf_caption",
2020-09-26 16:19:37 +02:00
)
H.append('<div class="bul_decision">' + field + "</div>")
# -----
if fmt == "pdf":
if self.scale_table_in_page:
# le scaling (pour tenir sur une page) semble incompatible avec
# le KeepTogether()
return story
else:
return [KeepTogether(story)]
elif fmt == "html":
2020-09-26 16:19:37 +02:00
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
2020-09-26 16:19:37 +02:00
def bul_signatures_pdf(self):
"""Génère les signatures placées en bas du bulletin PDF
Renvoie une liste d'objets platypus
"""
show_left = self.preferences["bul_show_sig_left"]
show_right = self.preferences["bul_show_sig_right"]
2023-02-15 16:15:53 +01:00
if self.with_img_signatures_pdf and (show_left or show_right):
2020-09-26 16:19:37 +02:00
if show_left:
L = [
[
sco_bulletins_pdf.process_field(
self.preferences["bul_pdf_sig_left"],
self.infos,
self.style_signature,
field_name="bul_pdf_sig_left",
2020-09-26 16:19:37 +02:00
)
]
]
else:
L = [[""]]
if show_right:
L[0].append(
sco_bulletins_pdf.process_field(
self.preferences["bul_pdf_sig_right"],
self.infos,
self.style_signature,
field_name="bul_pdf_sig_right",
2020-09-26 16:19:37 +02:00
)
)
else:
L[0].append("")
t = Table(L)
t._argW[0] = 10 * cm # fixe largeur colonne gauche
return [Spacer(1, 1.5 * cm), t] # espace vertical avant signatures
else:
return []
PDF_LINEWIDTH = 0.5
PDF_LINECOLOR = Color(0, 0, 0)
PDF_MODSEPCOLOR = Color(
170 / 255.0, 170 / 255.0, 170 / 255.0
) # lignes séparant les modules
PDF_UE_CUR_BG = Color(
210 / 255.0, 210 / 255.0, 210 / 255.0
) # fond UE courantes non prises en compte
PDF_LIGHT_GRAY = Color(0.75, 0.75, 0.75)
PDF_COLOR_CACHE = {} # (r,g,b) : pdf Color instance
def ue_color(self, ue_type=UE_STANDARD):
rgb_color = UE_COLORS.get(ue_type, UE_DEFAULT_COLOR)
color = self.PDF_COLOR_CACHE.get(rgb_color, None)
if not color:
color = Color(*rgb_color)
self.PDF_COLOR_CACHE[rgb_color] = color
return color
def ue_color_rgb(self, ue_type=UE_STANDARD):
rgb_color = UE_COLORS.get(ue_type, UE_DEFAULT_COLOR)
return "rgb(%d,%d,%d);" % (
rgb_color[0] * 255,
rgb_color[1] * 255,
rgb_color[2] * 255,
)
def build_bulletin_table(self):
2022-03-22 19:18:25 +01:00
"""Génère la table centrale du bulletin de notes classique (pas BUT)
2022-02-21 19:25:38 +01:00
Renvoie: col_keys, P, pdf_style, col_widths
- col_keys: nom des colonnes de la table (clés)
- table: liste de dicts de chaines de caractères
- pdf_style: commandes table Platypus
- col_widths: largeurs de colonnes pour PDF
2020-09-26 16:19:37 +02:00
"""
I = self.infos
P = [] # elems pour générer table avec gen_table (liste de dicts)
formsemestre_id = I["formsemestre_id"]
prefs = sco_preferences.SemPreferences(formsemestre_id)
2020-09-26 16:19:37 +02:00
# Colonnes à afficher:
with_col_abs = prefs["bul_show_abs_modules"]
with_col_minmax = (
prefs["bul_show_minmax"]
or prefs["bul_show_minmax_mod"]
or prefs["bul_show_minmax_eval"]
)
with_col_moypromo = prefs["bul_show_moypromo"]
with_col_rang = prefs["bul_show_rangs"]
with_col_coef = prefs["bul_show_coef"] or prefs["bul_show_ue_coef"]
2020-09-26 16:19:37 +02:00
with_col_ects = prefs["bul_show_ects"]
2022-02-21 19:25:38 +01:00
col_keys = ["titre", "module"] # noms des colonnes à afficher
2020-09-26 16:19:37 +02:00
if with_col_rang:
2022-02-21 19:25:38 +01:00
col_keys += ["rang"]
2020-09-26 16:19:37 +02:00
if with_col_minmax:
2022-02-21 19:25:38 +01:00
col_keys += ["min"]
2020-09-26 16:19:37 +02:00
if with_col_moypromo:
2022-02-21 19:25:38 +01:00
col_keys += ["moy"]
2020-09-26 16:19:37 +02:00
if with_col_minmax:
2022-02-21 19:25:38 +01:00
col_keys += ["max"]
col_keys += ["note"]
2020-09-26 16:19:37 +02:00
if with_col_coef:
2022-02-21 19:25:38 +01:00
col_keys += ["coef"]
2020-09-26 16:19:37 +02:00
if with_col_ects:
2022-02-21 19:25:38 +01:00
col_keys += ["ects"]
2020-09-26 16:19:37 +02:00
if with_col_abs:
2022-02-21 19:25:38 +01:00
col_keys += ["abs"]
2020-09-26 16:19:37 +02:00
colidx = {} # { nom_colonne : indice à partir de 0 } (pour styles platypus)
i = 0
2022-02-21 19:25:38 +01:00
for k in col_keys:
2020-09-26 16:19:37 +02:00
colidx[k] = i
i += 1
if prefs["bul_pdf_mod_colwidth"]:
bul_pdf_mod_colwidth = float(prefs["bul_pdf_mod_colwidth"]) * cm
else:
bul_pdf_mod_colwidth = None
2022-02-21 19:25:38 +01:00
col_widths = {
2020-09-26 16:19:37 +02:00
"titre": None,
"module": bul_pdf_mod_colwidth,
"min": 1.5 * cm,
"moy": 1.5 * cm,
"max": 1.5 * cm,
"rang": 2.2 * cm,
"note": 2 * cm,
"coef": 1.5 * cm,
"ects": 1.5 * cm,
"abs": 2.0 * cm,
}
# HTML specific
linktmpl = (
'<span onclick="toggle_vis_ue(this);" class="toggle_ue">%s</span>&nbsp;'
)
2020-12-28 14:43:12 +01:00
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")
2020-09-26 16:19:37 +02:00
# 1er ligne titres
t = {
"min": "Promotion",
"moy": "",
"max": "",
"rang": "Rang",
"note": "Note/20",
"coef": "Coef.",
"ects": "ECTS",
"abs": "Abs.",
"_min_colspan": 2,
"_css_row_class": "note_bold",
"_pdf_row_markup": ["b"],
"_pdf_style": [],
}
if with_col_moypromo and not with_col_minmax:
t["moy"] = "Promotion"
P.append(t)
# 2eme ligne titres si nécessaire
if with_col_minmax or with_col_abs:
t = {
"min": "min.",
2020-09-26 16:19:37 +02:00
"moy": "moy.",
"max": "max.",
2020-09-26 16:19:37 +02:00
"abs": "(Tot. / J.)",
"_css_row_class": "note_bold",
"_pdf_row_markup": ["b"],
"_pdf_style": [],
}
P.append(t)
P[-1]["_pdf_style"].append(
("LINEBELOW", (0, 0), (-1, 0), self.PDF_LINEWIDTH, self.PDF_LINECOLOR)
)
# Espacement sous la ligne moyenne générale:
P[-1]["_pdf_style"].append(("BOTTOMPADDING", (0, 1), (-1, 1), 8))
2020-09-26 16:19:37 +02:00
# Moyenne générale:
nbabs = I["nbabs"]
nbabsjust = I["nbabsjust"]
t = {
"titre": "Moyenne générale:",
"rang": I["rang_nt"],
2022-03-14 10:56:25 +01:00
"note": I.get("moy_gen", "-"),
"min": I.get("moy_min", "-"),
"max": I.get("moy_max", "-"),
"moy": I.get("moy_moy", "-"),
2020-09-26 16:19:37 +02:00
"abs": "%s / %s" % (nbabs, nbabsjust),
"_css_row_class": "notes_bulletin_row_gen",
"_titre_colspan": 2,
"_pdf_row_markup": ["b"], # bold. On peut ajouter 'font size="12"'
"_pdf_style": [
("LINEABOVE", (0, 1), (-1, 1), 1, self.PDF_LINECOLOR),
],
2020-09-26 16:19:37 +02:00
}
P.append(t)
# Rangs dans les partitions:
2021-08-19 10:28:35 +02:00
partitions, _ = sco_groups.get_formsemestre_groups(formsemestre_id)
2020-09-26 16:19:37 +02:00
for partition in partitions:
if partition["bul_show_rank"]:
partition_id = partition["partition_id"]
P.append(
{
"titre": "Rang dans %s %s: %s / %s inscrits"
% (
partition["partition_name"],
I["gr_name"][partition_id],
I["rang_gr"][partition_id],
I["ninscrits_gr"][partition_id],
),
"_titre_colspan": 3,
"_css_row_class": "notes_bulletin_row_rang",
}
)
# Chaque UE:
for ue in I["ues"]:
ue_type = None
2022-03-22 19:18:25 +01:00
coef_ue = ue["coef_ue_txt"] if prefs["bul_show_ue_coef"] else ""
2020-09-26 16:19:37 +02:00
ue_descr = ue["ue_descr_txt"]
rowstyle = ""
plusminus = minuslink #
if ue["ue_status"]["is_capitalized"]:
# UE capitalisée meilleure que UE courante:
if prefs["bul_show_ue_cap_details"]:
hidden = False
cssstyle = ""
plusminus = minuslink
else:
hidden = True
cssstyle = "sco_hide"
plusminus = pluslink
try:
ects_txt = str(int(ue["ects"]))
2023-01-10 13:52:11 +01:00
except (ValueError, KeyError, TypeError):
2020-09-26 16:19:37 +02:00
ects_txt = "-"
t = {
2022-06-29 09:08:31 +02:00
"titre": ue["acronyme"] + " " + (ue["titre"] or ""),
2022-02-10 11:54:03 +01:00
"_titre_html": plusminus
2022-06-30 09:31:05 +02:00
+ (ue["acronyme"] or "")
2022-02-10 11:54:03 +01:00
+ " "
2022-06-30 09:31:05 +02:00
+ (ue["titre"] or "")
2022-02-10 11:54:03 +01:00
+ ' <span class="bul_ue_descr">'
2022-06-30 09:31:05 +02:00
+ (ue["ue_descr_txt"] or "")
2022-02-10 11:54:03 +01:00
+ "</span>",
2022-06-30 09:31:05 +02:00
"_titre_help": ue["ue_descr_txt"] or "",
2020-09-26 16:19:37 +02:00
"_titre_colspan": 2,
"module": ue_descr,
"note": ue["moy_ue_txt"],
"coef": coef_ue,
"ects": ects_txt,
"_css_row_class": "notes_bulletin_row_ue",
"_tr_attrs": 'style="background-color: %s"' % self.ue_color_rgb(),
"_pdf_row_markup": ["b"],
"_pdf_style": [
("BACKGROUND", (0, 0), (-1, 0), self.ue_color()),
("LINEABOVE", (0, 0), (-1, 0), 1, self.PDF_LINECOLOR),
],
}
P.append(t)
# Notes de l'UE capitalisée obtenues antérieurement:
self._list_modules(
ue["modules_capitalized"],
matieres_modules=self.infos["matieres_modules_capitalized"],
ue_type=ue_type,
P=P,
prefs=prefs,
rowstyle=" bul_row_ue_cap %s" % cssstyle,
hidden=hidden,
)
ue_type = "cur"
ue_descr = ""
rowstyle = (
" bul_row_ue_cur" # style css pour indiquer UE non prise en compte
)
try:
ects_txt = str(int(ue["ects"]))
except:
ects_txt = "-"
2022-02-12 10:34:36 +01:00
titre = f"{ue['acronyme'] or ''} {ue['titre'] or ''}"
2020-09-26 16:19:37 +02:00
t = {
2022-02-12 10:34:36 +01:00
"titre": titre,
"_titre_html": minuslink + titre,
2020-09-26 16:19:37 +02:00
"_titre_colspan": 2,
"module": ue["titre"],
"rang": ue_descr,
"note": ue["cur_moy_ue_txt"],
"coef": coef_ue,
"ects": ects_txt,
"_css_row_class": "notes_bulletin_row_ue",
"_tr_attrs": 'style="background-color: %s"'
% self.ue_color_rgb(ue_type=ue["type"]),
"_pdf_row_markup": ["b"],
"_pdf_style": [
("BACKGROUND", (0, 0), (-1, 0), self.ue_color(ue_type=ue["type"])),
("LINEABOVE", (0, 0), (-1, 0), 1, self.PDF_LINECOLOR),
],
}
if ue_type == "cur":
t["module"] = "(en cours, non prise en compte)"
t["_css_row_class"] += " notes_bulletin_row_ue_cur"
t["_titre_help"] = "(en cours, non prise en compte)"
if prefs["bul_show_minmax"]:
2020-12-28 14:43:12 +01:00
t["min"] = scu.fmt_note(ue["min"])
t["max"] = scu.fmt_note(ue["max"])
2020-09-26 16:19:37 +02:00
if prefs["bul_show_moypromo"]:
2020-12-28 14:43:12 +01:00
t["moy"] = scu.fmt_note(ue["moy"]).replace("NA", "-")
2020-09-26 16:19:37 +02:00
# Cas particulier des UE sport (bonus)
if ue["type"] == UE_SPORT and not ue_descr:
del t["module"]
del t["coef"]
t["_pdf_style"].append(("SPAN", (colidx["note"], 0), (-1, 0)))
# t["_module_colspan"] = 3 # non car bug si aucune colonne additionnelle
2020-09-26 16:19:37 +02:00
# UE électives
if ue["type"] == UE_ELECTIVE:
t["module"] += " <i>(élective)</i>"
if ue["modules"]:
if (
ue_type != "cur" or prefs["bul_show_ue_cap_current"]
): # ne montre pas UE en cours et capitalisée, sauf si forcé
P.append(t)
self._list_modules(
ue["modules"],
matieres_modules=self.infos["matieres_modules"],
ue_type=ue_type,
P=P,
prefs=prefs,
rowstyle=rowstyle,
)
# Ligne somme ECTS
if with_col_ects:
t = {
"titre": "Crédits ECTS acquis:",
"ects": str(int(I["sum_ects"])), # incluant les UE capitalisees
"_css_row_class": "notes_bulletin_row_sum_ects",
"_pdf_row_markup": ["b"], # bold
"_pdf_style": [
("BACKGROUND", (0, 0), (-1, 0), self.PDF_LIGHT_GRAY),
("LINEABOVE", (0, 0), (-1, 0), 1, self.PDF_LINECOLOR),
],
}
P.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:
]
#
2022-02-21 19:25:38 +01:00
return col_keys, P, pdf_style, col_widths
2020-09-26 16:19:37 +02:00
def _list_modules(
self,
ue_modules,
matieres_modules={},
ue_type=None,
P=None,
prefs=None,
rowstyle="",
hidden=False,
):
"""Liste dans la table les descriptions des modules et, si version != short, des évaluations."""
2020-09-26 16:19:37 +02:00
if ue_type == "cur": # UE courante non prise en compte (car capitalisee)
pdf_style_bg = [("BACKGROUND", (0, 0), (-1, 0), self.PDF_UE_CUR_BG)]
else:
pdf_style_bg = []
pdf_style = pdf_style_bg + [
("LINEABOVE", (0, 0), (-1, 0), 1, self.PDF_MODSEPCOLOR),
("SPAN", (0, 0), (1, 0)),
]
if ue_type == "cur": # UE courante non prise en compte (car capitalisee)
pdf_style.append(("BACKGROUND", (0, 0), (-1, 0), self.PDF_UE_CUR_BG))
last_matiere_id = None
for mod in ue_modules:
if mod["mod_moy_txt"] == "NI":
continue # saute les modules où on n'est pas inscrit
# Matière:
matiere_id = mod["module"]["matiere_id"]
if prefs["bul_show_matieres"] and matiere_id != last_matiere_id:
mat = matieres_modules[matiere_id]
P.append(
{
"titre": mat["titre"],
#'_titre_help' : matiere_id,
"_titre_colspan": 2,
"note": mat["moy_txt"],
"_css_row_class": "notes_bulletin_row_mat%s" % rowstyle,
"_pdf_style": pdf_style_bg
+ [("LINEABOVE", (0, 0), (-1, 0), 2, self.PDF_MODSEPCOLOR)],
"_pdf_row_markup": ['font color="darkblue"'],
}
)
last_matiere_id = matiere_id
#
t = {
"titre": mod["code_txt"] + " " + mod["name"],
"_titre_colspan": 2,
"rang": mod["mod_rang_txt"], # vide si pas option rang
"note": mod["mod_moy_txt"],
"coef": mod["mod_coef_txt"] if prefs["bul_show_coef"] else "",
# vide si pas option show abs module:
"abs": mod.get("mod_abs_txt", ""),
"_css_row_class": f"notes_bulletin_row_mod{rowstyle}",
"_titre_target": url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=mod["moduleimpl_id"],
),
2020-09-26 16:19:37 +02:00
"_titre_help": mod["mod_descr_txt"],
"_hidden": hidden,
"_pdf_style": pdf_style,
}
if prefs["bul_show_minmax_mod"]:
2020-12-28 14:43:12 +01:00
t["min"] = scu.fmt_note(mod["stats"]["min"])
t["max"] = scu.fmt_note(mod["stats"]["max"])
2020-09-26 16:19:37 +02:00
if prefs["bul_show_moypromo"]:
2020-12-28 14:43:12 +01:00
t["moy"] = scu.fmt_note(mod["stats"]["moy"]).replace("NA", "-")
2020-09-26 16:19:37 +02:00
P.append(t)
if self.version != "short":
# --- notes de chaque eval:
nbeval = self._list_evals(
mod["evaluations"], P, rowstyle, pdf_style_bg, hidden, prefs=prefs
)
# evals futures ou incomplètes:
nbeval += self._list_evals(
mod["evaluations_incompletes"],
P,
rowstyle,
pdf_style_bg,
hidden,
incomplete=True,
prefs=prefs,
)
if nbeval: # boite autour des évaluations (en pdf)
2020-09-26 16:19:37 +02:00
P[-1]["_pdf_style"].append(
("BOX", (1, 1 - nbeval), (-1, 0), 0.2, self.PDF_LIGHT_GRAY)
)
def _list_evals(
self,
evals,
P,
rowstyle="",
pdf_style_bg=[],
hidden=False,
incomplete=False,
prefs={},
):
if incomplete: # style special pour evaluations incompletes:
rowstyle += " notes_bulletin_row_eval_incomplete"
pdf_row_markup = ['font color="red"']
else:
pdf_row_markup = []
# --- notes de chaque eval:
nbeval = 0
for e in evals:
2021-08-11 00:36:07 +02:00
if e["visibulletin"] or self.version == "long":
2020-09-26 16:19:37 +02:00
if nbeval == 0:
eval_style = " b_eval_first"
else:
eval_style = ""
t = {
"module": '<bullet indent="2mm">&bull;</bullet>&nbsp;' + e["name"],
"coef": (
(
f"<i>{e['coef_txt']}</i>"
if e["evaluation_type"] != Evaluation.EVALUATION_BONUS
else "bonus"
)
if prefs["bul_show_coef"]
else ""
),
2020-09-26 16:19:37 +02:00
"_hidden": hidden,
"_module_target": e["target_html"],
# '_module_help' : ,
"_css_row_class": "notes_bulletin_row_eval" + eval_style + rowstyle,
"_pdf_style": pdf_style_bg[:],
"_pdf_row_markup": pdf_row_markup,
}
if e["note_txt"]:
t["note"] = "<i>" + e["note_txt"] + "</i>"
else:
t["_module_colspan"] = 2
2020-12-28 14:43:12 +01:00
if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]:
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
2020-12-28 14:43:12 +01:00
if prefs["bul_show_minmax_eval"]:
t["min"] = etat["mini"]
t["max"] = etat["maxi"]
if prefs["bul_show_moypromo"]:
t["moy"] = etat["moy"]
2020-09-26 16:19:37 +02:00
P.append(t)
nbeval += 1
return nbeval
2021-08-29 19:57:32 +02:00
# sco_bulletins_generator.register_bulletin_class(BulletinGeneratorStandard)