698 lines
26 KiB
Python
698 lines
26 KiB
Python
# -*- mode: python -*-
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
|
#
|
|
# Gestion scolarite IUT
|
|
#
|
|
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
|
#
|
|
# 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 url_for, g
|
|
|
|
from reportlab.platypus import KeepTogether, Paragraph, Spacer, Table
|
|
from reportlab.lib.units import cm, mm
|
|
from reportlab.lib.colors import Color, blue
|
|
|
|
import app.scodoc.sco_utils as scu
|
|
from app.scodoc.sco_pdf import SU, make_paras
|
|
from app.scodoc import sco_preferences
|
|
from app.scodoc.sco_permissions import Permission
|
|
from app.scodoc.codes_cursus import (
|
|
UE_COLORS,
|
|
UE_DEFAULT_COLOR,
|
|
UE_ELECTIVE,
|
|
UE_SPORT,
|
|
UE_STANDARD,
|
|
)
|
|
from app.scodoc import sco_bulletins_generator
|
|
from app.scodoc import sco_bulletins_pdf
|
|
from app.scodoc import sco_groups
|
|
from app.scodoc import sco_evaluations
|
|
from app.scodoc import gen_tables
|
|
|
|
# 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)
|
|
class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
|
|
description = "standard ScoDoc (version 2011)" # la description doit être courte: elle apparait dans le menu de paramètrage ScoDoc
|
|
supported_formats = ["html", "pdf"]
|
|
|
|
def bul_title_pdf(self) -> 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
|
|
)
|
|
objects.append(
|
|
Spacer(1, 5 * mm)
|
|
) # impose un espace vertical entre le titre et la table qui suit
|
|
return objects
|
|
|
|
def bul_table(self, format="html"):
|
|
"""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),
|
|
html_class="notes_bulletin",
|
|
html_class_ignore_default=True,
|
|
html_with_td_classes=True,
|
|
)
|
|
|
|
return T.gen(format=format)
|
|
|
|
def bul_part_below(self, format="html"):
|
|
"""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
|
|
# ----- ABSENCES
|
|
if self.preferences["bul_show_abs"]:
|
|
nbabs = self.infos["nbabs"]
|
|
story.append(Spacer(1, 2 * mm))
|
|
if nbabs:
|
|
H.append(
|
|
"""<p class="bul_abs">
|
|
<a href="../Absences/CalAbs?etudid=%(etudid)s" class="bull_link">
|
|
<b>Absences :</b> %(nbabs)s demi-journées, dont %(nbabsjust)s justifiées
|
|
(pendant ce semestre).
|
|
</a></p>
|
|
"""
|
|
% self.infos
|
|
)
|
|
story.append(
|
|
Paragraph(
|
|
SU(
|
|
"%(nbabs)s absences (1/2 journées), dont %(nbabsjust)s justifiées."
|
|
% self.infos
|
|
),
|
|
self.CellStyle,
|
|
)
|
|
)
|
|
else:
|
|
H.append("""<p class="bul_abs">Pas d'absences signalées.</p>""")
|
|
story += make_paras("Pas d'absences signalées.", self.CellStyle)
|
|
|
|
# ---- APPRECIATIONS
|
|
# le dir. des etud peut ajouter des appreciations,
|
|
# mais aussi le chef (perm. ScoEtudInscrit)
|
|
can_edit_app = (self.authuser.id in self.infos["responsables"]) or (
|
|
self.authuser.has_permission(Permission.ScoEtudInscrit)
|
|
)
|
|
H.append('<div class="bull_appreciations">')
|
|
for app in self.infos["appreciations_list"]:
|
|
if can_edit_app:
|
|
mlink = (
|
|
'<a class="stdlink" href="appreciation_add_form?id=%s">modifier</a> <a class="stdlink" href="appreciation_add_form?id=%s&suppress=1">supprimer</a>'
|
|
% (app["id"], app["id"])
|
|
)
|
|
else:
|
|
mlink = ""
|
|
H.append(
|
|
'<p><span class="bull_appreciations_date">%s</span>%s<span class="bull_appreciations_link">%s</span></p>'
|
|
% (app["date"], app["comment"], mlink)
|
|
)
|
|
if can_edit_app:
|
|
H.append(
|
|
'<p><a class="stdlink" href="appreciation_add_form?etudid=%(etudid)s&formsemestre_id=%(formsemestre_id)s">Ajouter une appréciation</a></p>'
|
|
% self.infos
|
|
)
|
|
H.append("</div>")
|
|
# Appréciations sur PDF:
|
|
if self.infos.get("appreciations_list", False):
|
|
story.append(Spacer(1, 3 * mm))
|
|
story.append(
|
|
Paragraph(
|
|
SU("Appréciation : " + "\n".join(self.infos["appreciations_txt"])),
|
|
self.CellStyle,
|
|
)
|
|
)
|
|
|
|
# ----- DECISION JURY
|
|
if self.preferences["bul_show_decision"]:
|
|
story += sco_bulletins_pdf.process_field(
|
|
self.preferences["bul_pdf_caption"],
|
|
self.infos,
|
|
self.FieldStyle,
|
|
format="pdf",
|
|
)
|
|
field = sco_bulletins_pdf.process_field(
|
|
self.preferences["bul_pdf_caption"],
|
|
self.infos,
|
|
self.FieldStyle,
|
|
format="html",
|
|
)
|
|
H.append('<div class="bul_decision">' + field + "</div>")
|
|
|
|
# -----
|
|
if format == "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 format == "html":
|
|
return "\n".join(H)
|
|
|
|
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"]
|
|
if self.with_img_signatures_pdf and (show_left or show_right):
|
|
if show_left:
|
|
L = [
|
|
[
|
|
sco_bulletins_pdf.process_field(
|
|
self.preferences["bul_pdf_sig_left"],
|
|
self.infos,
|
|
self.FieldStyle,
|
|
)
|
|
]
|
|
]
|
|
else:
|
|
L = [[""]]
|
|
if show_right:
|
|
L[0].append(
|
|
sco_bulletins_pdf.process_field(
|
|
self.preferences["bul_pdf_sig_right"],
|
|
self.infos,
|
|
self.FieldStyle,
|
|
)
|
|
)
|
|
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):
|
|
"""Génère la table centrale du bulletin de notes classique (pas BUT)
|
|
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
|
|
"""
|
|
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)
|
|
|
|
# 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"]
|
|
with_col_ects = prefs["bul_show_ects"]
|
|
|
|
col_keys = ["titre", "module"] # noms des colonnes à afficher
|
|
if with_col_rang:
|
|
col_keys += ["rang"]
|
|
if with_col_minmax:
|
|
col_keys += ["min"]
|
|
if with_col_moypromo:
|
|
col_keys += ["moy"]
|
|
if with_col_minmax:
|
|
col_keys += ["max"]
|
|
col_keys += ["note"]
|
|
if with_col_coef:
|
|
col_keys += ["coef"]
|
|
if with_col_ects:
|
|
col_keys += ["ects"]
|
|
if with_col_abs:
|
|
col_keys += ["abs"]
|
|
colidx = {} # { nom_colonne : indice à partir de 0 } (pour styles platypus)
|
|
i = 0
|
|
for k in col_keys:
|
|
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
|
|
col_widths = {
|
|
"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> '
|
|
)
|
|
minuslink = linktmpl % scu.icontag("minus_img", border="0", alt="-")
|
|
pluslink = linktmpl % scu.icontag("plus_img", border="0", alt="+")
|
|
|
|
# 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.",
|
|
"moy": "moy.",
|
|
"max": "max.",
|
|
"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))
|
|
# Moyenne générale:
|
|
nbabs = I["nbabs"]
|
|
nbabsjust = I["nbabsjust"]
|
|
t = {
|
|
"titre": "Moyenne générale:",
|
|
"rang": I["rang_nt"],
|
|
"note": I.get("moy_gen", "-"),
|
|
"min": I.get("moy_min", "-"),
|
|
"max": I.get("moy_max", "-"),
|
|
"moy": I.get("moy_moy", "-"),
|
|
"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),
|
|
],
|
|
}
|
|
P.append(t)
|
|
|
|
# Rangs dans les partitions:
|
|
partitions, _ = sco_groups.get_formsemestre_groups(formsemestre_id)
|
|
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
|
|
coef_ue = ue["coef_ue_txt"] if prefs["bul_show_ue_coef"] else ""
|
|
|
|
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"]))
|
|
except (ValueError, KeyError, TypeError):
|
|
ects_txt = "-"
|
|
|
|
t = {
|
|
"titre": ue["acronyme"] + " " + (ue["titre"] or ""),
|
|
"_titre_html": plusminus
|
|
+ (ue["acronyme"] or "")
|
|
+ " "
|
|
+ (ue["titre"] or "")
|
|
+ ' <span class="bul_ue_descr">'
|
|
+ (ue["ue_descr_txt"] or "")
|
|
+ "</span>",
|
|
"_titre_help": ue["ue_descr_txt"] or "",
|
|
"_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 = "-"
|
|
titre = f"{ue['acronyme'] or ''} {ue['titre'] or ''}"
|
|
t = {
|
|
"titre": titre,
|
|
"_titre_html": minuslink + titre,
|
|
"_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"]:
|
|
t["min"] = scu.fmt_note(ue["min"])
|
|
t["max"] = scu.fmt_note(ue["max"])
|
|
if prefs["bul_show_moypromo"]:
|
|
t["moy"] = scu.fmt_note(ue["moy"]).replace("NA", "-")
|
|
# 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
|
|
# 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:
|
|
]
|
|
#
|
|
return col_keys, P, pdf_style, col_widths
|
|
|
|
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."""
|
|
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"],
|
|
),
|
|
"_titre_help": mod["mod_descr_txt"],
|
|
"_hidden": hidden,
|
|
"_pdf_style": pdf_style,
|
|
}
|
|
if prefs["bul_show_minmax_mod"]:
|
|
t["min"] = scu.fmt_note(mod["stats"]["min"])
|
|
t["max"] = scu.fmt_note(mod["stats"]["max"])
|
|
if prefs["bul_show_moypromo"]:
|
|
t["moy"] = scu.fmt_note(mod["stats"]["moy"]).replace("NA", "-")
|
|
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)
|
|
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:
|
|
if e["visibulletin"] or self.version == "long":
|
|
if nbeval == 0:
|
|
eval_style = " b_eval_first"
|
|
else:
|
|
eval_style = ""
|
|
t = {
|
|
"module": '<bullet indent="2mm">•</bullet> ' + e["name"],
|
|
"coef": ("<i>" + e["coef_txt"] + "</i>")
|
|
if prefs["bul_show_coef"]
|
|
else "",
|
|
"_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
|
|
if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]:
|
|
etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
|
|
if prefs["bul_show_minmax_eval"]:
|
|
t["min"] = scu.fmt_note(etat["mini"])
|
|
t["max"] = scu.fmt_note(etat["maxi"])
|
|
if prefs["bul_show_moypromo"]:
|
|
t["moy"] = scu.fmt_note(etat["moy"])
|
|
P.append(t)
|
|
nbeval += 1
|
|
return nbeval
|
|
|
|
|
|
# sco_bulletins_generator.register_bulletin_class(BulletinGeneratorStandard)
|