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.
104 lines
4.2 KiB
C#
104 lines
4.2 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using TrajetKmTracker.Api.Models.DTOs;
|
|
using TrajetKmTracker.Api.Services;
|
|
using TrajetKmTracker.Api.Services.Exceptions;
|
|
|
|
namespace TrajetKmTracker.Api.Controllers;
|
|
|
|
/// <summary>
|
|
/// Endpoints « Barème et remboursements » : montant prévisionnel (80% indicatif),
|
|
/// montants réglés (saisie/consultation) et régularisation annuelle (barème plein).
|
|
/// </summary>
|
|
[ApiController]
|
|
[Route("api")]
|
|
public class RemboursementController : ControllerBase
|
|
{
|
|
private readonly IMontantRegleService _montantRegleService;
|
|
private readonly IRemboursementService _remboursementService;
|
|
|
|
public RemboursementController(
|
|
IMontantRegleService montantRegleService,
|
|
IRemboursementService remboursementService)
|
|
{
|
|
_montantRegleService = montantRegleService;
|
|
_remboursementService = remboursementService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retourne le Montant_Previsionnel indicatif (80% du barème plein sur le total annuel partiel)
|
|
/// pour un (année, mois, véhicule). Purement informatif — hors régularisation (Exigences 13.5/13.6).
|
|
/// </summary>
|
|
[HttpGet("montant-previsionnel/{annee:int}/{mois:int}")]
|
|
[ProducesResponseType(typeof(MontantPrevisionnelDto), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
public async Task<ActionResult<MontantPrevisionnelDto>> GetMontantPrevisionnel(
|
|
int annee, int mois, [FromQuery] int vehiculeId, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
var dto = await _montantRegleService.GetMontantPrevisionnelAsync(
|
|
annee, mois, vehiculeId, cancellationToken);
|
|
return Ok(dto);
|
|
}
|
|
catch (VehiculeNotFoundException ex)
|
|
{
|
|
return Problem(detail: ex.Message, statusCode: StatusCodes.Status404NotFound);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retourne les Montant_Regle saisis pour une (année, véhicule), triés par mois croissant.
|
|
/// </summary>
|
|
[HttpGet("montants-regles/{annee:int}")]
|
|
[ProducesResponseType(typeof(IReadOnlyList<MontantRegleDto>), StatusCodes.Status200OK)]
|
|
public async Task<ActionResult<IReadOnlyList<MontantRegleDto>>> GetMontantsRegles(
|
|
int annee, [FromQuery] int vehiculeId, CancellationToken cancellationToken)
|
|
{
|
|
var montants = await _montantRegleService.GetMontantsReglesAsync(annee, vehiculeId, cancellationToken);
|
|
return Ok(montants);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enregistre ou met à jour (upsert) un Montant_Regle par (année, mois, véhicule).
|
|
/// Rejette un montant négatif avec un code HTTP 400 (Exigence 14.4).
|
|
/// </summary>
|
|
[HttpPut("montants-regles")]
|
|
[ProducesResponseType(typeof(MontantRegleDto), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
|
public async Task<ActionResult<MontantRegleDto>> UpsertMontantRegle(
|
|
[FromBody] MontantRegleDto dto, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
var result = await _montantRegleService.UpsertMontantRegleAsync(dto, cancellationToken);
|
|
return Ok(result);
|
|
}
|
|
catch (MontantRegleNegatifException ex)
|
|
{
|
|
return Problem(detail: ex.Message, statusCode: StatusCodes.Status400BadRequest);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retourne la synthèse annuelle de régularisation (barème plein) pour une (année, véhicule) :
|
|
/// tranche annuelle, 12 lignes mensuelles et totaux (km annuel, réglé, Montant_Reel, Regularisation).
|
|
/// </summary>
|
|
[HttpGet("regularisation/{annee:int}")]
|
|
[ProducesResponseType(typeof(RegularisationAnnuelleDto), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
public async Task<ActionResult<RegularisationAnnuelleDto>> GetRegularisation(
|
|
int annee, [FromQuery] int vehiculeId, CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
var dto = await _remboursementService.GetRegularisationAnnuelleAsync(
|
|
annee, vehiculeId, cancellationToken);
|
|
return Ok(dto);
|
|
}
|
|
catch (VehiculeNotFoundException ex)
|
|
{
|
|
return Problem(detail: ex.Message, statusCode: StatusCodes.Status404NotFound);
|
|
}
|
|
}
|
|
}
|