Nettoyage code table recap.
This commit is contained in:
parent
3ab0e89c2f
commit
c488ad3a62
@ -542,17 +542,18 @@ class ResultatsSemestre(ResultatsCache):
|
||||
# Le bonus sport appliqué sur cette UE
|
||||
if (self.bonus_ues is not None) and (ue.id in self.bonus_ues):
|
||||
val = self.bonus_ues[ue.id][etud.id] or ""
|
||||
val_fmt = fmt_note(val)
|
||||
val_fmt = val_fmt_html = fmt_note(val)
|
||||
if val:
|
||||
val_fmt = f'<span class="green-arrow-up"></span><span class="sp2l">{val_fmt}</span>'
|
||||
val_fmt_html = f'<span class="green-arrow-up"></span><span class="sp2l">{val_fmt}</span>'
|
||||
idx = add_cell(
|
||||
row,
|
||||
f"bonus_ue_{ue.id}",
|
||||
f"Bonus {ue.acronyme}",
|
||||
val_fmt,
|
||||
val_fmt_html,
|
||||
"col_ue_bonus",
|
||||
idx,
|
||||
)
|
||||
row[f"_bonus_ue_{ue.id}_xls"] = val_fmt
|
||||
# Les moyennes des modules (ou ressources et SAÉs) dans cette UE
|
||||
idx_malus = idx # place pour colonne malus à gauche des modules
|
||||
idx += 1
|
||||
@ -581,20 +582,21 @@ class ResultatsSemestre(ResultatsCache):
|
||||
col_id = (
|
||||
f"moy_{modimpl.module.type_abbrv()}_{modimpl.id}_{ue.id}"
|
||||
)
|
||||
val_fmt = fmt_note(val)
|
||||
val_fmt = val_fmt_html = fmt_note(val)
|
||||
if modimpl.module.module_type == scu.ModuleType.MALUS:
|
||||
val_fmt = (
|
||||
val_fmt_html = (
|
||||
(scu.EMO_RED_TRIANGLE_DOWN + val_fmt) if val else ""
|
||||
)
|
||||
idx = add_cell(
|
||||
row,
|
||||
col_id,
|
||||
modimpl.module.code,
|
||||
val_fmt,
|
||||
val_fmt_html,
|
||||
# class col_res mod_ue_123
|
||||
f"col_{modimpl.module.type_abbrv()} mod_ue_{ue.id}",
|
||||
idx,
|
||||
)
|
||||
row[f"_{col_id}_xls"] = val_fmt
|
||||
if modimpl.module.module_type == scu.ModuleType.MALUS:
|
||||
titles[f"_{col_id}_col_order"] = idx_malus
|
||||
titles_bot[f"_{col_id}_target"] = url_for(
|
||||
@ -611,17 +613,20 @@ class ResultatsSemestre(ResultatsCache):
|
||||
f"_{col_id}_target_attrs"
|
||||
] = f""" title="{modimpl.module.titre} ({nom_resp})" """
|
||||
modimpl_ids.add(modimpl.id)
|
||||
ue_valid_txt = f"{nb_ues_validables}/{len(ues_sans_bonus)}"
|
||||
ue_valid_txt = (
|
||||
ue_valid_txt_html
|
||||
) = f"{nb_ues_validables}/{len(ues_sans_bonus)}"
|
||||
if nb_ues_warning:
|
||||
ue_valid_txt += " " + scu.EMO_WARNING
|
||||
ue_valid_txt_html += " " + scu.EMO_WARNING
|
||||
add_cell(
|
||||
row,
|
||||
"ues_validables",
|
||||
"UEs",
|
||||
ue_valid_txt,
|
||||
ue_valid_txt_html,
|
||||
"col_ue col_ues_validables",
|
||||
29, # juste avant moy. gen.
|
||||
)
|
||||
row["_ues_validables_xls"] = ue_valid_txt
|
||||
if nb_ues_warning:
|
||||
row["_ues_validables_class"] += " moy_ue_warning"
|
||||
elif nb_ues_validables < len(ues_sans_bonus):
|
||||
|
@ -209,7 +209,8 @@ class GenTable(object):
|
||||
omit_hidden_lines=False,
|
||||
pdf_mode=False, # apply special pdf reportlab processing
|
||||
pdf_style_list=[], # modified: list of platypus table style commands
|
||||
):
|
||||
xls_mode=False, # get xls content if available
|
||||
) -> list:
|
||||
"table data as a list of lists (rows)"
|
||||
T = []
|
||||
line_num = 0 # line number in input data
|
||||
@ -237,9 +238,14 @@ class GenTable(object):
|
||||
# if colspan_count > 0:
|
||||
# continue # skip cells after a span
|
||||
if pdf_mode:
|
||||
content = row.get(f"_{cid}_pdf", "") or row.get(cid, "") or ""
|
||||
content = row.get(f"_{cid}_pdf", False) or row.get(cid, "")
|
||||
elif xls_mode:
|
||||
content = row.get(f"_{cid}_xls", False) or row.get(cid, "")
|
||||
else:
|
||||
content = row.get(cid, "") or "" # nota: None converted to ''
|
||||
content = row.get(cid, "")
|
||||
# Convert None to empty string ""
|
||||
content = "" if content is None else content
|
||||
|
||||
colspan = row.get("_%s_colspan" % cid, 0)
|
||||
if colspan > 1:
|
||||
pdf_style_list.append(
|
||||
@ -299,7 +305,7 @@ class GenTable(object):
|
||||
return self.xml()
|
||||
elif format == "json":
|
||||
return self.json()
|
||||
raise ValueError("GenTable: invalid format: %s" % format)
|
||||
raise ValueError(f"GenTable: invalid format: {format}")
|
||||
|
||||
def _gen_html_row(self, row, line_num=0, elem="td", css_classes=""):
|
||||
"row is a dict, returns a string <tr...>...</tr>"
|
||||
@ -479,23 +485,23 @@ class GenTable(object):
|
||||
def excel(self, wb=None):
|
||||
"""Simple Excel representation of the table"""
|
||||
if wb is None:
|
||||
ses = sco_excel.ScoExcelSheet(sheet_name=self.xls_sheet_name, wb=wb)
|
||||
sheet = sco_excel.ScoExcelSheet(sheet_name=self.xls_sheet_name, wb=wb)
|
||||
else:
|
||||
ses = wb.create_sheet(sheet_name=self.xls_sheet_name)
|
||||
ses.rows += self.xls_before_table
|
||||
sheet = wb.create_sheet(sheet_name=self.xls_sheet_name)
|
||||
sheet.rows += self.xls_before_table
|
||||
style_bold = sco_excel.excel_make_style(bold=True)
|
||||
style_base = sco_excel.excel_make_style()
|
||||
ses.append_row(ses.make_row(self.get_titles_list(), style_bold))
|
||||
for line in self.get_data_list():
|
||||
ses.append_row(ses.make_row(line, style_base))
|
||||
sheet.append_row(sheet.make_row(self.get_titles_list(), style_bold))
|
||||
for line in self.get_data_list(xls_mode=True):
|
||||
sheet.append_row(sheet.make_row(line, style_base))
|
||||
if self.caption:
|
||||
ses.append_blank_row() # empty line
|
||||
ses.append_single_cell_row(self.caption, style_base)
|
||||
sheet.append_blank_row() # empty line
|
||||
sheet.append_single_cell_row(self.caption, style_base)
|
||||
if self.origin:
|
||||
ses.append_blank_row() # empty line
|
||||
ses.append_single_cell_row(self.origin, style_base)
|
||||
sheet.append_blank_row() # empty line
|
||||
sheet.append_single_cell_row(self.origin, style_base)
|
||||
if wb is None:
|
||||
return ses.generate()
|
||||
return sheet.generate()
|
||||
|
||||
def text(self):
|
||||
"raw text representation of the table"
|
||||
|
@ -47,14 +47,15 @@
|
||||
qui est une description (humaine, format libre) de l'archive.
|
||||
|
||||
"""
|
||||
import chardet
|
||||
import datetime
|
||||
import glob
|
||||
import json
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import time
|
||||
import chardet
|
||||
|
||||
import flask
|
||||
from flask import g, request
|
||||
@ -63,7 +64,9 @@ from flask_login import current_user
|
||||
import app.scodoc.sco_utils as scu
|
||||
from config import Config
|
||||
from app import log
|
||||
from app.models import Departement
|
||||
from app.comp import res_sem
|
||||
from app.comp.res_compat import NotesTableCompat
|
||||
from app.models import Departement, FormSemestre
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||
from app.scodoc.sco_exceptions import (
|
||||
AccessDenied,
|
||||
@ -95,8 +98,8 @@ class BaseArchiver(object):
|
||||
self.root = os.path.join(*dirs)
|
||||
log("initialized archiver, path=" + self.root)
|
||||
path = dirs[0]
|
||||
for dir in dirs[1:]:
|
||||
path = os.path.join(path, dir)
|
||||
for directory in dirs[1:]:
|
||||
path = os.path.join(path, directory)
|
||||
try:
|
||||
scu.GSL.acquire()
|
||||
if not os.path.isdir(path):
|
||||
@ -117,11 +120,11 @@ class BaseArchiver(object):
|
||||
try:
|
||||
scu.GSL.acquire()
|
||||
if not os.path.isdir(dept_dir):
|
||||
log("creating directory %s" % dept_dir)
|
||||
log(f"creating directory {dept_dir}")
|
||||
os.mkdir(dept_dir)
|
||||
obj_dir = os.path.join(dept_dir, str(oid))
|
||||
if not os.path.isdir(obj_dir):
|
||||
log("creating directory %s" % obj_dir)
|
||||
log(f"creating directory {obj_dir}")
|
||||
os.mkdir(obj_dir)
|
||||
finally:
|
||||
scu.GSL.release()
|
||||
@ -163,8 +166,9 @@ class BaseArchiver(object):
|
||||
|
||||
def get_archive_date(self, archive_id):
|
||||
"""Returns date (as a DateTime object) of an archive"""
|
||||
dt = [int(x) for x in os.path.split(archive_id)[1].split("-")]
|
||||
return datetime.datetime(*dt)
|
||||
return datetime.datetime(
|
||||
*[int(x) for x in os.path.split(archive_id)[1].split("-")]
|
||||
)
|
||||
|
||||
def list_archive(self, archive_id: str) -> str:
|
||||
"""Return list of filenames (without path) in archive"""
|
||||
@ -195,8 +199,7 @@ class BaseArchiver(object):
|
||||
archive_id = os.path.join(self.get_obj_dir(oid), archive_name)
|
||||
if not os.path.isdir(archive_id):
|
||||
log(
|
||||
"invalid archive name: %s, oid=%s, archive_id=%s"
|
||||
% (archive_name, oid, archive_id)
|
||||
f"invalid archive name: {archive_name}, oid={oid}, archive_id={archive_id}"
|
||||
)
|
||||
raise ValueError("invalid archive name")
|
||||
return archive_id
|
||||
@ -223,7 +226,7 @@ class BaseArchiver(object):
|
||||
+ os.path.sep
|
||||
+ "-".join(["%02d" % x for x in time.localtime()[:6]])
|
||||
)
|
||||
log("creating archive: %s" % archive_id)
|
||||
log(f"creating archive: {archive_id}")
|
||||
try:
|
||||
scu.GSL.acquire()
|
||||
os.mkdir(archive_id) # if exists, raises an OSError
|
||||
@ -302,9 +305,14 @@ def do_formsemestre_archive(
|
||||
Store:
|
||||
- tableau recap (xls), pv jury (xls et pdf), bulletins (xml et pdf), lettres individuelles (pdf)
|
||||
"""
|
||||
from app.scodoc.sco_recapcomplet import make_formsemestre_recapcomplet
|
||||
from app.scodoc.sco_recapcomplet import (
|
||||
gen_formsemestre_recapcomplet_excel,
|
||||
gen_formsemestre_recapcomplet_html,
|
||||
gen_formsemestre_recapcomplet_json,
|
||||
)
|
||||
|
||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
sem_archive_id = formsemestre_id
|
||||
archive_id = PVArchive.create_obj_archive(sem_archive_id, description)
|
||||
date = PVArchive.get_archive_date(archive_id).strftime("%d/%m/%Y à %H:%M")
|
||||
@ -319,37 +327,38 @@ def do_formsemestre_archive(
|
||||
etudids = [m["etudid"] for m in groups_infos.members]
|
||||
|
||||
# Tableau recap notes en XLS (pour tous les etudiants, n'utilise pas les groupes)
|
||||
data, _, _ = make_formsemestre_recapcomplet(formsemestre_id, format="xls")
|
||||
data, _ = gen_formsemestre_recapcomplet_excel(
|
||||
formsemestre, res, include_evaluations=True, format="xls"
|
||||
)
|
||||
if data:
|
||||
PVArchive.store(archive_id, "Tableau_moyennes" + scu.XLSX_SUFFIX, data)
|
||||
# Tableau recap notes en HTML (pour tous les etudiants, n'utilise pas les groupes)
|
||||
data, _, _ = make_formsemestre_recapcomplet(
|
||||
formsemestre_id, format="html", disable_etudlink=True
|
||||
table_html = gen_formsemestre_recapcomplet_html(
|
||||
formsemestre, res, include_evaluations=True
|
||||
)
|
||||
if data:
|
||||
if table_html:
|
||||
data = "\n".join(
|
||||
[
|
||||
html_sco_header.sco_header(
|
||||
page_title="Moyennes archivées le %s" % date,
|
||||
head_message="Moyennes archivées le %s" % date,
|
||||
page_title=f"Moyennes archivées le {date}",
|
||||
head_message=f"Moyennes archivées le {date}",
|
||||
no_side_bar=True,
|
||||
),
|
||||
'<h2 class="fontorange">Valeurs archivées le %s</h2>' % date,
|
||||
f'<h2 class="fontorange">Valeurs archivées le {date}</h2>',
|
||||
'<style type="text/css">table.notes_recapcomplet tr { color: rgb(185,70,0); }</style>',
|
||||
data,
|
||||
table_html,
|
||||
html_sco_header.sco_footer(),
|
||||
]
|
||||
)
|
||||
data = data.encode(scu.SCO_ENCODING)
|
||||
PVArchive.store(archive_id, "Tableau_moyennes.html", data)
|
||||
|
||||
# Bulletins en XML (pour tous les etudiants, n'utilise pas les groupes)
|
||||
data, _, _ = make_formsemestre_recapcomplet(
|
||||
formsemestre_id, format="xml", xml_with_decisions=True
|
||||
)
|
||||
# Bulletins en JSON
|
||||
data = gen_formsemestre_recapcomplet_json(formsemestre_id, xml_with_decisions=True)
|
||||
data_js = json.dumps(data, indent=1, cls=scu.ScoDocJSONEncoder)
|
||||
data_js = data_js.encode(scu.SCO_ENCODING)
|
||||
if data:
|
||||
data = data.encode(scu.SCO_ENCODING)
|
||||
PVArchive.store(archive_id, "Bulletins.xml", data)
|
||||
PVArchive.store(archive_id, "Bulletins.json", data_js)
|
||||
# Decisions de jury, en XLS
|
||||
data = sco_pvjury.formsemestre_pvjury(formsemestre_id, format="xls", publish=False)
|
||||
if data:
|
||||
|
@ -185,13 +185,13 @@ def excel_make_style(
|
||||
|
||||
|
||||
class ScoExcelSheet:
|
||||
"""Représente une feuille qui peut être indépendante ou intégrée dans un SCoExcelBook.
|
||||
"""Représente une feuille qui peut être indépendante ou intégrée dans un ScoExcelBook.
|
||||
En application des directives de la bibliothèque sur l'écriture optimisée, l'ordre des opérations
|
||||
est imposé:
|
||||
* instructions globales (largeur/maquage des colonnes et ligne, ...)
|
||||
* construction et ajout des cellules et ligne selon le sens de lecture (occidental)
|
||||
ligne de haut en bas et cellules de gauche à droite (i.e. A1, A2, .. B1, B2, ..)
|
||||
* pour finit appel de la méthode de génération
|
||||
* pour finir appel de la méthode de génération
|
||||
"""
|
||||
|
||||
def __init__(self, sheet_name="feuille", default_style=None, wb=None):
|
||||
@ -260,7 +260,7 @@ class ScoExcelSheet:
|
||||
for i, val in enumerate(value):
|
||||
self.ws.column_dimensions[self.i2col(i)].width = val
|
||||
# No keys: value is a list of widths
|
||||
elif type(cle) == str: # accepts set_column_with("D", ...)
|
||||
elif isinstance(cle, str): # accepts set_column_with("D", ...)
|
||||
self.ws.column_dimensions[cle].width = value
|
||||
else:
|
||||
self.ws.column_dimensions[self.i2col(cle)].width = value
|
||||
@ -337,7 +337,8 @@ class ScoExcelSheet:
|
||||
|
||||
return cell
|
||||
|
||||
def make_row(self, values: list, style=None, comments=None):
|
||||
def make_row(self, values: list, style=None, comments=None) -> list:
|
||||
"build a row"
|
||||
# TODO make possible differents styles in a row
|
||||
if comments is None:
|
||||
comments = [None] * len(values)
|
||||
|
@ -184,9 +184,6 @@ def formsemestre_validation_etud_form(
|
||||
"notes.formsemestre_recapcomplet",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
modejury=1,
|
||||
hidemodules=1,
|
||||
hidebac=1,
|
||||
pref_override=0,
|
||||
formsemestre_id=formsemestre_id,
|
||||
sortcol=sortcol
|
||||
or None, # pour refaire tri sorttable du tableau de notes
|
||||
@ -437,14 +434,6 @@ def _redirect_valid_choice(formsemestre_id, etudid, Se, choice, desturl, sortcol
|
||||
# sinon renvoie au listing general,
|
||||
|
||||
|
||||
# if choice.new_code_prev:
|
||||
# flask.redirect( 'formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s&check=1&desturl=%s' % (formsemestre_id, etudid, desturl) )
|
||||
# else:
|
||||
# if not desturl:
|
||||
# desturl = 'formsemestre_recapcomplet?modejury=1&hidemodules=1&formsemestre_id=' + str(formsemestre_id)
|
||||
# flask.redirect(desturl)
|
||||
|
||||
|
||||
def _dispcode(c):
|
||||
if not c:
|
||||
return ""
|
||||
|
@ -382,18 +382,6 @@ class BasePreferences(object):
|
||||
"only_global": False,
|
||||
},
|
||||
),
|
||||
(
|
||||
"recap_hidebac",
|
||||
{
|
||||
"initvalue": 0,
|
||||
"title": "Cacher la colonne Bac",
|
||||
"explanation": "sur la table récapitulative",
|
||||
"input_type": "boolcheckbox",
|
||||
"category": "misc",
|
||||
"labels": ["non", "oui"],
|
||||
"only_global": False,
|
||||
},
|
||||
),
|
||||
# ------------------ Absences
|
||||
(
|
||||
"email_chefdpt",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.1.91"
|
||||
SCOVERSION = "9.1.92"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user