# -*- 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 # ############################################################################## """Vérification des absences à une évaluation """ from flask import url_for, g from flask_sqlalchemy.query import Query from app import db from app.models import Evaluation, FormSemestre, Identite, Assiduite import app.scodoc.sco_utils as scu from app.scodoc import html_sco_header from app.scodoc import sco_evaluations from app.scodoc import sco_evaluation_db from app.scodoc import sco_groups def evaluation_check_absences(evaluation: Evaluation): """Vérifie les absences au moment de cette évaluation. Cas incohérents que l'on peut rencontrer pour chaque étudiant: note et absent ABS et pas noté absent ABS et absent justifié EXC et pas noté absent EXC et pas justifie Ramene 5 listes d'etudid """ if not evaluation.date_debut or not evaluation.date_fin: return [], [], [], [], [] # evaluation sans date etudids = [ etudid for etudid, _ in sco_groups.do_evaluation_listeetuds_groups( evaluation.id, getallstudents=True ) ] deb, fin = scu.localize_datetime(evaluation.date_debut), scu.localize_datetime( evaluation.date_fin ) assiduites: Query = Assiduite.query.filter( Assiduite.etudid.in_(etudids), Assiduite.etat == scu.EtatAssiduite.ABSENT, fin >= Assiduite.date_debut, deb <= Assiduite.date_fin, ) abs_etudids = {assi.etudid for assi in assiduites} abs_nj_etudids = {assi.etudid for assi in assiduites if assi.est_just is False} just_etudids = {assi.etudid for assi in assiduites if assi.est_just is True} # Les notes: notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation.id) note_but_abs = [] # une note mais noté absent abs_non_signalee = [] # note ABS mais pas noté absent exc_non_signalee = [] # note EXC mais pas noté absent exc_non_just = [] # note EXC mais absent non justifie abs_but_exc = [] # note ABS mais justifié for etudid in etudids: if etudid in notes_db: val = notes_db[etudid]["value"] if ( val is not None and val != scu.NOTES_NEUTRALISE and val != scu.NOTES_ATTENTE ) and etudid in abs_etudids: # note valide et absent note_but_abs.append(etudid) if val is None and not etudid in abs_etudids: # absent mais pas signale comme tel abs_non_signalee.append(etudid) if val == scu.NOTES_NEUTRALISE and not etudid in abs_etudids: # Neutralisé mais pas signale absent exc_non_signalee.append(etudid) if val == scu.NOTES_NEUTRALISE and etudid in abs_nj_etudids: # EXC mais pas justifié exc_non_just.append(etudid) if val is None and etudid in just_etudids: # ABS mais justificatif abs_but_exc.append(etudid) return note_but_abs, abs_non_signalee, exc_non_signalee, exc_non_just, abs_but_exc def evaluation_check_absences_html( evaluation: Evaluation, with_header=True, show_ok=True ): """Affiche état vérification absences d'une évaluation""" ( note_but_abs, # une note alors qu'il était signalé abs abs_non_signalee, # note ABS alors que pas signalé abs exc_non_signalee, # note EXC alors que pas signalé abs exc_non_just, # note EXC alors que pas de justif abs_but_exc, # note ABS alors qu'il y a un justif ) = evaluation_check_absences(evaluation) if with_header: H = [ html_sco_header.html_sem_header( "Vérification absences à l'évaluation", formsemestre_id=evaluation.moduleimpl.formsemestre_id, ), sco_evaluations.evaluation_describe(evaluation_id=evaluation.id), """<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées.</p>""", ] else: # pas de header, mais un titre H = [ f"""<h2 class="eval_check_absences">{ evaluation.description or "évaluation" } du { evaluation.date_debut.strftime(scu.DATE_FMT) if evaluation.date_debut else "" } """ ] if ( not note_but_abs and not abs_non_signalee and not exc_non_signalee and not exc_non_just ): H.append(': <span class="eval_check_absences_ok">ok</span>') H.append("</h2>") def etudlist(etudids: list[int], linkabs=False): H.append("<ul>") if not etudids and show_ok: H.append("<li>aucun</li>") for etudid in etudids: etud: Identite = db.session.get(Identite, etudid) H.append( f"""<li><a class="discretelink" href="{ url_for( "scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid ) }">{etud.nomprenom}</a>""" ) if linkabs: url = url_for( "assiduites.signale_evaluation_abs", etudid=etudid, evaluation_id=evaluation.id, scodoc_dept=g.scodoc_dept, ) H.append( f"""<a style="margin-left: 16px;" class="stdlink" href="{ url}">signaler cette absence</a>""" ) H.append("</li>") H.append("</ul>") if note_but_abs or show_ok: H.append( "<h3>Étudiants ayant une note alors qu'ils sont signalés absents:</h3>" ) etudlist(note_but_abs) if abs_non_signalee or show_ok: H.append( """<h3>Étudiants avec note "ABS" alors qu'ils ne sont <em>pas</em> signalés absents:</h3>""" ) etudlist(abs_non_signalee, linkabs=True) if exc_non_signalee or show_ok: H.append( """<h3>Étudiants avec note "EXC" alors qu'ils ne sont <em>pas</em> signalés absents:</h3>""" ) etudlist(exc_non_signalee) if exc_non_just or show_ok: H.append( """<h3>Étudiants avec note "EXC" alors qu'ils sont absents <em>non justifiés</em>:</h3>""" ) etudlist(exc_non_just) if abs_but_exc or show_ok: H.append( """<h3>Étudiants avec note "ABS" alors qu'ils ont une <em>justification</em>:</h3>""" ) etudlist(abs_but_exc) if with_header: H.append(html_sco_header.sco_footer()) return "\n".join(H) def formsemestre_check_absences_html(formsemestre_id): """Affiche etat verification absences pour toutes les evaluations du semestre !""" formsemestre: FormSemestre = FormSemestre.query.filter_by( dept_id=g.scodoc_dept_id, id=formsemestre_id ).first_or_404() H = [ html_sco_header.html_sem_header( "Vérification absences aux évaluations de ce semestre", ), """<p class="help">Vérification de la cohérence entre les notes saisies et les absences signalées. Sont listés tous les modules avec des évaluations.<br>Aucune action n'est effectuée: il vous appartient de corriger les erreurs détectées si vous le jugez nécessaire. </p>""", ] # Modules, dans l'ordre for modimpl in formsemestre.modimpls_sorted: if modimpl.evaluations.count() > 0: H.append( f"""<div class="module_check_absences"> <h2><a href="{ url_for("notes.moduleimpl_status", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id) }">{modimpl.module.code or ""}: {modimpl.module.abbrev or ""}</a> </h2>""" ) for evaluation in modimpl.evaluations: H.append( evaluation_check_absences_html( evaluation, with_header=False, show_ok=False, ) ) H.append("</div>") H.append(html_sco_header.sco_footer()) return "\n".join(H)