Enlève l'ancien module de gestion des absences

This commit is contained in:
Emmanuel Viennet 2023-08-27 21:49:50 +02:00
parent deaeb88cf9
commit f7186c6316
23 changed files with 202 additions and 3197 deletions

View File

@ -66,7 +66,6 @@ def get_model_api_object(model_cls: db.Model, model_id: int, join_cls: db.Model
from app.api import tokens from app.api import tokens
from app.api import ( from app.api import (
absences,
assiduites, assiduites,
billets_absences, billets_absences,
departements, departements,

View File

@ -1,263 +0,0 @@
##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved.
# See LICENSE
##############################################################################
"""ScoDoc 9 API : Absences
"""
from flask_json import as_json
from app import db
from app.api import api_bp as bp, API_CLIENT_ERROR
from app.scodoc.sco_utils import json_error
from app.decorators import scodoc, permission_required
from app.models import Identite
from app.scodoc import notesdb as ndb
from app.scodoc import sco_abs
from app.scodoc.sco_groups import get_group_members
from app.scodoc.sco_permissions import Permission
# TODO XXX revoir routes web API et calcul des droits
@bp.route("/absences/etudid/<int:etudid>", methods=["GET"])
@scodoc
@permission_required(Permission.ScoView)
@as_json
def absences(etudid: int = None):
"""
Liste des absences de cet étudiant
Exemple de résultat:
[
{
"jour": "2022-04-15",
"matin": true,
"estabs": true,
"estjust": true,
"description": "",
"begin": "2022-04-15 08:00:00",
"end": "2022-04-15 11:59:59"
},
{
"jour": "2022-04-15",
"matin": false,
"estabs": true,
"estjust": false,
"description": "",
"begin": "2022-04-15 12:00:00",
"end": "2022-04-15 17:59:59"
}
]
"""
etud = db.session.get(Identite, etudid)
if etud is None:
return json_error(404, message="etudiant inexistant")
# Absences de l'étudiant
ndb.open_db_connection()
abs_list = sco_abs.list_abs_date(etud.id)
for absence in abs_list:
absence["jour"] = absence["jour"].isoformat()
return abs_list
@bp.route("/absences/etudid/<int:etudid>/just", methods=["GET"])
@scodoc
@permission_required(Permission.ScoView)
@as_json
def absences_just(etudid: int = None):
"""
Retourne la liste des absences justifiées d'un étudiant donné
etudid : l'etudid d'un étudiant
nip: le code nip d'un étudiant
ine : le code ine d'un étudiant
Exemple de résultat :
[
{
"jour": "2022-04-15",
"matin": true,
"estabs": true,
"estjust": true,
"description": "",
"begin": "2022-04-15 08:00:00",
"end": "2022-04-15 11:59:59"
},
{
"jour": "Fri, 15 Apr 2022 00:00:00 GMT",
"matin": false,
"estabs": true,
"estjust": true,
"description": "",
"begin": "2022-04-15 12:00:00",
"end": "2022-04-15 17:59:59"
}
]
"""
etud = db.session.get(Identite, etudid)
if etud is None:
return json_error(404, message="etudiant inexistant")
# Absences justifiées de l'étudiant
abs_just = [
absence for absence in sco_abs.list_abs_date(etud.id) if absence["estjust"]
]
for absence in abs_just:
absence["jour"] = absence["jour"].isoformat()
return abs_just
@bp.route(
"/absences/abs_group_etat/<int:group_id>",
methods=["GET"],
)
@bp.route(
"/absences/abs_group_etat/group_id/<int:group_id>/date_debut/<string:date_debut>/date_fin/<string:date_fin>",
methods=["GET"],
)
@scodoc
@permission_required(Permission.ScoView)
@as_json
def abs_groupe_etat(group_id: int, date_debut=None, date_fin=None):
"""
Liste des absences d'un groupe (possibilité de choisir entre deux dates)
group_id = l'id du groupe
date_debut = None par défaut, sinon la date ISO du début de notre filtre
date_fin = None par défaut, sinon la date ISO de la fin de notre filtre
Exemple de résultat :
[
{
"etudid": 1,
"list_abs": []
},
{
"etudid": 2,
"list_abs": [
{
"jour": "Fri, 15 Apr 2022 00:00:00 GMT",
"matin": true,
"estabs": true,
"estjust": true,
"description": "",
"begin": "2022-04-15 08:00:00",
"end": "2022-04-15 11:59:59"
},
{
"jour": "Fri, 15 Apr 2022 00:00:00 GMT",
"matin": false,
"estabs": true,
"estjust": false,
"description": "",
"begin": "2022-04-15 12:00:00",
"end": "2022-04-15 17:59:59"
},
]
},
...
]
"""
members = get_group_members(group_id)
data = []
# Filtre entre les deux dates renseignées
for member in members:
absence = {
"etudid": member["etudid"],
"list_abs": sco_abs.list_abs_date(member["etudid"], date_debut, date_fin),
}
data.append(absence)
return data
# XXX TODO EV: A REVOIR (data json dans le POST + modifier les routes)
# @bp.route(
# "/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs",
# methods=["POST"],
# defaults={"just_or_not": 0},
# )
# @bp.route(
# "/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs/only_not_just",
# methods=["POST"],
# defaults={"just_or_not": 1},
# )
# @bp.route(
# "/absences/etudid/<int:etudid>/list_abs/<string:list_abs>/reset_etud_abs/only_just",
# methods=["POST"],
# defaults={"just_or_not": 2},
# )
# @token_auth.login_required
# @token_permission_required(Permission.APIAbsChange)
# def reset_etud_abs(etudid: int, list_abs: str, just_or_not: int = 0):
# """
# Set la liste des absences d'un étudiant sur tout un semestre.
# (les absences existant pour cet étudiant sur cette période sont effacées)
# etudid : l'id d'un étudiant
# list_abs : json d'absences
# just_or_not : 0 (pour les absences justifiées et non justifiées),
# 1 (pour les absences justifiées),
# 2 (pour les absences non justifiées)
# """
# # Toutes les absences
# if just_or_not == 0:
# # suppression des absences et justificatif déjà existant pour éviter les doublons
# for abs in list_abs:
# # Récupération de la date au format iso
# jour = abs["jour"].isoformat()
# if abs["matin"] is True:
# annule_absence(etudid, jour, True)
# annule_justif(etudid, jour, True)
# else:
# annule_absence(etudid, jour, False)
# annule_justif(etudid, jour, False)
# # Ajout de la liste d'absences en base
# add_abslist(list_abs)
# # Uniquement les absences justifiées
# elif just_or_not == 1:
# list_abs_not_just = []
# # Trie des absences justifiées
# for abs in list_abs:
# if abs["estjust"] is False:
# list_abs_not_just.append(abs)
# # suppression des absences et justificatif déjà existant pour éviter les doublons
# for abs in list_abs:
# # Récupération de la date au format iso
# jour = abs["jour"].isoformat()
# if abs["matin"] is True:
# annule_absence(etudid, jour, True)
# annule_justif(etudid, jour, True)
# else:
# annule_absence(etudid, jour, False)
# annule_justif(etudid, jour, False)
# # Ajout de la liste d'absences en base
# add_abslist(list_abs_not_just)
# # Uniquement les absences non justifiées
# elif just_or_not == 2:
# list_abs_just = []
# # Trie des absences non justifiées
# for abs in list_abs:
# if abs["estjust"] is True:
# list_abs_just.append(abs)
# # suppression des absences et justificatif déjà existant pour éviter les doublons
# for abs in list_abs:
# # Récupération de la date au format iso
# jour = abs["jour"].isoformat()
# if abs["matin"] is True:
# annule_absence(etudid, jour, True)
# annule_justif(etudid, jour, True)
# else:
# annule_absence(etudid, jour, False)
# annule_justif(etudid, jour, False)
# # Ajout de la liste d'absences en base
# add_abslist(list_abs_just)

File diff suppressed because it is too large Load Diff

View File

@ -364,7 +364,7 @@ def get_all_justified(
# Gestion du cache # Gestion du cache
def get_assiduites_count(etudid, sem): def get_assiduites_count(etudid: int, sem: dict) -> tuple[int, int]:
"""Les comptes d'absences de cet étudiant dans ce semestre: """Les comptes d'absences de cet étudiant dans ce semestre:
tuple (nb abs non justifiées, nb abs justifiées) tuple (nb abs non justifiées, nb abs justifiées)
Utilise un cache. Utilise un cache.
@ -378,25 +378,43 @@ def get_assiduites_count(etudid, sem):
) )
def formsemestre_get_assiduites_count(
etudid: int, formsemestre: FormSemestre
) -> tuple[int, int]:
"""Les comptes d'absences de cet étudiant dans ce semestre:
tuple (nb abs non justifiées, nb abs justifiées)
Utilise un cache.
"""
metrique = sco_preferences.get_preference("assi_metrique", formsemestre.id)
return get_assiduites_count_in_interval(
etudid,
date_debut=formsemestre.date_debut,
date_fin=formsemestre.date_fin,
metrique=scu.translate_assiduites_metric(metrique),
)
def get_assiduites_count_in_interval( def get_assiduites_count_in_interval(
etudid, date_debut_iso, date_fin_iso, metrique="demi" etudid,
date_debut_iso: str = "",
date_fin_iso: str = "",
metrique="demi",
date_debut: datetime = None,
date_fin: datetime = None,
): ):
"""Les comptes d'absences de cet étudiant entre ces deux dates, incluses: """Les comptes d'absences de cet étudiant entre ces deux dates, incluses:
tuple (nb abs, nb abs justifiées) tuple (nb abs, nb abs justifiées)
On peut spécifier les dates comme datetime ou iso.
Utilise un cache. Utilise un cache.
""" """
key = ( date_debut_iso = date_debut_iso or date_debut.isoformat()
str(etudid) date_fin_iso = date_fin_iso or date_fin.isoformat()
+ "_" key = f"{etudid}_{date_debut_iso}_{date_fin_iso}{metrique}_assiduites"
+ date_debut_iso
+ "_"
+ date_fin_iso
+ f"{metrique}_assiduites"
)
r = sco_cache.AbsSemEtudCache.get(key) r = sco_cache.AbsSemEtudCache.get(key)
if not r: if not r:
date_debut: datetime.datetime = scu.is_iso_formated(date_debut_iso, True) date_debut: datetime = date_debut or datetime.fromisoformat(date_debut_iso)
date_fin: datetime.datetime = scu.is_iso_formated(date_fin_iso, True) date_fin: datetime = date_fin or datetime.fromisoformat(date_fin_iso)
assiduites: Assiduite = Assiduite.query.filter_by(etudid=etudid) assiduites: Assiduite = Assiduite.query.filter_by(etudid=etudid)
assiduites = assiduites.filter(Assiduite.etat == scu.EtatAssiduite.ABSENT) assiduites = assiduites.filter(Assiduite.etat == scu.EtatAssiduite.ABSENT)

View File

@ -58,14 +58,12 @@ from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import htmlutils from app.scodoc import htmlutils
from app.scodoc import sco_assiduites from app.scodoc import sco_assiduites
from app.scodoc import sco_abs_views
from app.scodoc import sco_bulletins_generator from app.scodoc import sco_bulletins_generator
from app.scodoc import sco_bulletins_json from app.scodoc import sco_bulletins_json
from app.scodoc import sco_bulletins_pdf from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_bulletins_xml from app.scodoc import sco_bulletins_xml
from app.scodoc import codes_cursus from app.scodoc import codes_cursus
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
@ -1116,9 +1114,10 @@ def mail_bulletin(formsemestre_id, infos, pdfdata, filename, recipient_addr):
hea = "" hea = ""
if sco_preferences.get_preference("bul_mail_list_abs"): if sco_preferences.get_preference("bul_mail_list_abs"):
hea += "\n\n" + sco_abs_views.ListeAbsEtud( hea += "\n\n" + "(LISTE D'ABSENCES NON DISPONIBLE)" # XXX TODO-ASSIDUITE
etud["etudid"], with_evals=False, format="text" # sco_abs_views.ListeAbsEtud(
) # etud["etudid"], with_evals=False, format="text"
# )
subject = f"""Relevé de notes de {etud["nomprenom"]}""" subject = f"""Relevé de notes de {etud["nomprenom"]}"""
recipients = [recipient_addr] recipients = [recipient_addr]

View File

@ -132,10 +132,13 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
if sco_preferences.get_preference( if sco_preferences.get_preference(
"bul_show_minmax_mod", formsemestre_id "bul_show_minmax_mod", formsemestre_id
): ):
rang_minmax = '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>' % ( rang_minmax = (
mod["mod_rang_txt"], '%s <span class="bul_minmax" title="[min, max] UE">[%s, %s]</span>'
scu.fmt_note(mod["stats"]["min"]), % (
scu.fmt_note(mod["stats"]["max"]), mod["mod_rang_txt"],
scu.fmt_note(mod["stats"]["min"]),
scu.fmt_note(mod["stats"]["max"]),
)
) )
else: else:
rang_minmax = mod["mod_rang_txt"] # vide si pas option rang rang_minmax = mod["mod_rang_txt"] # vide si pas option rang
@ -301,9 +304,11 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
authuser = self.authuser authuser = self.authuser
H = [] H = []
# --- Absences # --- Absences
# XXX TODO-ASSIDUITE
# au passage, utiliser url_for...
H.append( H.append(
"""<p> """<p>
<a href="../Absences/CalAbs?etudid=%(etudid)s" class="bull_link"> XXX <a href="../Absences/CalAbs?etudid=%(etudid)s" class="bull_link">
<b>Absences :</b> %(nbabs)s demi-journées, dont %(nbabsjust)s justifiées <b>Absences :</b> %(nbabs)s demi-journées, dont %(nbabsjust)s justifiées
(pendant ce semestre). (pendant ce semestre).
</a></p> </a></p>

View File

@ -124,9 +124,12 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
nbabs = self.infos["nbabs"] nbabs = self.infos["nbabs"]
story.append(Spacer(1, 2 * mm)) story.append(Spacer(1, 2 * mm))
if nbabs: if nbabs:
# XXX TODO-ASSIDUITE
# et utiliser url_for...
H.append( H.append(
"""<p class="bul_abs"> """<p class="bul_abs">
<a href="../Absences/CalAbs?etudid=%(etudid)s" class="bull_link"> <a href="../Absences/CalAbs?etudid=%(etudid)s" class="bull_link">
XXX
<b>Absences :</b> %(nbabs)s demi-journées, dont %(nbabsjust)s justifiées <b>Absences :</b> %(nbabs)s demi-journées, dont %(nbabsjust)s justifiées
(pendant ce semestre). (pendant ce semestre).
</a></p> </a></p>

View File

@ -30,18 +30,16 @@
from flask import url_for, g from flask import url_for, g
from app import db from app import db
from app.models import Evaluation, Identite from app.models import Evaluation, FormSemestre, Identite
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import html_sco_header 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_evaluations
from app.scodoc import sco_evaluation_db from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formsemestre from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
# XXX TODO-ASSIDUITE https://scodoc.org/git/ScoDoc/ScoDoc/issues/685
def evaluation_check_absences(evaluation: Evaluation): def evaluation_check_absences(evaluation: Evaluation):
"""Vérifie les absences au moment de cette évaluation. """Vérifie les absences au moment de cette évaluation.
Cas incohérents que l'on peut rencontrer pour chaque étudiant: Cas incohérents que l'on peut rencontrer pour chaque étudiant:
@ -52,6 +50,8 @@ def evaluation_check_absences(evaluation: Evaluation):
EXC et pas justifie EXC et pas justifie
Ramene 5 listes d'etudid Ramene 5 listes d'etudid
""" """
raise ScoValueError("Fonction non disponible, patience !") # XXX TODO-ASSIDUITE
if not evaluation.date_debut: if not evaluation.date_debut:
return [], [], [], [], [] # evaluation sans date return [], [], [], [], [] # evaluation sans date
@ -169,7 +169,7 @@ def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True
) )
if linkabs: if linkabs:
url = url_for( url = url_for(
"absences.doSignaleAbsence", "absences.doSignaleAbsence", # XXX TODO-ASSIDUITE
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
etudid=etudid, etudid=etudid,
# par defaut signale le jour du début de l'éval # par defaut signale le jour du début de l'éval
@ -221,7 +221,9 @@ def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True
def formsemestre_check_absences_html(formsemestre_id): def formsemestre_check_absences_html(formsemestre_id):
"""Affiche etat verification absences pour toutes les evaluations du semestre !""" """Affiche etat verification absences pour toutes les evaluations du semestre !"""
sem = sco_formsemestre.get_formsemestre(formsemestre_id) formsemestre: FormSemestre = FormSemestre.query.filter_by(
dept_id=g.scodoc_dept_id, id=formsemestre_id
).first_or_404()
H = [ H = [
html_sco_header.html_sem_header( html_sco_header.html_sem_header(
"Vérification absences aux évaluations de ce semestre", "Vérification absences aux évaluations de ce semestre",
@ -232,29 +234,27 @@ def formsemestre_check_absences_html(formsemestre_id):
</p>""", </p>""",
] ]
# Modules, dans l'ordre # Modules, dans l'ordre
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id) for modimpl in formsemestre.modimpls_sorted:
for M in Mlist: if modimpl.evaluations.count() > 0:
evals = sco_evaluation_db.get_evaluation_dict(
{"moduleimpl_id": M["moduleimpl_id"]}
)
if evals:
H.append( H.append(
'<div class="module_check_absences"><h2><a href="moduleimpl_status?moduleimpl_id=%s">%s: %s</a></h2>' f"""<div class="module_check_absences">
% ( <h2><a href="{
M["moduleimpl_id"], url_for("notes.moduleimpl_status",
M["module"]["code"] or "", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
M["module"]["abbrev"] or "", }">{modimpl.module.code or ""}: {modimpl.module.abbrev or ""}</a>
) </h2>"""
) )
for E in evals: for evaluation in modimpl.evaluations.order_by(
H.append( Evaluation.numero, Evaluation.date_debut
evaluation_check_absences_html( ):
E["evaluation_id"], H.append(
with_header=False, evaluation_check_absences_html(
show_ok=False, evaluation.id, # XXX TODO-ASSIDUITE remplacer par evaluation ...
with_header=False,
show_ok=False,
)
) )
)
if evals:
H.append("</div>") H.append("</div>")
H.append(html_sco_header.sco_footer()) H.append(html_sco_header.sco_footer())
return "\n".join(H) return "\n".join(H)

View File

@ -46,8 +46,8 @@ from app.scodoc.sco_utils import ModuleType
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc.gen_tables import GenTable from app.scodoc.gen_tables import GenTable
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_cal
from app.scodoc import sco_evaluation_db from app.scodoc import sco_evaluation_db
from app.scodoc import sco_abs
from app.scodoc import sco_edit_module from app.scodoc import sco_edit_module
from app.scodoc import sco_edit_ue from app.scodoc import sco_edit_ue
from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_formsemestre_inscriptions
@ -475,7 +475,7 @@ def formsemestre_evaluations_cal(formsemestre_id):
if color == color_futur: if color == color_futur:
event[2] = color_futur event[2] = color_futur
cal_html = sco_abs.YearTable( cal_html = sco_cal.YearTable(
year, events=list(events.values()), halfday=False, pad_width=None year, events=list(events.values()), halfday=False, pad_width=None
) )

View File

@ -888,13 +888,14 @@ def _make_listes_sem(formsemestre: FormSemestre, with_absences=True):
if n_members == 0: if n_members == 0:
continue # skip empty groups continue # skip empty groups
partition_is_empty = False partition_is_empty = False
group["url_etat"] = url_for( # XXX TODO-ASSIDUITE
"absences.EtatAbsencesGr", group["url_etat"] = "non disponible" # url_for(
group_ids=group["group_id"], # "absences.EtatAbsencesGr",
debut=formsemestre.date_debut.strftime("%d/%m/%Y"), # group_ids=group["group_id"],
fin=formsemestre.date_fin.strftime("%d/%m/%Y"), # debut=formsemestre.date_debut.strftime("%d/%m/%Y"),
scodoc_dept=g.scodoc_dept, # fin=formsemestre.date_fin.strftime("%d/%m/%Y"),
) # scodoc_dept=g.scodoc_dept,
# )
if group["group_name"]: if group["group_name"]:
group["label"] = "groupe %(group_name)s" % group group["label"] = "groupe %(group_name)s" % group
else: else:

View File

@ -45,7 +45,7 @@ from app import db
from app.models import FormSemestre from app.models import FormSemestre
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import sco_abs from app.scodoc import sco_cal
from app.scodoc import sco_excel from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups from app.scodoc import sco_groups
@ -829,7 +829,8 @@ def tab_absences_html(groups_infos, etat=None):
"<li>", "<li>",
form_choix_jour_saisie_hebdo(groups_infos), form_choix_jour_saisie_hebdo(groups_infos),
"</li>", "</li>",
"""<li><a class="stdlink" href="Absences/EtatAbsencesGr?%s&debut=%s&fin=%s">État des absences du groupe</a></li>""" # XXX TODO-ASSIDUITE
"""<li><a class="stdlink" href="Absences/EtatAbsencesGr?%s&debut=%s&fin=%s">XXX État des absences du groupe</a></li>"""
% ( % (
groups_infos.groups_query_args, groups_infos.groups_query_args,
groups_infos.formsemestre["date_debut"], groups_infos.formsemestre["date_debut"],
@ -890,12 +891,13 @@ def form_choix_jour_saisie_hebdo(groups_infos, moduleimpl_id=None):
if not authuser.has_permission(Permission.ScoAbsChange): if not authuser.has_permission(Permission.ScoAbsChange):
return "" return ""
sem = groups_infos.formsemestre sem = groups_infos.formsemestre
first_monday = sco_abs.ddmmyyyy(sem["date_debut"]).prev_monday() first_monday = sco_cal.ddmmyyyy(sem["date_debut"]).prev_monday()
today_idx = datetime.date.today().weekday() today_idx = datetime.date.today().weekday()
FA = [] # formulaire avec menu saisi absences FA = [] # formulaire avec menu saisi absences
FA.append( FA.append(
'<form id="form_choix_jour_saisie_hebdo" action="Absences/SignaleAbsenceGrSemestre" method="get">' # TODO-ASSIDUITE et utiliser url_for... (was Absences/SignaleAbsenceGrSemestre)
'<form id="form_choix_jour_saisie_hebdo" action="XXX" method="get">'
) )
FA.append('<input type="hidden" name="datefin" value="%(date_fin)s"/>' % sem) FA.append('<input type="hidden" name="datefin" value="%(date_fin)s"/>' % sem)
FA.append(groups_infos.get_form_elem()) FA.append(groups_infos.get_form_elem())
@ -906,12 +908,12 @@ def form_choix_jour_saisie_hebdo(groups_infos, moduleimpl_id=None):
FA.append('<input type="hidden" name="destination" value=""/>') FA.append('<input type="hidden" name="destination" value=""/>')
FA.append( FA.append(
"""<input type="button" onclick="$('#form_choix_jour_saisie_hebdo')[0].destination.value=get_current_url(); $('#form_choix_jour_saisie_hebdo').submit();" value="Saisir absences du "/>""" """<input type="button" onclick="$('#form_choix_jour_saisie_hebdo')[0].destination.value=get_current_url(); $('#form_choix_jour_saisie_hebdo').submit();" value="Saisir absences du (NON DISPONIBLE) "/>"""
) )
FA.append("""<select name="datedebut">""") FA.append("""<select name="datedebut">""")
date = first_monday date = first_monday
i = 0 i = 0
for jour in sco_abs.day_names(): for jour in sco_cal.day_names():
if i == today_idx: if i == today_idx:
sel = "selected" sel = "selected"
else: else:
@ -945,14 +947,17 @@ def form_choix_saisie_semaine(groups_infos):
) # car ici utilisee dans un format string ! ) # car ici utilisee dans un format string !
DateJour = time.strftime("%d/%m/%Y") DateJour = time.strftime("%d/%m/%Y")
datelundi = sco_abs.ddmmyyyy(DateJour).prev_monday() datelundi = sco_cal.ddmmyyyy(DateJour).prev_monday()
FA = [] # formulaire avec menu saisie hebdo des absences FA = [] # formulaire avec menu saisie hebdo des absences
# XXX TODO-ASSIDUITE et utiliser un POST
FA.append('<form action="Absences/SignaleAbsenceGrHebdo" method="get">') FA.append('<form action="Absences/SignaleAbsenceGrHebdo" method="get">')
FA.append('<input type="hidden" name="datelundi" value="%s"/>' % datelundi) FA.append('<input type="hidden" name="datelundi" value="%s"/>' % datelundi)
FA.append('<input type="hidden" name="moduleimpl_id" value="%s"/>' % moduleimpl_id) FA.append('<input type="hidden" name="moduleimpl_id" value="%s"/>' % moduleimpl_id)
FA.append('<input type="hidden" name="destination" value="%s"/>' % destination) FA.append('<input type="hidden" name="destination" value="%s"/>' % destination)
FA.append(groups_infos.get_form_elem()) FA.append(groups_infos.get_form_elem())
FA.append('<input type="submit" class="button" value="Saisie à la semaine" />') FA.append(
'<input type="submit" class="button" value="Saisie à la semaine (NON DISPONIBLE)" />'
) # XXX
FA.append("</form>") FA.append("</form>")
return "\n".join(FA) return "\n".join(FA)

View File

@ -230,7 +230,7 @@ def do_moduleimpl_inscription_list(moduleimpl_id=None, etudid=None):
return _moduleimpl_inscriptionEditor.list(cnx, args) return _moduleimpl_inscriptionEditor.list(cnx, args)
def moduleimpl_listeetuds(moduleimpl_id): def moduleimpl_listeetuds(moduleimpl_id): # XXX OBSOLETE
"retourne liste des etudids inscrits a ce module" "retourne liste des etudids inscrits a ce module"
req = """SELECT DISTINCT Im.etudid req = """SELECT DISTINCT Im.etudid
FROM notes_moduleimpl_inscription Im, FROM notes_moduleimpl_inscription Im,

View File

@ -47,7 +47,7 @@ from app.scodoc.sco_permissions import Permission
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.scodoc import htmlutils from app.scodoc import htmlutils
from app.scodoc import sco_abs from app.scodoc import sco_cal
from app.scodoc import sco_compute_moy from app.scodoc import sco_compute_moy
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db from app.scodoc import sco_evaluation_db
@ -332,10 +332,6 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
'<tr><td colspan="4">' '<tr><td colspan="4">'
# <em title="mode de calcul de la moyenne du module">règle de calcul standard</em>' # <em title="mode de calcul de la moyenne du module">règle de calcul standard</em>'
) )
# if sco_moduleimpl.can_change_ens(moduleimpl_id, raise_exc=False):
# H.append(
# f' (<a class="stdlink" href="edit_moduleimpl_expr?moduleimpl_id={moduleimpl_id}">changer</a>)'
# )
H.append("</td></tr>") H.append("</td></tr>")
H.append( H.append(
f"""<tr><td colspan="4"><span class="moduleimpl_abs_link"><a class="stdlink" f"""<tr><td colspan="4"><span class="moduleimpl_abs_link"><a class="stdlink"
@ -349,17 +345,20 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
current_user.has_permission(Permission.ScoAbsChange) current_user.has_permission(Permission.ScoAbsChange)
and formsemestre.est_courant() and formsemestre.est_courant()
): ):
datelundi = sco_abs.ddmmyyyy(time.strftime("%d/%m/%Y")).prev_monday() datelundi = sco_cal.ddmmyyyy(time.strftime("%d/%m/%Y")).prev_monday()
group_id = sco_groups.get_default_group(formsemestre_id) group_id = sco_groups.get_default_group(formsemestre_id)
H.append( H.append(
f""" f"""
<span class="moduleimpl_abs_link"><a class="stdlink" <span class="moduleimpl_abs_link"><a class="stdlink" href="XXX"
href="{url_for("absences.SignaleAbsenceGrHebdo", >Saisie Absences hebdo. (INDISPONIBLE)</a></span>
scodoc_dept=g.scodoc_dept,formsemestre_id=formsemestre_id,
moduleimpl_id=moduleimpl_id, datelundi=datelundi, group_ids=group_id)}">
Saisie Absences hebdo.</a></span>
""" """
) )
# TODO-ASSIDUITE
# href="{
# url_for("absences.SignaleAbsenceGrHebdo",
# scodoc_dept=g.scodoc_dept,formsemestre_id=formsemestre_id,
# moduleimpl_id=moduleimpl_id, datelundi=datelundi, group_ids=group_id)
# }"
H.append("</td></tr></table>") H.append("</td></tr></table>")
# #

View File

@ -45,7 +45,6 @@ from app.models import (
FormSemestre, FormSemestre,
Module, Module,
ModuleImpl, ModuleImpl,
NotesNotes,
ScolarNews, ScolarNews,
) )
from app.models.etudiants import Identite from app.models.etudiants import Identite
@ -54,16 +53,13 @@ from app.scodoc.sco_exceptions import (
AccessDenied, AccessDenied,
InvalidNoteValue, InvalidNoteValue,
NoteProcessError, NoteProcessError,
ScoBugCatcher,
ScoException, ScoException,
ScoInvalidParamError, ScoInvalidParamError,
ScoValueError, ScoValueError,
) )
from app.scodoc import html_sco_header, sco_users from app.scodoc import html_sco_header, sco_users
from app.scodoc import htmlutils from app.scodoc import htmlutils
from app.scodoc import sco_abs
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_edit_module
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc import sco_evaluation_db from app.scodoc import sco_evaluation_db
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
@ -71,7 +67,6 @@ from app.scodoc import sco_excel
from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_groups_view from app.scodoc import sco_groups_view
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_permissions_check from app.scodoc import sco_permissions_check
from app.scodoc import sco_undo_notes from app.scodoc import sco_undo_notes
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
@ -1113,16 +1108,16 @@ def _get_sorted_etuds(evaluation: Evaluation, etudids: list, formsemestre_id: in
) )
warn_abs_lst = [] warn_abs_lst = []
if evaluation.is_matin(): if evaluation.is_matin():
nbabs = sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=True) nbabs = 0 # TODO-ASSIDUITE sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=True)
nbabsjust = sco_abs.count_abs_just(etudid, jour_iso, jour_iso, matin=True) nbabsjust = 0 # TODO-ASSIDUITE sco_abs.count_abs_just(etudid, jour_iso, jour_iso, matin=True)
if nbabs: if nbabs:
if nbabsjust: if nbabsjust:
warn_abs_lst.append("absent justifié le matin !") warn_abs_lst.append("absent justifié le matin !")
else: else:
warn_abs_lst.append("absent le matin !") warn_abs_lst.append("absent le matin !")
if evaluation.is_apresmidi(): if evaluation.is_apresmidi():
nbabs = sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=0) nbabs = 0 # TODO-ASSIDUITE sco_abs.count_abs(etudid, jour_iso, jour_iso, matin=0)
nbabsjust = sco_abs.count_abs_just(etudid, jour_iso, jour_iso, matin=0) nbabsjust = 0 # TODO-ASSIDUITE sco_abs.count_abs_just(etudid, jour_iso, jour_iso, matin=0)
if nbabs: if nbabs:
if nbabsjust: if nbabsjust:
warn_abs_lst.append("absent justifié l'après-midi !") warn_abs_lst.append("absent justifié l'après-midi !")

View File

@ -41,7 +41,7 @@ from reportlab.lib.units import cm
from reportlab.platypus import KeepInFrame, Paragraph, Table, TableStyle from reportlab.platypus import KeepInFrame, Paragraph, Table, TableStyle
from reportlab.platypus.doctemplate import BaseDocTemplate from reportlab.platypus.doctemplate import BaseDocTemplate
from app.scodoc import sco_abs from app.scodoc import sco_cal
from app.scodoc import sco_etud from app.scodoc import sco_etud
from app.scodoc.sco_exceptions import ScoPDFFormatError from app.scodoc.sco_exceptions import ScoPDFFormatError
from app.scodoc import sco_groups from app.scodoc import sco_groups
@ -299,9 +299,9 @@ def pdf_feuille_releve_absences(
NB_CELL_PM = sco_preferences.get_preference("feuille_releve_abs_PM") NB_CELL_PM = sco_preferences.get_preference("feuille_releve_abs_PM")
col_width = 0.85 * cm col_width = 0.85 * cm
if sco_preferences.get_preference("feuille_releve_abs_samedi"): if sco_preferences.get_preference("feuille_releve_abs_samedi"):
days = sco_abs.DAYNAMES[:6] # Lundi, ..., Samedi days = sco_cal.DAYNAMES[:6] # Lundi, ..., Samedi
else: else:
days = sco_abs.DAYNAMES[:5] # Lundi, ..., Vendredi days = sco_cal.DAYNAMES[:5] # Lundi, ..., Vendredi
nb_days = len(days) nb_days = len(days)
# Informations sur les groupes à afficher: # Informations sur les groupes à afficher:

View File

@ -1,47 +0,0 @@
// JS Ajax code for SignaleAbsenceGrSemestre
// Contributed by YLB
function ajaxFunction(mod, etudid, dat) {
var ajaxRequest; // The variable that makes Ajax possible!
try {
// Opera 8.0+, Firefox, Safari
ajaxRequest = new XMLHttpRequest();
} catch (e) {
// Internet Explorer Browsers
try {
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
// Something went wrong
alert("Your browser broke!");
return false;
}
}
}
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function () {
if (ajaxRequest.readyState == 4 && ajaxRequest.status == 200) {
document.getElementById("AjaxDiv").innerHTML = ajaxRequest.responseText;
}
}
ajaxRequest.open("POST", SCO_URL + "/Absences/doSignaleAbsenceGrSemestre", true);
ajaxRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var oSelectOne = $("#abs_form")[0].elements["moduleimpl_id"];
var index = oSelectOne.selectedIndex;
var modul_id = oSelectOne.options[index].value;
if (mod == 'add') {
ajaxRequest.send("reply=0&moduleimpl_id=" + modul_id + "&abslist:list=" + etudid + ":" + dat);
}
if (mod == 'remove') {
ajaxRequest.send("reply=0&moduleimpl_id=" + modul_id + "&etudids=" + etudid + "&dates=" + dat);
}
}
// -----
function change_moduleimpl(url) {
document.location = url + '&moduleimpl_id=' + document.getElementById('moduleimpl_id').value;
}

File diff suppressed because it is too large Load Diff

View File

@ -547,7 +547,6 @@ def signal_assiduites_group():
+ [ + [
# Voir fonctionnement JS # Voir fonctionnement JS
"js/etud_info.js", "js/etud_info.js",
"js/abs_ajax.js",
"js/groups_view.js", "js/groups_view.js",
"js/assiduites.js", "js/assiduites.js",
"libjs/moment.new.min.js", "libjs/moment.new.min.js",

View File

@ -97,9 +97,9 @@ from app.scodoc.sco_exceptions import (
) )
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
from app.pe import pe_view from app.pe import pe_view
from app.scodoc import sco_abs
from app.scodoc import sco_apogee_compare from app.scodoc import sco_apogee_compare
from app.scodoc import sco_archives from app.scodoc import sco_archives
from app.scodoc import sco_assiduites
from app.scodoc import sco_bulletins from app.scodoc import sco_bulletins
from app.scodoc import sco_bulletins_pdf from app.scodoc import sco_bulletins_pdf
from app.scodoc import sco_cache from app.scodoc import sco_cache
@ -1152,175 +1152,64 @@ def edit_moduleimpl_resp(moduleimpl_id: int):
) )
_EXPR_HELP = """<p class="help">Expérimental: formule de calcul de la moyenne %(target)s</p>
<p class="help">Attention: l'utilisation de formules ralentit considérablement
les traitements. A utiliser uniquement dans les cas ne pouvant pas être traités autrement.</p>
<p class="help">Dans la formule, les variables suivantes sont définies:</p>
<ul class="help">
<li><tt>moy</tt> la moyenne, calculée selon la règle standard (moyenne pondérée)</li>
<li><tt>moy_is_valid</tt> vrai si la moyenne est valide (numérique)</li>
<li><tt>moy_val</tt> la valeur de la moyenne (nombre, valant 0 si invalide)</li>
<li><tt>notes</tt> vecteur des notes (/20) aux %(objs)s</li>
<li><tt>coefs</tt> vecteur des coefficients des %(objs)s, les coefs des %(objs)s sans notes (ATT, EXC) étant mis à zéro</li>
<li><tt>cmask</tt> vecteur de 0/1, 0 si le coef correspondant a été annulé</li>
<li>Nombre d'absences: <tt>nb_abs</tt>, <tt>nb_abs_just</tt>, <tt>nb_abs_nojust</tt> (en demi-journées)</li>
</ul>
<p class="help">Les éléments des vecteurs sont ordonnés dans l'ordre des %(objs)s%(ordre)s.</p>
<p class="help">Les fonctions suivantes sont utilisables: <tt>abs, cmp, dot, len, map, max, min, pow, reduce, round, sum, ifelse</tt>.</p>
<p class="help">La notation <tt>V(1,2,3)</tt> représente un vecteur <tt>(1,2,3)</tt>.</p>
<p class="help"></p>Pour indiquer que la note calculée n'existe pas, utiliser la chaîne <tt>'NA'</tt>.</p>
<p class="help">Vous pouvez désactiver la formule (et revenir au mode de calcul "classique")
en supprimant le texte ou en faisant précéder la première ligne par <tt>#</tt></p>
"""
@bp.route("/edit_moduleimpl_expr", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def edit_moduleimpl_expr(moduleimpl_id):
"""Edition formule calcul moyenne module
Accessible par Admin, dir des etud et responsable module
Inutilisé en ScoDoc 9.
"""
M, sem = sco_moduleimpl.can_change_ens(moduleimpl_id)
H = [
html_sco_header.html_sem_header(
'Modification règle de calcul du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>'
% (moduleimpl_id, M["module"]["titre"]),
),
_EXPR_HELP
% {
"target": "du module",
"objs": "évaluations",
"ordre": " (le premier élément est la plus ancienne évaluation)",
},
]
initvalues = M
form = [
("moduleimpl_id", {"input_type": "hidden"}),
(
"computation_expr",
{
"title": "Formule de calcul",
"input_type": "textarea",
"rows": 4,
"cols": 60,
"explanation": "formule de calcul (expérimental)",
},
),
]
tf = TrivialFormulator(
request.base_url,
scu.get_request_args(),
form,
submitlabel="Modifier formule de calcul",
cancelbutton="Annuler",
initvalues=initvalues,
)
if tf[0] == 0:
return "\n".join(H) + tf[1] + html_sco_header.sco_footer()
elif tf[0] == -1:
return flask.redirect(
url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=moduleimpl_id,
)
)
else:
sco_moduleimpl.do_moduleimpl_edit(
{
"moduleimpl_id": moduleimpl_id,
"computation_expr": tf[2]["computation_expr"],
},
formsemestre_id=sem["formsemestre_id"],
)
sco_cache.invalidate_formsemestre(
formsemestre_id=sem["formsemestre_id"]
) # > modif regle calcul
flash("règle de calcul modifiée")
return flask.redirect(
url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=moduleimpl_id,
)
)
@bp.route("/delete_moduleimpl_expr", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.ScoView)
@scodoc7func
def delete_moduleimpl_expr(moduleimpl_id):
"""Suppression formule calcul moyenne module
Accessible par Admin, dir des etud et responsable module
"""
modimpl = ModuleImpl.query.get_or_404(moduleimpl_id)
sco_moduleimpl.can_change_ens(moduleimpl_id)
modimpl.computation_expr = None
db.session.add(modimpl)
db.session.commit()
flash("Ancienne formule supprimée")
return flask.redirect(
url_for(
"notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=moduleimpl_id,
)
)
@bp.route("/view_module_abs") @bp.route("/view_module_abs")
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func @scodoc7func
def view_module_abs(moduleimpl_id, format="html"): def view_module_abs(moduleimpl_id, fmt="html"):
"""Visualisation des absences a un module""" """Visualisation des absences a un module"""
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0] modimpl: ModuleImpl = (
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"]) ModuleImpl.query.filter_by(id=moduleimpl_id)
debut_sem = ndb.DateDMYtoISO(sem["date_debut"]) .join(FormSemestre)
fin_sem = ndb.DateDMYtoISO(sem["date_fin"]) .filter_by(dept_id=g.scodoc_dept_id)
list_insc = sco_moduleimpl.moduleimpl_listeetuds(moduleimpl_id) ).first_or_404()
T = [] debut_sem = modimpl.formsemestre.date_debut
for etudid in list_insc: fin_sem = modimpl.formsemestre.date_fin
nb_abs = sco_abs.count_abs( inscrits: list[Identite] = sorted(
etudid=etudid, [i.etud for i in modimpl.inscriptions], key=lambda e: e.sort_key
debut=debut_sem, )
fin=fin_sem,
moduleimpl_id=moduleimpl_id, rows = []
for etud in inscrits:
# TODO-ASSIDUITE ne va pas car ne filtre pas sur le moduleimpl
# nb_abs, nb_abs_just = sco_assiduites.formsemestre_get_assiduites_count(etud.id, modimpl.formsemestre)
nb_abs, nb_abs_just = 0, 0 # XXX TODO-ASSIDUITE
# nb_abs = sco_abs.count_abs(
# etudid=etud.id,
# debut=debut_sem,
# fin=fin_sem,
# moduleimpl_id=moduleimpl_id,
# )
# if nb_abs:
# nb_abs_just = sco_abs.count_abs_just(
# etudid=etud.id,
# debut=debut_sem,
# fin=fin_sem,
# moduleimpl_id=moduleimpl_id,
# )
rows.append(
{
"nomprenom": etud.nomprenom,
"just": nb_abs_just,
"nojust": nb_abs - nb_abs_just,
"total": nb_abs,
"_nomprenom_target": url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id
),
}
) )
if nb_abs:
nb_abs_just = sco_abs.count_abs_just(
etudid=etudid,
debut=debut_sem,
fin=fin_sem,
moduleimpl_id=moduleimpl_id,
)
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
T.append(
{
"nomprenom": etud["nomprenom"],
"just": nb_abs_just,
"nojust": nb_abs - nb_abs_just,
"total": nb_abs,
"_nomprenom_target": url_for(
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid
),
}
)
H = [ H = [
html_sco_header.html_sem_header( html_sco_header.html_sem_header(
'Absences du <a href="moduleimpl_status?moduleimpl_id=%s">module %s</a>' f"""Absences du <a href="{
% (moduleimpl_id, M["module"]["titre"]), url_for("notes.moduleimpl_status",
page_title="Absences du module %s" % (M["module"]["titre"]), scodoc_dept=g.scodoc_dept, moduleimpl_id=moduleimpl_id
)}">module {modimpl.module.titre_str()}</a>""",
page_title=f"Absences du module {modimpl.module.titre_str()}",
) )
] ]
if not T and format == "html": if not rows and fmt == "html":
return ( return (
"\n".join(H) "\n".join(H)
+ "<p>Aucune absence signalée</p>" + "<p>Aucune absence signalée</p>"
@ -1335,16 +1224,16 @@ def view_module_abs(moduleimpl_id, format="html"):
"total": "Total", "total": "Total",
}, },
columns_ids=("nomprenom", "just", "nojust", "total"), columns_ids=("nomprenom", "just", "nojust", "total"),
rows=T, rows=rows,
html_class="table_leftalign", html_class="table_leftalign",
base_url="%s?moduleimpl_id=%s" % (request.base_url, moduleimpl_id), base_url=f"{request.base_url}?moduleimpl_id={moduleimpl_id}",
filename="absmodule_" + scu.make_filename(M["module"]["titre"]), filename="absmodule_" + scu.make_filename(modimpl.module.titre_str()),
caption="Absences dans le module %s" % M["module"]["titre"], caption=f"Absences dans le module {modimpl.module.titre_str()}",
preferences=sco_preferences.SemPreferences(), preferences=sco_preferences.SemPreferences(),
) )
if format != "html": if fmt != "html":
return tab.make_page(format=format) return tab.make_page(format=fmt)
return "\n".join(H) + tab.html() + html_sco_header.sco_footer() return "\n".join(H) + tab.html() + html_sco_header.sco_footer()

View File

@ -1,117 +0,0 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
"""
Comptage des absences
"""
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
from tests.unit import sco_fake_gen
from app.scodoc import sco_abs, sco_formsemestre
from app.scodoc import sco_abs_views
def test_abs_counts(test_client):
"""Comptage des absences"""
G = sco_fake_gen.ScoFake(verbose=False)
# --- Création d'étudiants
etud = G.create_etud(code_nip=None)
# --- Création d'une formation
formation_id = G.create_formation(acronyme="")
ue_id = G.create_ue(formation_id=formation_id, acronyme="TST1", titre="ue test")
matiere_id = G.create_matiere(ue_id=ue_id, titre="matière test")
module_id = G.create_module(
matiere_id=matiere_id,
code="TSM1",
coefficient=1.0,
titre="module test",
)
# --- Mise place d'un semestre
formsemestre_id = G.create_formsemestre(
formation_id=formation_id,
semestre_id=1,
date_debut="01/01/2021",
date_fin="30/06/2021",
)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
_ = G.create_moduleimpl(
module_id=module_id,
formsemestre_id=formsemestre_id,
)
# --- Inscription des étudiants
G.inscrit_etudiant(formsemestre_id, etud)
# --- Saisie absences
etudid = etud["etudid"]
for debut, fin, demijournee in [
("01/01/2020", "31/01/2020", 2), # hors semestre
("15/01/2021", "15/01/2021", 1),
("18/01/2021", "18/01/2021", 0),
("19/01/2021", "19/01/2021", 2),
("22/01/2021", "22/01/2021", 1),
("30/06/2021", "30/06/2021", 2), # dernier jour
]:
sco_abs_views.doSignaleAbsence(
datedebut=debut,
datefin=fin,
demijournee=demijournee,
etudid=etudid,
)
# --- Justification de certaines absences
for debut, fin, demijournee in [
("15/01/2021", "15/01/2021", 1),
("18/01/2021", "18/01/2021", 0),
("19/01/2021", "19/01/2021", 2),
]:
sco_abs_views.doJustifAbsence(
datedebut=debut,
datefin=fin,
demijournee=demijournee,
etudid=etudid,
)
# --- Utilisation de get_abs_count() de sco_abs
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
# --- Utilisation de sco_abs.count_abs()
nb_abs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
nb_absj2 = sco_abs.count_abs_just(
etudid=etudid, debut="2021-01-01", fin="2021-06-30"
)
assert nbabs == nb_abs2 == 7
assert nbabsjust == nb_absj2 == 4
# --- Nombre de justificatifs:
justifs = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
assert len(justifs) == 4
# --- Suppression d'absence
_ = sco_abs_views.doAnnuleAbsence("19/01/2021", "19/01/2021", 2, etudid=etudid)
# --- Vérification
justifs_2 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
assert len(justifs_2) == len(justifs)
new_nbabs, _ = sco_abs.get_abs_count(etudid, sem) # version cachée
new_nbabs2 = sco_abs.count_abs(etudid=etudid, debut="2021-01-01", fin="2021-06-30")
assert new_nbabs == new_nbabs2
assert new_nbabs == (nbabs - 2) # on a supprimé deux absences
# --- annulation absence sans supprimer le justificatif
sco_abs_views.AnnuleAbsencesDatesNoJust(etudid, ["2021-01-15"])
nbabs_3, nbjust_3 = sco_abs.get_abs_count(etudid, sem)
assert nbabs_3 == new_nbabs
justifs_3 = sco_abs.list_abs_justifs(etudid, "2021-01-01", datefin="2021-06-30")
assert len(justifs_3) == len(justifs_2)
# XXX à continuer

View File

@ -1,344 +0,0 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
"""
Créer et justifier des absences en utilisant le parametre demijournee
"""
# test écrit par Fares Amer, mai 2021 et porté sur ScoDoc 8 en juillet 2021
import datetime
import json
from tests.unit import sco_fake_gen
from app import db
from app.models import Module
from app.scodoc import sco_abs
from app.scodoc import sco_abs_views
from app.scodoc import sco_groups
from app.scodoc import sco_formsemestre
from app.scodoc import sco_preferences
from app.views import absences
def test_abs_demijournee(test_client):
"""Opération élémentaires sur les absences, tests demi-journées
Travaille dans base TEST00 (defaut)
"""
G = sco_fake_gen.ScoFake(verbose=False)
# --- Création d'étudiants
etud = G.create_etud(code_nip=None)
# --- Création d'une formation
formation_id = G.create_formation(acronyme="")
ue_id = G.create_ue(formation_id=formation_id, acronyme="TST1", titre="ue test")
matiere_id = G.create_matiere(ue_id=ue_id, titre="matière test")
module_id = G.create_module(
matiere_id=matiere_id,
code="TSM1",
coefficient=1.0,
titre="module test",
)
# --- Mise place d'un semestre
formsemestre_id = G.create_formsemestre(
formation_id=formation_id,
semestre_id=1,
date_debut="01/01/2021",
date_fin="30/06/2021",
)
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
_ = G.create_moduleimpl(
module_id=module_id,
formsemestre_id=formsemestre_id,
)
# --- Inscription des étudiants
G.inscrit_etudiant(formsemestre_id, etud)
# --- Saisie absences
etudid = etud["etudid"]
_ = sco_abs_views.doSignaleAbsence(
"15/01/2021",
"15/01/2021",
demijournee=2,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
"18/01/2021",
"18/01/2021",
demijournee=1,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
"19/01/2021",
"19/01/2021",
demijournee=0,
etudid=etudid,
)
# --- Justification de certaines absences
_ = sco_abs_views.doJustifAbsence(
"18/01/2021",
"18/01/2021",
demijournee=1,
etudid=etudid,
)
_ = sco_abs_views.doJustifAbsence(
"19/01/2021",
"19/01/2021",
demijournee=2,
etudid=etudid,
)
# NE JUSTIFIE QUE LE MATIN MALGRES LE PARAMETRE demijournee = 2
# --- Test
nbabs, nbabs_just = sco_abs.get_abs_count(etudid, sem)
assert (
nbabs == 4
) # l'étudiant a été absent le 15 journée compléte (2 abs : 1 matin, 1 apres midi) et le 18 (1 matin), et le 19 (1 apres midi).
assert nbabs_just == 2 # Justifie abs du matin + abs après midi
def test_abs_basic(test_client):
"""creation de 10 étudiants, formation, semestre, ue, module, absences le matin, l'apres midi, la journée compléte
et justification d'absences, supression d'absences, création d'une liste etat absences, creation d'un groupe afin
de tester la fonction EtatAbsencesGroupes
Fonctions de l'API utilisé :
- doSignaleAbsence
- doAnnuleAbsence
- doJustifAbsence
- get_partition_groups
- get_partitions_list
- sco_abs.get_abs_count(etudid, sem)
- ListeAbsEtud
- partition_create
- create_group
- set_group
- EtatAbsencesGr
- AddBilletAbsence
- billets_etud
"""
G = sco_fake_gen.ScoFake(verbose=False)
# --- Création d'étudiants
etuds = [G.create_etud(code_nip=None) for _ in range(10)]
# --- Création d'une formation
formation_id = G.create_formation(acronyme="")
ue_id = G.create_ue(formation_id=formation_id, acronyme="TST1", titre="ue test")
matiere_id = G.create_matiere(ue_id=ue_id, titre="matière test")
module_id = G.create_module(
matiere_id=matiere_id,
code="TSM1",
coefficient=1.0,
titre="module test",
)
# --- Mise place d'un semestre
formsemestre_id = G.create_formsemestre(
formation_id=formation_id,
semestre_id=1,
date_debut="01/01/2021",
date_fin="30/06/2021",
)
moduleimpl_id = G.create_moduleimpl(
module_id=module_id,
formsemestre_id=formsemestre_id,
)
# --- Inscription des étudiants
for etud in etuds:
G.inscrit_etudiant(formsemestre_id, etud)
# --- Création d'une évaluation
e = G.create_evaluation(
moduleimpl_id=moduleimpl_id,
date_debut=datetime.datetime(2021, 1, 22),
description="evaluation test",
coefficient=1.0,
)
# --- Saisie absences
etudid = etuds[0]["etudid"]
_ = sco_abs_views.doSignaleAbsence(
"15/01/2021",
"15/01/2021",
demijournee=1,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
"18/01/2021",
"18/01/2021",
demijournee=0,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
"19/01/2021",
"19/01/2021",
demijournee=2,
etudid=etudid,
)
_ = sco_abs_views.doSignaleAbsence(
"22/01/2021",
"22/01/2021",
demijournee=1,
etudid=etudid,
)
# --- Justification de certaines absences
_ = sco_abs_views.doJustifAbsence(
"15/01/2021",
"15/01/2021",
demijournee=1,
etudid=etudid,
)
_ = sco_abs_views.doJustifAbsence(
"18/01/2021",
"18/01/2021",
demijournee=0,
etudid=etudid,
)
_ = sco_abs_views.doJustifAbsence(
"19/01/2021",
"19/01/2021",
demijournee=2,
etudid=etudid,
)
# --- Test
b = sco_abs.is_work_saturday()
assert b == 0 # samedi ne sont pas compris
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
# l'étudiant a été absent le 15 (apres midi) , (16 et 17 we),
# 18 (matin) et 19 janvier (matin et apres midi), et 22 (matin)
assert nbabs == 5
# l'étudiant justifie ses abs du 15, 18 et 19
assert nbabsjust == 4
# --- Suppression d'une absence et d'une justification
_ = sco_abs_views.doAnnuleAbsence("19/01/2021", "19/01/2021", 2, etudid=etudid)
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
assert nbabs == 3
assert nbabsjust == 2
# --- suppression d'une justification pas encore disponible à l'aide de python.
# --- Création d'une liste d'abs
liste_abs = sco_abs_views.ListeAbsEtud(
etudid, format="json", absjust_only=1, sco_year="2020"
).get_data(as_text=True)
liste_abs2 = sco_abs_views.ListeAbsEtud(
etudid, format="json", sco_year="2020"
).get_data(as_text=True)
load_liste_abs = json.loads(liste_abs)
load_liste_abs2 = json.loads(liste_abs2)
assert len(load_liste_abs2) == 1
assert len(load_liste_abs) == 2
assert load_liste_abs2[0]["ampm"] == 1
assert load_liste_abs2[0]["datedmy"] == "22/01/2021"
mod = db.session.get(Module, module_id)
assert load_liste_abs2[0]["exams"] == mod.code
# absjust_only -> seulement les abs justifiés
# --- Création d'un groupe
_ = sco_groups.partition_create(
formsemestre_id=sem["formsemestre_id"],
partition_name="Eleve",
)
li1 = sco_groups.get_partitions_list(sem["formsemestre_id"])
_ = sco_groups.create_group(li1[0]["partition_id"], "Groupe 1")
# --- Affectation des élèves dans des groupes
li_grp1 = sco_groups.get_partition_groups(li1[0])
for etud in etuds:
sco_groups.set_group(etud["etudid"], li_grp1[0]["group_id"])
# --- Test de EtatAbsencesGroupes
grp1_abs = absences.EtatAbsencesGr(
group_ids=[li_grp1[0]["group_id"]],
debut="01/01/2021",
fin="30/06/2021",
format="json",
)
# grp1_abs est une Response car on a appelé une vue (1er appel)
load_grp1_abs = json.loads(grp1_abs.get_data(as_text=True))
assert len(load_grp1_abs) == 10
tab_id = [] # tab des id present dans load_grp1_abs
for un_etud in load_grp1_abs:
tab_id.append(un_etud["etudid"])
for (
etud
) in (
etuds
): # verification si tous les etudiants sont present dans la liste du groupe d'absence
assert etud["etudid"] in tab_id
for un_etud in load_grp1_abs:
if un_etud["etudid"] == etudid:
assert un_etud["nbabs"] == 3
assert un_etud["nbjustifs_noabs"] == 2
assert un_etud["nbabsjust"] == 2
assert un_etud["nbabsnonjust"] == 1
assert un_etud["nomprenom"] == etuds[0]["nomprenom"]
# --- Création de billets
# Active la gestion de billets:
sco_preferences.get_base_preferences().set(None, "handle_billets_abs", 1)
b1 = absences.AddBilletAbsence(
begin="2021-01-22 00:00",
end="2021-01-22 23:59",
etudid=etudid,
description="abs du 22",
justified=False,
code_nip=etuds[0]["code_nip"],
code_ine=etuds[0]["code_ine"],
)
b2 = absences.AddBilletAbsence(
begin="2021-01-15 00:00",
end="2021-01-15 23:59",
etudid=etudid,
description="abs du 15",
code_nip=etuds[0]["code_nip"],
code_ine=etuds[0]["code_ine"],
)
li_bi = absences.billets_etud(etudid=etudid, format="json").get_data(as_text=True)
assert isinstance(li_bi, str)
load_li_bi = json.loads(li_bi)
assert len(load_li_bi) == 2
assert (
load_li_bi[1]["description"] == "abs du 15"
or load_li_bi[1]["description"] == "abs du 22"
)

View File

@ -12,7 +12,9 @@ import app.scodoc.sco_assiduites as scass
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app import db from app import db
from app.models import Assiduite, FormSemestre, Identite, Justificatif, ModuleImpl from app.models import Assiduite, FormSemestre, Identite, Justificatif, ModuleImpl
from app.scodoc import sco_abs_views, sco_formsemestre
# from app.scodoc import sco_abs_views, sco_formsemestre TODO-ASSIDUITE
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
from tests.unit import sco_fake_gen from tests.unit import sco_fake_gen
from tools import downgrade_module, migrate_abs_to_assiduites from tools import downgrade_module, migrate_abs_to_assiduites
@ -36,6 +38,7 @@ def test_bi_directional_enum(test_client):
assert BiInt.inverse()[1] == BiInt.A and BiInt.inverse()[2] == BiInt.B assert BiInt.inverse()[1] == BiInt.A and BiInt.inverse()[2] == BiInt.B
@pytest.mark.skip # XXX TODO-ASSIDUITE (issue #690)
def test_general(test_client): def test_general(test_client):
"""tests général du modèle assiduite""" """tests général du modèle assiduite"""
@ -76,7 +79,9 @@ def test_general(test_client):
date_fin="31/07/2024", date_fin="31/07/2024",
) )
formsemestre_1 = sco_formsemestre.get_formsemestre(formsemestre_id_1) formsemestre_1 = sco_formsemestre.get_formsemestre(
formsemestre_id_1
) # Utiliser plutot FormSemestre de nos jours TODO-ASSIDUITE
formsemestre_2 = sco_formsemestre.get_formsemestre(formsemestre_id_2) formsemestre_2 = sco_formsemestre.get_formsemestre(formsemestre_id_2)
formsemestre_3 = sco_formsemestre.get_formsemestre(formsemestre_id_3) formsemestre_3 = sco_formsemestre.get_formsemestre(formsemestre_id_3)
@ -143,6 +148,7 @@ def test_general(test_client):
editer_supprimer_justificatif(etuds[0]) editer_supprimer_justificatif(etuds[0])
@pytest.mark.skip # XXX TODO-ASSIDUITE (issue #696)
def verif_migration_abs_assiduites(): def verif_migration_abs_assiduites():
"""Vérification que le script de migration fonctionne correctement""" """Vérification que le script de migration fonctionne correctement"""
downgrade_module(assiduites=True, justificatifs=True) downgrade_module(assiduites=True, justificatifs=True)
@ -301,7 +307,7 @@ def verif_migration_abs_assiduites():
False, False,
), # 3 assi 22-23-24/02/2023 08h > 13h (3dj) JUSTI(ext) ), # 3 assi 22-23-24/02/2023 08h > 13h (3dj) JUSTI(ext)
]: ]:
sco_abs_views.doSignaleAbsence( sco_abs_views.doSignaleAbsence( # TODO-ASSIDUITE
datedebut=debut, datedebut=debut,
datefin=fin, datefin=fin,
demijournee=demijournee, demijournee=demijournee,

View File

@ -25,8 +25,6 @@ from app.comp import res_sem
from app.comp.res_compat import NotesTableCompat from app.comp.res_compat import NotesTableCompat
from app.models import FormSemestre from app.models import FormSemestre
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import sco_abs
from app.scodoc import sco_abs_views
from app.scodoc import sco_bulletins from app.scodoc import sco_bulletins
from app.scodoc import codes_cursus from app.scodoc import codes_cursus
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
@ -188,20 +186,21 @@ def run_sco_basic(verbose=False) -> FormSemestre:
# ----------------------- # -----------------------
etudid = etuds[0]["etudid"] etudid = etuds[0]["etudid"]
_ = sco_abs_views.doSignaleAbsence( # XXX TODO-ASSIDUITE
"15/01/2020", "18/01/2020", demijournee=2, etudid=etudid # _ = sco_abs_views.doSignaleAbsence(
) # "15/01/2020", "18/01/2020", demijournee=2, etudid=etudid
# )
_ = sco_abs_views.doJustifAbsence( # _ = sco_abs_views.doJustifAbsence(
"17/01/2020", # "17/01/2020",
"18/01/2020", # "18/01/2020",
demijournee=2, # demijournee=2,
etudid=etudid, # etudid=etudid,
) # )
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem) # nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
assert nbabs == 6, f"incorrect nbabs ({nbabs})" # assert nbabs == 6, f"incorrect nbabs ({nbabs})"
assert nbabsjust == 2, f"incorrect nbabsjust ({nbabsjust})" # assert nbabsjust == 2, f"incorrect nbabsjust ({nbabsjust})"
# --- Permission saisie notes et décisions de jury, avec ou sans démission ou défaillance # --- Permission saisie notes et décisions de jury, avec ou sans démission ou défaillance
# on n'a pas encore saisi de décisions # on n'a pas encore saisi de décisions