< Summary

Information
Class: FAU.API.Controllers.InstructivosBeneficiosController
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/InstructivosBeneficiosController.cs
Line coverage
88%
Covered lines: 55
Uncovered lines: 7
Coverable lines: 62
Total lines: 202
Line coverage: 88.7%
Branch coverage
50%
Covered branches: 1
Total branches: 2
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetAsigFamiliar()100%11100%
ToFirstDayUtc(...)50%2266.66%
PostAsigFamiliar()100%11100%
GetPsf()100%11100%
PostPsf()100%1175%
GetHogar()100%11100%
PostHogar()100%1175%

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/InstructivosBeneficiosController.cs

#LineLine coverage
 1using FAU.Logica.DTOs;
 2using FAU.Logica.Services;
 3using Microsoft.AspNetCore.Authorization;
 4using Microsoft.AspNetCore.Http;
 5using Microsoft.AspNetCore.Mvc;
 6
 7namespace FAU.API.Controllers;
 8
 9[ApiController]
 10[Route("api/instructivos")]
 11[Authorize(Roles = "Administrador")]
 12[Produces("application/json")]
 13public class InstructivosBeneficiosController : ControllerBase
 14{
 15    private readonly IInstructivoBeneficiosService _service;
 16    private readonly ILogger<InstructivosBeneficiosController> _logger;
 17
 1518    public InstructivosBeneficiosController(
 1519        IInstructivoBeneficiosService service,
 1520        ILogger<InstructivosBeneficiosController> logger)
 21    {
 1522        _service = service;
 1523        _logger  = logger;
 1524    }
 25
 26    // ── Asignación Familiar ───────────────────────────────────────────────────
 27
 28    [HttpGet("asig-familiar")]
 29    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 30    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 31    public async Task<IActionResult> GetAsigFamiliar([FromQuery] bool vigente = true)
 32    {
 33        try
 34        {
 235            var items = await _service.ObtenerAsigFamiliarAsync(vigente);
 136            return Ok(ApiResponse<object>.SuccessResult(items));
 37        }
 138        catch (Exception ex)
 39        {
 140            _logger.LogError(ex, "Error al obtener instructivo asig. familiar");
 141            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 42        }
 243    }
 44
 45    private static DateTime ToFirstDayUtc(string vigenteDesdeStr)
 46    {
 47        // Parse YYYY-MM-DD directly to avoid timezone conversion issues
 48        // The frontend sends "YYYY-MM-01T00:00:00Z" so we extract year and month
 949        if (DateTime.TryParse(vigenteDesdeStr, out var dt))
 950            return DateTime.SpecifyKind(new DateTime(dt.Year, dt.Month, 1), DateTimeKind.Utc);
 051        throw new ArgumentException($"Formato de fecha inválido: {vigenteDesdeStr}");
 52    }
 53
 54    [HttpPost("asig-familiar")]
 55    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 56    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 57    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 58    public async Task<IActionResult> PostAsigFamiliar([FromBody] RegistrarAsigFamiliarRequest request)
 59    {
 60        try
 61        {
 362            var items = await _service.RegistrarAsigFamiliarAsync(
 363                ToFirstDayUtc(request.VigenteDesde.ToString()), request.Franja8, request.Franja16, request.Discapacidad)
 164            return Ok(ApiResponse<object>.SuccessResult(items, "Instructivo Asig. Familiar registrado correctamente"));
 65        }
 166        catch (ArgumentException ex)
 67        {
 168            return BadRequest(ApiResponse<string>.ErrorResult(ex.Message));
 69        }
 170        catch (Exception ex)
 71        {
 172            _logger.LogError(ex, "Error al registrar instructivo asig. familiar");
 173            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 74        }
 375    }
 76
 77    // ── PSF ───────────────────────────────────────────────────────────────────
 78
 79    [HttpGet("psf")]
 80    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 81    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 82    public async Task<IActionResult> GetPsf([FromQuery] bool vigente = true)
 83    {
 84        try
 85        {
 286            var items = await _service.ObtenerPsfAsync(vigente);
 187            return Ok(ApiResponse<object>.SuccessResult(items));
 88        }
 189        catch (Exception ex)
 90        {
 191            _logger.LogError(ex, "Error al obtener instructivo PSF");
 192            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 93        }
 294    }
 95
 96    [HttpPost("psf")]
 97    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 98    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 99    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 100    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 101    public async Task<IActionResult> PostPsf([FromBody] RegistrarPsfRequest request)
 102    {
 103        try
 104        {
 3105            var categorias = request.Categorias
 1106                .Select(c => ((short)c.NumeroCategoria, c.Descripcion, c.Importe))
 3107                .ToList()
 3108                .AsReadOnly();
 3109            var items = await _service.RegistrarPsfAsync(
 3110                ToFirstDayUtc(request.VigenteDesde.ToString()), categorias);
 1111            return Ok(ApiResponse<object>.SuccessResult(items, "Instructivo PSF registrado correctamente"));
 112        }
 2113        catch (ArgumentException ex)  { return BadRequest(ApiResponse<string>.ErrorResult(ex.Message)); }
 2114        catch (InvalidOperationException ex) { return Conflict(ApiResponse<string>.ErrorResult(ex.Message)); }
 0115        catch (Exception ex)
 116        {
 0117            _logger.LogError(ex, "Error al registrar instructivo PSF");
 0118            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 119        }
 3120    }
 121
 122    // ── Hogar Constituido ─────────────────────────────────────────────────────
 123
 124    [HttpGet("hogar")]
 125    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 126    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 127    public async Task<IActionResult> GetHogar([FromQuery] bool vigente = true)
 128    {
 129        try
 130        {
 2131            var items = await _service.ObtenerHogarAsync(vigente);
 1132            return Ok(ApiResponse<object>.SuccessResult(items));
 133        }
 1134        catch (Exception ex)
 135        {
 1136            _logger.LogError(ex, "Error al obtener tabla hogar constituido");
 1137            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 138        }
 2139    }
 140
 141    [HttpPost("hogar")]
 142    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 143    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 144    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 145    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 146    public async Task<IActionResult> PostHogar([FromBody] RegistrarHogarRequest request)
 147    {
 148        try
 149        {
 3150            var tramos = request.Tramos
 1151                .Select(t => (t.HastaHaberes, t.Importe, t.RefPorcentaje))
 3152                .ToList()
 3153                .AsReadOnly();
 3154            var items = await _service.RegistrarHogarAsync(
 3155                ToFirstDayUtc(request.VigenteDesde.ToString()), tramos);
 1156            return Ok(ApiResponse<object>.SuccessResult(items, "Tabla Hogar Constituido registrada correctamente"));
 157        }
 2158        catch (ArgumentException ex)  { return BadRequest(ApiResponse<string>.ErrorResult(ex.Message)); }
 2159        catch (InvalidOperationException ex) { return Conflict(ApiResponse<string>.ErrorResult(ex.Message)); }
 0160        catch (Exception ex)
 161        {
 0162            _logger.LogError(ex, "Error al registrar tabla hogar");
 0163            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 164        }
 3165    }
 166}
 167
 168// ── Request DTOs ──────────────────────────────────────────────────────────────
 169
 170public class RegistrarAsigFamiliarRequest
 171{
 172    public DateTime VigenteDesde { get; set; }
 173    public decimal Franja8 { get; set; }
 174    public decimal Franja16 { get; set; }
 175    public decimal Discapacidad { get; set; }
 176}
 177
 178public class RegistrarPsfRequest
 179{
 180    public DateTime VigenteDesde { get; set; }
 181    public List<PsfCategoriaRequest> Categorias { get; set; } = [];
 182}
 183
 184public class PsfCategoriaRequest
 185{
 186    public int NumeroCategoria { get; set; }
 187    public string Descripcion { get; set; } = string.Empty;
 188    public decimal Importe { get; set; }
 189}
 190
 191public class RegistrarHogarRequest
 192{
 193    public DateTime VigenteDesde { get; set; }
 194    public List<HogarTramoRequest> Tramos { get; set; } = [];
 195}
 196
 197public class HogarTramoRequest
 198{
 199    public decimal? HastaHaberes { get; set; }
 200    public decimal Importe { get; set; }
 201    public string? RefPorcentaje { get; set; }
 202}