2021-11-20 17:53:21 +01:00
|
|
|
# -*- mode: python -*-
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
##############################################################################
|
|
|
|
#
|
|
|
|
# Gestion scolarite IUT
|
|
|
|
#
|
2023-01-02 13:16:27 +01:00
|
|
|
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
|
2021-11-20 17:53:21 +01:00
|
|
|
#
|
|
|
|
# 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
|
|
|
|
#
|
|
|
|
##############################################################################
|
|
|
|
|
2022-04-10 17:38:59 +02:00
|
|
|
"""Vérification des absences à une évaluation
|
2021-11-20 17:53:21 +01:00
|
|
|
"""
|
|
|
|
from flask import url_for, g
|
|
|
|
|
2023-08-25 17:58:57 +02:00
|
|
|
from app import db
|
2023-08-27 21:49:50 +02:00
|
|
|
from app.models import Evaluation, FormSemestre, Identite
|
2021-11-20 17:53:21 +01:00
|
|
|
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
|
2023-08-27 21:49:50 +02:00
|
|
|
from app.scodoc.sco_exceptions import ScoValueError
|
2021-11-20 17:53:21 +01:00
|
|
|
from app.scodoc import sco_groups
|
|
|
|
|
|
|
|
|
2023-08-27 21:49:50 +02:00
|
|
|
# XXX TODO-ASSIDUITE https://scodoc.org/git/ScoDoc/ScoDoc/issues/685
|
2023-08-25 17:58:57 +02:00
|
|
|
def evaluation_check_absences(evaluation: Evaluation):
|
2021-11-20 17:53:21 +01:00
|
|
|
"""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
|
2023-08-25 17:58:57 +02:00
|
|
|
Ramene 5 listes d'etudid
|
2021-11-20 17:53:21 +01:00
|
|
|
"""
|
2023-08-27 21:49:50 +02:00
|
|
|
raise ScoValueError("Fonction non disponible, patience !") # XXX TODO-ASSIDUITE
|
|
|
|
|
2023-08-25 17:58:57 +02:00
|
|
|
if not evaluation.date_debut:
|
2021-11-20 17:53:21 +01:00
|
|
|
return [], [], [], [], [] # evaluation sans date
|
|
|
|
|
2023-08-25 17:58:57 +02:00
|
|
|
am, pm = evaluation.is_matin(), evaluation.is_apresmidi()
|
2021-11-20 17:53:21 +01:00
|
|
|
|
|
|
|
# Liste les absences à ce moment:
|
2023-08-25 17:58:57 +02:00
|
|
|
absences = sco_abs.list_abs_jour(evaluation.date_debut, am=am, pm=pm)
|
|
|
|
abs_etudids = set([x["etudid"] for x in absences]) # ensemble des etudiants absents
|
|
|
|
abs_non_just = sco_abs.list_abs_non_just_jour(
|
|
|
|
evaluation.date_debut.date(), am=am, pm=pm
|
|
|
|
)
|
|
|
|
abs_nj_etudids = set(
|
|
|
|
[x["etudid"] for x in abs_non_just]
|
|
|
|
) # ensemble des etudiants absents non justifies
|
|
|
|
justifs = sco_abs.list_abs_jour(
|
|
|
|
evaluation.date_debut.date(), am=am, pm=pm, is_abs=None, is_just=True
|
2021-11-20 17:53:21 +01:00
|
|
|
)
|
2023-08-25 17:58:57 +02:00
|
|
|
just_etudids = set(
|
|
|
|
[x["etudid"] for x in justifs]
|
|
|
|
) # ensemble des etudiants avec justif
|
2021-11-20 17:53:21 +01:00
|
|
|
|
|
|
|
# Les notes:
|
2023-08-25 17:58:57 +02:00
|
|
|
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation.id)
|
2021-11-20 17:53:21 +01:00
|
|
|
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(
|
2023-08-25 17:58:57 +02:00
|
|
|
evaluation.id, getallstudents=True
|
2021-11-20 17:53:21 +01:00
|
|
|
):
|
2022-01-17 00:18:08 +01:00
|
|
|
if etudid in notes_db:
|
|
|
|
val = notes_db[etudid]["value"]
|
2021-11-20 17:53:21 +01:00
|
|
|
if (
|
2023-08-25 17:58:57 +02:00
|
|
|
val is not None
|
|
|
|
and val != scu.NOTES_NEUTRALISE
|
|
|
|
and val != scu.NOTES_ATTENTE
|
|
|
|
) and etudid in abs_etudids:
|
2021-11-20 17:53:21 +01:00
|
|
|
# note valide et absent
|
|
|
|
ValButAbs.append(etudid)
|
2023-08-25 17:58:57 +02:00
|
|
|
if val is None and not etudid in abs_etudids:
|
2021-11-20 17:53:21 +01:00
|
|
|
# absent mais pas signale comme tel
|
|
|
|
AbsNonSignalee.append(etudid)
|
2023-08-25 17:58:57 +02:00
|
|
|
if val == scu.NOTES_NEUTRALISE and not etudid in abs_etudids:
|
2021-11-20 17:53:21 +01:00
|
|
|
# Neutralisé mais pas signale absent
|
|
|
|
ExcNonSignalee.append(etudid)
|
2023-08-25 17:58:57 +02:00
|
|
|
if val == scu.NOTES_NEUTRALISE and etudid in abs_nj_etudids:
|
2021-11-20 17:53:21 +01:00
|
|
|
# EXC mais pas justifié
|
|
|
|
ExcNonJust.append(etudid)
|
2023-08-25 17:58:57 +02:00
|
|
|
if val is None and etudid in just_etudids:
|
2021-11-20 17:53:21 +01:00
|
|
|
# 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"""
|
2023-08-25 17:58:57 +02:00
|
|
|
evaluation: Evaluation = db.session.get(Evaluation, evaluation_id)
|
|
|
|
am, pm = evaluation.is_matin(), evaluation.is_apresmidi()
|
|
|
|
# 1 si matin, 0 si apres midi, 2 si toute la journee:
|
|
|
|
match am, pm:
|
|
|
|
case False, True:
|
|
|
|
demijournee = 0
|
|
|
|
case True, False:
|
|
|
|
demijournee = 1
|
|
|
|
case _:
|
|
|
|
demijournee = 2
|
2021-11-20 17:53:21 +01:00
|
|
|
|
|
|
|
(
|
|
|
|
ValButAbs,
|
|
|
|
AbsNonSignalee,
|
|
|
|
ExcNonSignalee,
|
|
|
|
ExcNonJust,
|
|
|
|
AbsButExc,
|
2023-08-25 17:58:57 +02:00
|
|
|
) = evaluation_check_absences(evaluation)
|
2021-11-20 17:53:21 +01:00
|
|
|
|
|
|
|
if with_header:
|
|
|
|
H = [
|
|
|
|
html_sco_header.html_sem_header("Vérification absences à l'évaluation"),
|
2023-08-25 17:58:57 +02:00
|
|
|
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>""",
|
2021-11-20 17:53:21 +01:00
|
|
|
]
|
|
|
|
else:
|
|
|
|
# pas de header, mais un titre
|
|
|
|
H = [
|
2023-08-25 17:58:57 +02:00
|
|
|
f"""<h2 class="eval_check_absences">{
|
|
|
|
evaluation.description or "évaluation"
|
|
|
|
} du {
|
|
|
|
evaluation.date_debut.strftime("%d/%m/%Y") if evaluation.date_debut else ""
|
|
|
|
} """
|
2021-11-20 17:53:21 +01:00
|
|
|
]
|
|
|
|
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:
|
2023-08-25 17:58:57 +02:00
|
|
|
etud: Identite = db.session.get(Identite, etudid)
|
2021-11-20 17:53:21 +01:00
|
|
|
H.append(
|
2023-08-25 17:58:57 +02:00
|
|
|
f"""<li><a class="discretelink" href="{
|
|
|
|
url_for(
|
|
|
|
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid
|
|
|
|
)
|
|
|
|
}">{etud.nomprenom}</a>"""
|
2021-11-20 17:53:21 +01:00
|
|
|
)
|
|
|
|
if linkabs:
|
2023-08-25 17:58:57 +02:00
|
|
|
url = url_for(
|
2023-08-27 21:49:50 +02:00
|
|
|
"absences.doSignaleAbsence", # XXX TODO-ASSIDUITE
|
2021-11-20 17:53:21 +01:00
|
|
|
scodoc_dept=g.scodoc_dept,
|
2023-08-25 17:58:57 +02:00
|
|
|
etudid=etudid,
|
|
|
|
# par defaut signale le jour du début de l'éval
|
|
|
|
datedebut=evaluation.date_debut.strftime("%d/%m/%Y"),
|
|
|
|
datefin=evaluation.date_debut.strftime("%d/%m/%Y"),
|
2021-11-20 17:53:21 +01:00
|
|
|
demijournee=demijournee,
|
2023-08-25 17:58:57 +02:00
|
|
|
moduleimpl_id=evaluation.moduleimpl_id,
|
|
|
|
)
|
|
|
|
H.append(
|
|
|
|
f"""<a class="stdlink" href="{url}">signaler cette absence</a>"""
|
2021-11-20 17:53:21 +01:00
|
|
|
)
|
|
|
|
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 !"""
|
2023-08-27 21:49:50 +02:00
|
|
|
formsemestre: FormSemestre = FormSemestre.query.filter_by(
|
|
|
|
dept_id=g.scodoc_dept_id, id=formsemestre_id
|
|
|
|
).first_or_404()
|
2021-11-20 17:53:21 +01:00
|
|
|
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.
|
2022-10-02 23:43:29 +02:00
|
|
|
Sont listés tous les modules avec des évaluations.<br>Aucune action n'est effectuée:
|
2021-11-20 17:53:21 +01:00
|
|
|
il vous appartient de corriger les erreurs détectées si vous le jugez nécessaire.
|
|
|
|
</p>""",
|
|
|
|
]
|
|
|
|
# Modules, dans l'ordre
|
2023-08-27 21:49:50 +02:00
|
|
|
for modimpl in formsemestre.modimpls_sorted:
|
|
|
|
if modimpl.evaluations.count() > 0:
|
2021-11-20 17:53:21 +01:00
|
|
|
H.append(
|
2023-08-27 21:49:50 +02:00
|
|
|
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>"""
|
2021-11-20 17:53:21 +01:00
|
|
|
)
|
2023-08-27 21:49:50 +02:00
|
|
|
for evaluation in modimpl.evaluations.order_by(
|
|
|
|
Evaluation.numero, Evaluation.date_debut
|
|
|
|
):
|
|
|
|
H.append(
|
|
|
|
evaluation_check_absences_html(
|
|
|
|
evaluation.id, # XXX TODO-ASSIDUITE remplacer par evaluation ...
|
|
|
|
with_header=False,
|
|
|
|
show_ok=False,
|
|
|
|
)
|
2021-11-20 17:53:21 +01:00
|
|
|
)
|
|
|
|
H.append("</div>")
|
2023-08-27 21:49:50 +02:00
|
|
|
|
2021-11-20 17:53:21 +01:00
|
|
|
H.append(html_sco_header.sco_footer())
|
|
|
|
return "\n".join(H)
|