2023-10-26 13:12:22 +02:00
|
|
|
|
from datetime import datetime
|
2023-12-01 13:46:33 +01:00
|
|
|
|
|
2023-10-26 13:12:22 +02:00
|
|
|
|
from flask import url_for
|
2023-12-01 13:46:33 +01:00
|
|
|
|
from flask_sqlalchemy.query import Pagination, Query
|
|
|
|
|
from sqlalchemy import desc, literal, union
|
|
|
|
|
|
|
|
|
|
from app import db, g
|
|
|
|
|
from app.auth.models import User
|
|
|
|
|
from app.models import Assiduite, Identite, Justificatif
|
|
|
|
|
from app.scodoc.sco_utils import EtatAssiduite, EtatJustificatif, to_bool
|
|
|
|
|
from app.tables import table_builder as tb
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ListeAssiJusti(tb.Table):
|
|
|
|
|
"""
|
|
|
|
|
Table listant les Assiduites et Justificatifs d'une collection d'étudiants
|
|
|
|
|
L'affichage par défaut se fait par ordre de date de fin décroissante.
|
|
|
|
|
"""
|
|
|
|
|
|
2023-11-24 13:58:03 +01:00
|
|
|
|
NB_PAR_PAGE: int = 25
|
2023-11-24 18:07:30 +01:00
|
|
|
|
MAX_PAR_PAGE: int = 200
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
2023-12-01 13:46:33 +01:00
|
|
|
|
table_data: "AssiJustifData",
|
|
|
|
|
filtre: "AssiFiltre" = None,
|
|
|
|
|
options: "AssiDisplayOptions" = None,
|
2023-10-26 13:12:22 +02:00
|
|
|
|
**kwargs,
|
|
|
|
|
) -> None:
|
|
|
|
|
"""
|
|
|
|
|
__init__ Instancie un nouveau table de liste d'assiduités/justificaitifs
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
filtre (Filtre, optional): Filtrage des objets à afficher. Defaults to None.
|
|
|
|
|
page (int, optional): numéro de page de la pagination. Defaults to 1.
|
|
|
|
|
"""
|
2023-12-01 13:46:33 +01:00
|
|
|
|
self.table_data: "AssiJustifData" = table_data
|
2023-10-26 13:12:22 +02:00
|
|
|
|
# Gestion du filtre, par défaut un filtre vide
|
2023-12-01 13:46:33 +01:00
|
|
|
|
self.filtre = filtre if filtre is not None else AssiFiltre()
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
# Gestion des options, par défaut un objet Options vide
|
2023-12-01 13:46:33 +01:00
|
|
|
|
self.options = options if options is not None else AssiDisplayOptions()
|
2023-11-22 16:49:13 +01:00
|
|
|
|
|
|
|
|
|
self.total_page: int = None
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
# les lignes du tableau
|
|
|
|
|
self.rows: list["RowAssiJusti"] = []
|
|
|
|
|
|
|
|
|
|
# Instanciation de la classe parent
|
|
|
|
|
super().__init__(
|
|
|
|
|
row_class=RowAssiJusti,
|
2023-12-05 21:04:38 +01:00
|
|
|
|
classes=["liste_assi", "gt_table", "gt_left"],
|
2023-10-26 13:12:22 +02:00
|
|
|
|
**kwargs,
|
|
|
|
|
with_foot_titles=False,
|
|
|
|
|
)
|
|
|
|
|
|
2023-12-07 22:10:51 +01:00
|
|
|
|
self.add_assiduites()
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
2023-12-07 22:10:51 +01:00
|
|
|
|
def add_assiduites(self):
|
|
|
|
|
"Ajoute le contenu de la table, avec assiduités et justificatif réunis"
|
2023-10-26 13:12:22 +02:00
|
|
|
|
# Générer les query assiduités et justificatifs
|
|
|
|
|
assiduites_query_etudiants: Query = None
|
|
|
|
|
justificatifs_query_etudiants: Query = None
|
|
|
|
|
|
|
|
|
|
# Récupération du filtrage des objets -> 0 : tout, 1 : Assi, 2: Justi
|
|
|
|
|
type_obj = self.filtre.type_obj()
|
|
|
|
|
|
|
|
|
|
if type_obj in [0, 1]:
|
2023-11-24 13:58:03 +01:00
|
|
|
|
assiduites_query_etudiants = self.table_data.assiduites_query
|
|
|
|
|
|
|
|
|
|
# Non affichage des présences
|
|
|
|
|
if not self.options.show_pres:
|
|
|
|
|
assiduites_query_etudiants = assiduites_query_etudiants.filter(
|
|
|
|
|
Assiduite.etat != EtatAssiduite.PRESENT
|
|
|
|
|
)
|
|
|
|
|
# Non affichage des retards
|
|
|
|
|
if not self.options.show_reta:
|
|
|
|
|
assiduites_query_etudiants = assiduites_query_etudiants.filter(
|
|
|
|
|
Assiduite.etat != EtatAssiduite.RETARD
|
|
|
|
|
)
|
|
|
|
|
|
2023-10-26 13:12:22 +02:00
|
|
|
|
if type_obj in [0, 2]:
|
2023-11-24 13:58:03 +01:00
|
|
|
|
justificatifs_query_etudiants = self.table_data.justificatifs_query
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
# Combinaison des requêtes
|
|
|
|
|
|
|
|
|
|
query_finale: Query = self.joindre(
|
|
|
|
|
query_assiduite=assiduites_query_etudiants,
|
|
|
|
|
query_justificatif=justificatifs_query_etudiants,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Paginer la requête pour ne pas envoyer trop d'informations au client
|
|
|
|
|
pagination: Pagination = self.paginer(query_finale)
|
2023-11-22 16:49:13 +01:00
|
|
|
|
self.total_pages: int = pagination.pages
|
2023-10-26 13:12:22 +02:00
|
|
|
|
# Générer les lignes de la page
|
|
|
|
|
for ligne in pagination.items:
|
|
|
|
|
row: RowAssiJusti = self.row_class(self, ligne._asdict())
|
|
|
|
|
row.ajouter_colonnes()
|
|
|
|
|
self.add_row(row)
|
|
|
|
|
|
|
|
|
|
def paginer(self, query: Query) -> Pagination:
|
|
|
|
|
"""
|
|
|
|
|
Applique la pagination à une requête SQLAlchemy en fonction des paramètres de la classe.
|
|
|
|
|
|
2023-12-05 21:04:38 +01:00
|
|
|
|
Cette méthode prend une requête SQLAlchemy et applique la pagination en utilisant les
|
|
|
|
|
attributs `page` et `NB_PAR_PAGE` de la classe `ListeAssiJusti`.
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
Args:
|
2023-12-05 21:04:38 +01:00
|
|
|
|
query (Query): La requête SQLAlchemy à paginer. Il s'agit d'une requête qui a déjà
|
|
|
|
|
été construite et qui est prête à être exécutée.
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Pagination: Un objet Pagination qui encapsule les résultats de la requête paginée.
|
|
|
|
|
|
|
|
|
|
Note:
|
2023-12-05 21:04:38 +01:00
|
|
|
|
Cette méthode ne modifie pas la requête originale; elle renvoie plutôt un nouvel
|
|
|
|
|
objet qui contient les résultats paginés.
|
2023-10-26 13:12:22 +02:00
|
|
|
|
"""
|
|
|
|
|
return query.paginate(
|
2023-11-24 13:58:03 +01:00
|
|
|
|
page=self.options.page, per_page=self.options.nb_ligne_page, error_out=False
|
2023-10-26 13:12:22 +02:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def joindre(self, query_assiduite: Query = None, query_justificatif: Query = None):
|
|
|
|
|
"""
|
|
|
|
|
Combine les requêtes d'assiduités et de justificatifs en une seule requête.
|
|
|
|
|
|
2023-12-05 21:04:38 +01:00
|
|
|
|
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.
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
Les colonnes sélectionnées sont:
|
|
|
|
|
- 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)
|
2023-11-03 14:57:22 +01:00
|
|
|
|
- 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
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
Args:
|
2023-12-05 21:04:38 +01:00
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
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.
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
Returns:
|
2023-12-05 21:04:38 +01:00
|
|
|
|
sqlalchemy.orm.Query: Une requête combinée qui peut être exécutée pour
|
|
|
|
|
obtenir les résultats.
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
Raises:
|
|
|
|
|
ValueError: Si aucune requête n'est fournie (les deux paramètres sont None).
|
|
|
|
|
"""
|
|
|
|
|
queries = []
|
|
|
|
|
|
|
|
|
|
# Définir les colonnes pour la requête d'assiduité
|
|
|
|
|
if query_assiduite:
|
2023-11-24 13:58:03 +01:00
|
|
|
|
assiduites_entities: list = [
|
2023-10-26 13:12:22 +02:00
|
|
|
|
Assiduite.assiduite_id.label("obj_id"),
|
|
|
|
|
Assiduite.etudid.label("etudid"),
|
|
|
|
|
Assiduite.entry_date.label("entry_date"),
|
|
|
|
|
Assiduite.date_debut.label("date_debut"),
|
|
|
|
|
Assiduite.date_fin.label("date_fin"),
|
|
|
|
|
Assiduite.etat.label("etat"),
|
|
|
|
|
literal("assiduite").label("type"),
|
2023-11-03 14:57:22 +01:00
|
|
|
|
Assiduite.est_just.label("est_just"),
|
|
|
|
|
Assiduite.user_id.label("user_id"),
|
2023-11-24 13:58:03 +01:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
if self.options.show_desc:
|
|
|
|
|
assiduites_entities.append(Assiduite.description.label("description"))
|
|
|
|
|
|
|
|
|
|
query_assiduite = query_assiduite.with_entities(*assiduites_entities)
|
2023-10-26 13:12:22 +02:00
|
|
|
|
queries.append(query_assiduite)
|
|
|
|
|
|
|
|
|
|
# Définir les colonnes pour la requête de justificatif
|
|
|
|
|
if query_justificatif:
|
2023-11-24 13:58:03 +01:00
|
|
|
|
justificatifs_entities: list = [
|
2023-10-26 13:12:22 +02:00
|
|
|
|
Justificatif.justif_id.label("obj_id"),
|
|
|
|
|
Justificatif.etudid.label("etudid"),
|
|
|
|
|
Justificatif.entry_date.label("entry_date"),
|
|
|
|
|
Justificatif.date_debut.label("date_debut"),
|
|
|
|
|
Justificatif.date_fin.label("date_fin"),
|
|
|
|
|
Justificatif.etat.label("etat"),
|
|
|
|
|
literal("justificatif").label("type"),
|
2023-11-03 14:57:22 +01:00
|
|
|
|
# On doit avoir les mêmes colonnes sur les deux requêtes,
|
|
|
|
|
# donc on la met en nul car un justifcatif ne peut être justifié
|
|
|
|
|
literal(None).label("est_just"),
|
|
|
|
|
Justificatif.user_id.label("user_id"),
|
2023-11-24 13:58:03 +01:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
if self.options.show_desc:
|
|
|
|
|
justificatifs_entities.append(Justificatif.raison.label("description"))
|
|
|
|
|
|
|
|
|
|
query_justificatif = query_justificatif.with_entities(
|
|
|
|
|
*justificatifs_entities
|
2023-10-26 13:12:22 +02:00
|
|
|
|
)
|
|
|
|
|
queries.append(query_justificatif)
|
|
|
|
|
|
|
|
|
|
# S'assurer qu'au moins une requête est fournie
|
|
|
|
|
if not queries:
|
|
|
|
|
raise ValueError(
|
|
|
|
|
"Au moins une query (assiduité ou justificatif) doit être fournie"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Combiner les requêtes avec une union
|
|
|
|
|
query_combinee = union(*queries).alias("combinee")
|
|
|
|
|
|
|
|
|
|
query_combinee = db.session.query(query_combinee).order_by(desc("date_debut"))
|
|
|
|
|
|
|
|
|
|
return query_combinee
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RowAssiJusti(tb.Row):
|
2023-12-07 22:10:51 +01:00
|
|
|
|
"Ligne de table pour une assiduité"
|
|
|
|
|
|
2023-10-26 13:12:22 +02:00
|
|
|
|
def __init__(self, table: ListeAssiJusti, ligne: dict):
|
|
|
|
|
self.ligne: dict = ligne
|
|
|
|
|
self.etud: Identite = Identite.get_etud(ligne["etudid"])
|
|
|
|
|
|
|
|
|
|
super().__init__(
|
|
|
|
|
table=table,
|
|
|
|
|
row_id=f'{ligne["etudid"]}_{ligne["type"]}_{ligne["obj_id"]}',
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def ajouter_colonnes(self, lien_redirection: str = None):
|
2023-12-14 21:55:46 +01:00
|
|
|
|
"Ajoute colonnes actions, étudiant, type, dates..."
|
2023-12-05 21:04:38 +01:00
|
|
|
|
# Ajout colonne actions
|
|
|
|
|
if self.table.options.show_actions:
|
|
|
|
|
self._actions()
|
|
|
|
|
|
2023-11-03 14:57:22 +01:00
|
|
|
|
# Ajout de l'étudiant
|
|
|
|
|
self.table: ListeAssiJusti
|
2023-11-24 13:58:03 +01:00
|
|
|
|
if self.table.options.show_etu:
|
2023-11-24 18:07:30 +01:00
|
|
|
|
self._etud(lien_redirection)
|
2023-11-03 14:57:22 +01:00
|
|
|
|
|
|
|
|
|
# Type d'objet
|
|
|
|
|
self._type()
|
|
|
|
|
|
|
|
|
|
# Date de début
|
2023-12-14 21:55:46 +01:00
|
|
|
|
multi_days = self.ligne["date_debut"].date() != self.ligne["date_fin"].date()
|
|
|
|
|
# En excel, on export les "vraes dates".
|
|
|
|
|
# En HTML, on écrit en français (on laisse les dates pour le tri)
|
2023-11-03 14:57:22 +01:00
|
|
|
|
self.add_cell(
|
|
|
|
|
"date_debut",
|
|
|
|
|
"Date de début",
|
2023-12-14 21:55:46 +01:00
|
|
|
|
self.ligne["date_debut"].strftime("%d/%m/%y")
|
|
|
|
|
if multi_days
|
|
|
|
|
else self.ligne["date_debut"].strftime("%d/%m/%y de %H:%M"),
|
2023-11-03 14:57:22 +01:00
|
|
|
|
data={"order": self.ligne["date_debut"]},
|
2023-11-24 13:58:03 +01:00
|
|
|
|
raw_content=self.ligne["date_debut"],
|
2023-12-12 03:05:31 +01:00
|
|
|
|
column_classes={"date", "date-debut"},
|
2023-11-03 14:57:22 +01:00
|
|
|
|
)
|
|
|
|
|
# Date de fin
|
|
|
|
|
self.add_cell(
|
|
|
|
|
"date_fin",
|
|
|
|
|
"Date de fin",
|
2023-12-14 21:55:46 +01:00
|
|
|
|
self.ligne["date_fin"].strftime("%d/%m/%y")
|
|
|
|
|
if multi_days
|
|
|
|
|
else self.ligne["date_fin"].strftime("à %H:%M"),
|
|
|
|
|
raw_content=self.ligne["date_fin"], # Pour excel
|
2023-11-03 14:57:22 +01:00
|
|
|
|
data={"order": self.ligne["date_fin"]},
|
2023-12-12 03:05:31 +01:00
|
|
|
|
column_classes={"date", "date-fin"},
|
2023-11-03 14:57:22 +01:00
|
|
|
|
)
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
# Ajout des colonnes optionnelles
|
|
|
|
|
self._optionnelles()
|
|
|
|
|
|
2023-12-07 22:10:51 +01:00
|
|
|
|
# Ajout de l'utilisateur ayant saisi l'objet
|
2023-11-24 13:58:03 +01:00
|
|
|
|
self._utilisateur()
|
|
|
|
|
|
2023-11-03 14:57:22 +01:00
|
|
|
|
# Date de saisie
|
|
|
|
|
self.add_cell(
|
|
|
|
|
"entry_date",
|
|
|
|
|
"Saisie le",
|
|
|
|
|
self.ligne["entry_date"].strftime("%d/%m/%y à %H:%M"),
|
|
|
|
|
data={"order": self.ligne["entry_date"]},
|
2023-11-24 13:58:03 +01:00
|
|
|
|
raw_content=self.ligne["entry_date"],
|
|
|
|
|
classes=["small-font"],
|
2023-12-05 21:04:38 +01:00
|
|
|
|
column_classes={"entry_date"},
|
2023-11-03 14:57:22 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def _type(self) -> None:
|
|
|
|
|
obj_type: str = ""
|
|
|
|
|
is_assiduite: bool = self.ligne["type"] == "assiduite"
|
|
|
|
|
if is_assiduite:
|
2023-12-12 03:05:31 +01:00
|
|
|
|
justifiee: str = "Justifiée" if self.ligne["est_just"] else ""
|
2023-12-07 22:10:51 +01:00
|
|
|
|
self.classes.append("row-assiduite")
|
|
|
|
|
self.classes.append(EtatAssiduite(self.ligne["etat"]).name.lower())
|
2023-12-12 03:05:31 +01:00
|
|
|
|
if self.ligne["est_just"]:
|
|
|
|
|
self.classes.append("justifiee")
|
2023-11-03 14:57:22 +01:00
|
|
|
|
etat: str = {
|
|
|
|
|
EtatAssiduite.PRESENT: "Présence",
|
|
|
|
|
EtatAssiduite.ABSENT: "Absence",
|
|
|
|
|
EtatAssiduite.RETARD: "Retard",
|
|
|
|
|
}.get(self.ligne["etat"])
|
|
|
|
|
obj_type = f"{etat} {justifiee}"
|
|
|
|
|
else:
|
2023-12-07 22:10:51 +01:00
|
|
|
|
self.classes.append("row-justificatif")
|
|
|
|
|
self.classes.append(EtatJustificatif(self.ligne["etat"]).name.lower())
|
2023-11-03 14:57:22 +01:00
|
|
|
|
etat: str = {
|
|
|
|
|
EtatJustificatif.VALIDE: "valide",
|
|
|
|
|
EtatJustificatif.ATTENTE: "soumis",
|
|
|
|
|
EtatJustificatif.MODIFIE: "modifié",
|
|
|
|
|
EtatJustificatif.NON_VALIDE: "invalide",
|
|
|
|
|
}.get(self.ligne["etat"])
|
|
|
|
|
obj_type = f"Justificatif {etat}"
|
|
|
|
|
|
2023-12-07 22:10:51 +01:00
|
|
|
|
self.add_cell("obj_type", "Type", obj_type, classes=["assi-type"])
|
2023-11-03 14:57:22 +01:00
|
|
|
|
|
2023-11-24 18:07:30 +01:00
|
|
|
|
def _etud(self, lien_redirection) -> None:
|
2023-10-26 13:12:22 +02:00
|
|
|
|
etud = self.etud
|
|
|
|
|
self.table.group_titles.update(
|
|
|
|
|
{
|
|
|
|
|
"etud_codes": "Codes",
|
|
|
|
|
"identite_detail": "",
|
|
|
|
|
"identite_court": "",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Ajout des informations de l'étudiant
|
|
|
|
|
|
|
|
|
|
self.add_cell(
|
|
|
|
|
"nom_disp",
|
|
|
|
|
"Nom",
|
|
|
|
|
etud.nom_disp(),
|
|
|
|
|
"etudinfo",
|
|
|
|
|
attrs={"id": str(etud.id)},
|
|
|
|
|
data={"order": etud.sort_key},
|
|
|
|
|
target=lien_redirection,
|
|
|
|
|
target_attrs={"class": "discretelink"},
|
|
|
|
|
)
|
|
|
|
|
self.add_cell(
|
|
|
|
|
"prenom",
|
|
|
|
|
"Prénom",
|
|
|
|
|
etud.prenom_str,
|
|
|
|
|
"etudinfo",
|
|
|
|
|
attrs={"id": str(etud.id)},
|
|
|
|
|
data={"order": etud.sort_key},
|
|
|
|
|
target=lien_redirection,
|
|
|
|
|
target_attrs={"class": "discretelink"},
|
|
|
|
|
)
|
|
|
|
|
|
2023-11-24 13:58:03 +01:00
|
|
|
|
def _optionnelles(self) -> None:
|
|
|
|
|
if self.table.options.show_desc:
|
|
|
|
|
self.add_cell(
|
|
|
|
|
"description",
|
|
|
|
|
"Description",
|
|
|
|
|
self.ligne["description"] if self.ligne["description"] else "",
|
|
|
|
|
)
|
|
|
|
|
if self.table.options.show_module:
|
|
|
|
|
if self.ligne["type"] == "assiduite":
|
|
|
|
|
assi: Assiduite = Assiduite.query.get(self.ligne["obj_id"])
|
|
|
|
|
mod: str = assi.get_module(True)
|
|
|
|
|
self.add_cell("module", "Module", mod, data={"order": mod})
|
|
|
|
|
else:
|
|
|
|
|
self.add_cell("module", "Module", "", data={"order": ""})
|
|
|
|
|
|
2023-11-03 14:57:22 +01:00
|
|
|
|
def _utilisateur(self) -> None:
|
2023-12-05 21:04:38 +01:00
|
|
|
|
utilisateur: User = (
|
|
|
|
|
User.query.get(self.ligne["user_id"]) if self.ligne["user_id"] else None
|
|
|
|
|
)
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
self.add_cell(
|
2023-11-03 14:57:22 +01:00
|
|
|
|
"user",
|
|
|
|
|
"Saisie par",
|
|
|
|
|
"Inconnu" if utilisateur is None else utilisateur.get_nomprenom(),
|
2023-11-24 13:58:03 +01:00
|
|
|
|
classes=["small-font"],
|
2023-10-26 13:12:22 +02:00
|
|
|
|
)
|
|
|
|
|
|
2023-11-03 14:57:22 +01:00
|
|
|
|
def _actions(self) -> None:
|
2023-11-24 13:58:03 +01:00
|
|
|
|
url: str
|
|
|
|
|
html: list[str] = []
|
|
|
|
|
|
|
|
|
|
# Détails
|
|
|
|
|
url = url_for(
|
|
|
|
|
"assiduites.tableau_assiduite_actions",
|
|
|
|
|
type=self.ligne["type"],
|
|
|
|
|
action="details",
|
|
|
|
|
obj_id=self.ligne["obj_id"],
|
|
|
|
|
scodoc_dept=g.scodoc_dept,
|
|
|
|
|
)
|
2023-12-05 21:04:38 +01:00
|
|
|
|
html.append(f'<a title="Détails" href="{url}">ℹ️</a>')
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
# Modifier
|
|
|
|
|
url = url_for(
|
|
|
|
|
"assiduites.tableau_assiduite_actions",
|
|
|
|
|
type=self.ligne["type"],
|
|
|
|
|
action="modifier",
|
|
|
|
|
obj_id=self.ligne["obj_id"],
|
|
|
|
|
scodoc_dept=g.scodoc_dept,
|
|
|
|
|
)
|
2023-12-05 21:04:38 +01:00
|
|
|
|
html.append(f'<a title="Modifier" href="{url}">📝</a>')
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
# Supprimer
|
|
|
|
|
url = url_for(
|
|
|
|
|
"assiduites.tableau_assiduite_actions",
|
|
|
|
|
type=self.ligne["type"],
|
|
|
|
|
action="supprimer",
|
|
|
|
|
obj_id=self.ligne["obj_id"],
|
|
|
|
|
scodoc_dept=g.scodoc_dept,
|
|
|
|
|
)
|
2023-11-24 18:07:30 +01:00
|
|
|
|
html.append(f'<a title="Supprimer" href="{url}">❌</a>') # utiliser url_for
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
2023-12-05 21:04:38 +01:00
|
|
|
|
self.add_cell(
|
|
|
|
|
"actions",
|
|
|
|
|
"",
|
|
|
|
|
" ".join(html),
|
|
|
|
|
no_excel=True,
|
|
|
|
|
column_classes={"actions"},
|
|
|
|
|
)
|
2023-11-03 14:57:22 +01:00
|
|
|
|
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
2023-12-01 13:46:33 +01:00
|
|
|
|
class AssiFiltre:
|
2023-10-26 13:12:22 +02:00
|
|
|
|
"""
|
|
|
|
|
Classe représentant le filtrage qui sera appliqué aux objets
|
|
|
|
|
du Tableau `ListeAssiJusti`
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
type_obj: int = 0,
|
|
|
|
|
entry_date: tuple[int, datetime] = None,
|
|
|
|
|
date_debut: tuple[int, datetime] = None,
|
|
|
|
|
date_fin: tuple[int, datetime] = None,
|
|
|
|
|
) -> None:
|
|
|
|
|
"""
|
|
|
|
|
__init__ Instancie un nouvel objet filtre.
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
"""
|
|
|
|
|
|
2023-11-24 13:58:03 +01:00
|
|
|
|
self.filtres = {"type_obj": type_obj}
|
2023-10-26 13:12:22 +02:00
|
|
|
|
|
|
|
|
|
if entry_date is not None:
|
|
|
|
|
self.filtres["entry_date"]: tuple[int, datetime] = entry_date
|
|
|
|
|
|
|
|
|
|
if date_debut is not None:
|
|
|
|
|
self.filtres["date_debut"]: tuple[int, datetime] = date_debut
|
|
|
|
|
|
|
|
|
|
if date_fin is not None:
|
|
|
|
|
self.filtres["date_fin"]: tuple[int, datetime] = date_fin
|
|
|
|
|
|
|
|
|
|
def filtrage(self, query: Query, obj_class: db.Model) -> Query:
|
|
|
|
|
"""
|
|
|
|
|
filtrage Filtre la query passée en paramètre et retourne l'objet filtré
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
query (Query): La query à filtrer
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Query: La query filtrée
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
query_filtree: Query = query
|
|
|
|
|
|
|
|
|
|
cle_filtre: str
|
|
|
|
|
for cle_filtre, val_filtre in self.filtres.items():
|
|
|
|
|
if "date" in cle_filtre:
|
|
|
|
|
type_filtrage: int
|
|
|
|
|
date: datetime
|
|
|
|
|
|
|
|
|
|
type_filtrage, date = val_filtre
|
|
|
|
|
|
|
|
|
|
match (type_filtrage):
|
2023-12-12 03:05:31 +01:00
|
|
|
|
# On garde uniquement les dates supérieures au filtre
|
2023-10-26 13:12:22 +02:00
|
|
|
|
case 2:
|
|
|
|
|
query_filtree = query_filtree.filter(
|
|
|
|
|
getattr(obj_class, cle_filtre) > date
|
|
|
|
|
)
|
2023-12-12 03:05:31 +01:00
|
|
|
|
# On garde uniquement les dates inférieures au filtre
|
2023-10-26 13:12:22 +02:00
|
|
|
|
case 1:
|
|
|
|
|
query_filtree = query_filtree.filter(
|
|
|
|
|
getattr(obj_class, cle_filtre) < date
|
|
|
|
|
)
|
|
|
|
|
# Par défaut on garde uniquement les dates égales au filtre
|
|
|
|
|
case _:
|
|
|
|
|
query_filtree = query_filtree.filter(
|
|
|
|
|
getattr(obj_class, cle_filtre) == date
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if cle_filtre == "etats":
|
|
|
|
|
etats: list[int | EtatJustificatif | EtatAssiduite] = val_filtre
|
|
|
|
|
# On garde uniquement les objets ayant un état compris dans le filtre
|
|
|
|
|
query_filtree = query_filtree.filter(obj_class.etat.in_(etats))
|
|
|
|
|
|
|
|
|
|
return query_filtree
|
|
|
|
|
|
|
|
|
|
def type_obj(self) -> int:
|
|
|
|
|
"""
|
|
|
|
|
type_obj Renvoi le/les types d'objets à représenter
|
|
|
|
|
|
|
|
|
|
(0:Tout, 1: Assi, 2:Justi)
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
int: le/les types d'objets à afficher
|
|
|
|
|
"""
|
|
|
|
|
return self.filtres.get("type_obj", 0)
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
|
2023-12-01 13:46:33 +01:00
|
|
|
|
class AssiDisplayOptions:
|
|
|
|
|
"Options pour affichage tableau"
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
page: int = 1,
|
|
|
|
|
nb_ligne_page: int = None,
|
|
|
|
|
show_pres: str | bool = False,
|
|
|
|
|
show_reta: str | bool = False,
|
|
|
|
|
show_desc: str | bool = False,
|
|
|
|
|
show_etu: str | bool = True,
|
|
|
|
|
show_actions: str | bool = True,
|
|
|
|
|
show_module: str | bool = False,
|
|
|
|
|
):
|
|
|
|
|
self.page: int = page
|
|
|
|
|
self.nb_ligne_page: int = nb_ligne_page
|
2023-11-24 18:07:30 +01:00
|
|
|
|
if self.nb_ligne_page is not None:
|
|
|
|
|
self.nb_ligne_page = min(nb_ligne_page, ListeAssiJusti.MAX_PAR_PAGE)
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
2023-12-01 13:46:33 +01:00
|
|
|
|
self.show_pres = to_bool(show_pres)
|
|
|
|
|
self.show_reta = to_bool(show_reta)
|
|
|
|
|
self.show_desc = to_bool(show_desc)
|
|
|
|
|
self.show_etu = to_bool(show_etu)
|
|
|
|
|
self.show_actions = to_bool(show_actions)
|
|
|
|
|
self.show_module = to_bool(show_module)
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
def remplacer(self, **kwargs):
|
2023-12-09 15:53:45 +01:00
|
|
|
|
"Positionne options booléennes selon arguments"
|
2023-11-24 13:58:03 +01:00
|
|
|
|
for k, v in kwargs.items():
|
|
|
|
|
if k.startswith("show_"):
|
2023-12-01 13:46:33 +01:00
|
|
|
|
setattr(self, k, to_bool(v))
|
2023-11-24 13:58:03 +01:00
|
|
|
|
elif k in ["page", "nb_ligne_page"]:
|
2023-11-24 18:07:30 +01:00
|
|
|
|
setattr(self, k, int(v))
|
|
|
|
|
if k == "nb_ligne_page":
|
|
|
|
|
self.nb_ligne_page = min(
|
|
|
|
|
self.nb_ligne_page, ListeAssiJusti.MAX_PAR_PAGE
|
|
|
|
|
)
|
2023-11-24 13:58:03 +01:00
|
|
|
|
|
|
|
|
|
|
2023-12-01 13:46:33 +01:00
|
|
|
|
class AssiJustifData:
|
|
|
|
|
"Les assiduités et justificatifs"
|
|
|
|
|
|
2023-11-24 13:58:03 +01:00
|
|
|
|
def __init__(
|
|
|
|
|
self, assiduites_query: Query = None, justificatifs_query: Query = None
|
|
|
|
|
):
|
|
|
|
|
self.assiduites_query: Query = assiduites_query
|
|
|
|
|
self.justificatifs_query: Query = justificatifs_query
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2023-12-01 13:46:33 +01:00
|
|
|
|
def from_etudiants(*etudiants: Identite) -> "AssiJustifData":
|
|
|
|
|
data = AssiJustifData()
|
2023-11-24 13:58:03 +01:00
|
|
|
|
data.assiduites_query = Assiduite.query.filter(
|
|
|
|
|
Assiduite.etudid.in_([e.etudid for e in etudiants])
|
|
|
|
|
)
|
|
|
|
|
data.justificatifs_query = Justificatif.query.filter(
|
|
|
|
|
Justificatif.etudid.in_([e.etudid for e in etudiants])
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
def get(self) -> tuple[Query, Query]:
|
|
|
|
|
return self.assiduites_query, self.justificatifs_query
|