diff --git a/app/scodoc/sco_assiduites.py b/app/scodoc/sco_assiduites.py index fd309866..b429187e 100644 --- a/app/scodoc/sco_assiduites.py +++ b/app/scodoc/sco_assiduites.py @@ -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 diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 2fd6a13b..a02811c2 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -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

Note: sauf exception, l'UE n'a pas de coefficient associé. Seuls les modules ont des coefficients.

""", - f""" + ( + f"""

UE du semestre S{ue.semestre_idx}

""" - if is_apc and ue - else "", + if is_apc and ue + else "" + ), ] ue_types = cursus.ALLOWED_UE_TYPES diff --git a/app/tables/visu_assiduites.py b/app/tables/visu_assiduites.py index 357fd9c8..f4061280 100644 --- a/app/tables/visu_assiduites.py +++ b/app/tables/visu_assiduites.py @@ -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 }, ) diff --git a/app/templates/assiduites/pages/visu_assi_group.j2 b/app/templates/assiduites/pages/visu_assi_group.j2 index 04f56cb2..2b99c8a1 100644 --- a/app/templates/assiduites/pages/visu_assi_group.j2 +++ b/app/templates/assiduites/pages/visu_assi_group.j2 @@ -8,6 +8,13 @@ {% block app_content %} + +

Visualisation de l'assiduité {{gr_tit|safe}}

@@ -18,6 +25,12 @@ {{scu.ICON_XLS|safe}} + + +
{{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; + }); }) diff --git a/app/views/assiduites.py b/app/views/assiduites.py index c58c0a84..81ee9527 100644 --- a/app/views/assiduites.py +++ b/app/views/assiduites.py @@ -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