forked from ScoDoc/ScoDoc
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.
|
||||
"""
|
||||
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from pytz import UTC
|
||||
|
||||
from flask import g
|
||||
from flask_sqlalchemy.query import Query
|
||||
|
||||
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.etudiants import Identite
|
||||
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
||||
from app.scodoc import sco_formsemestre_inscriptions
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_etud
|
||||
from app.models import ScoDocSiteConfig
|
||||
from flask import g
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
|
||||
class CountCalculator:
|
||||
@ -93,9 +99,9 @@ class CountCalculator:
|
||||
evening if evening else ScoDocSiteConfig.get("assi_afternoon_time", "18:00")
|
||||
)
|
||||
|
||||
self.non_work_days: list[
|
||||
scu.NonWorkDays
|
||||
] = scu.NonWorkDays.get_all_non_work_days(dept_id=g.scodoc_dept_id)
|
||||
self.non_work_days: list[scu.NonWorkDays] = (
|
||||
scu.NonWorkDays.get_all_non_work_days(dept_id=g.scodoc_dept_id)
|
||||
)
|
||||
|
||||
delta_total: timedelta = datetime.combine(
|
||||
date.min, self.evening
|
||||
@ -371,6 +377,10 @@ def get_assiduites_stats(
|
||||
assiduites = filter_by_formsemestre(
|
||||
assiduites, Assiduite, filtered[key]
|
||||
)
|
||||
case "formsemestre_modimpls":
|
||||
assiduites = filter_by_modimpls(
|
||||
assiduites, Assiduite, filtered[key]
|
||||
)
|
||||
case "est_just":
|
||||
assiduites = filter_assiduites_by_est_just(
|
||||
assiduites, filtered[key]
|
||||
@ -489,7 +499,9 @@ def filter_by_formsemestre(
|
||||
formsemestre: FormSemestre,
|
||||
) -> 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:
|
||||
@ -514,6 +526,41 @@ def filter_by_formsemestre(
|
||||
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:
|
||||
"""
|
||||
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
|
||||
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
|
||||
# XXX TODO utiliser UniteEns.create_from_dict
|
||||
ue_id = _ueEditor.create(cnx, 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é.
|
||||
Seuls les <em>modules</em> ont des coefficients.
|
||||
</p>""",
|
||||
(
|
||||
f"""
|
||||
<h4>UE du semestre S{ue.semestre_idx}</h4>
|
||||
"""
|
||||
if is_apc and ue
|
||||
else "",
|
||||
else ""
|
||||
),
|
||||
]
|
||||
|
||||
ue_types = cursus.ALLOWED_UE_TYPES
|
||||
|
@ -18,7 +18,12 @@ from app.scodoc import sco_utils as scu
|
||||
|
||||
class TableAssi(tb.Table):
|
||||
"""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.
|
||||
"""
|
||||
@ -28,6 +33,7 @@ class TableAssi(tb.Table):
|
||||
etuds: list[Identite] = None,
|
||||
dates: tuple[str, str] = None,
|
||||
formsemestre: FormSemestre = None,
|
||||
formsemestre_modimpls: FormSemestre | None = None,
|
||||
convert_values=False,
|
||||
**kwargs,
|
||||
):
|
||||
@ -35,6 +41,7 @@ class TableAssi(tb.Table):
|
||||
classes = ["gt_table"]
|
||||
self.dates = [str(dates[0]) + "T00:00", str(dates[1]) + "T23:59"]
|
||||
self.formsemestre = formsemestre
|
||||
self.formsemestre_modimpls = formsemestre_modimpls
|
||||
if convert_values:
|
||||
self.fmt_num = lambda x: f"{x:2.3g}"
|
||||
else:
|
||||
@ -140,6 +147,7 @@ class RowAssi(tb.Row):
|
||||
"""
|
||||
Renvoie le comptage (dans la métrique du département) des différents états
|
||||
d'assiduité d'un étudiant.
|
||||
Considère les dates.
|
||||
|
||||
Returns :
|
||||
{
|
||||
@ -167,6 +175,7 @@ class RowAssi(tb.Row):
|
||||
"date_debut": self.dates[0],
|
||||
"date_fin": self.dates[1],
|
||||
"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
|
||||
},
|
||||
)
|
||||
|
@ -8,6 +8,13 @@
|
||||
|
||||
{% block app_content %}
|
||||
|
||||
<style>
|
||||
label.stats_checkbox {
|
||||
font-weight: normal;
|
||||
margin-left: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h2>Visualisation de l'assiduité {{gr_tit|safe}}</h2>
|
||||
|
||||
<div class="stats-inputs">
|
||||
@ -18,6 +25,12 @@
|
||||
<button onclick="stats()">Changer</button>
|
||||
|
||||
<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>
|
||||
|
||||
{{tableau | safe}}
|
||||
@ -40,6 +53,19 @@
|
||||
window.addEventListener('load', () => {
|
||||
document.querySelector('#stats_date_debut').value = date_debut;
|
||||
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>
|
||||
|
@ -1301,6 +1301,8 @@ def visu_assi_group():
|
||||
- date_debut, date_fin (format ISO)
|
||||
- fmt : format d'export, html (défaut) ou xls
|
||||
- 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
|
||||
@ -1308,6 +1310,12 @@ def visu_assi_group():
|
||||
"debut": request.args.get("date_debut"),
|
||||
"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")
|
||||
|
||||
group_ids: list[int] = request.args.get("group_ids", None)
|
||||
@ -1327,7 +1335,8 @@ def visu_assi_group():
|
||||
etuds=etuds,
|
||||
dates=list(dates.values()),
|
||||
formsemestre=formsemestre,
|
||||
convert_values=fmt == "html",
|
||||
formsemestre_modimpls=formsemestre_modimpls,
|
||||
convert_values=(fmt == "html"),
|
||||
)
|
||||
|
||||
# Export en XLS
|
||||
|
Loading…
Reference in New Issue
Block a user