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:
@@ -0,0 +1,87 @@
|
||||
using TrajetKmTracker.Api.Models.Entities;
|
||||
|
||||
namespace TrajetKmTracker.Api.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Accès aux données des trajets et gestion des positions au sein d'une journée.
|
||||
/// <para>
|
||||
/// La <see cref="Trajet.Position"/> est une valeur décimale (REAL) permettant l'insertion
|
||||
/// sans réordonnancement systématique : ajout en fin de journée → <c>max(Position) + 1.0</c>,
|
||||
/// insertion entre deux positions P₁ et P₂ → <c>(P₁ + P₂) / 2</c>. Lorsque l'écart devient
|
||||
/// trop faible (< <see cref="SeuilRenumerotation"/>), la journée est renumérotée par pas de
|
||||
/// 1.0 en transaction en préservant l'ordre relatif (Property 15, Exigences 11.7/11.8).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Ce repository fournit uniquement les primitives d'accès et de calcul de position ;
|
||||
/// la logique métier (validation, calcul de distance, mise en cache) relève de TrajetService.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public interface ITrajetRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Seuil de précision en deçà duquel une renumérotation de la journée est déclenchée.
|
||||
/// Conforme à la conception : écart < 0.001.
|
||||
/// </summary>
|
||||
const decimal SeuilRenumerotation = 0.001m;
|
||||
|
||||
/// <summary>Retourne le trajet par identifiant, ou <c>null</c> s'il n'existe pas.</summary>
|
||||
Task<Trajet?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Retourne les trajets d'une journée triés par <see cref="Trajet.Position"/> croissante.</summary>
|
||||
Task<List<Trajet>> GetByDateAsync(DateOnly date, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Résout le véhicule applicable à la date du trajet et copie sa <c>PuissanceFiscale</c>
|
||||
/// sur le trajet (dénormalisation, Exigence 10.14). Ne modifie ni <c>VehiculeId</c> ni
|
||||
/// <c>PuissanceFiscale</c> si aucun véhicule n'est applicable à cette date.
|
||||
/// Coordonné avec <see cref="Services.IVehiculeService.GetVehiculeADateAsync"/>.
|
||||
/// </summary>
|
||||
Task AppliquerVehiculeADateAsync(Trajet trajet, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Calcule la position d'un trajet ajouté en fin de journée : <c>max(Position) + 1.0</c>
|
||||
/// pour la date, ou <c>1.0</c> si la journée est vide.
|
||||
/// </summary>
|
||||
Task<decimal> CalculerPositionFinDeJourneeAsync(DateOnly date, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Calcule la position d'un trajet inséré entre les positions <paramref name="positionPrecedente"/>
|
||||
/// (P₁) et <paramref name="positionSuivante"/> (P₂) : <c>(P₁ + P₂) / 2</c>.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Si P₁ n'est pas strictement inférieure à P₂.</exception>
|
||||
decimal CalculerPositionEntre(decimal positionPrecedente, decimal positionSuivante);
|
||||
|
||||
/// <summary>
|
||||
/// Indique si l'écart entre deux positions adjacentes est devenu trop faible
|
||||
/// (< <see cref="SeuilRenumerotation"/>) pour insérer une nouvelle valeur intermédiaire.
|
||||
/// </summary>
|
||||
bool NecessiteRenumerotation(decimal positionPrecedente, decimal positionSuivante);
|
||||
|
||||
/// <summary>Ajoute un trajet (sans persister). L'appelant gère la transaction et l'appel à <see cref="SauvegarderAsync"/>.</summary>
|
||||
Task AddAsync(Trajet trajet, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Marque un trajet existant comme modifié (sans persister).</summary>
|
||||
void Update(Trajet trajet);
|
||||
|
||||
/// <summary>Supprime un trajet (sans persister).</summary>
|
||||
void Delete(Trajet trajet);
|
||||
|
||||
/// <summary>Persiste les changements en attente.</summary>
|
||||
Task<int> SauvegarderAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Applique un réordonnancement manuel : met à jour uniquement la <see cref="Trajet.Position"/>
|
||||
/// des trajets fournis (par identifiant) sans altérer leurs autres champs, en transaction.
|
||||
/// Les identifiants inconnus sont ignorés.
|
||||
/// </summary>
|
||||
Task ReordonnerAsync(
|
||||
IReadOnlyList<(int Id, decimal Position)> positions,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Renumérote les trajets d'une journée par pas de 1.0 (1.0, 2.0, 3.0, …) en préservant
|
||||
/// l'ordre relatif courant (tri par Position puis Id), en transaction. Retourne la liste
|
||||
/// renumérotée triée par Position croissante (Property 15).
|
||||
/// </summary>
|
||||
Task<List<Trajet>> RenumeroterJourneeAsync(DateOnly date, CancellationToken cancellationToken = default);
|
||||
}
|
||||
Reference in New Issue
Block a user