1
0
Fork 0
ScoDoc-Front/app/scodoc/sco_liste_notes.py

864 lines
29 KiB
Python

# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""Liste des notes d'une évaluation
"""
import flask
from flask import url_for, g, request
from app import models
from app.models.evaluations import Evaluation
from app.models.moduleimpls import ModuleImpl
import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb
from app import log
from app.comp import moy_mod
from app.scodoc.TrivialFormulator import TrivialFormulator
from app.scodoc import sco_cache
from app.scodoc import sco_edit_module
from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_preferences
from app.scodoc import sco_etud
from app.scodoc import sco_users
import sco_version
from app.scodoc.gen_tables import GenTable
from app.scodoc.htmlutils import histogram_notes
def do_evaluation_listenotes(
evaluation_id=None, moduleimpl_id=None, format="html"
) -> tuple[str, str]:
"""
Affichage des notes d'une évaluation (si evaluation_id)
ou de toutes les évaluations d'un module (si moduleimpl_id)
"""
mode = None
if moduleimpl_id:
mode = "module"
evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
elif evaluation_id:
mode = "eval"
evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})
else:
raise ValueError("missing argument: evaluation or module")
if not evals:
return "<p>Aucune évaluation !</p>", f"ScoDoc"
E = evals[0] # il y a au moins une evaluation
modimpl = ModuleImpl.query.get(E["moduleimpl_id"])
# description de l'evaluation
if mode == "eval":
H = [sco_evaluations.evaluation_describe(evaluation_id=evaluation_id)]
page_title = f"Notes {E['description'] or modimpl.module.code}"
else:
H = []
page_title = f"Notes {modimpl.module.code}"
# groupes
groups = sco_groups.do_evaluation_listegroupes(
E["evaluation_id"], include_default=True
)
grlabs = [g["group_name"] or "tous" for g in groups] # legendes des boutons
grnams = [str(g["group_id"]) for g in groups] # noms des checkbox
if len(evals) > 1:
descr = [
("moduleimpl_id", {"default": E["moduleimpl_id"], "input_type": "hidden"})
]
else:
descr = [
("evaluation_id", {"default": E["evaluation_id"], "input_type": "hidden"})
]
if len(grnams) > 1:
descr += [
(
"s",
{
"input_type": "separator",
"title": "<b>Choix du ou des groupes d'étudiants:</b>",
},
),
(
"group_ids",
{
"input_type": "checkbox",
"title": "",
"allowed_values": grnams,
"labels": grlabs,
"attributes": ('onclick="document.tf.submit();"',),
},
),
]
else:
if grnams:
def_nam = grnams[0]
else:
def_nam = ""
descr += [
(
"group_ids",
{"input_type": "hidden", "type": "list", "default": [def_nam]},
)
]
descr += [
(
"anonymous_listing",
{
"input_type": "checkbox",
"title": "",
"allowed_values": ("yes",),
"labels": ('listing "anonyme"',),
"attributes": ('onclick="document.tf.submit();"',),
"template": '<tr><td class="tf-fieldlabel">%(label)s</td><td class="tf-field">%(elem)s &nbsp;&nbsp;',
},
),
(
"note_sur_20",
{
"input_type": "checkbox",
"title": "",
"allowed_values": ("yes",),
"labels": ("notes sur 20",),
"attributes": ('onclick="document.tf.submit();"',),
"template": "%(elem)s &nbsp;&nbsp;",
},
),
(
"hide_groups",
{
"input_type": "checkbox",
"title": "",
"allowed_values": ("yes",),
"labels": ("masquer les groupes",),
"attributes": ('onclick="document.tf.submit();"',),
"template": "%(elem)s &nbsp;&nbsp;",
},
),
(
"with_emails",
{
"input_type": "checkbox",
"title": "",
"allowed_values": ("yes",),
"labels": ("montrer les e-mails",),
"attributes": ('onclick="document.tf.submit();"',),
"template": "%(elem)s</td></tr>",
},
),
]
tf = TrivialFormulator(
request.base_url,
scu.get_request_args(),
descr,
cancelbutton=None,
submitbutton=None,
bottom_buttons=False,
method="GET",
cssclass="noprint",
name="tf",
is_submitted=True, # toujours "soumis" (démarre avec liste complète)
)
if tf[0] == 0:
return "\n".join(H) + "\n" + tf[1], page_title
elif tf[0] == -1:
return (
flask.redirect(
"%s/Notes/moduleimpl_status?moduleimpl_id=%s"
% (scu.ScoURL(), E["moduleimpl_id"])
),
"",
)
else:
anonymous_listing = tf[2]["anonymous_listing"]
note_sur_20 = tf[2]["note_sur_20"]
hide_groups = tf[2]["hide_groups"]
with_emails = tf[2]["with_emails"]
return (
_make_table_notes(
tf[1],
evals,
format=format,
note_sur_20=note_sur_20,
anonymous_listing=anonymous_listing,
group_ids=tf[2]["group_ids"],
hide_groups=hide_groups,
with_emails=with_emails,
mode=mode,
),
page_title,
)
def _make_table_notes(
html_form,
evals,
format="",
note_sur_20=False,
anonymous_listing=False,
hide_groups=False,
with_emails=False,
group_ids=[],
mode="module", # "eval" or "module"
):
"""Table liste notes (une seule évaluation ou toutes celles d'un module)"""
# Code à ré-écrire !
if not evals:
return "<p>Aucune évaluation !</p>"
E = evals[0]
moduleimpl_id = E["moduleimpl_id"]
modimpl_o = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
module = models.Module.query.get(modimpl_o["module_id"])
is_apc = module.formation.get_parcours().APC_SAE
if is_apc:
modimpl = ModuleImpl.query.get(moduleimpl_id)
is_conforme = modimpl.check_apc_conformity()
evals_poids, ues = moy_mod.load_evaluations_poids(moduleimpl_id)
if not ues:
is_apc = False
else:
evals_poids, ues = None, None
is_conforme = True
sem = sco_formsemestre.get_formsemestre(modimpl_o["formsemestre_id"])
# (debug) check that all evals are in same module:
for e in evals:
if e["moduleimpl_id"] != moduleimpl_id:
raise ValueError("invalid evaluations list")
if format == "xls":
keep_numeric = True # pas de conversion des notes en strings
else:
keep_numeric = False
# Si pas de groupe, affiche tout
if not group_ids:
group_ids = [sco_groups.get_default_group(modimpl_o["formsemestre_id"])]
groups = sco_groups.listgroups(group_ids)
gr_title = sco_groups.listgroups_abbrev(groups)
gr_title_filename = sco_groups.listgroups_filename(groups)
if anonymous_listing:
columns_ids = ["code"] # cols in table
else:
if format == "xls" or format == "xml":
columns_ids = ["nom", "prenom"]
else:
columns_ids = ["nomprenom"]
if not hide_groups:
columns_ids.append("group")
titles = {
"code": "Code",
"group": "Groupe",
"nom": "Nom",
"prenom": "Prénom",
"nomprenom": "Nom",
"expl_key": "Rem.",
"email": "e-mail",
"emailperso": "e-mail perso",
"signatures": "Signatures",
}
rows = []
class KeyManager(dict): # comment : key (pour regrouper les comments a la fin)
def __init__(self):
self.lastkey = 1
def nextkey(self):
r = self.lastkey
self.lastkey += 1
# self.lastkey = chr(ord(self.lastkey)+1)
return str(r)
key_mgr = KeyManager()
# code pour listings anonyme, à la place du nom
if sco_preferences.get_preference("anonymous_lst_code") == "INE":
anonymous_lst_key = "code_ine"
elif sco_preferences.get_preference("anonymous_lst_code") == "NIP":
anonymous_lst_key = "code_nip"
else:
anonymous_lst_key = "etudid"
etudid_etats = sco_groups.do_evaluation_listeetuds_groups(
E["evaluation_id"], groups, include_dems=True
)
for etudid, etat in etudid_etats:
css_row_class = None
# infos identite etudiant
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
if etat == "I": # si inscrit, indique groupe
groups = sco_groups.get_etud_groups(etudid, sem)
grc = sco_groups.listgroups_abbrev(groups)
else:
if etat == "D":
grc = "DEM" # attention: ce code est re-ecrit plus bas, ne pas le changer (?)
css_row_class = "etuddem"
else:
grc = etat
code = etud.get(anonymous_lst_key)
if not code: # laisser le code vide n'aurait aucun sens, prenons l'etudid
code = etudid
rows.append(
{
"code": str(code), # INE, NIP ou etudid
"_code_td_attrs": 'style="padding-left: 1em; padding-right: 2em;"',
"etudid": etudid,
"nom": etud["nom"].upper(),
"_nomprenom_target": "formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s"
% (modimpl_o["formsemestre_id"], etudid),
"_nomprenom_td_attrs": 'id="%s" class="etudinfo"' % (etud["etudid"]),
"prenom": etud["prenom"].lower().capitalize(),
"nomprenom": etud["nomprenom"],
"group": grc,
"email": etud["email"],
"emailperso": etud["emailperso"],
"_css_row_class": css_row_class or "",
}
)
# Lignes en tête:
row_coefs = {
"nom": "",
"prenom": "",
"nomprenom": "",
"group": "",
"code": "",
"_css_row_class": "sorttop fontitalic",
"_table_part": "head",
}
row_poids = {
"nom": "",
"prenom": "",
"nomprenom": "",
"group": "",
"code": "",
"_css_row_class": "sorttop poids",
"_table_part": "head",
}
row_note_max = {
"nom": "",
"prenom": "",
"nomprenom": "",
"group": "",
"code": "",
"_css_row_class": "sorttop fontitalic",
"_table_part": "head",
}
row_moys = {
"_css_row_class": "moyenne sortbottom",
"_table_part": "foot",
#'_nomprenom_td_attrs' : 'colspan="2" ',
"nomprenom": "Moyenne (sans les absents) :",
"comment": "",
}
# Ajoute les notes de chaque évaluation:
for e in evals:
e["eval_state"] = sco_evaluations.do_evaluation_etat(e["evaluation_id"])
notes, nb_abs, nb_att = _add_eval_columns(
e,
evals_poids,
ues,
rows,
titles,
row_coefs,
row_poids,
row_note_max,
row_moys,
is_apc,
key_mgr,
note_sur_20,
keep_numeric,
format=format,
)
columns_ids.append(e["evaluation_id"])
#
if anonymous_listing:
rows.sort(key=lambda x: x["code"] or "")
else:
rows.sort(
key=lambda x: (x["nom"] or "", x["prenom"] or "")
) # sort by nom, prenom
# Si module, ajoute la (les) "moyenne(s) du module:
if mode == "module":
if len(evals) > 1:
# Moyenne de l'étudiant dans le module
# Affichée même en APC à titre indicatif
_add_moymod_column(
sem["formsemestre_id"],
moduleimpl_id,
rows,
columns_ids,
titles,
row_coefs,
row_poids,
row_note_max,
row_moys,
is_apc,
keep_numeric,
)
if is_apc:
# Ajoute une colonne par UE
_add_apc_columns(
moduleimpl_id,
evals_poids,
ues,
rows,
columns_ids,
titles,
is_conforme,
row_coefs,
row_poids,
row_note_max,
row_moys,
keep_numeric,
)
# Ajoute colonnes emails tout à droite:
if with_emails:
columns_ids += ["email", "emailperso"]
# Ajoute lignes en tête et moyennes
if len(evals) > 0 and format != "bordereau":
rows_head = [row_coefs]
if is_apc:
rows_head.append(row_poids)
rows_head.append(row_note_max)
rows = rows_head + rows
rows.append(row_moys)
# ajout liens HTMl vers affichage une evaluation:
if format == "html" and len(evals) > 1:
rlinks = {"_table_part": "head"}
for e in evals:
rlinks[e["evaluation_id"]] = "afficher"
rlinks[
"_" + str(e["evaluation_id"]) + "_help"
] = "afficher seulement les notes de cette évaluation"
rlinks["_" + str(e["evaluation_id"]) + "_target"] = url_for(
"notes.evaluation_listenotes",
scodoc_dept=g.scodoc_dept,
evaluation_id=e["evaluation_id"],
)
rlinks["_" + str(e["evaluation_id"]) + "_td_attrs"] = ' class="tdlink" '
rows.append(rlinks)
if len(evals) == 1: # colonne "Rem." seulement si une eval
if format == "html": # pas d'indication d'origine en pdf (pour affichage)
columns_ids.append("expl_key")
elif format == "xls" or format == "xml":
columns_ids.append("comment")
elif format == "bordereau":
columns_ids.append("signatures")
# titres divers:
gl = "".join(["&group_ids%3Alist=" + str(g) for g in group_ids])
if note_sur_20:
gl = "&note_sur_20%3Alist=yes" + gl
if anonymous_listing:
gl = "&anonymous_listing%3Alist=yes" + gl
if hide_groups:
gl = "&hide_groups%3Alist=yes" + gl
if with_emails:
gl = "&with_emails%3Alist=yes" + gl
if len(evals) == 1:
evalname = "%s-%s" % (module.code, ndb.DateDMYtoISO(E["jour"]))
hh = "%s, %s (%d étudiants)" % (E["description"], gr_title, len(etudid_etats))
filename = scu.make_filename("notes_%s_%s" % (evalname, gr_title_filename))
if format == "bordereau":
hh = " %d étudiants" % (len(etudid_etats))
hh += " %d absent" % (nb_abs)
if nb_abs > 1:
hh += "s"
hh += ", %d en attente." % (nb_att)
pdf_title = "<br/> BORDEREAU DE SIGNATURES"
pdf_title += "<br/><br/>%(titre)s" % sem
pdf_title += "<br/>(%(mois_debut)s - %(mois_fin)s)" % sem
pdf_title += " semestre %s %s" % (
sem["semestre_id"],
sem.get("modalite", ""),
)
pdf_title += f"<br/>Notes du module {module.code} - {module.titre}"
pdf_title += "<br/>Evaluation : %(description)s " % e
if len(e["jour"]) > 0:
pdf_title += " (%(jour)s)" % e
pdf_title += "(noté sur %(note_max)s )<br/><br/>" % e
else:
hh = " %s, %s (%d étudiants)" % (
E["description"],
gr_title,
len(etudid_etats),
)
if len(e["jour"]) > 0:
pdf_title = "%(description)s (%(jour)s)" % e
else:
pdf_title = "%(description)s " % e
caption = hh
html_title = ""
base_url = "evaluation_listenotes?evaluation_id=%s" % E["evaluation_id"] + gl
html_next_section = (
'<div class="notes_evaluation_stats">%d absents, %d en attente.</div>'
% (nb_abs, nb_att)
)
else:
filename = scu.make_filename("notes_%s_%s" % (module.code, gr_title_filename))
title = f"Notes {module.type_name()} {module.code} {module.titre}"
title += " semestre %(titremois)s" % sem
if gr_title and gr_title != "tous":
title += " %s" % gr_title
caption = title
html_next_section = ""
if format == "pdf" or format == "bordereau":
caption = "" # same as pdf_title
pdf_title = title
html_title = f"""<h2 class="formsemestre">Notes {module.type_name()} <a href="{
url_for("notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id)
}">{module.code} {module.titre}</a></h2>
"""
if not is_conforme:
html_title += (
"""<div class="warning">Poids des évaluations non conformes !</div>"""
)
base_url = "evaluation_listenotes?moduleimpl_id=%s" % moduleimpl_id + gl
# display
tab = GenTable(
titles=titles,
columns_ids=columns_ids,
rows=rows,
html_sortable=True,
base_url=base_url,
filename=filename,
origin="Généré par %s le " % sco_version.SCONAME
+ scu.timedate_human_repr()
+ "",
caption=caption,
html_next_section=html_next_section,
page_title="Notes de " + sem["titremois"],
html_title=html_title,
pdf_title=pdf_title,
html_class="table_leftalign notes_evaluation",
preferences=sco_preferences.SemPreferences(modimpl_o["formsemestre_id"]),
# html_generate_cells=False # la derniere ligne (moyennes) est incomplete
)
if format == "bordereau":
format = "pdf"
t = tab.make_page(format=format, with_html_headers=False)
if format != "html":
return t
if len(evals) > 1:
all_complete = True
for e in evals:
if not e["eval_state"]["evalcomplete"]:
all_complete = False
if all_complete:
eval_info = '<span class="eval_info eval_complete">Evaluations prises en compte dans les moyennes</span>'
else:
eval_info = '<span class="eval_info help">Les évaluations en vert et orange sont prises en compte dans les moyennes. Celles en rouge n\'ont pas toutes leurs notes.</span>'
return html_form + eval_info + t + "<p></p>"
else:
# Une seule evaluation: ajoute histogramme
histo = histogram_notes(notes)
# 2 colonnes: histo, comments
C = [
f'<br><a class="stdlink" href="{base_url}&format=bordereau">Bordereau de Signatures (version PDF)</a>',
"<table><tr><td><div><h4>Répartition des notes:</h4>"
+ histo
+ "</div></td>\n",
'<td style="padding-left: 50px; vertical-align: top;"><p>',
]
commentkeys = list(key_mgr.items()) # [ (comment, key), ... ]
commentkeys.sort(key=lambda x: int(x[1]))
for (comment, key) in commentkeys:
C.append(
'<span class="colcomment">(%s)</span> <em>%s</em><br/>' % (key, comment)
)
if commentkeys:
C.append(
'<span><a class=stdlink" href="evaluation_list_operations?evaluation_id=%s">Gérer les opérations</a></span><br/>'
% E["evaluation_id"]
)
eval_info = "xxx"
if E["eval_state"]["evalcomplete"]:
eval_info = '<span class="eval_info eval_complete">Evaluation prise en compte dans les moyennes</span>'
elif E["eval_state"]["evalattente"]:
eval_info = '<span class="eval_info eval_attente">Il y a des notes en attente (les autres sont prises en compte)</span>'
else:
eval_info = '<span class="eval_info eval_incomplete">Notes incomplètes, évaluation non prise en compte dans les moyennes</span>'
return (
sco_evaluations.evaluation_describe(evaluation_id=E["evaluation_id"])
+ eval_info
+ html_form
+ t
+ "\n".join(C)
)
def _add_eval_columns(
e,
evals_poids,
ues,
rows,
titles,
row_coefs,
row_poids,
row_note_max,
row_moys,
is_apc,
K,
note_sur_20,
keep_numeric,
format="html",
):
"""Add eval e"""
nb_notes = 0
nb_abs = 0
nb_att = 0
sum_notes = 0
notes = [] # liste des notes numeriques, pour calcul histogramme uniquement
evaluation_id = e["evaluation_id"]
e_o = Evaluation.query.get(evaluation_id) # XXX en attendant ré-écriture
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
for row in rows:
etudid = row["etudid"]
if etudid in NotesDB:
val = NotesDB[etudid]["value"]
if val is None:
nb_abs += 1
if val == scu.NOTES_ATTENTE:
nb_att += 1
# calcul moyenne SANS LES ABSENTS
if val != None and val != scu.NOTES_NEUTRALISE and val != scu.NOTES_ATTENTE:
if e["note_max"] > 0:
valsur20 = val * 20.0 / e["note_max"] # remet sur 20
else:
valsur20 = 0
notes.append(valsur20) # toujours sur 20 pour l'histogramme
if note_sur_20:
val = valsur20 # affichage notes / 20 demandé
nb_notes = nb_notes + 1
sum_notes += val
val_fmt = scu.fmt_note(val, keep_numeric=keep_numeric)
comment = NotesDB[etudid]["comment"]
if comment is None:
comment = ""
explanation = "%s (%s) %s" % (
NotesDB[etudid]["date"].strftime("%d/%m/%y %Hh%M"),
sco_users.user_info(NotesDB[etudid]["uid"])["nomcomplet"],
comment,
)
else:
explanation = ""
val_fmt = ""
val = None
if val is None:
row["_" + str(evaluation_id) + "_td_attrs"] = 'class="etudabs" '
if not row.get("_css_row_class", ""):
row["_css_row_class"] = "etudabs"
# regroupe les commentaires
if explanation:
if explanation in K:
expl_key = "(%s)" % K[explanation]
else:
K[explanation] = K.nextkey()
expl_key = "(%s)" % K[explanation]
else:
expl_key = ""
row.update(
{
evaluation_id: val_fmt,
"_" + str(evaluation_id) + "_help": explanation,
# si plusieurs evals seront ecrasés et non affichés:
"comment": explanation,
"expl_key": expl_key,
"_expl_key_help": explanation,
}
)
row_coefs[evaluation_id] = "coef. %s" % e["coefficient"]
if is_apc:
if format == "html":
row_poids[evaluation_id] = _mini_table_eval_ue_poids(
evaluation_id, evals_poids, ues
)
else:
row_poids[evaluation_id] = e_o.get_ue_poids_str()
if note_sur_20:
nmax = 20.0
else:
nmax = e["note_max"]
if keep_numeric:
row_note_max[evaluation_id] = nmax
else:
row_note_max[evaluation_id] = "/ %s" % nmax
if nb_notes > 0:
row_moys[evaluation_id] = scu.fmt_note(
sum_notes / nb_notes, keep_numeric=keep_numeric
)
row_moys[
"_" + str(evaluation_id) + "_help"
] = "moyenne sur %d notes (%s le %s)" % (
nb_notes,
e["description"],
e["jour"],
)
else:
row_moys[evaluation_id] = ""
if len(e["jour"]) > 0:
titles[evaluation_id] = "%(description)s (%(jour)s)" % e
else:
titles[evaluation_id] = "%(description)s " % e
if e["eval_state"]["evalcomplete"]:
titles["_" + str(evaluation_id) + "_td_attrs"] = 'class="eval_complete"'
elif e["eval_state"]["evalattente"]:
titles["_" + str(evaluation_id) + "_td_attrs"] = 'class="eval_attente"'
else:
titles["_" + str(evaluation_id) + "_td_attrs"] = 'class="eval_incomplete"'
return notes, nb_abs, nb_att # pour histogramme
def _mini_table_eval_ue_poids(evaluation_id, evals_poids, ues):
"contenu de la cellule: poids"
return (
"""<table class="eval_poids" title="poids vers les UE"><tr><td>"""
+ "</td><td>".join([f"{ue.acronyme}" for ue in ues])
+ "</td></tr>"
+ "<tr><td>"
+ "</td><td>".join([f"{evals_poids[ue.id][evaluation_id]}" for ue in ues])
+ "</td></tr></table>"
)
def _add_moymod_column(
formsemestre_id,
moduleimpl_id,
rows,
columns_ids,
titles,
row_coefs,
row_poids,
row_note_max,
row_moys,
is_apc,
keep_numeric,
):
"""Ajoute la colonne moymod à rows"""
col_id = "moymod"
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_mod_moy
nb_notes = 0
sum_notes = 0
notes = [] # liste des notes numeriques, pour calcul histogramme uniquement
for row in rows:
etudid = row["etudid"]
val = nt.get_etud_mod_moy(moduleimpl_id, etudid) # note sur 20, ou 'NA','NI'
row[col_id] = scu.fmt_note(val, keep_numeric=keep_numeric)
row["_" + col_id + "_td_attrs"] = ' class="moyenne" '
if not isinstance(val, str):
notes.append(val)
nb_notes = nb_notes + 1
sum_notes += val
row_coefs[col_id] = "(avec abs)"
if is_apc:
row_poids[col_id] = "à titre indicatif"
if keep_numeric:
row_note_max[col_id] = 20.0
else:
row_note_max[col_id] = "/ 20"
titles[col_id] = "Moyenne module"
columns_ids.append(col_id)
if nb_notes > 0:
row_moys[col_id] = "%.3g" % (sum_notes / nb_notes)
row_moys["_" + col_id + "_help"] = "moyenne des moyennes"
else:
row_moys[col_id] = ""
def _add_apc_columns(
moduleimpl_id,
evals_poids,
ues,
rows,
columns_ids,
titles,
is_conforme: bool,
row_coefs,
row_poids,
row_note_max,
row_moys,
keep_numeric,
):
"""Ajoute les colonnes moyennes vers les UE"""
# On raccorde ici les nouveaux calculs de notes (BUT 2021)
# sur l'ancien code ScoDoc
# => On recharge tout dans les nouveaux modèles
# rows est une liste de dict avec une clé "etudid"
# on va y ajouter une clé par UE du semestre
modimpl = ModuleImpl.query.get(moduleimpl_id)
evals_notes, evaluations, evaluations_completes = moy_mod.df_load_modimpl_notes(
moduleimpl_id
)
etuds_moy_module = moy_mod.compute_module_moy(
evals_notes, evals_poids, evaluations, evaluations_completes
)
if is_conforme:
# valeur des moyennes vers les UEs:
for row in rows:
for ue in ues:
moy_ue = etuds_moy_module[ue.id].get(row["etudid"], "?")
row[f"moy_ue_{ue.id}"] = scu.fmt_note(moy_ue, keep_numeric=keep_numeric)
row[f"_moy_ue_{ue.id}_class"] = "moy_ue"
# Nom et coefs des UE (lignes titres):
ue_coefs = modimpl.module.ue_coefs
if is_conforme:
coef_class = "coef_mod_ue"
else:
coef_class = "coef_mod_ue_non_conforme"
for ue in ues:
col_id = f"moy_ue_{ue.id}"
titles[col_id] = ue.acronyme
columns_ids.append(col_id)
coefs = [uc for uc in ue_coefs if uc.ue_id == ue.id]
if coefs:
row_coefs[f"moy_ue_{ue.id}"] = coefs[0].coef
row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = f' class="{coef_class}" '