< Summary

Information
Class: FAU.API.Controllers.AguinaldosController
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/AguinaldosController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 111
Coverable lines: 111
Total lines: 305
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 44
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
Validar()100%210%
Calcular()0%2040%
ValidarBaja()100%210%
CalcularBaja()0%2040%
CompletarHistorico()0%2040%
ObtenerPorPeriodoBaja()0%4260%
GenerarRecibosSemestral()0%210140%
GenerarReciboPdfSemestral()100%210%
GenerarRecibosBaja()0%4260%
GenerarPadronSemestral()0%4260%
GenerarReciboPdfBaja()100%210%

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/AguinaldosController.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/[controller]")]
 11[Authorize]
 12public class AguinaldosController : ControllerBase
 13{
 14    private readonly IAguinaldoSemestralService _service;
 15    private readonly IAguinaldoBajaService _bajaService;
 16    private readonly IAguinaldoHistoricoService _historicoService;
 17    private readonly IAguinaldoReciboService _reciboService;
 18    private readonly IAguinaldoPadronService _padronService;
 19    private readonly ILogger<AguinaldosController> _logger;
 20
 021    public AguinaldosController(
 022        IAguinaldoSemestralService service,
 023        IAguinaldoBajaService bajaService,
 024        IAguinaldoHistoricoService historicoService,
 025        IAguinaldoReciboService reciboService,
 026        IAguinaldoPadronService padronService,
 027        ILogger<AguinaldosController> logger)
 28    {
 029        _service = service;
 030        _bajaService = bajaService;
 031        _historicoService = historicoService;
 032        _reciboService = reciboService;
 033        _padronService = padronService;
 034        _logger = logger;
 035    }
 36
 37    [HttpPost("validar")]
 38    public async Task<IActionResult> Validar([FromBody] CalcularAguinaldoSemestralRequest request)
 39    {
 40        try
 41        {
 042            var resultado = await _service.ValidarHistoricoAsync(request);
 043            return Ok(ApiResponse<AguinaldoValidacionDto>.SuccessResult(resultado));
 44        }
 045        catch (Exception ex)
 46        {
 047            _logger.LogError(ex, "Error validando histórico de aguinaldo");
 048            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 49        }
 050    }
 51
 52    [HttpPost("calcular")]
 53    public async Task<IActionResult> Calcular([FromBody] CalcularAguinaldoSemestralRequest request)
 54    {
 55        try
 56        {
 057            var (success, resultados, error) = await _service.CalcularAguinaldoSemestralAsync(request);
 058            if (!success)
 59            {
 060                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error en cálculo"));
 61            }
 62
 063            return Ok(ApiResponse<IEnumerable<AguinaldoSemestralDto>>.SuccessResult(resultados));
 64        }
 065        catch (Exception ex)
 66        {
 067            _logger.LogError(ex, "Error calculando aguinaldo semestral");
 068            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 69        }
 070    }
 71
 72    [HttpPost("validar/baja")]
 73    public async Task<IActionResult> ValidarBaja([FromBody] CalcularAguinaldoBajaRequest request)
 74    {
 75        try
 76        {
 077            var resultado = await _bajaService.ValidarHistoricoAsync(request);
 078            return Ok(ApiResponse<AguinaldoValidacionDto>.SuccessResult(resultado));
 79        }
 080        catch (Exception ex)
 81        {
 082            _logger.LogError(ex, "Error validando histórico de aguinaldo por baja");
 083            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 84        }
 085    }
 86
 87    [HttpPost("calcular/baja")]
 88    public async Task<IActionResult> CalcularBaja([FromBody] CalcularAguinaldoBajaRequest request)
 89    {
 90        try
 91        {
 092            var (success, resultados, error) = await _bajaService.CalcularAguinaldoBajaAsync(request);
 093            if (!success)
 94            {
 095                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error en cálculo de aguinaldo por baja"));
 96            }
 97
 098            return Ok(ApiResponse<IEnumerable<AguinaldoBajaDto>>.SuccessResult(resultados));
 99        }
 0100        catch (Exception ex)
 101        {
 0102            _logger.LogError(ex, "Error calculando aguinaldo por baja");
 0103            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 104        }
 0105    }
 106
 107    [HttpPost("completar-historico")]
 108    public async Task<IActionResult> CompletarHistorico([FromBody] CompletarHistoricoAguinaldoRequest request)
 109    {
 110        try
 111        {
 0112            if (request.Funcionarios == null || !request.Funcionarios.Any())
 0113                return BadRequest(ApiResponse<string>.ErrorResult("La lista de funcionarios no puede estar vacía."));
 114
 0115            var resultado = await _historicoService.CompletarHistoricoAsync(request);
 0116            return Ok(ApiResponse<CompletarHistoricoAguinaldoResultadoDto>.SuccessResult(resultado));
 117        }
 0118        catch (Exception ex)
 119        {
 0120            _logger.LogError(ex, "Error completando histórico de aguinaldo");
 0121            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 122        }
 0123    }
 124
 125    [HttpGet("periodo/baja")]
 126    public async Task<IActionResult> ObtenerPorPeriodoBaja([FromQuery] int anio, [FromQuery] int mes)
 127    {
 128        try
 129        {
 0130            if (anio <= 0 || (mes != 6 && mes != 12))
 131            {
 0132                return BadRequest(ApiResponse<string>.ErrorResult("El período de consulta debe usar mes 6 o 12 y un año 
 133            }
 134
 0135            var resultados = await _bajaService.ObtenerPorPeriodoAsync(anio, mes);
 0136            return Ok(ApiResponse<IEnumerable<AguinaldoBajaDto>>.SuccessResult(resultados));
 137        }
 0138        catch (Exception ex)
 139        {
 0140            _logger.LogError(ex, "Error consultando aguinaldo por baja");
 0141            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 142        }
 0143    }
 144
 145    /// <summary>
 146    /// Genera un ZIP con los recibos PDF del aguinaldo semestral para los funcionarios indicados.
 147    /// Si PersonaIds es null o vacío, genera para todos los del período.
 148    /// POST /api/aguinaldos/recibos/semestral
 149    /// </summary>
 150    [HttpPost("recibos/semestral")]
 151    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 152    [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
 153    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 154    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 155    public async Task<IActionResult> GenerarRecibosSemestral([FromBody] GenerarRecibosAguinaldoSemestralRequest request)
 156    {
 157        try
 158        {
 0159            if (request.Anio <= 0 || (request.Semestre != 1 && request.Semestre != 2))
 0160                return BadRequest(ApiResponse<string>.ErrorResult("Año y semestre inválidos. El semestre debe ser 1 o 2.
 161
 0162            var personaIds = request.PersonaIds?.Count > 0 ? request.PersonaIds : null;
 163
 0164            if (personaIds?.Count == 1)
 165            {
 0166                var (pdfBytes, fileName) = await _reciboService.GenerarPdfSemestralAsync(
 0167                    personaIds[0], request.Anio, request.Semestre);
 0168                return File(pdfBytes, "application/pdf", fileName);
 169            }
 170
 0171            var (zipStream, zipName) = await _reciboService.GenerarLoteSemestralZipAsync(
 0172                request.Anio, request.Semestre, personaIds);
 0173            return File(zipStream, "application/zip", zipName);
 174        }
 0175        catch (KeyNotFoundException ex)
 176        {
 0177            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 178        }
 0179        catch (Exception ex)
 180        {
 0181            _logger.LogError(ex, "Error generando recibos de aguinaldo semestral");
 0182            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 183        }
 0184    }
 185
 186    /// <summary>
 187    /// Genera el PDF del recibo de aguinaldo semestral de un funcionario individual.
 188    /// GET /api/aguinaldos/recibos/semestral/{personaId}?anio=2026&amp;semestre=1
 189    /// </summary>
 190    [HttpGet("recibos/semestral/{personaId}")]
 191    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 192    [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
 193    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 194    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 195    public async Task<IActionResult> GenerarReciboPdfSemestral(
 196        long personaId,
 197        [FromQuery] int anio,
 198        [FromQuery] short semestre)
 199    {
 200        try
 201        {
 0202            var (pdfBytes, fileName) = await _reciboService.GenerarPdfSemestralAsync(personaId, anio, semestre);
 0203            return File(pdfBytes, "application/pdf", fileName);
 204        }
 0205        catch (KeyNotFoundException ex)
 206        {
 0207            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 208        }
 0209        catch (Exception ex)
 210        {
 0211            _logger.LogError(ex, "Error generando PDF de aguinaldo semestral para persona {PersonaId}", personaId);
 0212            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 213        }
 0214    }
 215
 216    /// <summary>
 217    /// Genera un ZIP con los recibos PDF de aguinaldo por baja para los ids indicados.
 218    /// POST /api/aguinaldos/recibos/baja
 219    /// </summary>
 220    [HttpPost("recibos/baja")]
 221    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 222    [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
 223    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 224    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 225    public async Task<IActionResult> GenerarRecibosBaja([FromBody] GenerarRecibosAguinaldoBajaRequest request)
 226    {
 227        try
 228        {
 0229            if (request.AguinaldoBajaIds == null || !request.AguinaldoBajaIds.Any())
 0230                return BadRequest(ApiResponse<string>.ErrorResult("Debe indicar al menos un id de aguinaldo por baja."))
 231
 0232            if (request.AguinaldoBajaIds.Count == 1)
 233            {
 0234                var (pdfBytes, fileName) = await _reciboService.GenerarPdfBajaAsync(request.AguinaldoBajaIds[0]);
 0235                return File(pdfBytes, "application/pdf", fileName);
 236            }
 237
 0238            var (zipStream, zipName) = await _reciboService.GenerarLoteBajaZipAsync(request.AguinaldoBajaIds);
 0239            return File(zipStream, "application/zip", zipName);
 240        }
 0241        catch (KeyNotFoundException ex)
 242        {
 0243            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 244        }
 0245        catch (Exception ex)
 246        {
 0247            _logger.LogError(ex, "Error generando recibos de aguinaldo por baja");
 0248            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 249        }
 0250    }
 251
 252    /// <summary>
 253    /// Genera el padrón de aguinaldo semestral en formato Excel.
 254    /// Incluye listado de funcionarios con sus montos, totales generales y subtotales por situación, unidad y grado.
 255    /// GET /api/aguinaldos/padron/semestral?anio=2026&amp;mes=6
 256    /// </summary>
 257    [HttpGet("padron/semestral")]
 258    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 259    [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
 260    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 261    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 262    public async Task<IActionResult> GenerarPadronSemestral([FromQuery] int anio, [FromQuery] int mes)
 263    {
 264        try
 265        {
 0266            if (anio <= 0 || (mes != 6 && mes != 12))
 0267                return BadRequest(ApiResponse<string>.ErrorResult("El año debe ser válido y el mes debe ser 6 o 12."));
 268
 0269            var (bytes, fileName) = await _padronService.GenerarPadronExcelAsync(anio, mes);
 0270            return File(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
 271        }
 0272        catch (Exception ex)
 273        {
 0274            _logger.LogError(ex, "Error generando padrón de aguinaldo semestral {Anio}/{Mes}", anio, mes);
 0275            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 276        }
 0277    }
 278
 279    /// <summary>
 280    /// Genera el PDF del recibo de aguinaldo por baja individual.
 281    /// GET /api/aguinaldos/recibos/baja/{aguinaldoBajaId}
 282    /// </summary>
 283    [HttpGet("recibos/baja/{aguinaldoBajaId}")]
 284    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 285    [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
 286    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 287    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 288    public async Task<IActionResult> GenerarReciboPdfBaja(long aguinaldoBajaId)
 289    {
 290        try
 291        {
 0292            var (pdfBytes, fileName) = await _reciboService.GenerarPdfBajaAsync(aguinaldoBajaId);
 0293            return File(pdfBytes, "application/pdf", fileName);
 294        }
 0295        catch (KeyNotFoundException ex)
 296        {
 0297            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 298        }
 0299        catch (Exception ex)
 300        {
 0301            _logger.LogError(ex, "Error generando PDF de aguinaldo por baja {AguinaldoBajaId}", aguinaldoBajaId);
 0302            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 303        }
 0304    }
 305}