diff --git a/app/models/assiduites.py b/app/models/assiduites.py
index 29b8b889..297a4014 100644
--- a/app/models/assiduites.py
+++ b/app/models/assiduites.py
@@ -21,6 +21,7 @@ from app.scodoc import sco_abs_notification
from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
from app.scodoc.sco_exceptions import ScoValueError
from app.scodoc.sco_permissions import Permission
+from app.scodoc import sco_preferences
from app.scodoc import sco_utils as scu
from app.scodoc.sco_utils import (
EtatAssiduite,
@@ -188,6 +189,12 @@ class Assiduite(ScoDocModel):
):
raise ScoValueError("La date de fin n'est pas un jour travaillé")
+ # Vérification de l'activation du module
+ if (err_msg := has_assiduites_disable_pref(formsemestre_date_debut)) or (
+ err_msg := has_assiduites_disable_pref(formsemestre_date_fin)
+ ):
+ raise ScoValueError(err_msg)
+
# Vérification de non duplication des périodes
assiduites: Query = etud.assiduites
if is_period_conflicting(date_debut, date_fin, assiduites, Assiduite):
@@ -817,3 +824,29 @@ def get_formsemestre_from_data(data: dict[str, datetime | int]) -> FormSemestre:
)
.first()
)
+
+
+def has_assiduites_disable_pref(formsemestre: FormSemestre) -> str | bool:
+ """
+ Vérifie si le semestre possède la préférence "assiduites_disable"
+ et renvoie le message d'erreur associé.
+
+ La préférence est un text field. Il est considéré comme vide si :
+ - la chaine de caractère est vide
+ - si elle n'est composée que de caractères d'espacement (espace, tabulation, retour à la ligne)
+
+
+ Si la chaine est vide, la fonction renvoie False
+ """
+
+ # Si pas de formsemestre, on ne peut pas vérifier la préférence
+ # On considère que la préférence n'est pas activée
+ if formsemestre is None:
+ return False
+
+ pref: str = (
+ sco_preferences.get_preference("assiduites_disable", formsemestre.id) or ""
+ )
+ pref = pref.strip()
+
+ return pref if pref else False
diff --git a/app/scodoc/sco_assiduites.py b/app/scodoc/sco_assiduites.py
index 6626c903..f085a83f 100644
--- a/app/scodoc/sco_assiduites.py
+++ b/app/scodoc/sco_assiduites.py
@@ -3,9 +3,10 @@ Ecrit par Matthias Hartmann.
"""
from datetime import date, datetime, time, timedelta
+from functools import wraps
from pytz import UTC
-from flask import g
+from flask import g, request
from flask_sqlalchemy.query import Query
from app import log, db, set_sco_dept
@@ -18,12 +19,13 @@ from app.models import (
ModuleImplInscription,
ScoDocSiteConfig,
)
-from app.models.assiduites import Assiduite, Justificatif
+from app.models.assiduites import Assiduite, Justificatif, has_assiduites_disable_pref
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_preferences
from app.scodoc import sco_cache
from app.scodoc import sco_etud
import app.scodoc.sco_utils as scu
+from app.scodoc.sco_exceptions import ScoValueError
class CountCalculator:
@@ -819,6 +821,38 @@ def get_etud_evaluations_assiduites(etud: Identite) -> list[dict]:
return etud_evaluations_assiduites
+# --- Décorateur ---
+
+
+def check_disabled(func):
+ """
+ Vérifie sur le module a été désactivé dans les préférences du semestre.
+ Récupère le formsemestre depuis l'url (formsemestre_id)
+ Si le formsemestre est trouvé :
+ - Vérifie si le module a été désactivé dans les préférences du semestre
+ - Si le module a été désactivé, une ScoValueError est levée
+ Sinon :
+ Il ne se passe rien
+ """
+
+ @wraps(func)
+ def decorated_function(*args, **kwargs):
+ # Récupération du formsemestre depuis l'url
+ formsemestre_id = request.args.get("formsemestre_id")
+ # Si on a un formsemestre_id
+ if formsemestre_id:
+ # Récupération du formsemestre
+ formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
+ # Vériication si le module a été désactivé (avec la préférence)
+ pref: str | bool = has_assiduites_disable_pref(formsemestre)
+ # Le module est désactivé si on récupère un message d'erreur (str)
+ if pref:
+ raise ScoValueError(pref, dest_url=request.referrer)
+ return func(*args, **kwargs)
+
+ return decorated_function
+
+
# Gestion du cache
def get_assiduites_count(etudid: int, sem: dict) -> tuple[int, int, int]:
"""Les comptes d'absences de cet étudiant dans ce semestre:
diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py
index 019cec65..fb1021cb 100644
--- a/app/scodoc/sco_preferences.py
+++ b/app/scodoc/sco_preferences.py
@@ -625,6 +625,16 @@ class BasePreferences:
"explanation": "Désactive la saisie et l'affichage des présences",
},
),
+ (
+ "assiduites_disable",
+ {
+ "initvalue": "",
+ "title": "Désactiver le module d'assiduité",
+ "size": 40,
+ "category": "assi",
+ "explanation": "Laisser vide pour ne pas désactiver. Sinon mettre un message à afficher",
+ },
+ ),
(
"nb_heures_par_jour",
{
@@ -2293,9 +2303,7 @@ class BasePreferences:
if "explanation" in descr:
del descr["explanation"]
if formsemestre_id:
- descr[
- "explanation"
- ] = f"""ou utiliser paramètre global"""
if formsemestre_id and self.is_global(formsemestre_id, pref_name):
diff --git a/app/views/assiduites.py b/app/views/assiduites.py
index 8db1da15..10e092cb 100644
--- a/app/views/assiduites.py
+++ b/app/views/assiduites.py
@@ -96,6 +96,7 @@ from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
+
# --------------------------------------------------------------------
#
# Assiduité (/ScoDoc//Scolarite/Assiduites/...)
@@ -106,6 +107,7 @@ CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS
@bp.route("/")
@bp.route("/bilan_dept")
@scodoc
+@scass.check_disabled
@permission_required(Permission.AbsChange)
def bilan_dept():
"""Gestionnaire assiduités, page principale"""
@@ -212,6 +214,7 @@ def bilan_dept():
@bp.route("/ajout_assiduite_etud", methods=["GET", "POST"])
@scodoc
+@scass.check_disabled
@permission_required(Permission.AbsChange)
def ajout_assiduite_etud() -> str | Response:
"""
@@ -1016,6 +1019,7 @@ def calendrier_assi_etud():
@bp.route("/signal_assiduites_group")
@scodoc
+@scass.check_disabled
@permission_required(Permission.AbsChange)
def signal_assiduites_group():
"""
@@ -1324,6 +1328,11 @@ def visu_assi_group():
# Récupération des groupes, du semestre et des étudiants
groups_infos = sco_groups_view.DisplayedGroupsInfos(group_ids)
formsemestre = db.session.get(FormSemestre, groups_infos.formsemestre_id)
+
+ # Vérification de la désactivation de l'assiduité
+ if err_msg := scass.has_assiduites_disable_pref(formsemestre):
+ raise ScoValueError(err_msg, request.referrer)
+
etuds = etuds_sorted_from_ids([m["etudid"] for m in groups_infos.members])
# Génération du tableau des assiduités
@@ -1795,6 +1804,7 @@ def signale_evaluation_abs(etudid: int = None, evaluation_id: int = None):
@scodoc
@permission_required(Permission.JustifValidate)
@permission_required(Permission.AbsJustifView)
+@scass.check_disabled
def traitement_justificatifs():
"""Page de traitement des justificatifs
On traite les justificatifs par formsemestre
@@ -1864,6 +1874,7 @@ def traitement_justificatifs():
@bp.route("signal_assiduites_hebdo")
@scodoc
@permission_required(Permission.ScoView)
+@scass.check_disabled
def signal_assiduites_hebdo():
"""
signal_assiduites_hebdo
@@ -2049,6 +2060,10 @@ def edit_assiduite_etud(assiduite_id: int):
etud: Identite = assi.etudiant
formsemestre: FormSemestre = assi.get_formsemestre()
+ # Vérification de la désactivation de l'assiduité
+ if err_msg := scass.has_assiduites_disable_pref(formsemestre):
+ raise ScoValueError(err_msg, request.referrer)
+
readonly: bool = not current_user.has_permission(Permission.AbsChange)
form: EditAssiForm = EditAssiForm(request.form)
@@ -2228,6 +2243,7 @@ def generate_bul_list(etud: Identite, semestre: FormSemestre) -> str:
@bp.route("feuille_abs_hebdo", methods=["GET", "POST"])
@scodoc
@permission_required(Permission.AbsChange)
+@scass.check_disabled
def feuille_abs_hebdo():
"""
GET : Renvoie un tableau excel pour permettre la saisie des absences
@@ -2374,6 +2390,8 @@ def feuille_abs_hebdo():
@bp.route("feuille_abs_formsemestre", methods=["GET", "POST"])
@scodoc
+@permission_required(Permission.AbsChange)
+@scass.check_disabled
def feuille_abs_formsemestre():
"""
Permet l'importation d'une liste d'assiduités depuis un fichier excel