Assiduite : fixe forcer module Fix #798

This commit is contained in:
Iziram 2023-10-26 15:52:53 +02:00
parent 903a03dbd6
commit 5e0b9f95cc
9 changed files with 157 additions and 32 deletions

View File

@ -25,7 +25,11 @@ from app.models import (
Scolog, Scolog,
) )
from flask_sqlalchemy.query import Query 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_exceptions import ScoValueError
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_utils import json_error 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() assiduite_unique: Assiduite = Assiduite.query.filter_by(id=assiduite_id).first()
if assiduite_unique is None: if assiduite_unique is None:
return (404, "Assiduite non existante") 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() ass_dict = assiduite_unique.to_dict()
log(f"delete_assiduite: {assiduite_unique.etudiant.id} {assiduite_unique}") log(f"delete_assiduite: {assiduite_unique.etudiant.id} {assiduite_unique}")
Scolog.logdb( Scolog.logdb(
@ -800,6 +807,9 @@ def assiduites_edit():
def _edit_singular(assiduite_unique, data): 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] = [] errors: list[str] = []
# Vérifications de data # 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 = external_data if external_data is not None else {}
external_data["module"] = "Autre" external_data["module"] = "Autre"
assiduite_unique.external_data = external_data assiduite_unique.external_data = external_data
else: else:
try: try:
moduleimpl = ModuleImpl.query.filter_by( moduleimpl = ModuleImpl.query.filter_by(
@ -854,7 +863,20 @@ def _edit_singular(assiduite_unique, data):
else: else:
assiduite_unique.moduleimpl_id = moduleimpl_id assiduite_unique.moduleimpl_id = moduleimpl_id
else: 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 # Cas 3 : desc
desc = data.get("desc", False) desc = data.get("desc", False)

View File

@ -4,7 +4,7 @@
from datetime import datetime from datetime import datetime
from app import db, log 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.models.etudiants import Identite
from app.auth.models import User from app.auth.models import User
from app.scodoc import sco_abs_notification from app.scodoc import sco_abs_notification
@ -13,6 +13,7 @@ from app.scodoc.sco_utils import (
EtatAssiduite, EtatAssiduite,
EtatJustificatif, EtatJustificatif,
localize_datetime, localize_datetime,
is_assiduites_module_forced,
) )
from flask_sqlalchemy.query import Query from flask_sqlalchemy.query import Query
@ -162,6 +163,23 @@ class Assiduite(db.Model):
moduleimpl_id = moduleimpl.id moduleimpl_id = moduleimpl.id
else: else:
raise ScoValueError("L'étudiant n'est pas inscrit au module") 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( nouv_assiduite = Assiduite(
date_debut=date_debut, date_debut=date_debut,
date_fin=date_fin, date_fin=date_fin,
@ -413,3 +431,18 @@ def get_justifs_from_date(
justifs = justifs.filter(Justificatif.etat == EtatJustificatif.VALIDE) justifs = justifs.filter(Justificatif.etat == EtatJustificatif.VALIDE)
return [j.justif_id if not long else j.to_dict(True) for j in justifs] 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()
)

View File

@ -1448,3 +1448,22 @@ def is_entreprises_enabled():
from app.models import ScoDocSiteConfig from app.models import ScoDocSiteConfig
return ScoDocSiteConfig.is_entreprises_enabled() 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

View File

@ -84,19 +84,19 @@ function validateSelectors(btn) {
); );
}); });
// if (getModuleImplId() == null && window.forceModule) { if (getModuleImplId() == null && window.forceModule) {
// const HTML = ` const HTML = `
// <p>Attention, le module doit obligatoirement être renseigné.</p> <p>Attention, le module doit obligatoirement être renseigné.</p>
// <p>Cela vient de la configuration du semestre ou plus largement du département.</p> <p>Cela vient de la configuration du semestre ou plus largement du département.</p>
// <p>Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.</p> <p>Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.</p>
// `; `;
// const content = document.createElement("div"); const content = document.createElement("div");
// content.innerHTML = HTML; content.innerHTML = HTML;
// openAlertModal("Sélection du module", content); openAlertModal("Sélection du module", content);
// return; return;
// } }
getAssiduitesFromEtuds(true); getAssiduitesFromEtuds(true);
@ -905,6 +905,9 @@ function createAssiduite(etat, etudid) {
} }
const path = getUrl() + `/api/assiduite/${etudid}/create`; const path = getUrl() + `/api/assiduite/${etudid}/create`;
let with_errors = false;
sync_post( sync_post(
path, path,
[assiduite], [assiduite],
@ -913,14 +916,31 @@ function createAssiduite(etat, etudid) {
if (data.success.length > 0) { if (data.success.length > 0) {
let obj = data.success["0"].message.assiduite_id; 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 = `
<p>Attention, le module doit obligatoirement être renseigné.</p>
<p>Cela vient de la configuration du semestre ou plus largement du département.</p>
<p>Si c'est une erreur, veuillez voir avec le ou les responsables de votre scodoc.</p>
`;
const content = document.createElement("div");
content.innerHTML = HTML;
openAlertModal("Sélection du module", content);
}
with_errors = true;
}
}, },
(data, status) => { (data, status) => {
//error //error
console.error(data, status); console.error(data, status);
errorAlert(); errorAlert();
with_errors = true;
} }
); );
return true; return !with_errors;
} }
/** /**
@ -1000,7 +1020,33 @@ function editAssiduite(assiduite_id, etat, assi) {
(data, status) => { (data, status) => {
//error //error
console.error(data, status); console.error(data, status);
errorAlert(); try {
errorJson = data.responseJSON;
if (errorJson.message == "param 'moduleimpl_id': etud non inscrit") {
const html = `
<h3>L'étudiant n'est pas inscrit à ce module</h3>
`;
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 = `
<h3>Un module doit être spécifié</h3>
`;
const div = document.createElement("div");
div.innerHTML = html;
openAlertModal("Erreur Module", div);
return;
}
} catch (e) {
console.error(e);
//errorAlert();
}
} }
); );

View File

@ -16,7 +16,7 @@
<div> <div>
{{moduleimpl_select | safe }} {% include "assiduites/widgets/moduleimpl_dynamic_selector.j2" %}
<button class="btn" onclick="fastJustify(getCurrentAssiduite(etudid))" id="justif-rapide">Justifier</button> <button class="btn" onclick="fastJustify(getCurrentAssiduite(etudid))" id="justif-rapide">Justifier</button>
</div> </div>

View File

@ -1,9 +1,12 @@
<label for="moduleimpl_select"> <label for="moduleimpl_select">
Module Module
<select id="moduleimpl_select" class="dynaSelect"> <select id="moduleimpl_select" class="dynaSelect">
<option value="" selected> Non spécifié </option> {% include "assiduites/widgets/simplemoduleimpl_select.j2" %}
<option value="autre"> Autre </option>
</select> </select>
<div id="saved" style="display: none;">
{% include "assiduites/widgets/simplemoduleimpl_select.j2" %}
</div>
</label> </label>
@ -70,7 +73,7 @@
function populateSelect(sems, selected, query) { function populateSelect(sems, selected, query) {
const select = document.querySelector(query); const select = document.querySelector(query);
select.innerHTML = `<option value=""> Non spécifié </option><option value="autre"> Autre </option>` select.innerHTML = document.getElementById('saved').innerHTML
sems.forEach((mods, label) => { sems.forEach((mods, label) => {
const optGrp = document.createElement('optgroup'); const optGrp = document.createElement('optgroup');
optGrp.label = label optGrp.label = label

View File

@ -1,7 +1,6 @@
<select name="moduleimpl_select" id="moduleimpl_select"> <select name="moduleimpl_select" id="moduleimpl_select">
<option value="" {{selected}}> Non spécifié </option> {% include "assiduites/widgets/simplemoduleimpl_select.j2" %}
<option value="autre"> Autre </option>
{% for mod in modules %} {% for mod in modules %}
{% if mod.moduleimpl_id == moduleimpl_id %} {% if mod.moduleimpl_id == moduleimpl_id %}

View File

@ -0,0 +1,6 @@
{% if scu.is_assiduites_module_forced(request.args.get('formsemestre_id', None))%}
<option value="" selected disabled> Saisir Module</option>
{% else %}
<option value="" selected> Non spécifié </option>
{% endif %}
<option value="autre"> Tout module </option>

View File

@ -335,12 +335,11 @@ def signal_assiduites_etud():
"assi_afternoon_time", "18:00:00" "assi_afternoon_time", "18:00:00"
) )
select = """ select = f"""
<select class="dynaSelect"> <select class="dynaSelect">
<option value="" selected> Non spécifié </option> {render_template("assiduites/widgets/simplemoduleimpl_select.j2")}
</select> </select>
""" """
return HTMLBuilder( return HTMLBuilder(
header, header,
_mini_timeline(), _mini_timeline(),
@ -356,7 +355,6 @@ def signal_assiduites_etud():
forcer_module=sco_preferences.get_preference( forcer_module=sco_preferences.get_preference(
"forcer_module", dept_id=g.scodoc_dept_id "forcer_module", dept_id=g.scodoc_dept_id
), ),
moduleimpl_select=_dynamic_module_selector(),
diff=_differee( diff=_differee(
etudiants=[sco_etud.get_etud_info(etudid=etud.etudid, filled=True)[0]], etudiants=[sco_etud.get_etud_info(etudid=etud.etudid, filled=True)[0]],
moduleimpl_select=select, moduleimpl_select=select,
@ -630,10 +628,7 @@ def signal_assiduites_group():
if formsemestre.dept_id != g.scodoc_dept_id: if formsemestre.dept_id != g.scodoc_dept_id:
abort(404, "groupes inexistants dans ce département") abort(404, "groupes inexistants dans ce département")
require_module = sco_preferences.get_preference( require_module = sco_preferences.get_preference("forcer_module", formsemestre_id)
"abs_require_module", formsemestre_id
)
etuds = [ etuds = [
sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0] sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0]
for m in groups_infos.members for m in groups_infos.members
@ -1407,7 +1402,9 @@ def _module_selector(
def _dynamic_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: def _timeline(formsemestre_id=None) -> HTMLElement: