doc: document configuration and application routes
Co-authored-by: OpenAI/GPT-5.6-Terra <vibecoder@antoineve.me> Co-authored-by: Google/Gemini-3.5-Flash <vibecoder@antoineve.me> Co-authored-by: DeepSeek/DeepSeek-v4-Flash <vibecoder@antoineve.me>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
"""Package contenant les blueprints de routes de l'application.
|
||||
|
||||
Ce package regroupe les différents modules de routes (blueprints) de l'application :
|
||||
- `dashboard` : Gère l'affichage du tableau de bord principal.
|
||||
- `entries` : Gère la saisie, la modification et la suppression des entrées de temps.
|
||||
- `reports` : Gère la génération des rapports d'activité annuels et mensuels.
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
"""Blueprint des routes du tableau de bord principal.
|
||||
|
||||
Ce module gère l'affichage de la page d'accueil (le tableau de bord). Il calcule et rassemble
|
||||
les statistiques clés de la semaine courante et du mois en cours, ainsi que le solde des congés
|
||||
et RTT pour l'année civile.
|
||||
"""
|
||||
|
||||
from datetime import date, timedelta
|
||||
|
||||
import sqlalchemy as sa
|
||||
@@ -15,6 +22,27 @@ bp = Blueprint("dashboard", __name__)
|
||||
|
||||
@bp.route("/")
|
||||
def index():
|
||||
"""Affiche le tableau de bord principal de l'utilisateur.
|
||||
|
||||
Cette route effectue les opérations suivantes :
|
||||
1. Détermine la date du jour et calcule les limites de la semaine courante (du lundi au dimanche).
|
||||
2. Récupère toutes les entrées de temps (`WorkEntry`) de la semaine courante pour calculer :
|
||||
- Le temps de travail effectif cumulé (`week_actual`).
|
||||
- Le temps de travail de référence théorique (`week_ref`) selon le type de chaque journée.
|
||||
- Le solde d'heures de la semaine (`week_balance` = effectif - référence).
|
||||
3. Récupère toutes les entrées de temps du mois en cours (du 1er jour du mois jusqu'à aujourd'hui) pour calculer :
|
||||
- Les distances parcourues par véhicule (`month_km`) à partir des profils de trajets associés.
|
||||
- Les émissions de CO2 correspondantes (`month_co2`).
|
||||
4. Récupère ou initialise le solde annuel des congés et RTT (`balance`) et calcule les jours posés/utilisés (`used`).
|
||||
5. Vérifie s'il existe déjà une entrée de temps pour la journée d'aujourd'hui (`today_entry`).
|
||||
6. Rend le template `dashboard.html` avec l'ensemble de ces données de contexte.
|
||||
|
||||
Méthode HTTP :
|
||||
GET
|
||||
|
||||
Retourne:
|
||||
str: Le rendu HTML de la page du tableau de bord (`dashboard.html`).
|
||||
"""
|
||||
today = date.today()
|
||||
year = today.year
|
||||
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
"""Blueprint des routes de gestion des entrées de temps (WorkEntry).
|
||||
|
||||
Ce module gère le cycle de vie complet des entrées journalières de travail :
|
||||
- Affichage de la liste historique des entrées.
|
||||
- Création d'une nouvelle entrée (formulaire et traitement POST).
|
||||
- Modification d'une entrée existante (formulaire pré-rempli et traitement POST).
|
||||
- Suppression d'une entrée.
|
||||
|
||||
Règles de validation et de cohérence des données :
|
||||
1. Unicité de la date : Une seule entrée (`WorkEntry`) est autorisée par jour.
|
||||
2. Types de jours sans trajet : Si le type de jour est dans `day_types_without_journey()` (TT, MALADE, CONGE, RTT, FERIE),
|
||||
le profil de trajet (`journey_profile_id`) est forcé à `None`.
|
||||
3. Véhicule à moteur : Si le profil de trajet sélectionné n'inclut pas de véhicule à moteur (vérifié via `journey_has_motor`),
|
||||
le véhicule à moteur (`motor_vehicle_id`) est forcé à `None`.
|
||||
4. Plages horaires : Les plages horaires (`TimeSlot`) existantes d'une entrée sont supprimées et recréées à chaque soumission
|
||||
pour simplifier la mise à jour des plages multiples.
|
||||
"""
|
||||
|
||||
from datetime import date, time
|
||||
|
||||
import sqlalchemy as sa
|
||||
@@ -29,6 +47,17 @@ DAY_TYPES = [
|
||||
|
||||
@bp.route("/")
|
||||
def list_entries():
|
||||
"""Affiche la liste historique de toutes les entrées de temps enregistrées.
|
||||
|
||||
Cette route récupère l'ensemble des entrées (`WorkEntry`) triées par date décroissante
|
||||
et les transmet au template pour affichage sous forme de tableau ou de liste.
|
||||
|
||||
Méthode HTTP :
|
||||
GET
|
||||
|
||||
Retourne:
|
||||
str: Le rendu HTML de la liste des entrées (`entry_list.html`).
|
||||
"""
|
||||
entries = db.session.scalars(sa.select(WorkEntry).order_by(WorkEntry.date.desc())).all()
|
||||
return render_template("entry_list.html", entries=entries)
|
||||
|
||||
@@ -36,6 +65,37 @@ def list_entries():
|
||||
@bp.route("/new", methods=["GET", "POST"])
|
||||
@bp.route("/<int:entry_id>/edit", methods=["GET", "POST"])
|
||||
def entry_form(entry_id=None):
|
||||
"""Gère l'affichage du formulaire et l'enregistrement (création ou modification) d'une entrée.
|
||||
|
||||
Cette route est doublement mappée pour la création (`/new`) et l'édition (`/<entry_id>/edit`).
|
||||
|
||||
Comportement en GET :
|
||||
- Si `entry_id` est fourni, récupère l'entrée correspondante en base de données. Si elle n'existe pas,
|
||||
affiche un message d'erreur et redirige vers la liste des entrées.
|
||||
- Prépare le contexte nécessaire au formulaire : liste des types de jours, profils de trajets,
|
||||
véhicules à moteur disponibles, types de jours sans trajet, et la date du jour par défaut.
|
||||
- Rend le template `entry_form.html`.
|
||||
|
||||
Comportement en POST :
|
||||
- Extrait et valide les données du formulaire : date, type de jour, trajet, véhicule à moteur, commentaire.
|
||||
- Applique les règles de cohérence (mise à `None` du trajet ou du véhicule si les conditions ne sont pas remplies).
|
||||
- En création : vérifie qu'aucune entrée n'existe déjà à cette date. Si c'est le cas, affiche une erreur.
|
||||
- Enregistre ou met à jour l'objet `WorkEntry` en base de données.
|
||||
- Supprime toutes les plages horaires (`TimeSlot`) existantes associées à cette entrée.
|
||||
- Parcourt les listes d'heures de début (`start_time`) et de fin (`end_time`) soumises, et recrée les objets
|
||||
`TimeSlot` valides associés à l'entrée.
|
||||
- Valide la transaction en base de données (`db.session.commit()`), affiche un message de succès
|
||||
et redirige vers le tableau de bord.
|
||||
|
||||
Paramètres:
|
||||
entry_id (int | None): L'identifiant de l'entrée à modifier, ou None pour une nouvelle entrée.
|
||||
|
||||
Méthodes HTTP :
|
||||
GET, POST
|
||||
|
||||
Retourne:
|
||||
str | Response: Le rendu HTML du formulaire (GET) ou une redirection HTTP (POST / erreur).
|
||||
"""
|
||||
entry = None
|
||||
if entry_id:
|
||||
entry = db.session.get(WorkEntry, entry_id)
|
||||
@@ -101,6 +161,21 @@ def entry_form(entry_id=None):
|
||||
|
||||
@bp.route("/<int:entry_id>/delete", methods=["POST"])
|
||||
def delete_entry(entry_id):
|
||||
"""Supprime une entrée de temps existante.
|
||||
|
||||
Cette route récupère l'entrée par son identifiant, la supprime de la base de données
|
||||
(les plages horaires associées sont également supprimées en cascade si configuré, ou gérées par SQLAlchemy),
|
||||
valide la transaction, affiche un message de succès et redirige vers la liste des entrées.
|
||||
|
||||
Paramètres:
|
||||
entry_id (int): L'identifiant de l'entrée à supprimer.
|
||||
|
||||
Méthode HTTP :
|
||||
POST (sécurisé contre les suppressions accidentelles via GET)
|
||||
|
||||
Retourne:
|
||||
Response: Une redirection HTTP vers la liste des entrées (`entries.list_entries`).
|
||||
"""
|
||||
entry = db.session.get(WorkEntry, entry_id)
|
||||
if entry:
|
||||
db.session.delete(entry)
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
"""Blueprint des routes de génération des rapports et statistiques.
|
||||
|
||||
Ce module gère l'affichage des rapports annuels et mensuels. Il calcule les distances cumulées,
|
||||
les émissions de CO2, les frais réels selon le barème kilométrique officiel, et compile les statistiques
|
||||
de temps de travail (médianes quotidiennes et hebdomadaires) pour chaque mois de l'année sélectionnée.
|
||||
"""
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import date
|
||||
|
||||
@@ -30,6 +37,35 @@ MONTHS_FR = {
|
||||
|
||||
@bp.route("/")
|
||||
def index():
|
||||
"""Génère et affiche le rapport d'activité annuel et mensuel.
|
||||
|
||||
Cette route effectue les opérations suivantes :
|
||||
1. Récupère l'année cible depuis les paramètres de requête HTTP GET (`year`). Par défaut, utilise l'année en cours.
|
||||
2. Récupère toutes les entrées de temps (`WorkEntry`) de cette année civile.
|
||||
3. Récupère la configuration des véhicules et des trajets depuis le fichier TOML.
|
||||
4. Calcule les statistiques annuelles cumulées :
|
||||
- Distances parcourues par véhicule (`total_km`).
|
||||
- Émissions de CO2 totales en grammes (`total_co2`), converties ensuite en kilogrammes.
|
||||
- Frais réels remboursables par véhicule (`frais_reels`) en appliquant le barème kilométrique officiel
|
||||
de l'année correspondante (avec une majoration de +20% pour les véhicules électriques).
|
||||
- Nombre de jours par type de journée (`day_type_counts`).
|
||||
5. Regroupe les entrées par mois pour calculer les statistiques mensuelles :
|
||||
- Nom du mois en français.
|
||||
- Nombre de jours saisis.
|
||||
- Distances parcourues par véhicule et distance totale du mois.
|
||||
- Durée quotidienne médiane de travail et durée hebdomadaire médiane de travail (formatées en chaînes "HHhMM").
|
||||
6. Rend le template `reports.html` avec l'ensemble de ces données de contexte.
|
||||
|
||||
Méthode HTTP :
|
||||
GET
|
||||
|
||||
Paramètres de requête (Query Params) :
|
||||
year (int, optionnel) : L'année civile pour laquelle générer le rapport (ex: `?year=2026`).
|
||||
Par défaut, l'année courante.
|
||||
|
||||
Retourne:
|
||||
str: Le rendu HTML de la page des rapports (`reports.html`).
|
||||
"""
|
||||
year = request.args.get("year", date.today().year, type=int)
|
||||
start = date(year, 1, 1)
|
||||
end = date(year, 12, 31)
|
||||
|
||||
Reference in New Issue
Block a user