ajout export fichier par NIP

This commit is contained in:
Jean-Marie Place 2023-12-03 00:17:16 +01:00
parent a5e5ad6248
commit 5cd495e33e
2 changed files with 108 additions and 39 deletions

View File

@ -40,6 +40,8 @@ from openpyxl.comments import Comment
from openpyxl import Workbook, load_workbook from openpyxl import Workbook, load_workbook
from openpyxl.cell import WriteOnlyCell from openpyxl.cell import WriteOnlyCell
from openpyxl.styles import Font, Border, Side, Alignment, PatternFill from openpyxl.styles import Font, Border, Side, Alignment, PatternFill
from openpyxl.utils import quote_sheetname, absolute_coordinate
from openpyxl.workbook.defined_name import DefinedName
from openpyxl.worksheet.worksheet import Worksheet from openpyxl.worksheet.worksheet import Worksheet
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -218,6 +220,7 @@ class ScoExcelSheet:
self.rows = [] # list of list of cells self.rows = [] # list of list of cells
self.column_dimensions = {} self.column_dimensions = {}
self.row_dimensions = {} self.row_dimensions = {}
self.formulae = {}
def excel_make_composite_style( def excel_make_composite_style(
self, self,
@ -363,6 +366,9 @@ class ScoExcelSheet:
"""ajoute une ligne déjà construite à la feuille.""" """ajoute une ligne déjà construite à la feuille."""
self.rows.append(row) self.rows.append(row)
def set_formula(self, coord, formula):
self.formulae[coord] = formula
def prepare(self): def prepare(self):
"""génére un flux décrivant la feuille. """génére un flux décrivant la feuille.
Ce flux pourra ensuite être repris dans send_excel_file (classeur mono feille) Ce flux pourra ensuite être repris dans send_excel_file (classeur mono feille)
@ -383,6 +389,8 @@ class ScoExcelSheet:
# construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream) # construction d'un flux (https://openpyxl.readthedocs.io/en/stable/tutorial.html#saving-as-a-stream)
self.prepare() self.prepare()
for coord, formula in self.formulae.items():
self.ws[coord] = formula
with NamedTemporaryFile() as tmp: with NamedTemporaryFile() as tmp:
self.wb.save(tmp.name) self.wb.save(tmp.name)
tmp.seek(0) tmp.seek(0)
@ -433,7 +441,12 @@ def excel_simple_table(
return ws.generate() return ws.generate()
def excel_feuille_saisie(evaluation: "Evaluation", titreannee, description, lines): from openpyxl.utils import absolute_coordinate
def excel_feuille_saisie(
evaluation: "Evaluation", titreannee, description, lines, withnips=False
):
"""Genere feuille excel pour saisie des notes. """Genere feuille excel pour saisie des notes.
E: evaluation (dict) E: evaluation (dict)
lines: liste de tuples lines: liste de tuples
@ -450,6 +463,13 @@ def excel_feuille_saisie(evaluation: "Evaluation", titreannee, description, line
ws.set_column_dimension_width("D", 164.0 / 7) # groupes ws.set_column_dimension_width("D", 164.0 / 7) # groupes
ws.set_column_dimension_width("E", 115.0 / 7) # notes ws.set_column_dimension_width("E", 115.0 / 7) # notes
ws.set_column_dimension_width("F", 355.0 / 7) # remarques ws.set_column_dimension_width("F", 355.0 / 7) # remarques
if withnips:
ws.set_column_dimension_width("G", 11.0 / 7) # colonne NIP cachée
ws.set_column_dimension_width(
"H", 105.0 / 7
) # Colonne blanche entre liste et zone de saisie
ws.set_column_dimension_width("I", 90.0 / 7) # Saisie: NIP
ws.set_column_dimension_width("J", 115.0 / 7) # Saisie: Note
# fontes # fontes
font_base = Font(name="Arial", size=12) font_base = Font(name="Arial", size=12)
@ -497,15 +517,32 @@ def excel_feuille_saisie(evaluation: "Evaluation", titreannee, description, line
"font": font_blue, "font": font_blue,
"border": border_top, "border": border_top,
} }
style_input = {
"font": font_bold,
"border": border_top,
"fill": fill_light_yellow,
}
if withnips:
del style_notes["fill"]
list_top = 9
# ligne de titres # ligne de titres
ws.append_single_cell_row( ws.append_single_cell_row(
"Feuille saisie note (à enregistrer au format excel)", style_titres "Feuille saisie note (à enregistrer au format excel)", style_titres
) )
# lignes d'instructions # lignes d'instructions
ws.append_single_cell_row( if withnips:
"Saisir les notes dans la colonne E (cases jaunes)", style_expl ws.append_single_cell_row(
) "Saisir les (NIP, note) en colonne I et J (cases jaunes). ordre des NIP indifférent",
style_expl,
)
else:
ws.append_single_cell_row(
"Saisir les notes dans la colonne E (cases jaunes)", style_expl
)
ws.append_single_cell_row("Ne pas modifier les cases en mauve !", style_expl) ws.append_single_cell_row("Ne pas modifier les cases en mauve !", style_expl)
# Nom du semestre # Nom du semestre
ws.append_single_cell_row(scu.unescape_html(titreannee), style_titres) ws.append_single_cell_row(scu.unescape_html(titreannee), style_titres)
@ -518,19 +555,33 @@ def excel_feuille_saisie(evaluation: "Evaluation", titreannee, description, line
# ligne blanche # ligne blanche
ws.append_blank_row() ws.append_blank_row()
# code et titres colonnes # code et titres colonnes
ws.append_row( title_row = [
[ ws.make_cell("!%s" % evaluation.id, style_ro),
ws.make_cell("!%s" % evaluation.id, style_ro), ws.make_cell("Nom", style_titres),
ws.make_cell("Nom", style_titres), ws.make_cell("Prénom", style_titres),
ws.make_cell("Prénom", style_titres), ws.make_cell("Groupe", style_titres),
ws.make_cell("Groupe", style_titres), ws.make_cell("Note sur %g" % (evaluation.note_max or 0.0), style_titres),
ws.make_cell("Note sur %g" % (evaluation.note_max or 0.0), style_titres), ws.make_cell("Remarque", style_titres),
ws.make_cell("Remarque", style_titres), ]
if withnips:
title_row += [
ws.make_cell("NIP", style_titres),
ws.make_cell(),
ws.make_cell("NIP", style_titres),
ws.make_cell("Note sur 20", style_titres),
] ]
) ws.append_row(title_row)
# Calcul de la zone de saisie (au format $I$9:$J$45) pour intégration dans la formule
if withnips:
min_row = list_top
max_row = list_top + len(lines) - 1
min_col = "I"
max_col = "J"
input_range = absolute_coordinate(f"{min_col}{min_row}:{max_col}{max_row}")
# etudiants # etudiants
for line in lines: for line_number, line in enumerate(lines):
st = style_nom st = style_nom
if line[3] != "I": if line[3] != "I":
st = style_dem st = style_dem
@ -543,17 +594,30 @@ def excel_feuille_saisie(evaluation: "Evaluation", titreannee, description, line
try: try:
val = float(line[5]) val = float(line[5])
except ValueError: except ValueError:
val = line[5] if withnips and line[5] == "":
ws.append_row( ws.set_formula(
[ f"E{list_top + line_number}",
ws.make_cell("!" + line[0], style_ro), # code f"=VLOOKUP(G{list_top + line_number},{input_range}, 2, FALSE)",
ws.make_cell(line[1], st), )
ws.make_cell(line[2], st), val = ""
ws.make_cell(s, st), else:
ws.make_cell(val, style_notes), # note val = line[5]
ws.make_cell(line[6], style_comment), # comment row = [
ws.make_cell("!" + line[0], style_ro), # code
ws.make_cell(line[1], st),
ws.make_cell(line[2], st),
ws.make_cell(s, st),
ws.make_cell(val, style_notes), # note
ws.make_cell(line[6], style_comment), # comment
]
if withnips:
row += [
ws.make_cell(line[7], style_ro), # NIP
ws.make_cell(),
ws.make_cell("", style_input), # Saisie NIP
ws.make_cell("", style_input), # Saisie note
] ]
) ws.append_row(row)
# explication en bas # explication en bas
ws.append_row([None, ws.make_cell("Code notes", style_titres)]) ws.append_row([None, ws.make_cell("Code notes", style_titres)])

View File

@ -733,6 +733,8 @@ def saisie_notes_tableur(evaluation_id, group_ids=()):
<li><a class="stdlink" href="feuille_saisie_notes?evaluation_id={evaluation_id}&{ <li><a class="stdlink" href="feuille_saisie_notes?evaluation_id={evaluation_id}&{
groups_infos.groups_query_args}" groups_infos.groups_query_args}"
id="lnk_feuille_saisie">obtenir le fichier tableur à remplir</a> id="lnk_feuille_saisie">obtenir le fichier tableur à remplir</a>
&nbsp;(<a class="stdlink" href="feuille_saisie_notes?evaluation_id={evaluation_id}&{
groups_infos.groups_query_args}&withnips=1">saisie par NIP</a>)
</li> </li>
<li>ou <a class="stdlink" href="{url_for("notes.saisie_notes", <li>ou <a class="stdlink" href="{url_for("notes.saisie_notes",
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation_id) scodoc_dept=g.scodoc_dept, evaluation_id=evaluation_id)
@ -875,7 +877,7 @@ def saisie_notes_tableur(evaluation_id, group_ids=()):
return "\n".join(H) return "\n".join(H)
def feuille_saisie_notes(evaluation_id, group_ids=[]): def feuille_saisie_notes(evaluation_id, group_ids=[], withnips=0):
"""Document Excel pour saisie notes dans l'évaluation et les groupes indiqués""" """Document Excel pour saisie notes dans l'évaluation et les groupes indiqués"""
evaluation: Evaluation = db.session.get(Evaluation, evaluation_id) evaluation: Evaluation = db.session.get(Evaluation, evaluation_id)
if not evaluation: if not evaluation:
@ -922,28 +924,31 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]):
# une liste de liste de chaines: lignes de la feuille de calcul # une liste de liste de chaines: lignes de la feuille de calcul
rows = [] rows = []
etuds = _get_sorted_etuds(evaluation, etudids, formsemestre.id) etuds = _get_sorted_etuds(evaluation, etudids, formsemestre.id)
for e in etuds: for e in etuds:
etudid = e["etudid"] etudid = e["etudid"]
groups = sco_groups.get_etud_groups(etudid, formsemestre.id) groups = sco_groups.get_etud_groups(etudid, formsemestre.id)
grc = sco_groups.listgroups_abbrev(groups) grc = sco_groups.listgroups_abbrev(groups)
row = [
rows.append( str(etudid),
[ e["nom"].upper(),
str(etudid), e["prenom"].lower().capitalize(),
e["nom"].upper(), e["inscr"]["etat"],
e["prenom"].lower().capitalize(), grc,
e["inscr"]["etat"], e["val"],
grc, e["explanation"],
e["val"], ]
e["explanation"], if withnips == 1:
] row.append(e["code_nip"])
) rows.append(row)
filename = f"notes_{eval_name}_{gr_title_filename}" filename = f"notes_{eval_name}_{gr_title_filename}"
xls = sco_excel.excel_feuille_saisie( xls = sco_excel.excel_feuille_saisie(
evaluation, formsemestre.titre_annee(), description, lines=rows evaluation,
formsemestre.titre_annee(),
description,
lines=rows,
withnips=(withnips == 1),
) )
return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE) return scu.send_file(xls, filename, scu.XLSX_SUFFIX, mime=scu.XLSX_MIMETYPE)