# -*- mode: python -*- # -*- coding: utf-8 -*- ############################################################################## # # Gestion scolarite IUT # # Copyright (c) 1999 - 2023 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 import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb from app.scodoc import html_sco_header from app.scodoc import sco_abs from app.scodoc import sco_etud 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 # matin et/ou après-midi ? def _eval_demijournee(E): "1 si matin, 0 si apres midi, 2 si toute la journee" am, pm = False, False if E["heure_debut"] < "13:00": am = True if E["heure_fin"] > "13:00": pm = True if am and pm: demijournee = 2 elif am: demijournee = 1 else: demijournee = 0 pm = True return am, pm, demijournee def evaluation_check_absences(evaluation_id): """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 3 listes d'etudid """ E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0] if not E["jour"]: return [], [], [], [], [] # evaluation sans date am, pm, demijournee = _eval_demijournee(E) # Liste les absences à ce moment: A = sco_abs.list_abs_jour(ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm) As = set([x["etudid"] for x in A]) # ensemble des etudiants absents NJ = sco_abs.list_abs_non_just_jour(ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm) NJs = set([x["etudid"] for x in NJ]) # ensemble des etudiants absents non justifies Just = sco_abs.list_abs_jour( ndb.DateDMYtoISO(E["jour"]), am=am, pm=pm, is_abs=None, is_just=True ) Justs = set([x["etudid"] for x in Just]) # ensemble des etudiants avec justif # Les notes: notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id) ValButAbs = [] # une note mais noté absent AbsNonSignalee = [] # note ABS mais pas noté absent ExcNonSignalee = [] # note EXC mais pas noté absent ExcNonJust = [] # note EXC mais absent non justifie AbsButExc = [] # note ABS mais justifié for etudid, _ in sco_groups.do_evaluation_listeetuds_groups( evaluation_id, getallstudents=True ): if etudid in notes_db: val = notes_db[etudid]["value"] if ( val != None and val != scu.NOTES_NEUTRALISE and val != scu.NOTES_ATTENTE ) and etudid in As: # note valide et absent ValButAbs.append(etudid) if val is None and not etudid in As: # absent mais pas signale comme tel AbsNonSignalee.append(etudid) if val == scu.NOTES_NEUTRALISE and not etudid in As: # Neutralisé mais pas signale absent ExcNonSignalee.append(etudid) if val == scu.NOTES_NEUTRALISE and etudid in NJs: # EXC mais pas justifié ExcNonJust.append(etudid) if val is None and etudid in Justs: # ABS mais justificatif AbsButExc.append(etudid) return ValButAbs, AbsNonSignalee, ExcNonSignalee, ExcNonJust, AbsButExc def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True): """Affiche état vérification absences d'une évaluation""" E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0] am, pm, demijournee = _eval_demijournee(E) ( ValButAbs, AbsNonSignalee, ExcNonSignalee, ExcNonJust, AbsButExc, ) = evaluation_check_absences(evaluation_id) if with_header: H = [ html_sco_header.html_sem_header("Vérification absences à l'évaluation"), 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 = [ """<h2 class="eval_check_absences">%s du %s """ % (E["description"], E["jour"]) ] if ( not ValButAbs and not AbsNonSignalee and not ExcNonSignalee and not ExcNonJust ): H.append(': <span class="eval_check_absences_ok">ok</span>') H.append("</h2>") def etudlist(etudids, linkabs=False): H.append("<ul>") if not etudids and show_ok: H.append("<li>aucun</li>") for etudid in etudids: etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0] H.append( '<li><a class="discretelink" href="%s">' % url_for( "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud["etudid"] ) + "%(nomprenom)s</a>" % etud ) if linkabs: H.append( f"""<a class="stdlink" href="{url_for( 'absences.doSignaleAbsence', scodoc_dept=g.scodoc_dept, etudid=etud["etudid"], datedebut=E["jour"], datefin=E["jour"], demijournee=demijournee, moduleimpl_id=E["moduleimpl_id"], ) }">signaler cette absence</a>""" ) H.append("</li>") H.append("</ul>") if ValButAbs or show_ok: H.append( "<h3>Etudiants ayant une note alors qu'ils sont signalés absents:</h3>" ) etudlist(ValButAbs) if AbsNonSignalee or show_ok: H.append( """<h3>Etudiants avec note "ABS" alors qu'ils ne sont <em>pas</em> signalés absents:</h3>""" ) etudlist(AbsNonSignalee, linkabs=True) if ExcNonSignalee or show_ok: H.append( """<h3>Etudiants avec note "EXC" alors qu'ils ne sont <em>pas</em> signalés absents:</h3>""" ) etudlist(ExcNonSignalee) if ExcNonJust or show_ok: H.append( """<h3>Etudiants avec note "EXC" alors qu'ils sont absents <em>non justifiés</em>:</h3>""" ) etudlist(ExcNonJust) if AbsButExc or show_ok: H.append( """<h3>Etudiants avec note "ABS" alors qu'ils ont une <em>justification</em>:</h3>""" ) etudlist(AbsButExc) 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 !""" sem = sco_formsemestre.get_formsemestre(formsemestre_id) 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 Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id) for M in Mlist: evals = sco_evaluation_db.do_evaluation_list( {"moduleimpl_id": M["moduleimpl_id"]} ) if evals: H.append( '<div class="module_check_absences"><h2><a href="moduleimpl_status?moduleimpl_id=%s">%s: %s</a></h2>' % ( M["moduleimpl_id"], M["module"]["code"] or "", M["module"]["abbrev"] or "", ) ) for E in evals: H.append( evaluation_check_absences_html( E["evaluation_id"], with_header=False, show_ok=False, ) ) if evals: H.append("</div>") H.append(html_sco_header.sco_footer()) return "\n".join(H)