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,
)
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)

View File

@ -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()
)

View File

@ -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

View File

@ -84,19 +84,19 @@ function validateSelectors(btn) {
);
});
// if (getModuleImplId() == null && window.forceModule) {
// 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>
// `;
if (getModuleImplId() == null && window.forceModule) {
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;
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 = `
<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) => {
//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 = `
<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>
{{moduleimpl_select | safe }}
{% include "assiduites/widgets/moduleimpl_dynamic_selector.j2" %}
<button class="btn" onclick="fastJustify(getCurrentAssiduite(etudid))" id="justif-rapide">Justifier</button>
</div>

View File

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

View File

@ -1,7 +1,6 @@
<select name="moduleimpl_select" id="moduleimpl_select">
<option value="" {{selected}}> Non spécifié </option>
<option value="autre"> Autre </option>
{% include "assiduites/widgets/simplemoduleimpl_select.j2" %}
{% for mod in modules %}
{% 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"
)
select = """
select = f"""
<select class="dynaSelect">
<option value="" selected> Non spécifié </option>
{render_template("assiduites/widgets/simplemoduleimpl_select.j2")}
</select>
"""
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: