diff --git a/app/but/jury_but.py b/app/but/jury_but.py index 3a797ad83..d07618dd6 100644 --- a/app/but/jury_but.py +++ b/app/but/jury_but.py @@ -689,7 +689,23 @@ class DecisionsProposeesAnnee(DecisionsProposees): dec_rcue.descr_validation() for dec_rcue in self.decisions_rcue_by_niveau.values() ] - return line_sep.join([v for v in validations if v]) + return line_sep.join(v for v in validations if v) + + def descr_ues_validation(self, line_sep: str = "\n") -> str: + """Description textuelle des UE validées (enregistrés) + pour PV jurys + """ + validations = [] + for res in (self.res_impair, self.res_pair): + if res: + dec_ues = [ + self.decisions_ues[ue.id] + for ue in res.ues + if ue.type == UE_STANDARD and ue.id in self.decisions_ues + ] + valids = [dec_ue.descr_validation() for dec_ue in dec_ues] + validations.append(", ".join(v for v in valids if v)) + return line_sep.join(validations) class DecisionsProposeesRCUE(DecisionsProposees): @@ -900,7 +916,7 @@ class DecisionsProposeesUE(DecisionsProposees): def descr_validation(self) -> str: """Description validation niveau enregistrée, pour PV jury. - Si l'UE est validé, done son acronyme, sinon chaine vide. + Si l'UE est validée, donne son acronyme, sinon chaine vide. """ if self.code_valide in sco_codes.CODES_UE_VALIDES: return f"{self.ue.acronyme}" diff --git a/app/but/jury_but_pv.py b/app/but/jury_but_pv.py index 13f61cddb..095c5efc9 100644 --- a/app/but/jury_but_pv.py +++ b/app/but/jury_but_pv.py @@ -44,7 +44,7 @@ def pvjury_table_but(formsemestre_id: int, format="html") -> list[dict]: """ formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) assert formsemestre.formation.is_apc() - title = "Jury BUT annuel" + title = "Procès-verbal de jury BUT annuel" if format == "html": line_sep = "
" @@ -55,6 +55,7 @@ def pvjury_table_but(formsemestre_id: int, format="html") -> list[dict]: titles = { "nom": "Nom", "cursus": "Cursus", + "ues": "UE validées", "niveaux": "Niveaux de compétences validés", "decision_but": f"Décision BUT{annee_but}", "diplome": "Résultat au diplôme", @@ -76,7 +77,15 @@ def pvjury_table_but(formsemestre_id: int, format="html") -> list[dict]: row = { "nom": etud.etat_civil_pv(line_sep=line_sep), "_nom_order": etud.sort_key, + "_nom_target_attrs": f'class="etudinfo" id="{etud.id}"', + "_nom_td_attrs": f'id="{etud.id}" class="etudinfo"', + "_nom_target": url_for( + "scolar.ficheEtud", + scodoc_dept=g.scodoc_dept, + etudid=etud.id, + ), "cursus": _descr_cursus_but(etud), + "ues": deca.descr_ues_validation(line_sep=line_sep) if deca else "-", "niveaux": deca.descr_niveaux_validation(line_sep=line_sep) if deca else "-", @@ -93,21 +102,36 @@ def pvjury_table_but(formsemestre_id: int, format="html") -> list[dict]: xls_style_base["alignment"] = Alignment(wrapText=True, vertical="top") tab = GenTable( - columns_ids=titles.keys(), - rows=rows, - titles=titles, - origin=f"Généré par {scu.sco_version.SCONAME} le {scu.timedate_human_repr()}", + base_url=f"{request.base_url}?formsemestre_id={formsemestre_id}", caption=title, + columns_ids=titles.keys(), html_caption=title, html_class="pvjury_table_but table_leftalign", - # html_class_ignore_default=True, + html_title=f"""
{title} + + version excel
+ + """, html_with_td_classes=True, - xls_style_base=xls_style_base, - base_url=f"{request.base_url}?formsemestre_id={formsemestre_id}", + origin=f"Généré par {scu.sco_version.SCONAME} le {scu.timedate_human_repr()}", page_title=title, - html_title=f"

{title}

", pdf_title=title, preferences=sco_preferences.SemPreferences(), + rows=rows, table_id="formation_table_recap", + titles=titles, + xls_columns_width={ + "nom": 32, + "cursus": 12, + "ues": 32, + "niveaux": 32, + "decision_but": 14, + "diplome": 17, + "devenir": 8, + "observations": 12, + }, + xls_style_base=xls_style_base, ) - return tab.make_page(format=format, javascripts=[]) + return tab.make_page(format=format, javascripts=["js/etud_info.js"], init_qtip=True) diff --git a/app/forms/main/config_logos.py b/app/forms/main/config_logos.py index 0d0ac0d5a..424a2a8a5 100644 --- a/app/forms/main/config_logos.py +++ b/app/forms/main/config_logos.py @@ -43,7 +43,7 @@ from app.scodoc import sco_logos, html_sco_header from app.scodoc import sco_utils as scu from app.scodoc.sco_config_actions import LogoInsert - +from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_logos import find_logo @@ -199,9 +199,12 @@ class LogoForm(FlaskForm): def __init__(self, *args, **kwargs): kwargs["meta"] = {"csrf": False} super().__init__(*args, **kwargs) - self.logo = find_logo( + logo = find_logo( logoname=self.logo_id.data, dept_id=dept_key_to_id(self.dept_key.data) - ).select() + ) + if logo is None: + raise ScoValueError("logo introuvable") + self.logo = logo.select() self.description = None self.titre = None self.can_delete = True diff --git a/app/scodoc/gen_tables.py b/app/scodoc/gen_tables.py index 48e5d0630..0fab06eae 100644 --- a/app/scodoc/gen_tables.py +++ b/app/scodoc/gen_tables.py @@ -45,7 +45,7 @@ import random from collections import OrderedDict from xml.etree import ElementTree import json - +from openpyxl.utils import get_column_letter from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Frame, PageBreak from reportlab.platypus import Table, TableStyle, Image, KeepInFrame from reportlab.lib.colors import Color @@ -128,6 +128,7 @@ class GenTable(object): xls_sheet_name="feuille", xls_before_table=[], # liste de cellules a placer avant la table xls_style_base=None, # style excel pour les cellules + xls_columns_width=None, # { col_id : largeur en "pixels excel" } pdf_title="", # au dessus du tableau en pdf pdf_table_style=None, pdf_col_widths=None, @@ -153,6 +154,7 @@ class GenTable(object): self.pdf_link = pdf_link self.xls_link = xls_link self.xls_style_base = xls_style_base + self.xls_columns_width = xls_columns_width or {} self.xml_link = xml_link # HTML parameters: if not table_id: # random id @@ -508,6 +510,16 @@ class GenTable(object): if self.origin: sheet.append_blank_row() # empty line sheet.append_single_cell_row(self.origin, style_base) + # Largeurs des colonnes + columns_ids = list(self.columns_ids) + for col_id, width in self.xls_columns_width.items(): + try: + idx = columns_ids.index(col_id) + col = get_column_letter(idx + 1) + sheet.set_column_dimension_width(col, width) + except ValueError: + pass + if wb is None: return sheet.generate() diff --git a/app/scodoc/sco_logos.py b/app/scodoc/sco_logos.py index 27ce7573d..e6ba73f15 100644 --- a/app/scodoc/sco_logos.py +++ b/app/scodoc/sco_logos.py @@ -191,6 +191,9 @@ class Logo: ) self.mm = "Not initialized: call the select or create function before access" + def __repr__(self) -> str: + return f"Logo(logoname='{self.logoname}', filename='{self.filename}')" + def _set_format(self, fmt): self.suffix = fmt self.filepath = self.basepath + "." + fmt