""" Génération d'un calendrier (Classe abstraite à implémenter dans les classes filles) """ import datetime from flask import render_template import app.scodoc.sco_utils as scu from app import g class Jour: """ Représente un jour dans le calendrier Permet d'obtenir les informations sur le jour et générer une représentation html """ def __init__(self, date: datetime.date): self.date = date self.class_list: list[str] = [] if self.is_non_work(): self.class_list.append("non-travail") if self.is_current_week(): self.class_list.append("sem-courante") def get_nom(self, short=True): """ Renvoie le nom du jour "M19" ou "Mer 19" par défaut en version courte """ str_jour: str = scu.DAY_NAMES[self.date.weekday()].capitalize() return ( f"{str_jour[0] if short or self.is_non_work() else str_jour[:3]+' '}" + f"{self.date.day}" ) 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 is_current_week(self): """ Renvoie True si le jour est dans la semaine courante """ return self.date.isocalendar()[0:2] == datetime.date.today().isocalendar()[0:2] def get_date(self, fmt=scu.DATE_FMT) -> str: """ Renvoie la date du jour au format fmt ou "dd/mm/yyyy" par défaut """ return self.date.strftime(fmt) def get_html(self): """ Renvoie le code html du jour à surcharger dans les classes filles l'html final ressemblera à :
{{jour.get_nom()}}
{{jour.get_html() | safe}}
""" raise NotImplementedError("Méthode à implémenter dans les classes filles") def get_class(self): """ Renvoie la classe css du jour utilise self.class_list -> fait un join de la liste """ return " ".join(self.class_list) class Calendrier: """ Représente un calendrier Permet d'obtenir les informations sur les jours et générer une représentation html highlight: str -> ["jour", "semaine", "mois"] permet de mettre en valeur lors du passage de la souris """ def __init__( self, date_debut: datetime.date, date_fin: datetime.date, highlight: str = None, ): self.date_debut = date_debut self.date_fin = date_fin self.jours: dict[str, list[Jour]] = {} self.highlight: str = highlight def _get_dates_between(self) -> list[datetime.date]: """ get_dates_between Renvoie la liste des dates entre date_debut et date_fin Returns: list[datetime.date]: liste des dates entre date_debut et date_fin """ resultat = [] date_actuelle: datetime.date = self.date_debut while date_actuelle <= self.date_fin: if isinstance(date_actuelle, datetime.datetime): resultat.append(date_actuelle.date()) elif isinstance(date_actuelle, datetime.date): resultat.append(date_actuelle) date_actuelle += datetime.timedelta(days=1) return resultat def organize_by_month(self): """ Organise les jours par mois Instancie un objet Jour pour chaque jour met à jour self.jours """ organized = {} for date in self._get_dates_between(): # Récupérer le mois en français month = scu.MONTH_NAMES_ABBREV[date.month - 1] # Ajouter le jour à la liste correspondante au mois if month not in organized: organized[month] = {} # semaine {22: []} jour: Jour = self.instanciate_jour(date) semaine = date.strftime("%G-W%V") if semaine not in organized[month]: organized[month][semaine] = [] organized[month][semaine].append(jour) self.jours = organized def instanciate_jour(self, date: datetime.date) -> Jour: """ Instancie un objet Jour pour chaque jour A surcharger dans les classes filles si besoin """ raise NotImplementedError("Méthode à implémenter dans les classes filles") def get_html(self): """ get_html Renvoie le code html du calendrier """ self.organize_by_month() return render_template( "calendrier.j2", calendrier=self.jours, highlight=self.highlight ) class JourChoix(Jour): """ Représente un jour dans le calendrier pour choisir une date """ def get_html(self): return "" class CalendrierChoix(Calendrier): """ Représente un calendrier pour choisir une date """ def instanciate_jour(self, date: datetime.date) -> Jour: return JourChoix(date) def calendrier_choix_date( date_debut: datetime.date, date_fin: datetime.date, url: str, mode: str = "jour", titre: str = "Choisir une date", ): """ Permet d'afficher un calendrier pour choisir une date et renvoyer sur une url. mode : str - "jour" -> ajoutera "&day=yyyy-mm-dd" à l'url (ex: 2024-05-30) - "semaine" -> ajoutera "&week=yyyy-Www" à l'url (ex : 2024-W22) titre : str - texte à afficher au dessus du calendrier """ calendrier: CalendrierChoix = CalendrierChoix(date_debut, date_fin, highlight=mode) return render_template( "choix_date.j2", calendrier=calendrier.get_html(), url=url, titre=titre, mode=mode, )