diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py index 3ac60eeb..3f9890f6 100755 --- a/app/scodoc/sco_formsemestre_status.py +++ b/app/scodoc/sco_formsemestre_status.py @@ -838,6 +838,27 @@ def _make_listes_sem(formsemestre: FormSemestre) -> str: )}"> Saisir l'assiduité + """ + ) + # YYYY-Www (ISO 8601) : + current_week: str = datetime.datetime.now().strftime("%G-W%V") + H.append( + f""" +
+ + Saisir l'assiduité (Hebdo) +
+ """ + ) + if can_edit_abs: + H.append( + f"""
str: )}"> Justificatifs en attente
- """ + """ ) H.append( f""" diff --git a/app/scodoc/sco_groups_view.py b/app/scodoc/sco_groups_view.py index 0ebed472..80454b43 100644 --- a/app/scodoc/sco_groups_view.py +++ b/app/scodoc/sco_groups_view.py @@ -26,7 +26,7 @@ ############################################################################## """Affichage étudiants d'un ou plusieurs groupes - sous forme: de liste html (table exportable), de trombinoscope (exportable en pdf) +sous forme: de liste html (table exportable), de trombinoscope (exportable en pdf) """ # Re-ecriture en 2014 (re-organisation de l'interface, modernisation du code) @@ -585,8 +585,8 @@ def groups_table( etud_info["_nom_disp_order"] = etud_sort_key(etud_info) etud_info["_prenom_target"] = fiche_url - etud_info["_nom_disp_td_attrs"] = 'id="%s" class="etudinfo"' % ( - etud_info["etudid"] + etud_info["_nom_disp_td_attrs"] = ( + 'id="%s" class="etudinfo"' % (etud_info["etudid"]) ) etud_info["bourse_str"] = "oui" if etud_info["boursier"] else "non" if etud_info["etat"] == "D": @@ -998,12 +998,12 @@ def form_choix_saisie_semaine(groups_infos): return "" query_args = parse_qs(request.query_string) moduleimpl_id = query_args.get("moduleimpl_id", [None])[0] - semaine = datetime.date.today().isocalendar().week + semaine = datetime.datetime.now().strftime("%G-W%V") return f""" + + + + +

+ Le matin 9h à 12h et l'après-midi de 13h à 17h +

+ +{% if readonly %} +

+ Ouvert en mode lecture seule. +

+ +{% endif %} + + + + + + {% for jour in hebdo_jours %} + + {% if not jour[0] or jour[1][0] not in ['Samedi', 'Dimanche'] %} + + {% endif %} + + {% endfor %} + + + {% for jour in hebdo_jours %} + + {% if not jour[0] or jour[1][0] not in ['Samedi', 'Dimanche'] %} + + + {% endif %} + {% endfor %} + + {% if not readonly and not non_present %} + + {# Ne pas afficher si preference "non presences" / "readonly" #} + + {% for jour in hebdo_jours %} + {% if not jour[0] or jour[1][0] not in ['Samedi', 'Dimanche'] %} + + + {% endif %} + {% endfor %} + + {% endif %} + + + {% for etud in etudiants %} + + + {# Sera rempli en JS #} + {# Ne pas afficher bouton présent si pref "non présences" #} + {# + #} + + {% endfor %} + +
Étudiants{{ jour[1][0] }} {{jour[1][1] }}
MatinAprès-midi
+ + + +
{{ etud.nom_prenom() }} + + + + + + + +
+ +
+
+ × +

Choisissez les horaires

+
+ + +
+
+ + +
+ + +
+
+ +{% include "assiduites/widgets/alert.j2" %} +{% include "assiduites/widgets/toast.j2" %} +{% endblock app_content %} \ No newline at end of file diff --git a/app/views/assiduites.py b/app/views/assiduites.py index f5ffe223..99ce6ab6 100644 --- a/app/views/assiduites.py +++ b/app/views/assiduites.py @@ -1987,6 +1987,146 @@ def traitement_justificatifs(): ) +@bp.route("signal_assiduites_hebdo") +@scodoc +@permission_required(Permission.ScoView) +def signal_assiduites_hebdo(): + """ + signal_assiduites_hebdo + + paramètres obligatoires : + - formsemestre_id : id du formsemestre + - week : date semaine (iso 8601 -> 20XX-WXX) + - groups_id : id des groupes (séparés par des virgules -> 1,2,3) + + paramètres optionnels : + - moduleimpl_id : id du moduleimpl (par défaut None) + + + Permissions : + - ScoView -> page en lecture seule + - AbsChange -> page en lecture/écriture + """ + + # Récupération des paramètres + moduleimpl_id: int = request.args.get("moduleimpl_id", None) + week: str = request.args.get("week", None) + group_ids: str = request.args.get("group_ids", "") # ex: "1,2,3" + formsemestre_id: int = request.args.get("formsemestre_id", -1) + + # Vérification des paramètres + if week is None or group_ids == "" or formsemestre_id == -1: + raise ScoValueError("Paramètres manquants", dest_url=request.referrer) + + # Récupération du moduleimpl + try: + moduleimpl_id: int = int(moduleimpl_id) + except (ValueError, TypeError): + moduleimpl_id: str | None = None if moduleimpl_id != "autre" else moduleimpl_id + + # Récupération du formsemestre + formsemestre: FormSemestre = FormSemestre.get_formsemestre(formsemestre_id) + + # Vérification semaine dans format iso 8601 et formsemestre + regex_iso8601 = r"^\d{4}-W\d{2}$" + if not re.match(regex_iso8601, week): + raise ScoValueError("Semaine invalide", dest_url=request.referrer) + + fs_deb_iso8601 = formsemestre.date_debut.strftime("%Y-W%W") + fs_fin_iso8601 = formsemestre.date_fin.strftime("%Y-W%W") + + # Utilisation de la propriété de la norme iso 8601 + # les chaines sont triables par ordre alphanumérique croissant + # et produiront le même ordre que les dates par ordre chronologique croissant + if week < fs_deb_iso8601 or week > fs_fin_iso8601: + raise ScoValueError("Semaine hors du semestre", dest_url=request.referrer) + + # Vérification des groupes + group_ids = group_ids.split(",") if group_ids != "" else [] + + groups_infos = sco_groups_view.DisplayedGroupsInfos( + group_ids, formsemestre_id=formsemestre.id, select_all_when_unspecified=True + ) + if not groups_infos.members: + return ( + html_sco_header.sco_header(page_title="Assiduité: saisie hebdomadaire") + + "

Aucun étudiant !

" + + html_sco_header.sco_footer() + ) + + # Récupération des étudiants + etudiants: list[Identite] = [ + Identite.get_etud(etudid=m["etudid"]) for m in groups_infos.members + ] + + if groups_infos.tous_les_etuds_du_sem: + gr_tit = "en" + else: + if len(groups_infos.group_ids) > 1: + grp = "des groupes" + else: + grp = "du groupe" + gr_tit = ( + grp + ' ' + groups_infos.groups_titles + "" + ) + + # Gestion des jours + jours: dict[str, list[str]] = { + "lun": [ + "Lundi", + datetime.datetime.strptime(week + "-1", "%G-W%V-%u").strftime("%d/%m/%Y"), + ], + "mar": [ + "Mardi", + datetime.datetime.strptime(week + "-2", "%G-W%V-%u").strftime("%d/%m/%Y"), + ], + "mer": [ + "Mercredi", + datetime.datetime.strptime(week + "-3", "%G-W%V-%u").strftime("%d/%m/%Y"), + ], + "jeu": [ + "Jeudi", + datetime.datetime.strptime(week + "-4", "%G-W%V-%u").strftime("%d/%m/%Y"), + ], + "ven": [ + "Vendredi", + datetime.datetime.strptime(week + "-5", "%G-W%V-%u").strftime("%d/%m/%Y"), + ], + "sam": [ + "Samedi", + datetime.datetime.strptime(week + "-6", "%G-W%V-%u").strftime("%d/%m/%Y"), + ], + "dim": [ + "Dimanche", + datetime.datetime.strptime(week + "-7", "%G-W%V-%u").strftime("%d/%m/%Y"), + ], + } + + non_travail = sco_preferences.get_preference("non_travail") + non_travail = non_travail.replace(" ", "").split(",") + + hebdo_jours: list[tuple[bool, str]] = [] + for key, val in jours.items(): + hebdo_jours.append((key in non_travail, val)) + + return render_template( + "assiduites/pages/signal_assiduites_hebdo.j2", + title="Assiduité: saisie hebdomadaire", + gr=gr_tit, + etudiants=etudiants, + moduleimpl_select=_module_selector( + formsemestre=formsemestre, moduleimpl_id=moduleimpl_id + ), + hebdo_jours=hebdo_jours, + readonly=not current_user.has_permission(Permission.AbsChange), + non_present=sco_preferences.get_preference( + "non_present", + formsemestre_id=formsemestre_id, + dept_id=g.scodoc_dept_id, + ), + ) + + def generate_bul_list(etud: Identite, semestre: FormSemestre) -> str: """Génère la liste des assiduités d'un étudiant pour le bulletin mail"""