# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2024 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 # ############################################################################## """Tableau de bord module """ import math import time import datetime from flask import g, url_for from flask_login import current_user from app import db from app.auth.models import User from app.comp import res_sem from app.comp.res_common import ResultatsSemestre from app.comp.res_compat import NotesTableCompat from app.models import Evaluation, FormSemestre, Module, ModuleImpl, UniteEns import app.scodoc.sco_utils as scu from app.scodoc.codes_cursus import UE_SPORT from app.scodoc.sco_exceptions import ScoInvalidIdType from app.scodoc.sco_cursus_dut import formsemestre_has_decisions from app.scodoc.sco_permissions import Permission from app.scodoc import html_sco_header from app.scodoc import htmlutils from app.scodoc import sco_cal from app.scodoc import sco_compute_moy from app.scodoc import sco_evaluations from app.scodoc import sco_formsemestre_status from app.scodoc import sco_groups from app.scodoc import sco_moduleimpl from app.scodoc import sco_permissions_check from app.tables import list_etuds # menu evaluation dans moduleimpl def moduleimpl_evaluation_menu(evaluation: Evaluation, nbnotes: int = 0) -> str: "Menu avec actions sur une evaluation" modimpl: ModuleImpl = evaluation.moduleimpl group_id = sco_groups.get_default_group(modimpl.formsemestre_id) evaluation_id = evaluation.id can_edit_notes = modimpl.can_edit_notes(current_user, allow_ens=False) can_edit_notes_ens = modimpl.can_edit_notes(current_user) if can_edit_notes and nbnotes != 0: sup_label = "Supprimer évaluation impossible (il y a des notes)" else: sup_label = "Supprimer évaluation" menu_eval = [ { "title": "Saisir notes", "endpoint": "notes.saisie_notes", "args": { "evaluation_id": evaluation_id, }, "enabled": can_edit_notes_ens, }, { "title": "Modifier évaluation", "endpoint": "notes.evaluation_edit", "args": { "evaluation_id": evaluation_id, }, "enabled": can_edit_notes, }, { "title": sup_label, "endpoint": "notes.evaluation_delete", "args": { "evaluation_id": evaluation_id, }, "enabled": nbnotes == 0 and can_edit_notes, }, { "title": "Supprimer toutes les notes", "endpoint": "notes.evaluation_suppress_alln", "args": { "evaluation_id": evaluation_id, }, "enabled": can_edit_notes, }, { "title": "Afficher les notes", "endpoint": "notes.evaluation_listenotes", "args": { "evaluation_id": evaluation_id, }, "enabled": nbnotes > 0, }, { "title": "Placement étudiants", "endpoint": "notes.placement_eval_selectetuds", "args": { "evaluation_id": evaluation_id, }, "enabled": can_edit_notes_ens, }, { "title": "Absences ce jour", "endpoint": "assiduites.etat_abs_date", "args": { "group_ids": group_id, "evaluation_id": evaluation.id, "date_debut": ( evaluation.date_debut.isoformat() if evaluation.date_debut else "" ), "date_fin": ( evaluation.date_fin.isoformat() if evaluation.date_fin else "" ), }, "enabled": evaluation.date_debut is not None and evaluation.date_fin is not None, }, { "title": "Vérifier notes vs absents", "endpoint": "notes.evaluation_check_absences_html", "args": { "evaluation_id": evaluation_id, }, "enabled": nbnotes > 0 and evaluation.date_debut is not None, }, ] return htmlutils.make_menu("actions", menu_eval, alone=True) def _ue_coefs_html(coefs_lst) -> str: """ """ max_coef = max([x[1] for x in coefs_lst]) if coefs_lst else 1.0 H = """ <div id="modimpl_coefs"> <div>Coefficients vers les UE</div> """ if coefs_lst: H += ( f""" <div class="coefs_histo" style="--max:{max_coef}"> """ + "\n".join( [ f"""<div style="--coef:{coef}; {'background-color: ' + ue.color + ';' if ue.color else ''} "><div>{coef}</div>{ue.acronyme}</div>""" for ue, coef in coefs_lst if coef > 0 ] ) + "</div>" ) else: H += """<div class="missing_value">non définis</div>""" H += "</div>" return H def moduleimpl_status(moduleimpl_id=None, partition_id=None): """Tableau de bord module (liste des evaluations etc)""" if not isinstance(moduleimpl_id, int): raise ScoInvalidIdType("moduleimpl_id must be an integer !") modimpl: ModuleImpl = ModuleImpl.query.get_or_404(moduleimpl_id) g.current_moduleimpl_id = modimpl.id module: Module = modimpl.module formsemestre_id = modimpl.formsemestre_id formsemestre: FormSemestre = modimpl.formsemestre mod_inscrits = sco_moduleimpl.do_moduleimpl_inscription_list( moduleimpl_id=moduleimpl_id ) nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) # Evaluations, par numéros ou la plus RECENTE en tête evaluations = modimpl.evaluations.order_by( Evaluation.numero.desc(), Evaluation.date_debut.desc(), ).all() nb_evaluations = len(evaluations) max_poids = max( [ max([p.poids for p in e.ue_poids] or [0]) * (e.coefficient or 0.0) for e in evaluations ] or [0] ) # sem_locked = not formsemestre.etat can_edit_evals = ( modimpl.can_edit_notes(current_user, allow_ens=formsemestre.ens_can_edit_eval) and not sem_locked ) can_edit_notes = modimpl.can_edit_notes(current_user) and not sem_locked arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags() # module_resp = db.session.get(User, modimpl.responsable_id) mod_type_name = scu.MODULE_TYPE_NAMES[module.module_type] H = [ html_sco_header.sco_header( page_title=f"{mod_type_name} {module.code} {module.titre}", javascripts=["js/etud_info.js"], init_qtip=True, ), f"""<h2 class="formsemestre">{mod_type_name} <tt>{module.code}</tt> {module.titre} {"dans l'UE " + modimpl.module.ue.acronyme if modimpl.module.module_type == scu.ModuleType.MALUS else "" } </h2> <div class="moduleimpl_tableaubord moduleimpl_type_{ scu.ModuleType(module.module_type).name.lower()}"> <table> <tr> <td class="fichetitre2">Responsable: </td><td class="redboldtext"> {module_resp.get_nomcomplet()} <span class="blacktt">({module_resp.user_name})</span> """, ] if modimpl.can_change_responsable(current_user): H.append( f"""<a class="stdlink" href="{url_for("notes.edit_moduleimpl_resp", scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id) }" >modifier</a>""" ) H.append("""</td><td>""") H.append(", ".join([u.get_nomprenom() for u in modimpl.enseignants])) H.append("""</td><td>""") if modimpl.can_change_ens(raise_exc=False): H.append( f"""<a class="stdlink" href="{ url_for("notes.edit_enseignants_form", scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id ) }">modifier les enseignants</a>""" ) H.append("""</td></tr>""") # 2ieme ligne: Semestre, Coef H.append("""<tr><td class="fichetitre2">""") if formsemestre.semestre_id >= 0: H.append("""Semestre: </td><td>%s""" % formsemestre.semestre_id) else: H.append("""</td><td>""") if sem_locked: H.append(scu.icontag("lock32_img", title="verrouillé")) H.append("""</td><td class="fichetitre2">""") if modimpl.module.is_apc(): H.append(_ue_coefs_html(modimpl.module.ue_coefs_list())) else: H.append( f"""Coef. dans le semestre: { "non défini" if modimpl.module.coefficient is None else modimpl.module.coefficient }""" ) H.append("""</td><td></td></tr>""") # 3ieme ligne: Formation H.append( f"""<tr> <td class="fichetitre2">Formation: </td><td>{formsemestre.formation.titre}</td> </tr> """ ) # Ligne: Inscrits H.append( f"""<tr><td class="fichetitre2">Inscrits: </td><td> {len(mod_inscrits)} étudiants""" ) if current_user.has_permission(Permission.EtudInscrit): H.append( f"""<a class="stdlink" style="margin-left:2em;" href="moduleimpl_inscriptions_edit?moduleimpl_id={modimpl.id}">modifier</a>""" ) H.append("</td></tr>") # Ligne: règle de calcul has_expression = sco_compute_moy.moduleimpl_has_expression(modimpl) if has_expression: H.append( """<tr> <td class="fichetitre2" colspan="4">Règle de calcul: <span class="warning">inutilisée dans cette version de ScoDoc</span> </td> </tr> """ ) else: H.append('<tr><td colspan="4">') H.append("</td></tr>") H.append( f"""<tr><td colspan="4"><span class="moduleimpl_abs_link"><a class="stdlink" href="{ url_for("notes.view_module_abs", scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id) }">Absences dans ce module</a></span>""" ) # Adapté à partir d'une suggestion de DS (Le Havre) # Liens saisies absences seulement si permission et date courante dans le semestre if current_user.has_permission(Permission.AbsChange) and formsemestre.est_courant(): group_id = sco_groups.get_default_group(formsemestre_id) H.append( f""" <span class="moduleimpl_abs_link"><a class="stdlink" href="{ url_for("assiduites.signal_assiduites_group", scodoc_dept=g.scodoc_dept) }?group_ids={group_id}&jour={ datetime.date.today().isoformat() }&formsemestre_id={formsemestre.id} &moduleimpl_id={moduleimpl_id} " >Saisie Absences journée</a></span> """ ) year, week, day = datetime.date.today().isocalendar() semaine: str = f"{year}-W{week}" H.append( f""" <span class="moduleimpl_abs_link"><a class="stdlink" href="{ url_for( "assiduites.signal_assiduites_diff", scodoc_dept=g.scodoc_dept, group_ids=group_id, semaine=semaine, formsemestre_id=formsemestre.id, moduleimpl_id="" if moduleimpl_id is None else moduleimpl_id )}" >Saisie Absences hebdo</a></span> """ ) H.append("</td></tr></table>") # if not modimpl.check_apc_conformity(nt): H.append( """<div class="warning conformite">Les poids des évaluations de ce module ne sont pas encore conformes au PN. Ses notes ne peuvent pas être prises en compte dans les moyennes d'UE. </div>""" ) if formsemestre_has_decisions(formsemestre_id): H.append( """<div class="formsemestre-warning-box"> <div class="warning">Décisions de jury saisies: seul le ou la responsable du semestre peut saisir des notes (elle devra modifier les décisions de jury). </div> </div>""" ) # H.append( f"""<p><form name="f"> <span style="font-size:120%%; font-weight: bold;">{nb_evaluations} évaluations :</span> <span style="padding-left: 30px;"> <input type="hidden" name="moduleimpl_id" value="{moduleimpl_id}"/>""" ) # # Liste les noms de partitions partitions = sco_groups.get_partitions_list(formsemestre.id) H.append( """Afficher les groupes de <select name="partition_id" onchange="document.f.submit();">""" ) been_selected = False for partition in partitions: if not partition_id and not been_selected: selected = "selected" been_selected = True if partition["partition_id"] == partition_id: selected = "selected" else: selected = "" name = partition["partition_name"] if name is None: name = "Tous" H.append( f"""<option value="{partition['partition_id']}" {selected}>{name}</option>""" ) H.append( f"""</select> <a class="stdlink" href="{ url_for("notes.evaluation_listenotes", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id) }">Voir toutes les notes</a> </span> </form> </p> """ ) # -------- Tableau des evaluations top_table_links = "" if can_edit_evals: top_table_links = f"""<a class="stdlink" href="{ url_for("notes.evaluation_create", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id) }">Créer nouvelle évaluation</a> """ if nb_evaluations > 0: top_table_links += f""" <a class="stdlink" style="margin-left:2em;" href="{ url_for("notes.moduleimpl_evaluation_renumber", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id) }">Trier par date</a> """ if nb_evaluations > 0: H.append( '<div class="moduleimpl_evaluations_top_links">' + top_table_links + "</div>" ) H.append("""<table class="moduleimpl_evaluations">""") eval_index = nb_evaluations - 1 first_eval = True for evaluation in evaluations: H.append( _ligne_evaluation( modimpl, evaluation, first_eval=first_eval, partition_id=partition_id, arrow_down=arrow_down, arrow_none=arrow_none, arrow_up=arrow_up, can_edit_evals=can_edit_evals, can_edit_notes=can_edit_notes, eval_index=eval_index, nb_evals=nb_evaluations, is_apc=nt.is_apc, max_poids=max_poids, ) ) eval_index -= 1 first_eval = False # H.append("""<tr><td colspan="8">""") if sem_locked: H.append(f"""{scu.icontag("lock32_img")} semestre verrouillé""") elif can_edit_evals: H.append(top_table_links) H.append( f"""</td></tr> </table> <div class="list_etuds_attente"> {_html_modimpl_etuds_attente(nt, modimpl)} </div> </div> <!-- LEGENDE --> <hr> <h4>Légende</h4> <ul> <li>{scu.icontag("edit_img")} : modifie description de l'évaluation (date, heure, coefficient, ...) </li> <li>{scu.icontag("notes_img")} : saisie des notes</li> <li>{scu.icontag("delete_img")} : indique qu'il n'y a aucune note entrée (cliquer pour supprimer cette évaluation) </li> <li>{scu.icontag("status_orange_img")} : indique qu'il manque quelques notes dans cette évaluation </li> <li>{scu.icontag("status_green_img")} : toutes les notes sont entrées (cliquer pour les afficher) </li> <li>{scu.icontag("status_visible_img")} : indique que cette évaluation sera mentionnée dans les bulletins au format "intermédiaire" </li> </ul> <p>Rappel : seules les notes des évaluations complètement saisies (affichées en vert) apparaissent dans les bulletins. </p> """ ) H.append(html_sco_header.sco_footer()) return "".join(H) def _ligne_evaluation( modimpl: ModuleImpl, evaluation: Evaluation, first_eval: bool = True, partition_id: int = None, arrow_down=None, arrow_none=None, arrow_up=None, can_edit_evals: bool = False, can_edit_notes: bool = False, eval_index: int = 0, nb_evals: int = 0, is_apc: bool = False, max_poids: float = 0.0, ) -> str: """Ligne <tr> décrivant une évaluation dans le tableau de bord moduleimpl.""" H = [] # evaluation: Evaluation = db.session.get(Evaluation, eval_dict["evaluation_id"]) etat = sco_evaluations.do_evaluation_etat( evaluation.id, partition_id=partition_id, select_first_partition=True, ) if evaluation.evaluation_type == Evaluation.EVALUATION_RATTRAPAGE: tr_class = "mievr mievr_rattr" elif evaluation.evaluation_type == Evaluation.EVALUATION_SESSION2: tr_class = "mievr mievr_session2" elif evaluation.evaluation_type == Evaluation.EVALUATION_BONUS: tr_class = "mievr mievr_bonus" else: tr_class = "mievr" if not evaluation.visibulletin: tr_class += " non_visible_inter" tr_class_1 = "mievr" if evaluation.is_blocked(): tr_class += " evaluation_blocked" tr_class_1 += " evaluation_blocked" if not first_eval: H.append("""<tr><td colspan="8"> </td></tr>""") tr_class_1 += " mievr_spaced" H.append( f"""<tr class="{tr_class_1} mievr_tit"><td class="mievr_tit" colspan="8">""" ) coef = evaluation.coefficient if is_apc: if not evaluation.get_ue_poids_dict(): # Au cas où les poids par défaut n'existent pas encore: if evaluation.set_default_poids(): db.session.commit() coef *= sum(evaluation.get_ue_poids_dict().values()) if modimpl.module.ue.type != UE_SPORT: # Avertissement si coefs x poids nuls if coef < scu.NOTES_PRECISION: if modimpl.module.module_type == scu.ModuleType.MALUS: H.append("""<span class="eval_warning_coef">malus</span>""") else: H.append("""<span class="eval_warning_coef">coef. nul !</span>""") elif is_apc: # visualisation des poids (Hinton map) H.append(_evaluation_poids_html(evaluation, max_poids)) H.append("""<div class="evaluation_titre">""") if evaluation.date_debut: H.append(evaluation.descr_date()) else: H.append( f"""<a href="{url_for("notes.evaluation_edit", scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }" class="mievr_evalnodate">Évaluation sans date</a>""" ) H.append(f" <em>{evaluation.description}</em>") if evaluation.evaluation_type == Evaluation.EVALUATION_RATTRAPAGE: H.append( """<span class="mievr_rattr" title="remplace si meilleure note">rattrapage</span>""" ) elif evaluation.evaluation_type == Evaluation.EVALUATION_SESSION2: H.append( """<span class="mievr_session2" title="remplace autres notes">session 2</span>""" ) elif evaluation.evaluation_type == Evaluation.EVALUATION_BONUS: H.append( """<span class="mievr_bonus" title="s'ajoute aux moyennes de ce module">bonus</span>""" ) # if etat["last_modif"]: H.append( f"""<span class="mievr_lastmodif">(dernière modif le { etat["last_modif"].strftime("%d/%m/%Y à %Hh%M")})</span>""" ) # H.append( f""" </td> <td class="evaluation_order"> <span class="evalindex" title="Indice dans les vecteurs (formules)">{ eval_index:2}</span> <span class="eval_arrows_chld"> """ ) # Fleches: if eval_index != (nb_evals - 1) and can_edit_evals: H.append( f"""<a href="{url_for("notes.moduleimpl_evaluation_move", scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id, after=0) }" class="aud">{arrow_up}</a>""" ) else: H.append(arrow_none) if (eval_index > 0) and can_edit_evals: H.append( f"""<a href="{url_for("notes.moduleimpl_evaluation_move", scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id, after=1) }" class="aud">{arrow_down}</a>""" ) else: H.append(arrow_none) if evaluation.is_blocked(): etat_txt = f"""évaluation bloquée { "jusqu'au " + evaluation.blocked_until.strftime("%d/%m/%Y") if evaluation.blocked_until < Evaluation.BLOCKED_FOREVER else "" } """ etat_descr = """prise en compte bloquée""" elif etat["evalcomplete"]: etat_txt = f"""Moyenne (prise en compte{ "" if evaluation.visibulletin else ", cachée en intermédiaire"}) """ etat_descr = f"""notes utilisées dans les moyennes{ ", évaluation cachée sur les bulletins en version intermédiaire et sur la passerelle" }""" elif etat["evalattente"] and not evaluation.publish_incomplete: etat_txt = "Moyenne (prise en compte, mais <b>notes en attente</b>)" etat_descr = "il y a des notes en attente" elif evaluation.publish_incomplete: etat_txt = """(prise en compte <b>immédiate</b>)""" etat_descr = ( "il manque des notes, mais la prise en compte immédiate a été demandée" ) elif etat["nb_notes"] != 0: etat_txt = "Moyenne (<b>non</b> prise en compte)" etat_descr = "il manque des notes" else: etat_txt = "" if etat_txt: if can_edit_evals: etat_txt = f"""<a href="{ url_for("notes.evaluation_edit", scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }" title="{etat_descr}">{etat_txt}</a>""" H.append( f"""</span></span></td> </tr> <tr class="{tr_class} mievr_in"> <th class="moduleimpl_evaluations" colspan="2"> </th> <th class="moduleimpl_evaluations">Durée</th> <th class="moduleimpl_evaluations">Coef.</th> <th class="moduleimpl_evaluations">Notes</th> <th class="moduleimpl_evaluations">Abs</th> <th class="moduleimpl_evaluations">N</th> <th class="moduleimpl_evaluations moduleimpl_evaluation_moy" colspan="2"><span>{etat_txt}</span></th> </tr> <tr class="{tr_class} mievr_in"> <td class="mievr">""" ) if can_edit_evals: H.append( f"""<a class="smallbutton" href="{url_for('notes.evaluation_edit', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">{scu.icontag("edit_img", alt="modifier", title="Modifier informations")}</a>""" ) if can_edit_notes: H.append( f"""<a class="smallbutton" href="{url_for('notes.saisie_notes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">{scu.icontag("notes_img", alt="saisie notes", title="Saisie des notes")}</a>""" ) if etat["nb_notes"] == 0: if can_edit_evals: H.append( f"""<a class="smallbutton" href="{url_for('notes.evaluation_delete', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">""" ) H.append(scu.icontag("delete_img", alt="supprimer", title="Supprimer")) if can_edit_evals: H.append("""</a>""") elif etat["evalcomplete"]: H.append( f"""<a class="smallbutton" href="{url_for('notes.evaluation_listenotes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">{scu.icontag("status_green_img", title="ok")}</a>""" ) else: if etat["evalattente"]: H.append( f"""<a class="smallbutton" href="{url_for('notes.evaluation_listenotes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">{scu.icontag( "status_greenorange_img", file_format="gif", title="notes en attente", )}</a>""" ) else: H.append( f"""<a class="smallbutton" href="{url_for('notes.evaluation_listenotes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">{scu.icontag("status_orange_img", title="il manque des notes")}</a>""" ) # if evaluation.visibulletin: H.append( scu.icontag( "status_visible_img", title="visible dans bulletins intermédiaires" ) ) else: H.append(" ") H.append('</td><td class="mievr_menu">') if can_edit_notes: H.append( moduleimpl_evaluation_menu( evaluation, nbnotes=etat["nb_notes"], ) ) # H.append( f"""</td> <td class="mievr_dur">{evaluation.descr_duree()}</td> <td class="rightcell mievr_coef">{evaluation.coefficient:g}</td> """ ) H.append( f""" <td class="rightcell mievr_nbnotes">{etat["nb_notes"]} / {etat["nb_inscrits"]}</td> <td class="rightcell mievr_coef">{etat["nb_abs"]}</td> <td class="rightcell mievr_coef">{etat["nb_neutre"]}</td> <td class="rightcell" colspan="2">""" % etat ) if etat["moy"]: H.append( f"""<b>{etat["moy"]} / 20</b> (<a class="stdlink" href="{ url_for('notes.evaluation_listenotes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">afficher</a>)""" ) else: H.append( f"""<a class="redlink" href="{url_for('notes.saisie_notes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id) }">saisir notes</a> """ ) H.append("""</td></tr>""") # if etat["nb_notes"] == 0: H.append(f"""<tr class="{tr_class}"><td></td>""") if modimpl.module.is_apc(): H.append( f"""<td colspan="8" class="eval_poids">{ evaluation.get_ue_poids_str()}</td>""" ) else: H.append('<td colspan="8"></td>') H.append("""</tr>""") else: # il y a deja des notes saisies gr_moyennes = etat["gr_moyennes"] first_group = True for gr_moyenne in gr_moyennes: H.append(f"""<tr class="{tr_class}"><td> </td>""") if first_group and modimpl.module.is_apc(): H.append( f"""<td class="eval_poids" colspan="4">{ evaluation.get_ue_poids_str()}</td>""" ) else: H.append("""<td colspan="4"></td>""") first_group = False if gr_moyenne["group_name"] is None: name = "Tous" # tous else: name = f"""Groupe {gr_moyenne["group_name"]}""" H.append( f"""<td colspan="2" class="mievr_grtit">{name} </td> <td colspan="2">""" ) if gr_moyenne["gr_nb_notes"] > 0: H.append( f"""{gr_moyenne["gr_moy"]} (<a href="{ url_for('notes.evaluation_listenotes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id, tf_submitted=1, **{'group_ids:list': gr_moyenne["group_id"]}) }">{gr_moyenne["gr_nb_notes"]} notes</a>""" ) if gr_moyenne["gr_nb_att"] > 0: H.append( f""", <span class="redboldtext">{ gr_moyenne["gr_nb_att"]} en attente</span>""" ) H.append(""")""") if gr_moyenne["group_id"] in etat["gr_incomplets"]: H.append("""[<font color="red">""") if can_edit_notes: H.append( f"""<a class="redlink" href="{url_for('notes.saisie_notes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id, **{'group_ids:list': gr_moyenne["group_id"]}) }">incomplet</a></font>]""" ) else: H.append("""incomplet</font>]""") else: H.append("""<span class="redboldtext"> """) if can_edit_notes: H.append( f"""<a class="redlink" href="{url_for('notes.saisie_notes', scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id, **{'group_ids:list': gr_moyenne["group_id"]}) }">""" ) H.append("pas de notes") if can_edit_notes: H.append("""</a>""") H.append("</span>") H.append("""</td></tr>""") return "\n".join(H) def _evaluation_poids_html(evaluation: Evaluation, max_poids: float = 0.0) -> str: """graphe html (Hinton map) montrant les poids x coef de l'évaluation""" ue_poids = evaluation.get_ue_poids_dict(sort=True) # { ue_id : poids } if not ue_poids: return "" if max_poids < scu.NOTES_PRECISION: return "" H = ( """<div class="evaluation_poids">""" + "\n".join( [ f"""<div title="poids vers {ue.acronyme}: {poids:g}"> <div style="--size:{math.sqrt(poids*(evaluation.coefficient)/max_poids*144)}px; {'background-color: ' + ue.color + ';' if ue.color else ''} "></div> </div>""" for ue, poids in ( (db.session.get(UniteEns, ue_id), poids) for ue_id, poids in ue_poids.items() ) ] ) + "</div>" ) return H def _html_modimpl_etuds_attente(res: ResultatsSemestre, modimpl: ModuleImpl) -> str: """Affiche la liste des étudiants ayant au moins une note en attente dans ce modimpl""" m_res = res.modimpls_results.get(modimpl.id) if m_res: if not m_res.etudids_attente: return "<div><em>Aucun étudiant n'a de notes en attente.</em></div>" elif len(m_res.etudids_attente) < 10: return f""" <h4>Étudiants avec une note en attente :</h4> {list_etuds.html_table_etuds(m_res.etudids_attente)} """ else: return f"""<div class="warning"><em>{ len(m_res.etudids_attente) } étudiants ont des notes en attente.</em></div>""" return ""