diff --git a/app/api/assiduites.py b/app/api/assiduites.py index a9451ae73..2e0c06c6c 100644 --- a/app/api/assiduites.py +++ b/app/api/assiduites.py @@ -25,7 +25,11 @@ from app.models import ( Scolog, ) from flask_sqlalchemy.query import Query -from app.models.assiduites import get_assiduites_justif, get_justifs_from_date +from app.models.assiduites import ( + get_assiduites_justif, + get_justifs_from_date, + get_formsemestre_from_data, +) from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_permissions import Permission from app.scodoc.sco_utils import json_error @@ -694,6 +698,9 @@ def _delete_singular(assiduite_id: int, database): assiduite_unique: Assiduite = Assiduite.query.filter_by(id=assiduite_id).first() if assiduite_unique is None: return (404, "Assiduite non existante") + if g.scodoc_dept is None and assiduite_unique.etudiant.dept_id is not None: + # route sans département + set_sco_dept(assiduite_unique.etudiant.departement.acronym) ass_dict = assiduite_unique.to_dict() log(f"delete_assiduite: {assiduite_unique.etudiant.id} {assiduite_unique}") Scolog.logdb( @@ -800,6 +807,9 @@ def assiduites_edit(): def _edit_singular(assiduite_unique, data): + if g.scodoc_dept is None and assiduite_unique.etudiant.dept_id is not None: + # route sans département + set_sco_dept(assiduite_unique.etudiant.departement.acronym) errors: list[str] = [] # Vérifications de data @@ -835,7 +845,6 @@ def _edit_singular(assiduite_unique, data): external_data = external_data if external_data is not None else {} external_data["module"] = "Autre" assiduite_unique.external_data = external_data - else: try: moduleimpl = ModuleImpl.query.filter_by( @@ -854,7 +863,20 @@ def _edit_singular(assiduite_unique, data): else: assiduite_unique.moduleimpl_id = moduleimpl_id else: - assiduite_unique.moduleimpl_id = None + formsemestre: FormSemestre = get_formsemestre_from_data( + assiduite_unique.to_dict() + ) + force: bool + + if formsemestre: + force = scu.is_assiduites_module_forced(formsemestre_id=formsemestre.id) + else: + force = scu.is_assiduites_module_forced(dept_id=etud.dept_id) + + if force: + errors.append( + "param 'moduleimpl_id' : le moduleimpl_id ne peut pas être nul" + ) # Cas 3 : desc desc = data.get("desc", False) diff --git a/app/models/assiduites.py b/app/models/assiduites.py index a78e709df..57b7dfb77 100644 --- a/app/models/assiduites.py +++ b/app/models/assiduites.py @@ -4,7 +4,7 @@ from datetime import datetime from app import db, log -from app.models import ModuleImpl, Scolog +from app.models import ModuleImpl, Scolog, FormSemestre, FormSemestreInscription from app.models.etudiants import Identite from app.auth.models import User from app.scodoc import sco_abs_notification @@ -13,6 +13,7 @@ from app.scodoc.sco_utils import ( EtatAssiduite, EtatJustificatif, localize_datetime, + is_assiduites_module_forced, ) from flask_sqlalchemy.query import Query @@ -162,6 +163,23 @@ class Assiduite(db.Model): moduleimpl_id = moduleimpl.id else: raise ScoValueError("L'étudiant n'est pas inscrit au module") + elif not ( + external_data is not None and external_data.get("module") is not None + ): + # Vérification si module forcé + formsemestre: FormSemestre = get_formsemestre_from_data( + {"etudid": etud.id, "date_debut": date_debut, "date_fin": date_fin} + ) + force: bool + + if formsemestre: + force = is_assiduites_module_forced(formsemestre_id=formsemestre.id) + else: + force = is_assiduites_module_forced(dept_id=etud.dept_id) + + if force: + raise ScoValueError("Module non renseigné") + nouv_assiduite = Assiduite( date_debut=date_debut, date_fin=date_fin, @@ -413,3 +431,18 @@ def get_justifs_from_date( justifs = justifs.filter(Justificatif.etat == EtatJustificatif.VALIDE) return [j.justif_id if not long else j.to_dict(True) for j in justifs] + + +def get_formsemestre_from_data(data: dict[str, datetime | int]) -> FormSemestre: + return ( + FormSemestre.query.join( + FormSemestreInscription, + FormSemestre.id == FormSemestreInscription.formsemestre_id, + ) + .filter( + data["date_debut"] <= FormSemestre.date_fin, + data["date_fin"] >= FormSemestre.date_debut, + FormSemestreInscription.etudid == data["etudid"], + ) + .first() + ) diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index bbf785a7c..6faad0fbd 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -1448,3 +1448,22 @@ def is_entreprises_enabled(): from app.models import ScoDocSiteConfig return ScoDocSiteConfig.is_entreprises_enabled() + + +def is_assiduites_module_forced( + formsemestre_id: int = None, dept_id: int = None +) -> bool: + from app.scodoc import sco_preferences + + retour: bool + + if dept_id is None: + dept_id = g.scodoc_dept_id + + try: + retour = sco_preferences.get_preference( + "forcer_module", formsemestre_id=int(formsemestre_id) + ) + except (TypeError, ValueError): + retour = sco_preferences.get_preference("forcer_module", dept_id=dept_id) + return retour diff --git a/app/static/js/assiduites.js b/app/static/js/assiduites.js index ecc2ce516..74c0c4b9c 100644 --- a/app/static/js/assiduites.js +++ b/app/static/js/assiduites.js @@ -84,19 +84,19 @@ function validateSelectors(btn) { ); }); - // if (getModuleImplId() == null && window.forceModule) { - // const HTML = ` - //

Attention, le module doit obligatoirement être renseigné.

- //

Cela vient de la configuration du semestre ou plus largement du département.

- //

Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.

- // `; + if (getModuleImplId() == null && window.forceModule) { + const HTML = ` +

Attention, le module doit obligatoirement être renseigné.

+

Cela vient de la configuration du semestre ou plus largement du département.

+

Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.

+ `; - // const content = document.createElement("div"); - // content.innerHTML = HTML; + const content = document.createElement("div"); + content.innerHTML = HTML; - // openAlertModal("Sélection du module", content); - // return; - // } + openAlertModal("Sélection du module", content); + return; + } getAssiduitesFromEtuds(true); @@ -905,6 +905,9 @@ function createAssiduite(etat, etudid) { } const path = getUrl() + `/api/assiduite/${etudid}/create`; + + let with_errors = false; + sync_post( path, [assiduite], @@ -913,14 +916,31 @@ function createAssiduite(etat, etudid) { if (data.success.length > 0) { let obj = data.success["0"].message.assiduite_id; } + if (data.errors.length > 0) { + console.error(data.errors["0"].message); + if (data.errors["0"].message == "Module non renseigné") { + const HTML = ` +

Attention, le module doit obligatoirement être renseigné.

+

Cela vient de la configuration du semestre ou plus largement du département.

+

Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.

+ `; + + const content = document.createElement("div"); + content.innerHTML = HTML; + + openAlertModal("Sélection du module", content); + } + with_errors = true; + } }, (data, status) => { //error console.error(data, status); errorAlert(); + with_errors = true; } ); - return true; + return !with_errors; } /** @@ -1000,7 +1020,33 @@ function editAssiduite(assiduite_id, etat, assi) { (data, status) => { //error console.error(data, status); - errorAlert(); + try { + errorJson = data.responseJSON; + if (errorJson.message == "param 'moduleimpl_id': etud non inscrit") { + const html = ` +

L'étudiant n'est pas inscrit à ce module

+ `; + const div = document.createElement("div"); + div.innerHTML = html; + openAlertModal("Erreur Module", div); + return; + } + if ( + errorJson.message == + "param 'moduleimpl_id' : le moduleimpl_id ne peut pas être nul" + ) { + const html = ` +

Un module doit être spécifié

+ `; + const div = document.createElement("div"); + div.innerHTML = html; + openAlertModal("Erreur Module", div); + return; + } + } catch (e) { + console.error(e); + //errorAlert(); + } } ); diff --git a/app/templates/assiduites/pages/signal_assiduites_etud.j2 b/app/templates/assiduites/pages/signal_assiduites_etud.j2 index 7a55c7a9e..78f45d789 100644 --- a/app/templates/assiduites/pages/signal_assiduites_etud.j2 +++ b/app/templates/assiduites/pages/signal_assiduites_etud.j2 @@ -16,7 +16,7 @@
- {{moduleimpl_select | safe }} + {% include "assiduites/widgets/moduleimpl_dynamic_selector.j2" %}
diff --git a/app/templates/assiduites/widgets/moduleimpl_dynamic_selector.j2 b/app/templates/assiduites/widgets/moduleimpl_dynamic_selector.j2 index 045546d01..ffd25464c 100644 --- a/app/templates/assiduites/widgets/moduleimpl_dynamic_selector.j2 +++ b/app/templates/assiduites/widgets/moduleimpl_dynamic_selector.j2 @@ -1,9 +1,12 @@ @@ -70,7 +73,7 @@ function populateSelect(sems, selected, query) { const select = document.querySelector(query); - select.innerHTML = `` + select.innerHTML = document.getElementById('saved').innerHTML sems.forEach((mods, label) => { const optGrp = document.createElement('optgroup'); optGrp.label = label diff --git a/app/templates/assiduites/widgets/moduleimpl_selector.j2 b/app/templates/assiduites/widgets/moduleimpl_selector.j2 index ad010e2cd..78a08b226 100644 --- a/app/templates/assiduites/widgets/moduleimpl_selector.j2 +++ b/app/templates/assiduites/widgets/moduleimpl_selector.j2 @@ -1,7 +1,6 @@ - + {render_template("assiduites/widgets/simplemoduleimpl_select.j2")} """ - return HTMLBuilder( header, _mini_timeline(), @@ -356,7 +355,6 @@ def signal_assiduites_etud(): forcer_module=sco_preferences.get_preference( "forcer_module", dept_id=g.scodoc_dept_id ), - moduleimpl_select=_dynamic_module_selector(), diff=_differee( etudiants=[sco_etud.get_etud_info(etudid=etud.etudid, filled=True)[0]], moduleimpl_select=select, @@ -630,10 +628,7 @@ def signal_assiduites_group(): if formsemestre.dept_id != g.scodoc_dept_id: abort(404, "groupes inexistants dans ce département") - require_module = sco_preferences.get_preference( - "abs_require_module", formsemestre_id - ) - + require_module = sco_preferences.get_preference("forcer_module", formsemestre_id) etuds = [ sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0] for m in groups_infos.members @@ -1407,7 +1402,9 @@ def _module_selector( def _dynamic_module_selector(): - return render_template("assiduites/widgets/moduleimpl_dynamic_selector.j2") + return render_template( + "assiduites/widgets/moduleimpl_dynamic_selector.j2", + ) def _timeline(formsemestre_id=None) -> HTMLElement: