diff --git a/app/api/etudiants.py b/app/api/etudiants.py index c6d8cf2b6..af0aa32f1 100644 --- a/app/api/etudiants.py +++ b/app/api/etudiants.py @@ -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, diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index ca0c4ead3..481393c5e 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -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( diff --git a/app/but/bulletin_but_pdf.py b/app/but/bulletin_but_pdf.py index 0916e6cbd..cd78a9e8b 100644 --- a/app/but/bulletin_but_pdf.py +++ b/app/but/bulletin_but_pdf.py @@ -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"""{moy_ue.get("value", "-") - if moy_ue is not None else "-" - }""" - ), + "moyenne": Paragraph(f"""{moy_ue}"""), "_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 - if self.preferences["bul_show_ue_rangs"]: - fields_bmr.append( - f"Rang: {ue['moyenne']['rang']} / {ue['moyenne']['total']}" + + 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"""{ects_txt}"""), + "_coef_pdf": Paragraph(f"""{ects_txt}"""), "_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) diff --git a/app/comp/res_but.py b/app/comp/res_but.py index 9e8719ef9..c65fabc75 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -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) diff --git a/app/models/etudiants.py b/app/models/etudiants.py index 9cfc56a43..b7547a852 100644 --- a/app/models/etudiants.py +++ b/app/models/etudiants.py @@ -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 { diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 1c1694e04..1db285eac 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -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): diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py index 36e69cd68..ec5d258a7 100644 --- a/app/scodoc/sco_bulletins_generator.py +++ b/app/scodoc/sco_bulletins_generator.py @@ -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 diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py index a26397915..f99b2f998 100644 --- a/app/scodoc/sco_bulletins_pdf.py +++ b/app/scodoc/sco_bulletins_pdf.py @@ -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 value + 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 text = re.sub(r"<\s*para(\s*)(.*?)>", r"

", 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" diff --git a/app/scodoc/sco_bulletins_standard.py b/app/scodoc/sco_bulletins_standard.py index da854cbe1..c7c51135c 100644 --- a/app/scodoc/sco_bulletins_standard.py +++ b/app/scodoc/sco_bulletins_standard.py @@ -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('

' + field + "
") diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py index 4b2f5e887..5a2313fae 100644 --- a/app/scodoc/sco_etud.py +++ b/app/scodoc/sco_etud.py @@ -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" : , diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index c71184692..022b470c4 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -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, diff --git a/app/views/notes.py b/app/views/notes.py index ae2a69d37..62071bcf2 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -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",