Skip to content

Module — Dashboards & Reports

Synchronisé avec le code. Mettre à jour à chaque changement structurel.

Rôle

  • Dashboards : vues live UI pour les utilisateurs back-office (Direction, mgmt) — KPIs occupation, CA, statuts.
  • Reports : exports Excel / PDF à destination de la comptabilité et de la direction.

Emplacement

  • Pages : src/Web/Pages/Dashboards/, src/Web/Pages/Reports/
  • Services : DashboardService.cs, ReportService.cs
  • DTOs : Application/Dtos/Dashboard/
  • Frontend : ApexCharts pour les visualisations dans Razor

Entités principales

Aucune entité dédiée — agrégation cross-module sur :

  • Booking (volumes, CA)
  • Occurrence (taux d'occupation)
  • Invoice / Payment (CA réel, encaissé)
  • Customer (segmentation)

Règles métier spécifiques

  • Dashboards = données fraîches (queries directes EF + cache éventuel via OutputCache).
  • Reports = exports formels (Excel via EPPlus, PDF via Liquid+iText). Souvent paramétrés par période, type de voyage, business axis.
  • Travel.BusinessAxis est l'un des champs de segmentation analytique CA dans les reports.
  • Calcul d'occupation dans les dashboards : utiliser TravelOccupancyAndBookingStateService.CalculateOccupancyAndSetBookingState avec includeAllOccurrences: true quand on veut inclure les occurrences passées (statistiques historiques).

Points d'attention / pièges

  • Performance : les reports peuvent agréger sur de gros volumes — préférer IQueryable.Sum/Count côté SQL plutôt que .ToList().Sum() en mémoire.
  • Filtre soft-delete : par défaut les soft-deleted sont exclus. Pour des audit reports, utiliser IgnoreQueryFilters().
  • Locale fr-CH : formats de dates et nombres dans les exports → utiliser explicitement la culture pour éviter les surprises sur des serveurs en autre locale.
  • Données indicatives : OccurrenceCost et BreakEvenPoint sont indicatifs (cf. occurrence-capacity.md). Ne pas les utiliser dans des reports comptables stricts.
  • Taux de remplissage (DashboardService.GetOccurrencesOccupancyData) : la carte affiche le max du taux véhicule et du taux hébergement. Toute capacité peut valoir 0 (une course d'un jour n'a pas d'hébergement) → toujours garder la division derrière un test Capacity > 0. Sans ce garde-fou, 0.0/0 donne NaN, et comme toute comparaison avec NaN est fausse, le NaN remportait le max et s'affichait en NaN% (corrigé juil. 2026).
  • Report « Taux de remplissage et capacité » (ReportService.GetManagement) : distinguer deux colonnes passagers. « Passagers total » = occupation totale du départ (Occurrence.NumberOfPassengers, ou driveOcc.Occupancy pour les lignes OneDay) — non filtrée par la plage de dates de réservation du moteur de recherche. « Passagers » = sous-ensemble réservé dans la fenêtre [BookingStartDate, BookingEndDate], compté sur les mêmes statuts que l'occupation (ValidatingBookingStatus.BookingHasImpactOnOccurrenceOccupancy = Draft/Confirmed/Billed + PendingWebOrMobile avec transaction ou en hold CreatedAt >= PendingHoldCutoff()), passagers non annulés. Les colonnes monétaires (Total confirmé/facturé/Total) sont elles aussi filtrées par date mais sur Confirmed/Billed uniquement. ⚠ L'export Excel (Export) aligne les cellules par position (pas par référence de header comme le rendu UI) : ajouter une colonne impose donc d'insérer la cellule au bon rang dans la liste Cells de chaque branche.
    • Colonne « CA prestations (3010/3011) » (ajoutée juil. 2026) : à côté des colonnes nettes existantes. Les colonnes Total confirmé/Total facturé/Total restent le net facturé (Booking.FinalAmount, donc après rabais, commissions, bons, assurances) — ce qui faussait la comparaison avec la compta BC et le panier moyen (un bon de 3'000 sur un voyage à 3'000 → net 0 alors qu'il y a bien 1 pax et 3'000 de prestation). La nouvelle colonne = les prestations voyage/hébergement telles que BC les impute sur 3010/3011 (transport, hébergement, pension, excursions, supplément vol, supplément(s) booking, supplément global, net de la Réduction Early Booking qui est aussi postée sur 3010/3011) ; hors rabais/commissions (3902/3901/3908/3911), bons Croisitour (2062), bons cadeaux (2061), assurances (3021), points fidélité (3916/3917). Réconcilie par construction avec le solde BC des comptes 3010/3011 — pas de recalcul depuis les prix configurés.
      • InvoiceItem.Account est [NotMapped] (recalculé uniquement au sync NAV, jamais persisté) : filtrer par compte sur des items relus en base renvoie donc 0. Seuls Description, Price, FullPrice sont persistés. Le helper ReportService.GetPrestationAmount(booking) identifie donc les lignes hors 3010/3011 par préfixe de Description (NonPrestationDescriptionPrefixes : « Rabais », « Utilisation Bon Croisitour », « Assurance », « Bon cadeau », « Points fidélité ») et somme le FullPrice de tout le reste. Si une nouvelle catégorie de ligne hors 3010/3011 est ajoutée dans BookingService.CreateOrUpdateInvoice, penser à l'ajouter à cette liste.
      • Source par résa : facture Balance si elle existe (Enabled), sinon Confirmation ; FullPrice = montant plein (indépendant du split acompte/solde). Somme les résas Confirmed+Billed de la fenêtre de dates (analogue de la colonne Total).
      • ⚠ Comme les colonnes nettes existantes, une résa dont les passagers chargent sur plusieurs drives est attribuée à chaque drive touché (même sémantique que confirmedAmount/billedAmount). Nécessite l'Include des Invoices.InvoiceItems dans la requête loadFactor.
    • OneDay multi-lignes : le rapport produit une row par ligne (drive), et driveOcc.Occupancy ne compte que les passagers dont le LoadingStop est sur un arrêt de la ligne (le moteur CalculateDriveOccupancy ignore les LoadingStopId == null). Les passagers non rattachés à une ligne (stop null, ou stop hors des lignes actives) apparaissent donc dans une row de réconciliation « {Voyage} - Sans ligne assignée » ajoutée en fin de bloc OneDay. Son « Passagers total » est déduit par soustraction (Occurrence.NumberOfPassengers − Σ driveOcc.Occupancy, donc non filtré par date) et son « Passagers » compte les passagers sans ligne dans la fenêtre de dates. Le moteur d'occupation partagé n'est pas modifié (impact capacités/dispo ailleurs) — la correction est purement dans le rapport. Les colonnes monétaires de cette row restent vides (le CA d'une réservation est déjà compté sur sa ligne).

Conventions locales

  • Ajouter un nouveau report = créer une page Pages/Reports/<Name>.cshtml(.cs) + une méthode ReportService.GenerateXxx(filters) qui retourne un Stream (Excel) ou un byte[] (PDF).
  • Les DTOs Dashboard sont dans Dtos/Dashboard/ (folder dédié).

Dépendances

  • ← Toutes les sources de données métier (Booking, Occurrence, Invoice, Payment, Customer…).
  • → consommé par : Direction (Dashboards), Comptabilité (Reports).

Contributors

No contributors

Changelog

No recent changes