Compare commits
6 Commits
87aaf12d27
...
6b985620e9
Author | SHA1 | Date |
---|---|---|
Iziram | 6b985620e9 | |
Iziram | 4d234ba353 | |
Iziram | 5d45fcf656 | |
Iziram | 0a5919b788 | |
Iziram | 09f4525e66 | |
Emmanuel Viennet | 0bc57807de |
|
@ -3,14 +3,15 @@
|
|||
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
|
||||
# See LICENSE
|
||||
##############################################################################
|
||||
"""ScoDoc 9 API : Assiduités
|
||||
"""
|
||||
"""ScoDoc 9 API : Assiduités"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from flask import g, request
|
||||
from flask_json import as_json
|
||||
from flask_login import current_user, login_required
|
||||
from flask_sqlalchemy.query import Query
|
||||
from sqlalchemy.orm.exc import ObjectDeletedError
|
||||
|
||||
from app import db, log, set_sco_dept
|
||||
import app.scodoc.sco_assiduites as scass
|
||||
|
@ -858,7 +859,10 @@ def assiduite_edit(assiduite_id: int):
|
|||
msg=f"assiduite: modif {assiduite_unique}",
|
||||
)
|
||||
db.session.commit()
|
||||
scass.simple_invalidate_cache(assiduite_unique.to_dict())
|
||||
try:
|
||||
scass.simple_invalidate_cache(assiduite_unique.to_dict())
|
||||
except ObjectDeletedError:
|
||||
return json_error(404, "Assiduité supprimée / inexistante")
|
||||
|
||||
return {"OK": True}
|
||||
|
||||
|
|
|
@ -611,16 +611,17 @@ class BasePreferences:
|
|||
"explanation": "toute saisie d'absence doit indiquer le module concerné",
|
||||
},
|
||||
),
|
||||
# (
|
||||
# "forcer_present",
|
||||
# {
|
||||
# "initvalue": 0,
|
||||
# "title": "Forcer l'appel des présents",
|
||||
# "input_type": "boolcheckbox",
|
||||
# "labels": ["non", "oui"],
|
||||
# "category": "assi",
|
||||
# },
|
||||
# ),
|
||||
(
|
||||
"non_present",
|
||||
{
|
||||
"initvalue": 0,
|
||||
"title": "Désactiver la saisie des présences",
|
||||
"input_type": "boolcheckbox",
|
||||
"labels": ["non", "oui"],
|
||||
"category": "assi",
|
||||
"explanation": "Désactive la saisie et l'affichage des présences",
|
||||
},
|
||||
),
|
||||
(
|
||||
"periode_defaut",
|
||||
{
|
||||
|
@ -644,18 +645,18 @@ class BasePreferences:
|
|||
"category": "assi",
|
||||
},
|
||||
),
|
||||
(
|
||||
"assi_etat_defaut",
|
||||
{
|
||||
"explanation": "⚠ non fonctionnel, travaux en cours !",
|
||||
"initvalue": "aucun",
|
||||
"input_type": "menu",
|
||||
"labels": ["aucun", "present", "retard", "absent"],
|
||||
"allowed_values": ["aucun", "present", "retard", "absent"],
|
||||
"title": "Définir l'état par défaut",
|
||||
"category": "assi",
|
||||
},
|
||||
),
|
||||
# (
|
||||
# "assi_etat_defaut",
|
||||
# {
|
||||
# "explanation": "⚠ non fonctionnel, travaux en cours !",
|
||||
# "initvalue": "aucun",
|
||||
# "input_type": "menu",
|
||||
# "labels": ["aucun", "present", "retard", "absent"],
|
||||
# "allowed_values": ["aucun", "present", "retard", "absent"],
|
||||
# "title": "Définir l'état par défaut",
|
||||
# "category": "assi",
|
||||
# },
|
||||
# ),
|
||||
(
|
||||
"non_travail",
|
||||
{
|
||||
|
|
|
@ -730,31 +730,11 @@ tr.row-justificatif.non_valide td.assi-type {
|
|||
background-color: var(--color-defaut) !important;
|
||||
}
|
||||
|
||||
.color.est_just.sans_etat::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 25%;
|
||||
height: 100%;
|
||||
background-color: var(--color-justi) !important;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.color.invalide::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 25%;
|
||||
height: 100%;
|
||||
right: 0;
|
||||
.color.invalide {
|
||||
background-color: var(--color-justi-invalide) !important;
|
||||
}
|
||||
|
||||
.color.attente::before,
|
||||
.color.modifie::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 25%;
|
||||
height: 100%;
|
||||
right: 0;
|
||||
.color.attente {
|
||||
background: repeating-linear-gradient(to bottom,
|
||||
var(--color-justi-attente-stripe) 0px,
|
||||
var(--color-justi-attente-stripe) 4px,
|
||||
|
@ -762,6 +742,10 @@ tr.row-justificatif.non_valide td.assi-type {
|
|||
var(--color-justi-attente) 7px) !important;
|
||||
}
|
||||
|
||||
.color.est_just {
|
||||
background-color: var(--color-justi) !important;
|
||||
}
|
||||
|
||||
#gtrcontent .pdp {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -296,7 +296,13 @@ function creerLigneEtudiant(etud, index) {
|
|||
// Création des boutons d'assiduités
|
||||
if (readOnly) {
|
||||
} else if (currentAssiduite.type != "conflit") {
|
||||
["present", "retard", "absent"].forEach((abs) => {
|
||||
const etats = ["retard", "absent"];
|
||||
|
||||
if (!window.nonPresent) {
|
||||
etats.splice(0, 0, "present");
|
||||
}
|
||||
|
||||
etats.forEach((abs) => {
|
||||
const btn = document.createElement("input");
|
||||
btn.type = "checkbox";
|
||||
btn.value = abs;
|
||||
|
@ -425,7 +431,7 @@ async function getModuleImpl(assiduite) {
|
|||
return res.json();
|
||||
})
|
||||
.then((data) => {
|
||||
moduleimpls[id] = `${data.module.code} ${data.module.abbrev || ''}`;
|
||||
moduleimpls[id] = `${data.module.code} ${data.module.abbrev || ""}`;
|
||||
return moduleimpls[id];
|
||||
})
|
||||
.catch((_) => {
|
||||
|
@ -531,12 +537,7 @@ async function MiseAJourLigneEtud(etud) {
|
|||
|
||||
async function actionAssiduite(etud, etat, type, assiduite = null) {
|
||||
const modimpl_id = $("#moduleimpl_select").val();
|
||||
if (
|
||||
assiduite &&
|
||||
assiduite.etat.toLowerCase() === etat &&
|
||||
assiduite.moduleimpl_id == modimpl_id
|
||||
)
|
||||
type = "suppression";
|
||||
if (assiduite && assiduite.etat.toLowerCase() === etat) type = "suppression";
|
||||
|
||||
const { deb, fin } = getPeriodAsDate();
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
# See LICENSE
|
||||
##############################################################################
|
||||
|
||||
"""Liste simple d'étudiants
|
||||
"""
|
||||
"""Liste simple d'étudiants"""
|
||||
|
||||
import datetime
|
||||
from flask import g, url_for
|
||||
from app import log
|
||||
|
@ -140,6 +140,13 @@ class RowAssi(tb.Row):
|
|||
)
|
||||
stats = self._get_etud_stats(etud)
|
||||
for key, value in stats.items():
|
||||
if key == "present" and sco_preferences.get_preference(
|
||||
"non_present",
|
||||
dept_id=g.scodoc_dept_id,
|
||||
formsemestre_id=self.table.formsemestre.id,
|
||||
):
|
||||
continue
|
||||
|
||||
self.add_cell(key, value[0], fmt_num(value[1] - value[2]), "assi_stats")
|
||||
if key != "present":
|
||||
self.add_cell(
|
||||
|
|
|
@ -75,36 +75,7 @@ Calendrier de l'assiduité
|
|||
|
||||
<div class="help">
|
||||
<h3>Calendrier</h3>
|
||||
<p>Code couleur</p>
|
||||
<ul class="couleurs">
|
||||
<li><span title="Vert" class="present demo"></span> → présence de l'étudiant lors de la
|
||||
période
|
||||
</li>
|
||||
<li><span title="Bleu clair" class="nonwork demo"></span> → la période n'est pas travaillée
|
||||
</li>
|
||||
<li><span title="Rouge" class="absent demo"></span> → absence de l'étudiant lors de la
|
||||
période
|
||||
</li>
|
||||
<li><span title="Rose" class="demo color absent est_just"></span> → absence justifiée
|
||||
</li>
|
||||
<li><span title="Orange" class="retard demo"></span> → retard de l'étudiant lors de la
|
||||
période
|
||||
</li>
|
||||
<li><span title="Jaune clair" class="demo color retard est_just"></span> → retard justifié
|
||||
</li>
|
||||
|
||||
<li><span title="Quart Bleu" class="est_just demo"></span> → la période est couverte par un
|
||||
justificatif valide</li>
|
||||
<li><span title="Justif. non valide" class="invalide demo"></span> → la période est
|
||||
couverte par un justificatif non valide
|
||||
</li>
|
||||
<li><span title="Justif. en attente" class="attente demo"></span> → la période
|
||||
a un justificatif en attente de validation
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>Vous pouvez passer le curseur sur les jours colorés afin de voir les informations supplémentaires</p>
|
||||
{% include "assiduites/widgets/legende_couleur.j2" %}
|
||||
</div>
|
||||
<ul class="couleurs print">
|
||||
<li><span title="Vert" class="present demo"></span> présence
|
||||
|
@ -180,21 +151,8 @@ Calendrier de l'assiduité
|
|||
justify-content: start;
|
||||
}
|
||||
|
||||
.demo.invalide {
|
||||
background-color: var(--color-justi-invalide) !important;
|
||||
}
|
||||
|
||||
.demo.attente {
|
||||
background: repeating-linear-gradient(to bottom,
|
||||
var(--color-justi-attente-stripe) 0px,
|
||||
var(--color-justi-attente-stripe) 4px,
|
||||
var(--color-justi-attente) 4px,
|
||||
var(--color-justi-attente) 7px) !important;
|
||||
}
|
||||
|
||||
.demo.est_just {
|
||||
background-color: var(--color-justi) !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.demi .day.nonwork>span {
|
||||
|
|
|
@ -310,8 +310,13 @@ async function nouvellePeriode(period = null) {
|
|||
|
||||
const assi_btns = document.createElement('div');
|
||||
assi_btns.classList.add('assi-btns');
|
||||
const etats = ["retard", "absent"];
|
||||
|
||||
["present", "retard", "absent"].forEach((value) => {
|
||||
if(!window.nonPresent){
|
||||
etats.splice(0,0,"present");
|
||||
}
|
||||
|
||||
etats.forEach((value) => {
|
||||
const cbox = document.createElement("input");
|
||||
cbox.type = "checkbox";
|
||||
cbox.value = value;
|
||||
|
@ -499,6 +504,8 @@ const moduleimpls = new Map();
|
|||
const inscriptionsModules = new Map();
|
||||
const nonWorkDays = [{{ nonworkdays| safe }}];
|
||||
|
||||
window.nonPresent = {{ 'true' if non_present else 'false' }};
|
||||
|
||||
// Vérification du forçage de module
|
||||
window.forceModule = "{{ forcer_module }}" == "True";
|
||||
if (window.forceModule) {
|
||||
|
@ -518,12 +525,29 @@ if (window.forceModule) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
const defaultPlage = {{ nouv_plage | safe}} || [];
|
||||
|
||||
/**
|
||||
* Fonction exécutée au lancement de la page
|
||||
* - On affiche ou non les photos des étudiants
|
||||
* - On vérifie si la date est un jour travaillé
|
||||
*/
|
||||
async function main() {
|
||||
|
||||
// On initialise les sélecteurs avec les valeurs par défaut (si elles existent)
|
||||
if (defaultPlage.every((e) => e)) {
|
||||
$("#date").datepicker("setDate", defaultPlage[0]);
|
||||
$("#debut").val(defaultPlage[1]);
|
||||
$("#fin").val(defaultPlage[2]);
|
||||
|
||||
// On ajoute la période si la date est un jour travaillé
|
||||
if(dateCouranteEstTravaillee()){
|
||||
await nouvellePeriode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const checked = localStorage.getItem("scodoc-etud-pdp") == "true";
|
||||
afficherPDP(checked);
|
||||
$("#date").on("change", async function (d) {
|
||||
|
@ -532,7 +556,7 @@ async function main() {
|
|||
});
|
||||
}
|
||||
|
||||
main();
|
||||
window.addEventListener("load", main);
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -600,7 +624,9 @@ main();
|
|||
Intialiser les étudiants comme :
|
||||
<select name="etatDef" id="etatDef">
|
||||
<option value="">-</option>
|
||||
{% if not non_present %}
|
||||
<option value="present">présents</option>
|
||||
{% endif %}
|
||||
<option value="retard">en retard</option>
|
||||
<option value="absent">absents</option>
|
||||
</select>
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
const readOnly = {{ readonly }};
|
||||
|
||||
window.forceModule = "{{ forcer_module }}" == "True"
|
||||
window.nonPresent = {{ 'true' if non_present else 'false' }};
|
||||
|
||||
const etudsDefDem = {{ defdem | safe }}
|
||||
|
||||
|
@ -159,8 +160,10 @@
|
|||
<div class="mass-selection">
|
||||
<span>Mettre tout le monde :</span>
|
||||
<fieldset class="btns_field mass">
|
||||
{% if not non_present %}
|
||||
<input type="checkbox" value="present" name="mass_btn_assiduites" id="mass_rbtn_present"
|
||||
class="rbtn present" onclick="mettreToutLeMonde('present', this)" title="Present">
|
||||
{% endif %}
|
||||
<input type="checkbox" value="retard" name="mass_btn_assiduites" id="mass_rbtn_retard"
|
||||
class="rbtn retard" onclick="mettreToutLeMonde('retard', this)" title="Retard">
|
||||
<input type="checkbox" value="absent" name="mass_btn_assiduites" id="mass_rbtn_absent"
|
||||
|
@ -178,6 +181,11 @@
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div class="help">
|
||||
<h3>Calendrier</h3>
|
||||
{% include "assiduites/widgets/legende_couleur.j2" %}
|
||||
</div>
|
||||
|
||||
{% include "assiduites/widgets/toast.j2" %}
|
||||
{% include "assiduites/widgets/alert.j2" %}
|
||||
{% include "assiduites/widgets/prompt.j2" %}
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
<li><span title="Vert" class="present demo"></span> → présence de l'étudiant lors de la période
|
||||
</li>
|
||||
<li><span title="Orange" class="retard demo"></span> → retard de l'étudiant lors de la période
|
||||
</li>
|
||||
<li><span title="Rouge" class="absent demo"></span> → absence de l'étudiant lors de la période
|
||||
</li>
|
||||
<p>Code couleur</p>
|
||||
<ul class="couleurs">
|
||||
<li><span title="Vert" class="present demo"></span> → présence de l'étudiant lors de la
|
||||
période
|
||||
</li>
|
||||
<li><span title="Bleu clair" class="nonwork demo"></span> → la période n'est pas travaillée
|
||||
</li>
|
||||
<li><span title="Rouge" class="absent demo"></span> → absence de l'étudiant lors de la
|
||||
période
|
||||
</li>
|
||||
<li><span title="Rose" class="demo color absent est_just"></span> → absence justifiée
|
||||
</li>
|
||||
<li><span title="Orange" class="retard demo"></span> → retard de l'étudiant lors de la
|
||||
période
|
||||
</li>
|
||||
<li><span title="Jaune clair" class="demo color retard est_just"></span> → retard justifié
|
||||
</li>
|
||||
|
||||
<li><span title="Hachure Bleue" class="justified demo"></span> → l'assiduité est justifiée par un
|
||||
justificatif valide</li>
|
||||
<li><span title="Hachure Rouge" class="invalid_justified demo"></span> → l'assiduité est
|
||||
justifiée par un justificatif non valide / en attente de validation
|
||||
</li>
|
||||
<li><span title="Quart Bleu" class="est_just demo color"></span> → la période est couverte par un
|
||||
justificatif valide</li>
|
||||
<li><span title="Justif. non valide" class="invalide demo color "></span> → la période est
|
||||
couverte par un justificatif non valide
|
||||
</li>
|
||||
<li><span title="Justif. en attente" class="attente demo color"></span> → la période
|
||||
a un justificatif en attente de validation
|
||||
</li>
|
||||
</ul>
|
||||
<p>Vous pouvez passer le curseur sur les jours colorés afin de voir les informations supplémentaires</p>
|
||||
|
|
|
@ -74,7 +74,13 @@
|
|||
setupAssiduiteBubble(block, assiduité);
|
||||
}
|
||||
|
||||
// TODO: ajout couleur justificatif
|
||||
// ajout couleur justificatif
|
||||
const justificatifs = assiduité.justificatifs || [];
|
||||
const justified = justificatifs.some(
|
||||
(justificatif) => justificatif.etat === "VALIDE"
|
||||
)
|
||||
|
||||
if(justified) block.classList.add("est_just");
|
||||
|
||||
block.classList.add(assiduité.etat.toLowerCase());
|
||||
if(assiduité.etat != "CRENEAU") block.classList.add("color");
|
||||
|
|
|
@ -1132,6 +1132,11 @@ def signal_assiduites_group():
|
|||
formsemestre_id=formsemestre_id,
|
||||
dept_id=g.scodoc_dept_id,
|
||||
),
|
||||
non_present=sco_preferences.get_preference(
|
||||
"non_present",
|
||||
formsemestre_id=formsemestre_id,
|
||||
dept_id=g.scodoc_dept_id,
|
||||
),
|
||||
formsemestre_date_debut=str(formsemestre.date_debut),
|
||||
formsemestre_date_fin=str(formsemestre.date_fin),
|
||||
formsemestre_id=formsemestre_id,
|
||||
|
@ -1914,8 +1919,29 @@ def _preparer_objet(
|
|||
@scodoc
|
||||
@permission_required(Permission.AbsChange)
|
||||
def signal_assiduites_diff():
|
||||
"""TODO documenter
|
||||
"""
|
||||
Utilisé notamment par "Saisie différée" sur tableau de bord semetstre"
|
||||
|
||||
Arguments de la requête:
|
||||
|
||||
- group_ids : liste des groupes
|
||||
example : group_ids=1,2,3
|
||||
- formsemestre_id : id du formsemestre
|
||||
example : formsemestre_id=1
|
||||
- moduleimpl_id : id du moduleimpl
|
||||
example : moduleimpl_id=1
|
||||
|
||||
(Permet de pré-générer une plage. Si non renseigné, la plage sera vide)
|
||||
(Les trois valeurs suivantes doivent être renseignées ensemble)
|
||||
- date
|
||||
example : date=01/01/2021
|
||||
- heure_debut
|
||||
example : heure_debut=08:00
|
||||
- heure_fin
|
||||
example : heure_fin=10:00
|
||||
|
||||
Exemple de requête :
|
||||
signal_assiduites_diff?formsemestre_id=67&group_ids=400&moduleimpl_id=1229&date=15/04/2024&heure_debut=12:34&heure_fin=12:55
|
||||
"""
|
||||
# Récupération des paramètres de la requête
|
||||
group_ids: list[int] = request.args.get("group_ids", None)
|
||||
|
@ -1957,11 +1983,23 @@ def signal_assiduites_diff():
|
|||
grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
|
||||
)
|
||||
|
||||
# Pré-remplissage des sélecteurs
|
||||
moduleimpl_id = request.args.get("moduleimpl_id", -1)
|
||||
try:
|
||||
moduleimpl_id = int(moduleimpl_id)
|
||||
except ValueError:
|
||||
moduleimpl_id = -1
|
||||
# date fra (dd/mm/yyyy)
|
||||
date = request.args.get("date", "")
|
||||
# heures (hh:mm)
|
||||
heure_deb = request.args.get("heure_debut", "")
|
||||
heure_fin = request.args.get("heure_fin", "")
|
||||
|
||||
# vérifications des sélecteurs
|
||||
date = date if re.match(r"^\d{2}\/\d{2}\/\d{4}$", date) else ""
|
||||
heure_deb = heure_deb if re.match(r"^[0-2]\d:[0-5]\d$", heure_deb) else ""
|
||||
heure_fin = heure_fin if re.match(r"^[0-2]\d:[0-5]\d$", heure_fin) else ""
|
||||
nouv_plage: list[str] = [date, heure_deb, heure_fin]
|
||||
|
||||
return render_template(
|
||||
"assiduites/pages/signal_assiduites_diff.j2",
|
||||
|
@ -1977,6 +2015,12 @@ def signal_assiduites_diff():
|
|||
formsemestre_id=formsemestre_id,
|
||||
dept_id=g.scodoc_dept_id,
|
||||
),
|
||||
non_present=sco_preferences.get_preference(
|
||||
"non_present",
|
||||
formsemestre_id=formsemestre_id,
|
||||
dept_id=g.scodoc_dept_id,
|
||||
),
|
||||
nouv_plage=nouv_plage,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ mkdir -p "$optdir" || die "mkdir failure for $optdir"
|
|||
archive="$FACTORY_DIR"/"$PACKAGE_NAME-$RELEASE_TAG".tar.gz
|
||||
echo "Downloading $GIT_RELEASE_URL ..."
|
||||
# curl -o "$archive" "$GIT_RELEASE_URL" || die "curl failure for $GIT_RELEASE_URL"
|
||||
#wget --progress=dot -O "$archive" "$GIT_RELEASE_URL" || die "wget failure for $GIT_RELEASE_URL"
|
||||
wget --progress=dot -O "$archive" "$GIT_RELEASE_URL" || die "wget failure for $GIT_RELEASE_URL"
|
||||
# -nv
|
||||
|
||||
# On décomprime
|
||||
|
|
Loading…
Reference in New Issue