Assiduite: visu_assi_group avec restriction aux modules du semestre.
This commit is contained in:
parent
c8ac796347
commit
9ec0ef27ba
@ -1,22 +1,28 @@
|
|||||||
"""
|
"""
|
||||||
Ecrit par Matthias Hartmann.
|
Ecrit par Matthias Hartmann.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from datetime import date, datetime, time, timedelta
|
from datetime import date, datetime, time, timedelta
|
||||||
from pytz import UTC
|
from pytz import UTC
|
||||||
|
|
||||||
|
from flask import g
|
||||||
from flask_sqlalchemy.query import Query
|
from flask_sqlalchemy.query import Query
|
||||||
|
|
||||||
from app import log, db, set_sco_dept
|
from app import log, db, set_sco_dept
|
||||||
import app.scodoc.sco_utils as scu
|
from app.models import (
|
||||||
|
Identite,
|
||||||
|
FormSemestre,
|
||||||
|
FormSemestreInscription,
|
||||||
|
ModuleImpl,
|
||||||
|
ModuleImplInscription,
|
||||||
|
ScoDocSiteConfig,
|
||||||
|
)
|
||||||
from app.models.assiduites import Assiduite, Justificatif, compute_assiduites_justified
|
from app.models.assiduites import Assiduite, Justificatif, compute_assiduites_justified
|
||||||
from app.models.etudiants import Identite
|
|
||||||
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.models import ScoDocSiteConfig
|
import app.scodoc.sco_utils as scu
|
||||||
from flask import g
|
|
||||||
|
|
||||||
|
|
||||||
class CountCalculator:
|
class CountCalculator:
|
||||||
@ -93,9 +99,9 @@ class CountCalculator:
|
|||||||
evening if evening else ScoDocSiteConfig.get("assi_afternoon_time", "18:00")
|
evening if evening else ScoDocSiteConfig.get("assi_afternoon_time", "18:00")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.non_work_days: list[
|
self.non_work_days: list[scu.NonWorkDays] = (
|
||||||
scu.NonWorkDays
|
scu.NonWorkDays.get_all_non_work_days(dept_id=g.scodoc_dept_id)
|
||||||
] = scu.NonWorkDays.get_all_non_work_days(dept_id=g.scodoc_dept_id)
|
)
|
||||||
|
|
||||||
delta_total: timedelta = datetime.combine(
|
delta_total: timedelta = datetime.combine(
|
||||||
date.min, self.evening
|
date.min, self.evening
|
||||||
@ -371,6 +377,10 @@ def get_assiduites_stats(
|
|||||||
assiduites = filter_by_formsemestre(
|
assiduites = filter_by_formsemestre(
|
||||||
assiduites, Assiduite, filtered[key]
|
assiduites, Assiduite, filtered[key]
|
||||||
)
|
)
|
||||||
|
case "formsemestre_modimpls":
|
||||||
|
assiduites = filter_by_modimpls(
|
||||||
|
assiduites, Assiduite, filtered[key]
|
||||||
|
)
|
||||||
case "est_just":
|
case "est_just":
|
||||||
assiduites = filter_assiduites_by_est_just(
|
assiduites = filter_assiduites_by_est_just(
|
||||||
assiduites, filtered[key]
|
assiduites, filtered[key]
|
||||||
@ -489,7 +499,9 @@ def filter_by_formsemestre(
|
|||||||
formsemestre: FormSemestre,
|
formsemestre: FormSemestre,
|
||||||
) -> Query:
|
) -> Query:
|
||||||
"""
|
"""
|
||||||
Filtrage d'une collection en fonction d'un formsemestre
|
Filtrage d'une collection : conserve les élements
|
||||||
|
- si l'étudiant est inscrit au formsemestre
|
||||||
|
- Et que la plage de dates est complètement incluse dans le semestre (bizarre!)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if formsemestre is None:
|
if formsemestre is None:
|
||||||
@ -514,6 +526,41 @@ def filter_by_formsemestre(
|
|||||||
return collection_result.filter(collection_class.date_fin <= form_date_fin)
|
return collection_result.filter(collection_class.date_fin <= form_date_fin)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_by_modimpls(
|
||||||
|
collection_query: Assiduite | Justificatif,
|
||||||
|
collection_class: Assiduite | Justificatif,
|
||||||
|
formsemestre: FormSemestre,
|
||||||
|
) -> Query:
|
||||||
|
"""
|
||||||
|
Filtrage d'une collection d'assiduités: conserve les élements
|
||||||
|
- si l'étudiant est inscrit au formsemestre
|
||||||
|
- Et que l'assiduité concerne un moduleimpl de ce formsemestre
|
||||||
|
|
||||||
|
Ne fait rien sur les justificatifs.
|
||||||
|
Ne fait rien si formsemestre is None
|
||||||
|
"""
|
||||||
|
if (collection_class != Assiduite) or (formsemestre is None):
|
||||||
|
return collection_query
|
||||||
|
|
||||||
|
# restreint aux inscrits:
|
||||||
|
collection_result = (
|
||||||
|
collection_query.join(Identite, collection_class.etudid == Identite.id)
|
||||||
|
.join(
|
||||||
|
FormSemestreInscription,
|
||||||
|
Identite.id == FormSemestreInscription.etudid,
|
||||||
|
)
|
||||||
|
.filter(FormSemestreInscription.formsemestre_id == formsemestre.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
collection_result = (
|
||||||
|
collection_result.join(ModuleImpl)
|
||||||
|
.join(ModuleImplInscription)
|
||||||
|
.filter(ModuleImplInscription.etudid == collection_class.etudid)
|
||||||
|
)
|
||||||
|
|
||||||
|
return collection_result
|
||||||
|
|
||||||
|
|
||||||
def justifies(justi: Justificatif, obj: bool = False) -> list[int] | Query:
|
def justifies(justi: Justificatif, obj: bool = False) -> list[int] | Query:
|
||||||
"""
|
"""
|
||||||
Retourne la liste des assiduite_id qui sont justifié par la justification
|
Retourne la liste des assiduite_id qui sont justifié par la justification
|
||||||
|
@ -133,7 +133,15 @@ def do_ue_create(args, allow_empty_ue_code=False):
|
|||||||
break
|
break
|
||||||
args["ue_code"] = code
|
args["ue_code"] = code
|
||||||
|
|
||||||
|
# last checks
|
||||||
|
if not args.get("acronyme"):
|
||||||
|
raise ScoValueError("acronyme vide")
|
||||||
|
args["coefficient"] = args.get("coefficient", None)
|
||||||
|
if args["coefficient"] == "":
|
||||||
|
args["coefficient"] = None
|
||||||
|
|
||||||
# create
|
# create
|
||||||
|
# XXX TODO utiliser UniteEns.create_from_dict
|
||||||
ue_id = _ueEditor.create(cnx, args)
|
ue_id = _ueEditor.create(cnx, args)
|
||||||
log(f"do_ue_create: created {ue_id} with {args}")
|
log(f"do_ue_create: created {ue_id} with {args}")
|
||||||
|
|
||||||
@ -303,11 +311,13 @@ def ue_edit(ue_id=None, create=False, formation_id=None, default_semestre_idx=No
|
|||||||
<p class="help">Note: sauf exception, l'UE n'a pas de coefficient associé.
|
<p class="help">Note: sauf exception, l'UE n'a pas de coefficient associé.
|
||||||
Seuls les <em>modules</em> ont des coefficients.
|
Seuls les <em>modules</em> ont des coefficients.
|
||||||
</p>""",
|
</p>""",
|
||||||
|
(
|
||||||
f"""
|
f"""
|
||||||
<h4>UE du semestre S{ue.semestre_idx}</h4>
|
<h4>UE du semestre S{ue.semestre_idx}</h4>
|
||||||
"""
|
"""
|
||||||
if is_apc and ue
|
if is_apc and ue
|
||||||
else "",
|
else ""
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
ue_types = cursus.ALLOWED_UE_TYPES
|
ue_types = cursus.ALLOWED_UE_TYPES
|
||||||
|
@ -18,7 +18,12 @@ from app.scodoc import sco_utils as scu
|
|||||||
|
|
||||||
class TableAssi(tb.Table):
|
class TableAssi(tb.Table):
|
||||||
"""Table listant les statistiques d'assiduité des étudiants
|
"""Table listant les statistiques d'assiduité des étudiants
|
||||||
L'id de la ligne est etuid, et le row stocke etud.
|
L'id de la ligne est etudid, et le row stocke etud.
|
||||||
|
|
||||||
|
On considère les assiduités entre les dates indiquées.
|
||||||
|
|
||||||
|
Si formsemestre_modimpls est spécifié, restreint aux assiduités associées à des
|
||||||
|
moduleimpls de ce formsemestre.
|
||||||
|
|
||||||
Si convert_values, transforme les nombre en chaines ("12.34"), pour le html.
|
Si convert_values, transforme les nombre en chaines ("12.34"), pour le html.
|
||||||
"""
|
"""
|
||||||
@ -28,6 +33,7 @@ class TableAssi(tb.Table):
|
|||||||
etuds: list[Identite] = None,
|
etuds: list[Identite] = None,
|
||||||
dates: tuple[str, str] = None,
|
dates: tuple[str, str] = None,
|
||||||
formsemestre: FormSemestre = None,
|
formsemestre: FormSemestre = None,
|
||||||
|
formsemestre_modimpls: FormSemestre | None = None,
|
||||||
convert_values=False,
|
convert_values=False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
@ -35,6 +41,7 @@ class TableAssi(tb.Table):
|
|||||||
classes = ["gt_table"]
|
classes = ["gt_table"]
|
||||||
self.dates = [str(dates[0]) + "T00:00", str(dates[1]) + "T23:59"]
|
self.dates = [str(dates[0]) + "T00:00", str(dates[1]) + "T23:59"]
|
||||||
self.formsemestre = formsemestre
|
self.formsemestre = formsemestre
|
||||||
|
self.formsemestre_modimpls = formsemestre_modimpls
|
||||||
if convert_values:
|
if convert_values:
|
||||||
self.fmt_num = lambda x: f"{x:2.3g}"
|
self.fmt_num = lambda x: f"{x:2.3g}"
|
||||||
else:
|
else:
|
||||||
@ -140,6 +147,7 @@ class RowAssi(tb.Row):
|
|||||||
"""
|
"""
|
||||||
Renvoie le comptage (dans la métrique du département) des différents états
|
Renvoie le comptage (dans la métrique du département) des différents états
|
||||||
d'assiduité d'un étudiant.
|
d'assiduité d'un étudiant.
|
||||||
|
Considère les dates.
|
||||||
|
|
||||||
Returns :
|
Returns :
|
||||||
{
|
{
|
||||||
@ -167,6 +175,7 @@ class RowAssi(tb.Row):
|
|||||||
"date_debut": self.dates[0],
|
"date_debut": self.dates[0],
|
||||||
"date_fin": self.dates[1],
|
"date_fin": self.dates[1],
|
||||||
"etat": "absent,present,retard", # pour tout compter d'un coup
|
"etat": "absent,present,retard", # pour tout compter d'un coup
|
||||||
|
"formsemestre_modimpls": self.table.formsemestre_modimpls,
|
||||||
"split": 1, # afin d'avoir la division des stats en état, etatjust, etatnonjust
|
"split": 1, # afin d'avoir la division des stats en état, etatjust, etatnonjust
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -8,6 +8,13 @@
|
|||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
label.stats_checkbox {
|
||||||
|
font-weight: normal;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<h2>Visualisation de l'assiduité {{gr_tit|safe}}</h2>
|
<h2>Visualisation de l'assiduité {{gr_tit|safe}}</h2>
|
||||||
|
|
||||||
<div class="stats-inputs">
|
<div class="stats-inputs">
|
||||||
@ -18,6 +25,12 @@
|
|||||||
<button onclick="stats()">Changer</button>
|
<button onclick="stats()">Changer</button>
|
||||||
|
|
||||||
<a style="margin-left:32px;" href="{{request.url}}&fmt=xlsx">{{scu.ICON_XLS|safe}}</a>
|
<a style="margin-left:32px;" href="{{request.url}}&fmt=xlsx">{{scu.ICON_XLS|safe}}</a>
|
||||||
|
|
||||||
|
<label class="stats_checkbox">
|
||||||
|
<input type="checkbox" id="formsemestre_modimpls_box"> restreindre l'assiduité aux
|
||||||
|
modules de ce semestre
|
||||||
|
</label>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{tableau | safe}}
|
{{tableau | safe}}
|
||||||
@ -40,6 +53,19 @@
|
|||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
document.querySelector('#stats_date_debut').value = date_debut;
|
document.querySelector('#stats_date_debut').value = date_debut;
|
||||||
document.querySelector('#stats_date_fin').value = date_fin;
|
document.querySelector('#stats_date_fin').value = date_fin;
|
||||||
|
|
||||||
|
// La checkbox pour restreindre aux modules du semestre:
|
||||||
|
var url = new URL(window.location.href);
|
||||||
|
var checkbox = document.getElementById('formsemestre_modimpls_box');
|
||||||
|
checkbox.checked = url.searchParams.has('formsemestre_modimpls_id');
|
||||||
|
checkbox.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
url.searchParams.set('formsemestre_modimpls_id', {{sco.formsemestre.id}});
|
||||||
|
} else {
|
||||||
|
url.searchParams.delete('formsemestre_modimpls_id');
|
||||||
|
}
|
||||||
|
window.location.href = url.href;
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1301,6 +1301,8 @@ def visu_assi_group():
|
|||||||
- date_debut, date_fin (format ISO)
|
- date_debut, date_fin (format ISO)
|
||||||
- fmt : format d'export, html (défaut) ou xls
|
- fmt : format d'export, html (défaut) ou xls
|
||||||
- group_ids : liste des groupes
|
- group_ids : liste des groupes
|
||||||
|
- formsemestre_modimpls_id: id d'un formasemestre, si fournit restreint les
|
||||||
|
comptages aux assiduités liées à des modules de ce formsemestre.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Récupération des paramètres de la requête
|
# Récupération des paramètres de la requête
|
||||||
@ -1308,6 +1310,12 @@ def visu_assi_group():
|
|||||||
"debut": request.args.get("date_debut"),
|
"debut": request.args.get("date_debut"),
|
||||||
"fin": request.args.get("date_fin"),
|
"fin": request.args.get("date_fin"),
|
||||||
}
|
}
|
||||||
|
formsemestre_modimpls_id = request.args.get("formsemestre_modimpls_id")
|
||||||
|
formsemestre_modimpls = (
|
||||||
|
None
|
||||||
|
if formsemestre_modimpls_id is None
|
||||||
|
else FormSemestre.get_formsemestre(formsemestre_modimpls_id)
|
||||||
|
)
|
||||||
fmt = request.args.get("fmt", "html")
|
fmt = request.args.get("fmt", "html")
|
||||||
|
|
||||||
group_ids: list[int] = request.args.get("group_ids", None)
|
group_ids: list[int] = request.args.get("group_ids", None)
|
||||||
@ -1327,7 +1335,8 @@ def visu_assi_group():
|
|||||||
etuds=etuds,
|
etuds=etuds,
|
||||||
dates=list(dates.values()),
|
dates=list(dates.values()),
|
||||||
formsemestre=formsemestre,
|
formsemestre=formsemestre,
|
||||||
convert_values=fmt == "html",
|
formsemestre_modimpls=formsemestre_modimpls,
|
||||||
|
convert_values=(fmt == "html"),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Export en XLS
|
# Export en XLS
|
||||||
|
Loading…
Reference in New Issue
Block a user