diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index a533fb80..cba3732b 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -11,7 +11,7 @@ import datetime from flask import url_for, g from app.comp.res_but import ResultatsSemestreBUT -from app.models import FormSemestre, Identite, formsemestre +from app.models import FormSemestre, Identite from app.scodoc import sco_bulletins, sco_utils as scu from app.scodoc import sco_bulletins_json from app.scodoc import sco_bulletins_pdf @@ -171,6 +171,10 @@ class BulletinBUT: # eval_notes est une pd.Series avec toutes les notes des étudiants inscrits eval_notes = self.res.modimpls_results[e.moduleimpl_id].evals_notes[e.id] notes_ok = eval_notes.where(eval_notes > scu.NOTES_ABSENCE).dropna() + poids = { + ue.acronyme: self.res.modimpls_evals_poids[e.moduleimpl_id][ue.id][e.id] + for ue in self.res.ues + } d = { "id": e.id, "description": e.description, @@ -178,7 +182,7 @@ class BulletinBUT: "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": fmt_note(e.coefficient), - "poids": {p.ue.acronyme: p.poids for p in e.ue_poids}, + "poids": poids, "note": { "value": fmt_note( eval_notes[etud.id], @@ -330,11 +334,13 @@ class BulletinBUT: return d - def bulletin_etud_complet(self, etud: Identite) -> dict: + def bulletin_etud_complet(self, etud: Identite, version="long") -> dict: """Bulletin dict complet avec toutes les infos pour les bulletins BUT pdf Résultat compatible avec celui de sco_bulletins.formsemestre_bulletinetud_dict """ - d = self.bulletin_etud(etud, self.res.formsemestre, force_publishing=True) + d = self.bulletin_etud( + etud, self.res.formsemestre, version=version, force_publishing=True + ) d["etudid"] = etud.id d["etud"] = d["etudiant"] d["etud"]["nomprenom"] = etud.nomprenom diff --git a/app/but/bulletin_but_pdf.py b/app/but/bulletin_but_pdf.py index 6a317684..ea3291c8 100644 --- a/app/but/bulletin_but_pdf.py +++ b/app/but/bulletin_but_pdf.py @@ -6,8 +6,7 @@ """Génération bulletin BUT au format PDF standard """ -import itertools -from reportlab.platypus import KeepInFrame, Paragraph, Spacer +from reportlab.platypus import Paragraph, Spacer from app.scodoc.sco_pdf import blue, cm, mm @@ -35,11 +34,14 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): tables_infos = [ # ---- TABLE SYNTHESE UES self.but_table_synthese_ues(), - # ---- TABLE RESSOURCES - self.but_table_ressources(), - # ---- TABLE SAE - self.but_table_saes(), ] + if self.version != "short": + tables_infos += [ + # ---- 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( @@ -82,6 +84,7 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): "titre": "Unités d'enseignement", "moyenne": "Note/20", "coef": "Coef.", + "_coef_pdf": Paragraph("Coef."), "_css_row_class": "note_bold", "_pdf_row_markup": ["b"], "_pdf_style": [ @@ -97,7 +100,7 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): ], } ] - col_keys = ["titre", "moyenne", "coef"] # noms des colonnes à afficher + col_keys = ["titre", "coef", "moyenne"] # noms des colonnes à afficher for ue_acronym, ue in self.infos["ues"].items(): # 1er ligne titre UE moy_ue = ue.get("moyenne") @@ -120,16 +123,16 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): } rows.append(t) # 2eme ligne titre UE (bonus/malus/ects) + ects_txt = f'ECTS: {ue["ECTS"]["acquis"]:.3g} / {ue["ECTS"]["total"]:.3g}' t = { "titre": f"""Bonus: {ue['bonus']} - Malus: { ue["malus"]}""", - "moyenne": f"""ECTS: {ue["ECTS"]["acquis"]} / {ue["ECTS"]["total"]}""", - "_moyenne_colspan": 2, + "coef": ects_txt, + "_coef_pdf": Paragraph(f"""{ects_txt}"""), + "_coef_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", @@ -138,6 +141,14 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): self.PDF_LINEWIDTH, self.PDF_LINECOLOR, ), + # cadre autour du bonus/malus + ( + "BOX", + (0, 0), + (0, 0), + self.PDF_LINEWIDTH, + (0.7, 0.7, 0.7), # gris clair + ), ], } rows.append(t) @@ -192,40 +203,54 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): - pdf_style : commandes table Platypus - largeurs de colonnes pour PDF """ + poids_fontsize = "8" + # UE à utiliser pour les poids (# colonne/UE) + ue_acros = list(self.infos["ues"].keys()) # ['RT1.1', 'RT2.1', 'RT3.1'] + # Colonnes à afficher: + col_keys = ["titre"] + ue_acros + ["coef", "moyenne"] + # Largeurs des colonnes: col_widths = { "titre": None, + # "poids": None, "moyenne": 2 * cm, "coef": 2 * cm, } + for ue_acro in ue_acros: + col_widths[ue_acro] = 12 * mm # largeur col. poids + 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 + # Ligne de titres + t = { + "titre": title, + # "_titre_colspan": 1 + len(ue_acros), + "moyenne": "Note/20", + "coef": "Coef.", + "_coef_pdf": Paragraph("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, + ), + ], + } + for ue_acro in ue_acros: + t[ue_acro] = Paragraph( + f"{ue_acro}" + ) + rows = [t] 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 + "_titre_colspan": 2 + len(ue_acros), "_css_row_class": "note_bold", "_pdf_row_markup": ["b"], "_pdf_style": [ @@ -248,7 +273,7 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): "moyenne": e["note"]["value"], "coef": e["coef"], "_coef_pdf": Paragraph( - f"{e['coef']}" + f"{e['coef']}" ), "_pdf_style": [ ( @@ -260,6 +285,21 @@ class BulletinGeneratorStandardBUT(BulletinGeneratorStandard): ) ], } + col_idx = 1 # 1ere col. poids + for ue_acro in ue_acros: + t[ue_acro] = Paragraph( + f"""{e["poids"].get(ue_acro, "")}""" + ) + t["_pdf_style"].append( + ( + "BOX", + (col_idx, 0), + (col_idx, 0), + self.PDF_LINEWIDTH, + (0.7, 0.7, 0.7), # gris clair + ), + ) + col_idx += 1 rows.append(t) # Global pdf style commands: pdf_style = [ diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index efbe7cd3..6d80f0b7 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -197,6 +197,7 @@ def notes_sem_load_cube(formsemestre: FormSemestre) -> tuple: evals_poids, _ = moy_mod.load_evaluations_poids(modimpl.id) etuds_moy_module = mod_results.compute_module_moy(evals_poids) modimpls_results[modimpl.id] = mod_results + modimpls_evals_poids[modimpl.id] = evals_poids modimpls_notes.append(etuds_moy_module) if len(modimpls_notes): cube = notes_sem_assemble_cube(modimpls_notes) diff --git a/app/scodoc/gen_tables.py b/app/scodoc/gen_tables.py index 72326132..0a4b65ca 100644 --- a/app/scodoc/gen_tables.py +++ b/app/scodoc/gen_tables.py @@ -63,12 +63,15 @@ from app.scodoc.sco_pdf import SU from app import log -def mark_paras(L, tags): - """Put each (string) element of L between """ +def mark_paras(L, tags) -> list[str]: + """Put each (string) element of L between ..., + for each supplied tag. + Leave non string elements untouched. + """ for tag in tags: - b = "<" + tag + ">" - c = "" + tag.split()[0] + ">" - L = [b + (x or "") + c for x in L] + start = "<" + tag + ">" + end = "" + tag.split()[0] + ">" + L = [(start + (x or "") + end) if isinstance(x, str) else x for x in L] return L diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 65dcb3a9..b9ebdfcc 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -885,7 +885,7 @@ def do_formsemestre_bulletinetud( if formsemestre.formation.is_apc(): etud = Identite.query.get(etudid) r = bulletin_but.BulletinBUT(formsemestre) - I = r.bulletin_etud_complet(etud) + I = r.bulletin_etud_complet(etud, version=version) else: I = formsemestre_bulletinetud_dict(formsemestre.id, etudid) etud = I["etud"] @@ -980,7 +980,7 @@ def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr): except KeyError as e: raise ScoValueError( "format 'Message d'accompagnement' (bul_intro_mail) invalide, revoir les réglages dans les préférences" - ) + ) from e else: hea = "" @@ -1011,97 +1011,6 @@ def mail_bulletin(formsemestre_id, I, pdfdata, filename, recipient_addr): ) -def _formsemestre_bulletinetud_header_html_old_XXX( - etud: Identite, - formsemestre: FormSemestre, - format=None, - version=None, -): - H = [ - html_sco_header.sco_header( - page_title=f"Bulletin de {etud.nomprenom}", - javascripts=[ - "js/bulletin.js", - "libjs/d3.v3.min.js", - "js/radar_bulletin.js", - ], - cssstyles=["css/radar_bulletin.css"], - ), - f""" - {etud.nomprenom} - - - Bulletin {formsemestre.titre_mois()} - - - établi le {time.strftime("%d/%m/%Y à %Hh%M")} (notes sur 20) - - - - - - """, - ] - for (v, e) in ( - ("short", "Version courte"), - ("selectedevals", "Version intermédiaire"), - ("long", "Version complète"), - ): - if v == version: - selected = " selected" - else: - selected = "" - H.append('%s' % (v, selected, e)) - H.append("""""") - # Menu - endpoint = "notes.formsemestre_bulletinetud" - menu_autres_operations = make_menu_autres_operations( - formsemestre, etud, endpoint, version - ) - - H.append("""""") - H.append(menu_autres_operations) - H.append("""""") - H.append( - ' %s' - % ( - url_for( - "notes.formsemestre_bulletinetud", - scodoc_dept=g.scodoc_dept, - formsemestre_id=formsemestre.id, - etudid=etud.id, - format="pdf", - version=version, - ), - scu.ICON_PDF, - ) - ) - H.append("""""") - # - H.append( - """%s - """ - % ( - url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id), - sco_photos.etud_photo_html(etud, title="fiche de " + etud.nomprenom), - ) - ) - H.append( - """ - - """ - ) - - return "".join(H) - - def make_menu_autres_operations( formsemestre: FormSemestre, etud: Identite, endpoint: str, version: str ) -> str: diff --git a/app/views/notes.py b/app/views/notes.py index dfc8e644..345511ce 100644 --- a/app/views/notes.py +++ b/app/views/notes.py @@ -1885,7 +1885,6 @@ def formsemestre_bulletins_choice( formsemestre_id, title="", explanation="", choose_mail=False ): """Choix d'une version de bulletin""" - sem = sco_formsemestre.get_formsemestre(formsemestre_id) H = [ html_sco_header.html_sem_header(title), """