SchotzIAD KM Tracker : suivi des trajets kilométriques (Angular + .NET 8)

Application complète de saisie et de suivi des trajets kilométriques avec
calcul de distance routière (OpenRouteService), barème kilométrique, résumés
et régularisation annuelle.

Backend (ASP.NET Core .NET 8, EF Core, SQLite) :
- Trajets (CRUD, réordonnancement, insertion), calcul de distance ORS avec
  fallback Haversine, géométrie d'itinéraire stockée par trajet, recalcul en masse.
- Profil, véhicules (avec dénomination), carnet d'adresses nommées, cache d'adresses.
- Barème kilométrique : tranches multiples par puissance fiscale, borne max
  exclusive avec 'illimité' (KmMax nullable), coefficient à 3 décimales,
  recopie du dernier barème connu.
- Résumés mensuel/annuel, montants réglés, régularisation, export PDF.

Frontend (Angular 22, zoneless + signals) :
- Consultation par jour, navigation temporelle synchronisée, carte Leaflet,
  formulaire de trajet (adresses nommées, domicile, autocomplétion BAN).
- Détection de changement zoneless (indépendante de zone.js).

Hébergement : Docker Compose (nginx + backend), scripts run-dev.sh / run-docker.sh.
This commit is contained in:
2026-09-14 02:08:27 +02:00
commit e3f946f7d4
225 changed files with 38168 additions and 0 deletions
@@ -0,0 +1,59 @@
// Modèles Adresses — miroir de AdresseDtos.cs + réponse BAN.
/** Résultat de recherche BAN proxifié via le backend — miroir de BANAdresseDto. */
export interface BANAdresse {
label: string;
latitude: number;
longitude: number;
postcode: string;
city: string;
}
/** Suggestion d'autocomplétion issue du cache local — miroir de AdresseCacheDto. */
export interface AdresseCache {
adresse: string;
latitude: number;
longitude: number;
}
/** Adresse nommée du carnet d'adresses — miroir de AdresseNommeeDto. */
export interface AdresseNommee {
id: number;
denomination: string;
adresse: string;
latitude: number | null; // null si le géocodage a échoué
longitude: number | null; // null si le géocodage a échoué
}
/** Création / mise à jour d'une adresse nommée — miroir de SaveAdresseNommeeDto. */
export interface SaveAdresseNommee {
denomination: string; // 1 à 100 car., unique après normalisation
adresse: string; // 1 à 255 car.
latitude?: number | null; // fournies par le frontend si sélection BAN
longitude?: number | null;
}
/**
* Réponse brute de l'API Base Adresse Nationale (Feature GeoJSON).
* Source primaire d'autocomplétion appelée directement par le frontend.
*/
export interface BANFeature {
properties: {
label: string; // libellé complet normalisé
score: number; // score de pertinence 0–1
postcode: string;
city: string;
context: string;
type: string; // 'housenumber' | 'street' | 'locality' | 'municipality'
x: number; // longitude
y: number; // latitude
};
geometry: {
coordinates: [number, number]; // [longitude, latitude]
};
}
/** Enveloppe de la réponse BAN (FeatureCollection GeoJSON). */
export interface BANFeatureCollection {
features: BANFeature[];
}
@@ -0,0 +1,64 @@
// Modèles Barème & montants — miroir de BaremeDtos.cs.
/** Tranche de barème kilométrique — miroir de TrancheBaremeDto. */
export interface TrancheBareme {
id: number;
annee: number;
puissanceFiscale: number;
kmMin: number;
kmMax: number | null; // null = illimité (borne max exclusive : [kmMin, kmMax[)
coefficient: number;
base: number;
}
/** Création / mise à jour d'une tranche — miroir de SaveTrancheBaremeDto. */
export interface SaveTrancheBareme {
annee: number;
puissanceFiscale: number;
kmMin: number;
kmMax: number | null; // null = illimité
coefficient: number;
base: number;
}
/** Montant réglé pour une période et un véhicule — miroir de MontantRegleDto. */
export interface MontantRegle {
annee: number;
mois: number;
vehiculeId: number;
montant: number;
}
/** Indication de versement mensuel prévisionnel — miroir de MontantPrevisionnelDto. */
export interface MontantPrevisionnel {
annee: number;
mois: number;
vehiculeId: number;
totalAnnuelPartielKm: number;
montantBaremePlein: number; // barème plein sur le total partiel
montantPrevisionnel: number; // = 80% (indicatif uniquement)
}
/** Ligne mensuelle de la synthèse annuelle — miroir de LigneSyntheseMoisDto. */
export interface LigneSyntheseMois {
mois: number;
kmMois: number;
fraisPaye: number; // Montant_Regle du mois (saisi)
fraisReelMensuel: number; // km_du_mois × coefficient de la tranche annuelle
}
/** Synthèse annuelle de régularisation — miroir de RegularisationAnnuelleDto. */
export interface RegularisationAnnuelle {
annee: number;
vehiculeId: number;
plaque: string;
puissanceFiscale: number;
coefficientTranche: number;
baseTranche: number;
trancheLibelle: string;
mois: LigneSyntheseMois[]; // 12 lignes
totalKmAnnuel: number;
totalPaye: number; // somme des Montant_Regle
montantReel: number; // barème plein : total_km × coef + base
regularisation: number; // montantReel − totalPaye
}
+9
View File
@@ -0,0 +1,9 @@
// Barrel d'export des modèles du domaine (miroir des DTOs backend).
export * from './trajet.model';
export * from './resume-mensuel.model';
export * from './resume-annuel.model';
export * from './totaux.model';
export * from './vehicule.model';
export * from './profil.model';
export * from './bareme.model';
export * from './adresse.model';
@@ -0,0 +1,27 @@
// Modèles Profil — miroir de ProfilDtos.cs.
/** Profil — miroir de ProfilDto. */
export interface Profil {
nom: string | null;
prenom: string | null;
matricule: string | null;
adresseDomicile: string | null;
domicileGeocode: boolean;
}
/** Création / mise à jour du profil — miroir de SaveProfilDto. */
export interface SaveProfil {
nom?: string | null;
prenom?: string | null;
matricule?: string | null; // max 8 car.
adresseDomicile: string;
}
/**
* État de configuration du profil (onboarding première utilisation).
* Miroir de EtatProfilDto.
* estConfigure = true ssi Profil.Nom et Profil.Prenom non vides ET au moins un Vehicule existe.
*/
export interface EtatProfil {
estConfigure: boolean;
}
@@ -0,0 +1,8 @@
import { ResumeMensuel } from './resume-mensuel.model';
/** Résumé annuel — miroir de ResumeAnnuelDto. */
export interface ResumeAnnuel {
annee: number;
mois: ResumeMensuel[]; // toujours 12 éléments
totalKm: number;
}
@@ -0,0 +1,9 @@
import { Trajet } from './trajet.model';
/** Résumé mensuel — miroir de ResumeMensuelDto. */
export interface ResumeMensuel {
annee: number;
mois: number;
trajets: Trajet[];
totalKm: number; // somme des distances, 2 décimales
}
@@ -0,0 +1,8 @@
/** Totaux affichés dans le Panneau_Totaux — miroir de TotauxDto. */
export interface Totaux {
date: string; // ISO date
vehiculeId: number; // véhicule sur lequel portent les totaux
totalJour: number;
totalMois: number;
totalAnnuelPartiel: number; // cumul de l'année jusqu'au mois inclus
}
@@ -0,0 +1,73 @@
// Modèles Trajet — miroir des DTOs backend (TrajetDtos.cs).
/**
* Création d'un Trajet.
* Les coordonnées sont transmises par le Frontend (issues de la sélection BAN) ;
* elles sont nulles si l'adresse a été saisie manuellement sans autocomplétion.
*/
export interface CreateTrajet {
date: string; // JJ/MM/AAAA en entrée
adresseDepart: string;
departLatitude?: number | null;
departLongitude?: number | null;
adresseArrivee: string;
arriveeLatitude?: number | null;
arriveeLongitude?: number | null;
commentaire?: string | null; // optionnel, max 500 car.
vehiculeId?: number | null; // null -> véhicule courant à la date du trajet
}
/** Mise à jour d'un Trajet. */
export interface UpdateTrajet {
date: string;
adresseDepart: string;
departLatitude?: number | null;
departLongitude?: number | null;
adresseArrivee: string;
arriveeLatitude?: number | null;
arriveeLongitude?: number | null;
commentaire?: string | null;
vehiculeId?: number | null;
}
/** Réponse Trajet. */
export interface Trajet {
id: number;
date: string; // ISO date (yyyy-MM-dd) renvoyée par l'API
adresseDepart: string;
adresseArrivee: string;
distance: number | null; // km, 2 décimales ; null si non calculable (Exigence 2.4)
commentaire: string | null;
position: number; // rang dans la journée
vehiculeId: number;
puissanceFiscale: number;
}
/**
* Trajet enrichi pour l'affichage carte (géométries GeoJSON).
* Note : ce DTO ne porte PAS de `commentaire` (le commentaire n'est affiché que
* dans la liste des trajets, via l'interface `Trajet`, jamais dans l'infobulle carte).
*/
export interface TrajetCarte {
id: number;
date: string;
adresseDepart: string;
adresseArrivee: string;
distance: number;
departLatitude?: number | null;
departLongitude?: number | null;
arriveeLatitude?: number | null;
arriveeLongitude?: number | null;
geometrieJson: string | null; // GeoJSON LineString ou null
}
/** Position d'un trajet lors d'un réordonnancement. */
export interface TrajetPosition {
id: number;
position: number;
}
/** Réordonnancement manuel des trajets d'une journée. */
export interface ReordonnerTrajets {
trajets: TrajetPosition[];
}
@@ -0,0 +1,34 @@
// Modèles Véhicule — miroir de VehiculeDtos.cs.
/** Véhicule — miroir de VehiculeDto. */
export interface Vehicule {
id: number;
denomination: string;
plaque: string;
puissanceFiscale: number;
dateEffet: string; // ISO date
}
/** Création d'un véhicule — miroir de CreateVehiculeDto. */
export interface CreateVehicule {
denomination: string;
plaque: string;
puissanceFiscale: number;
dateEffet: string; // JJ/MM/AAAA, <= date du jour
}
/**
* Réponse à la création d'un véhicule.
* Indique s'il faut proposer une réaffectation des trajets existants.
*/
export interface VehiculeCree {
vehicule: Vehicule;
reaffectationProposee: boolean; // true si des trajets >= DateEffet ont une autre puissance fiscale
nombreTrajetsConcernes: number;
}
/** Requête de réaffectation — miroir de ReaffectationDto. */
export interface Reaffectation {
vehiculeId: number; // nouveau véhicule
accepter: boolean; // true = réaffecter les trajets >= DateEffet ; false = ne rien changer
}