diff --git a/app/forms/assiduite/ajout_assiduite_etud.py b/app/forms/assiduite/ajout_assiduite_etud.py index 4ece2b5bd..8c3423acc 100644 --- a/app/forms/assiduite/ajout_assiduite_etud.py +++ b/app/forms/assiduite/ajout_assiduite_etud.py @@ -126,6 +126,7 @@ class AjoutAssiOrJustForm(FlaskForm): class AjoutAssiduiteEtudForm(AjoutAssiOrJustForm): "Formulaire de saisie d'une assiduité pour un étudiant" + description = TextAreaField( "Description", render_kw={ @@ -152,6 +153,7 @@ class AjoutAssiduiteEtudForm(AjoutAssiOrJustForm): class AjoutJustificatifEtudForm(AjoutAssiOrJustForm): "Formulaire de saisie d'un justificatif pour un étudiant" + raison = TextAreaField( "Raison", render_kw={ @@ -176,6 +178,12 @@ class AjoutJustificatifEtudForm(AjoutAssiOrJustForm): class ChoixDateForm(FlaskForm): + """ + Formulaire de choix de date + (utilisé par la page de choix de date + si la date courante n'est pas dans le semestre) + """ + def __init__(self, *args, **kwargs): "Init form, adding a filed for our error messages" super().__init__(*args, **kwargs) diff --git a/app/models/assiduites.py b/app/models/assiduites.py index e08a92111..8580179bd 100644 --- a/app/models/assiduites.py +++ b/app/models/assiduites.py @@ -5,7 +5,6 @@ from datetime import datetime from flask_login import current_user from flask_sqlalchemy.query import Query -from sqlalchemy.exc import DataError from app import db, log, g, set_sco_dept from app.models import ( @@ -89,6 +88,8 @@ class Assiduite(ScoDocModel): lazy="select", ) + # Argument "restrict" obligatoire car on override la fonction "to_dict" de ScoDocModel + # pylint: disable-next=unused-argument def to_dict(self, format_api=True, restrict: bool | None = None) -> dict: """Retourne la représentation json de l'assiduité restrict n'est pas utilisé ici. @@ -307,6 +308,9 @@ class Assiduite(ScoDocModel): def supprime(self): "Supprime l'assiduité. Log et commit." + + # Obligatoire car import circulaire sinon + # pylint: disable-next=import-outside-toplevel from app.scodoc import sco_assiduites as scass if g.scodoc_dept is None and self.etudiant.dept_id is not None: @@ -356,7 +360,7 @@ class Assiduite(ScoDocModel): date: str = self.entry_date.strftime("%d/%m/%Y à %H:%M") utilisateur: str = "" - if self.user != None: + if self.user is not None: self.user: User utilisateur = f"par {self.user.get_prenomnom()}" @@ -515,6 +519,8 @@ class Justificatif(ScoDocModel): def create_justificatif( cls, etudiant: Identite, + # On a besoin des arguments mais on utilise "locals" pour les récupérer + # pylint: disable=unused-argument date_debut: datetime, date_fin: datetime, etat: EtatJustificatif, @@ -538,8 +544,10 @@ class Justificatif(ScoDocModel): def supprime(self): "Supprime le justificatif. Log et commit." + + # Obligatoire car import circulaire sinon + # pylint: disable-next=import-outside-toplevel from app.scodoc import sco_assiduites as scass - from app.scodoc.sco_archives_justificatifs import JustificatifArchiver # Récupération de l'archive du justificatif archive_name: str = self.fichier diff --git a/app/scodoc/sco_archives_justificatifs.py b/app/scodoc/sco_archives_justificatifs.py index 0b3ff9137..a4c56cca1 100644 --- a/app/scodoc/sco_archives_justificatifs.py +++ b/app/scodoc/sco_archives_justificatifs.py @@ -20,8 +20,11 @@ class Trace: Role des fichiers traces : - Sauvegarder la date de dépôt du fichier - - Sauvegarder la date de suppression du fichier (dans le cas de plusieurs fichiers pour un même justif) - - Sauvegarder l'user_id de l'utilisateur ayant déposé le fichier (=> permet de montrer les fichiers qu'aux personnes qui l'on déposé / qui ont le rôle AssiJustifView) + - Sauvegarder la date de suppression du fichier + (dans le cas de plusieurs fichiers pour un même justif) + - Sauvegarder l'user_id de l'utilisateur ayant déposé le fichier + (=> permet de montrer les fichiers qu'aux personnes + qui l'on déposé / qui ont le rôle AssiJustifView) _trace.csv : nom_fichier_srv,datetime_depot,datetime_suppr,user_id diff --git a/app/scodoc/sco_assiduites.py b/app/scodoc/sco_assiduites.py index 23252ddb5..3729d8673 100644 --- a/app/scodoc/sco_assiduites.py +++ b/app/scodoc/sco_assiduites.py @@ -21,6 +21,7 @@ from app.models.assiduites import Assiduite, Justificatif, compute_assiduites_ju from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_preferences from app.scodoc import sco_cache +from app.scodoc import sco_compute_moy from app.scodoc import sco_etud import app.scodoc.sco_utils as scu @@ -37,21 +38,34 @@ class CountCalculator: ------------ 1. Initialisation : La classe peut être initialisée avec des horaires personnalisés pour le matin, le midi et le soir, ainsi qu'une durée de pause déjeuner. - Si non spécifiés, les valeurs par défaut seront chargées depuis la configuration `ScoDocSiteConfig`. + Si non spécifiés, les valeurs par défaut seront + chargées depuis la configuration `ScoDocSiteConfig`. Exemple d'initialisation : - calculator = CountCalculator(morning="08:00", noon="13:00", evening="18:00", nb_heures_par_jour=8) + calculator = CountCalculator( + morning="08:00", + noon="13:00", + evening="18:00", + nb_heures_par_jour=8 + ) 2. Ajout d'assiduités : Exemple d'ajout d'assiduité : - calculator.compute_assiduites(etudiant.assiduites) - - calculator.compute_assiduites([, , , ]) + - calculator.compute_assiduites([ + , + , + , + + ]) - 3. Accès aux métriques : Après l'ajout des assiduités, on peut accéder aux métriques telles que : + 3. Accès aux métriques : Après l'ajout des assiduités, + on peut accéder aux métriques telles que : le nombre total de jours, de demi-journées et d'heures calculées. Exemple d'accès aux métriques : metrics = calculator.to_dict() - 4.Réinitialisation du comptage: Si besoin on peut réinitialisé le compteur sans perdre la configuration + 4.Réinitialisation du comptage: Si besoin on peut réinitialiser + le compteur sans perdre la configuration (horaires personnalisés) Exemple de réinitialisation : calculator.reset() @@ -61,8 +75,10 @@ class CountCalculator: - reset() : Réinitialise les compteurs de la classe. - add_half_day(day: date, is_morning: bool) : Ajoute une demi-journée au comptage. - add_day(day: date) : Ajoute un jour complet au comptage. - - compute_long_assiduite(assi: Assiduite) : Traite les assiduités s'étendant sur plus d'un jour. - - compute_assiduites(assiduites: Query | list) : Calcule les métriques pour une collection d'assiduités. + - compute_long_assiduite(assi: Assiduite) : Traite les assiduités + s'étendant sur plus d'un jour. + - compute_assiduites(assiduites: Query | list) : Calcule les métriques pour + une collection d'assiduités. - to_dict() : Retourne les métriques sous forme de dictionnaire. Notes : @@ -85,27 +101,20 @@ class CountCalculator: evening: str = None, nb_heures_par_jour: int = None, ) -> None: - # Transformation d'une heure "HH:MM" en time(h,m) - STR_TIME = lambda x: time(*list(map(int, x.split(":")))) - - self.morning: time = STR_TIME( + self.morning: time = str_to_time( morning if morning else ScoDocSiteConfig.get("assi_morning_time", "08:00") ) # Date pivot pour déterminer les demi-journées - self.noon: time = STR_TIME( + self.noon: time = str_to_time( noon if noon else ScoDocSiteConfig.get("assi_lunch_time", "13:00") ) - self.evening: time = STR_TIME( + self.evening: time = str_to_time( 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) - ) - - delta_total: timedelta = datetime.combine( - date.min, self.evening - ) - datetime.combine(date.min, self.morning) + self.non_work_days: list[ + scu.NonWorkDays + ] = scu.NonWorkDays.get_all_non_work_days(dept_id=g.scodoc_dept_id) # Sera utilisé pour les assiduités longues (> 1 journée) self.nb_heures_par_jour = ( @@ -340,17 +349,27 @@ class CountCalculator: def setup_data(self): """Met en forme les données - pour les journées et les demi-journées : au lieu d'avoir list[str] on a le nombre (len(list[str])) + pour les journées et les demi-journées : + au lieu d'avoir list[str] on a le nombre (len(list[str])) """ - for key in self.data: - self.data[key]["journee"] = len(self.data[key]["journee"]) - self.data[key]["demi"] = len(self.data[key]["demi"]) + for value in self.data.values(): + value["journee"] = len(value["journee"]) + value["demi"] = len(value["demi"]) def to_dict(self, only_total: bool = True) -> dict[str, int | float]: """Retourne les métriques sous la forme d'un dictionnaire""" return self.data["total"] if only_total else self.data +def str_to_time(time_str: str) -> time: + """Convertit une chaîne de caractères représentant une heure en objet time + exemples : + - "08:00" -> time(8, 0) + - "18:00:00" -> time(18, 0, 0) + """ + return time(*list(map(int, time_str.split(":")))) + + def get_assiduites_stats( assiduites: Query, metric: str = "all", filtered: dict[str, object] = None ) -> dict[str, int | float]: @@ -756,7 +775,6 @@ def invalidate_assiduites_etud_date(etudid: int, the_date: datetime): pour cet étudiant et cette date. Invalide cache absence et caches semestre """ - from app.scodoc import sco_compute_moy # Semestres a cette date: etud = sco_etud.get_etud_info(etudid=etudid, filled=True) @@ -818,4 +836,4 @@ def simple_invalidate_cache(obj: dict, etudid: str | int = None): pattern=f"tableau-etud-{etudid}*" ) # Invalide les tableaux "bilan dept" - sco_cache.RequeteTableauAssiduiteCache.delete_pattern(pattern=f"tableau-dept*") + sco_cache.RequeteTableauAssiduiteCache.delete_pattern(pattern="tableau-dept*") diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 7e03f38f7..61c8f1ee5 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -130,7 +130,8 @@ def print_progress_bar( decimals - Optional : nombres de chiffres après la virgule (Int) length - Optional : taille de la barre en nombre de caractères (Int) fill - Optional : charactère de remplissange de la barre (Str) - autosize - Optional : Choisir automatiquement la taille de la barre en fonction du terminal (Bool) + autosize - Optional : Choisir automatiquement la taille de la barre + en fonction du terminal (Bool) """ percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) color = TerminalColor.RED @@ -174,11 +175,15 @@ class BiDirectionalEnum(Enum): @classmethod def contains(cls, attr: str): """Vérifie sur un attribut existe dans l'enum""" + + # Existe dans la classe parent de Enum (EnumType) + # pylint: disable-next=no-member return attr.upper() in cls._member_names_ @classmethod def all(cls, keys=True): """Retourne toutes les clés de l'enum""" + # pylint: disable-next=no-member return cls._member_names_ if keys else list(cls._value2member_map_.keys()) @classmethod @@ -207,6 +212,9 @@ class EtatAssiduite(int, BiDirectionalEnum): ABSENT = 2 def version_lisible(self) -> str: + """Retourne une version lisible des états d'assiduités + Est utilisé pour les vues. + """ return { EtatAssiduite.PRESENT: "Présence", EtatAssiduite.ABSENT: "Absence", @@ -225,6 +233,9 @@ class EtatJustificatif(int, BiDirectionalEnum): MODIFIE = 3 def version_lisible(self) -> str: + """Retourne une version lisible des états de justificatifs + Est utilisé pour les vues. + """ return { EtatJustificatif.VALIDE: "valide", EtatJustificatif.ATTENTE: "soumis", @@ -254,11 +265,13 @@ class NonWorkDays(int, BiDirectionalEnum): cls, formsemestre_id: int = None, dept_id: int = None ) -> list["NonWorkDays"]: """ - get_all_non_work_days Récupère la liste des non workdays (str) depuis les préférences + get_all_non_work_days Récupère la liste des non workdays + (str) depuis les préférences puis renvoie une liste BiDirectionnalEnum NonWorkDays Example: - non_work_days : list[NonWorkDays] = NonWorkDays.get_all_non_work_days(dept_id=g.scodoc_dept_id) + non_work_days : list[NonWorkDays] = + NonWorkDays.get_all_non_work_days(dept_id=g.scodoc_dept_id) if datetime.datetime.now().weekday() in non_work_days: print("Aujourd'hui est un jour non travaillé") @@ -269,6 +282,8 @@ class NonWorkDays(int, BiDirectionalEnum): Returns: list[NonWorkDays]: La liste des NonWorkDays en version BiDirectionnalEnum """ + # Import circulaire + # pylint: disable=import-outside-toplevel from app.scodoc import sco_preferences return [ diff --git a/app/tables/liste_assiduites.py b/app/tables/liste_assiduites.py index 2d1de9e65..2441f1016 100644 --- a/app/tables/liste_assiduites.py +++ b/app/tables/liste_assiduites.py @@ -1,9 +1,14 @@ +""" +Gestion des listes d'assiduités et justificatifs +(affichage, pagination, filtrage, options d'affichage, tableaux) +""" + from datetime import datetime from flask import url_for from flask_login import current_user from flask_sqlalchemy.query import Query -from sqlalchemy import desc, literal, literal_column, union, asc +from sqlalchemy import desc, literal, union, asc from app import db, g from app.auth.models import User @@ -34,9 +39,11 @@ class Pagination: On peut ensuite récupérer les éléments de la page courante avec la méthode `items()` Cette classe ne permet pas de changer de page. - (Pour cela, il faut créer une nouvelle instance, avec la collection originelle et la nouvelle page) + (Pour cela, il faut créer une nouvelle instance, + avec la collection originelle et la nouvelle page) - l'intéret est de ne pas garder en mémoire toute la collection, mais seulement la page courante + l'intéret est de ne pas garder en mémoire toute la collection, + mais seulement la page courante """ @@ -45,9 +52,11 @@ class Pagination: __init__ Instancie un nouvel objet Pagination Args: - collection (list): La collection à paginer. Il s'agit par exemple d'une requête + collection (list): La collection à paginer. + Il s'agit par exemple d'une requête page (int, optional): le numéro de la page à voir. Defaults to 1. - per_page (int, optional): le nombre d'éléments par page. Defaults to -1. (-1 = pas de pagination/tout afficher) + per_page (int, optional): le nombre d'éléments par page. + Defaults to -1. (-1 = pas de pagination/tout afficher) """ # par défaut le total des pages est 1 (même si la collection est vide) self.total_pages = 1 @@ -231,15 +240,17 @@ class ListeAssiJusti(tb.Table): attributs `page` et `NB_PAR_PAGE` de la classe `ListeAssiJusti`. Args: - collection (list): La collection à paginer. Il s'agit par exemple d'une requête qui a déjà + collection (list): La collection à paginer. + Il s'agit par exemple d'une requête qui a déjà été construite et qui est prête à être exécutée. Returns: - Pagination: Un objet Pagination qui encapsule les résultats de la requête paginée. + Pagination: Un objet Pagination qui encapsule les résultats de + la requête paginée. Note: - Cette méthode ne modifie pas la collection originelle; elle renvoie plutôt un nouvel - objet qui contient les résultats paginés. + Cette méthode ne modifie pas la collection originelle; + elle renvoie plutôt un nouvel objet qui contient les résultats paginés. """ return Pagination( collection, @@ -251,29 +262,35 @@ class ListeAssiJusti(tb.Table): """ Combine les requêtes d'assiduités et de justificatifs en une seule requête. - Cette fonction prend en entrée deux requêtes optionnelles, une pour les assiduités - et une pour les justificatifs, et renvoie une requête combinée qui sélectionne - un ensemble spécifique de colonnes pour chaque type d'objet. + Cette fonction prend en entrée deux requêtes optionnelles, + une pour les assiduités et une pour les justificatifs, + et renvoie une requête combinée qui sélectionne un ensemble + spécifique de colonnes pour chaque type d'objet. Les colonnes sélectionnées sont: - - obj_id: l'identifiant de l'objet (assiduite_id pour les assiduités, justif_id pour les justificatifs) + - obj_id: l'identifiant de l'objet + (assiduite_id pour les assiduités, justif_id pour les justificatifs) - etudid: l'identifiant de l'étudiant - entry_date: la date de saisie de l'objet - date_debut: la date de début de l'objet - date_fin: la date de fin de l'objet - etat: l'état de l'objet - - type: le type de l'objet ("assiduite" pour les assiduités, "justificatif" pour les justificatifs) + - type: le type de l'objet + ("assiduite" pour les assiduités, "justificatif" pour les justificatifs) - est_just : si l'assiduité est justifié (booléen) None pour les justificatifs - - user_id : l'identifiant de l'utilisateur qui a signalé l'assiduité ou le justificatif + - user_id : l'identifiant de l'utilisateur qui a + signalé l'assiduité ou le justificatif Args: query_assiduite (sqlalchemy.orm.Query, optional): Une requête SQLAlchemy pour les assiduités. - Si None (default), aucune assiduité ne sera incluse dans la requête combinée. + Si None (default), aucune assiduité ne sera incluse + dans la requête combinée. query_justificatif (sqlalchemy.orm.Query, optional): Une requête SQLAlchemy pour les justificatifs. - Si None (default), aucun justificatif ne sera inclus dans la requête combinée. + Si None (default), aucun justificatif ne sera + inclus dans la requête combinée. Returns: sqlalchemy.orm.Query: Une requête combinée qui peut être exécutée pour @@ -618,10 +635,15 @@ class AssiFiltre: Args: type_obj (int, optional): type d'objet (0:Tout, 1: Assi, 2:Justi). Defaults to 0. - entry_date (tuple[int, datetime], optional): (0: egal, 1: avant, 2: après) + datetime(avec TZ). Defaults to None. - date_debut (tuple[int, datetime], optional): (0: egal, 1: avant, 2: après) + datetime(avec TZ). Defaults to None. - date_fin (tuple[int, datetime], optional): (0: egal, 1: avant, 2: après) + datetime(avec TZ). Defaults to None. - etats (list[int | EtatJustificatif | EtatAssiduite], optional): liste d'états valides (int | EtatJustificatif | EtatAssiduite). Defaults to None. + entry_date (tuple[int, datetime], optional): + (0: egal, 1: avant, 2: après) + datetime(avec TZ). Defaults to None. + date_debut (tuple[int, datetime], optional): + (0: egal, 1: avant, 2: après) + datetime(avec TZ). Defaults to None. + date_fin (tuple[int, datetime], optional): + (0: egal, 1: avant, 2: après) + datetime(avec TZ). Defaults to None. + etats (list[int | EtatJustificatif | EtatAssiduite], optional): + liste d'états valides (int | EtatJustificatif | EtatAssiduite). + Defaults to None. """ self.filtres = {"type_obj": type_obj} @@ -753,6 +775,10 @@ class AssiJustifData: @staticmethod def from_etudiants(*etudiants: Identite) -> "AssiJustifData": + """ + Génère un object AssiJustifData à partir d'une liste d'étudiants + (Récupère les assiduités et justificatifs des étudiants) + """ data = AssiJustifData() data.assiduites_query = Assiduite.query.filter( Assiduite.etudid.in_([e.etudid for e in etudiants]) @@ -764,4 +790,5 @@ class AssiJustifData: return data def get(self) -> tuple[Query, Query]: + "Renvoi les requêtes d'assiduités et justificatifs" return self.assiduites_query, self.justificatifs_query diff --git a/app/tables/visu_assiduites.py b/app/tables/visu_assiduites.py index f40612806..8c99f493a 100644 --- a/app/tables/visu_assiduites.py +++ b/app/tables/visu_assiduites.py @@ -37,7 +37,7 @@ class TableAssi(tb.Table): convert_values=False, **kwargs, ): - self.rows: list["RowEtud"] = [] # juste pour que VSCode nous aide sur .rows + self.rows: list["RowAssi"] = [] # juste pour que VSCode nous aide sur .rows classes = ["gt_table"] self.dates = [str(dates[0]) + "T00:00", str(dates[1]) + "T23:59"] self.formsemestre = formsemestre diff --git a/app/views/assiduites.py b/app/views/assiduites.py index 5aecdb3be..2f7438f99 100644 --- a/app/views/assiduites.py +++ b/app/views/assiduites.py @@ -27,7 +27,6 @@ import datetime import json import re -from typing import Any from flask import g, request, render_template, flash from flask import abort, url_for, redirect, Response @@ -122,7 +121,6 @@ def bilan_dept(): if formsemestre_id: try: formsemestre: FormSemestre = FormSemestre.get_formsemestre(formsemestre_id) - annee = formsemestre.annee_scolaire() except AttributeError: formsemestre_id = "" @@ -533,7 +531,7 @@ def bilan_etud(): # Récupération des assiduités et justificatifs de l'étudiant data = liste_assi.AssiJustifData( etud.assiduites.filter( - Assiduite.etat != scu.EtatAssiduite.PRESENT, Assiduite.est_just == False + Assiduite.etat != scu.EtatAssiduite.PRESENT, Assiduite.est_just is False ), etud.justificatifs.filter( Justificatif.etat.in_( @@ -860,6 +858,15 @@ def calendrier_assi_etud(): @scodoc @permission_required(Permission.AbsChange) def choix_date() -> str: + """ + choix_date Choix de la date pour la saisie des assiduités + + Route utilisée uniquement si la date courante n'est pas dans le semestre + concerné par la requête vers une des pages suivantes : + - saisie_assiduites_group + - visu_assiduites_group + + """ formsemestre_id = request.args.get("formsemestre_id") formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id) @@ -976,9 +983,6 @@ def signal_assiduites_group(): if formsemestre.dept_id != g.scodoc_dept_id: abort(404, "groupes inexistants dans ce département") - # Vérification du forçage du module - require_module = sco_preferences.get_preference("forcer_module", formsemestre_id) - # Récupération des étudiants des groupes etuds = [ sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0] @@ -1110,9 +1114,6 @@ def visu_assiduites_group(): if formsemestre.dept_id != g.scodoc_dept_id: abort(404, "groupes inexistants dans ce département") - # Vérfication du forçage du module - require_module = sco_preferences.get_preference("forcer_module", formsemestre_id) - # Récupération des étudiants du/des groupe(s) etuds = [ sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0] @@ -1784,22 +1785,6 @@ def signal_assiduites_diff(): ) etudiants = list(sorted(etudiants, key=lambda etud: etud.sort_key)) - # Génération de l'HTML - - header: str = html_sco_header.sco_header( - page_title="Assiduité: saisie différée", - init_qtip=True, - cssstyles=[ - "css/assiduites.css", - ], - javascripts=html_sco_header.BOOTSTRAP_MULTISELECT_JS - + [ - "js/assiduites.js", - "js/date_utils.js", - "js/etud_info.js", - ], - ) - if groups_infos.tous_les_etuds_du_sem: gr_tit = "en" else: @@ -2078,8 +2063,8 @@ def _differee( etudiants (list[dict]): la liste des étudiants (représentés par des dictionnaires) moduleimpl_select (str): l'html représentant le selecteur de module date (str, optional): la première date à afficher. Defaults to None. - periode (dict[str, str], optional):La période par défaut de la première colonne. Defaults to None. - formsemestre_id (int, optional): l'id du semestre pour le selecteur de module. Defaults to None. + periode (dict[str, str], optional):La période par défaut de la première colonne. + formsemestre_id (int, optional): l'id du semestre pour le selecteur de module. Returns: str: le widget (html/css/js) @@ -2265,6 +2250,9 @@ def generate_calendar( etudiant: Identite, annee: int = None, ) -> dict[str, list["Jour"]]: + """ + Génère le calendrier d'assiduité de l'étudiant pour une année scolaire donnée + """ # Si pas d'année alors on prend l'année scolaire en cours if annee is None: annee = scu.annee_scolaire() @@ -2312,13 +2300,26 @@ class Jour: self.justificatifs = justificatifs def get_nom(self, mode_demi: bool = True) -> str: + """ + Renvoie le nom du jour + "M19" ou "Mer 19" + """ str_jour: str = scu.DAY_NAMES[self.date.weekday()].capitalize() - return f"{str_jour[0] if mode_demi or self.is_non_work() else str_jour[:3]+' '}{self.date.day}" + return ( + f"{str_jour[0] if mode_demi or self.is_non_work() else str_jour[:3]+' '}" + + f"{self.date.day}" + ) def get_date(self) -> str: + """ + Renvoie la date du jour au format "dd/mm/yyyy" + """ return self.date.strftime("%d/%m/%Y") def get_class(self, show_pres: bool = False, show_reta: bool = False) -> str: + """ + Retourne la classe css du jour (mode normal) + """ etat = "" est_just = "" @@ -2340,13 +2341,16 @@ class Jour: def get_demi_class( self, matin: bool, show_pres: bool = False, show_reta: bool = False ) -> str: - # Transformation d'une heure "HH:MM" en time(h,m) - str2time = lambda x: datetime.time(*list(map(int, x.split(":")))) + """ + Renvoie la class css de la demi journée + """ - heure_midi = str2time(ScoDocSiteConfig.get("assi_lunch_time", "13:00")) + heure_midi = scass.str_to_time(ScoDocSiteConfig.get("assi_lunch_time", "13:00")) if matin: - heure_matin = str2time(ScoDocSiteConfig.get("assi_morning_time", "08:00")) + heure_matin = scass.str_to_time( + ScoDocSiteConfig.get("assi_morning_time", "08:00") + ) matin = ( # date debut scu.localize_datetime( @@ -2382,7 +2386,9 @@ class Jour: return f"color {etat} {est_just}" - heure_soir = str2time(ScoDocSiteConfig.get("assi_afternoon_time", "17:00")) + heure_soir = scass.str_to_time( + ScoDocSiteConfig.get("assi_afternoon_time", "17:00") + ) # séparation en demi journées aprem = ( @@ -2421,21 +2427,24 @@ class Jour: return f"color {etat} {est_just}" def has_assiduites(self) -> bool: + """ + Renverra True si le jour a des assiduités + """ return self.assiduites.count() > 0 def generate_minitimeline(self) -> str: + """ + Génère la minitimeline du jour + """ # Récupérer le référenciel de la timeline - str2time = lambda x: _time_to_timedelta( + scass.str_to_time = lambda x: _time_to_timedelta( datetime.time(*list(map(int, x.split(":")))) ) - heure_matin: datetime.timedelta = str2time( + heure_matin: datetime.timedelta = scass.str_to_time( ScoDocSiteConfig.get("assi_morning_time", "08:00") ) - heure_midi: datetime.timedelta = str2time( - ScoDocSiteConfig.get("assi_lun_time", "13:00") - ) - heure_soir: datetime.timedelta = str2time( + heure_soir: datetime.timedelta = scass.str_to_time( ScoDocSiteConfig.get("assi_afternoon_time", "17:00") ) # longueur_timeline = heure_soir - heure_matin @@ -2484,17 +2493,21 @@ class Jour: ) def is_non_work(self): + """ + Renvoie True si le jour est un jour non travaillé + (en fonction de la préférence du département) + """ return self.date.weekday() in scu.NonWorkDays.get_all_non_work_days( dept_id=g.scodoc_dept_id ) def _get_etats_from_assiduites(self, assiduites: Query) -> list[scu.EtatAssiduite]: - return list(set([scu.EtatAssiduite(assi.etat) for assi in assiduites])) + return list(set(scu.EtatAssiduite(assi.etat) for assi in assiduites)) def _get_etats_from_justificatifs( self, justificatifs: Query ) -> list[scu.EtatJustificatif]: - return list(set([scu.EtatJustificatif(justi.etat) for justi in justificatifs])) + return list(set(scu.EtatJustificatif(justi.etat) for justi in justificatifs)) def _get_color_assiduites_cascade( self,