< Summary

Information
Class: FAU.API.Controllers.ArchivoOrganismoController
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/ArchivoOrganismoController.cs
Line coverage
84%
Covered lines: 49
Uncovered lines: 9
Coverable lines: 58
Total lines: 143
Line coverage: 84.4%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetBrouPreview()100%4475%
GetBrouCsv()100%4486.36%
GetSiifResumen()100%4475%

File(s)

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

#LineLine coverage
 1using FAU.Entidades;
 2using FAU.Logica.DTOs;
 3using FAU.Logica.Services;
 4using Microsoft.AspNetCore.Authorization;
 5using Microsoft.AspNetCore.Http;
 6using Microsoft.AspNetCore.Mvc;
 7
 8namespace FAU.API.Controllers;
 9
 10[ApiController]
 11[Route("api/liquidacion/organismos")]
 12[Authorize]
 13[Produces("application/json")]
 14public class ArchivoOrganismoController : ControllerBase
 15{
 16    private readonly IArchivoOrganismoService _service;
 17    private readonly IPeriodoService _periodoService;
 18    private readonly IAuditoriaService _auditoriaService;
 19    private readonly ICurrentUserContext _currentUser;
 20    private readonly ILogger<ArchivoOrganismoController> _logger;
 21
 922    public ArchivoOrganismoController(
 923        IArchivoOrganismoService service,
 924        IPeriodoService periodoService,
 925        IAuditoriaService auditoriaService,
 926        ICurrentUserContext currentUser,
 927        ILogger<ArchivoOrganismoController> logger)
 28    {
 929        _service          = service;
 930        _periodoService   = periodoService;
 931        _auditoriaService = auditoriaService;
 932        _currentUser      = currentUser;
 933        _logger           = logger;
 934    }
 35
 36    /// <summary>
 37    /// Vista previa del archivo BROU: filas con cuenta y excepciones sin cuenta.
 38    /// GET /api/liquidacion/organismos/{periodoId}/brou/preview
 39    /// </summary>
 40    [HttpGet("{periodoId}/brou/preview")]
 41    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 42    [ProducesResponseType(typeof(ApiResponse<BrouPreviewDto>), StatusCodes.Status200OK)]
 43    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 44    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 45    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 46    public async Task<IActionResult> GetBrouPreview(long periodoId)
 47    {
 48        try
 49        {
 350            var periodo = await _periodoService.ObtenerPorIdAsync(periodoId);
 351            if (periodo == null)
 152                return NotFound(ApiResponse<string>.ErrorResult("Período no encontrado"));
 53
 254            if (periodo.Estado != Periodo.EstadoCerrada)
 155                return Conflict(ApiResponse<string>.ErrorResult(
 156                    "El período no está cerrado; los archivos para organismos solo están disponibles para períodos en es
 57
 158            var preview = await _service.ObtenerPreviewBrouAsync(periodoId);
 159            return Ok(ApiResponse<BrouPreviewDto>.SuccessResult(preview));
 60        }
 061        catch (Exception ex)
 62        {
 063            _logger.LogError(ex, "Error al obtener preview BROU del período {PeriodoId}", periodoId);
 064            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 65        }
 366    }
 67
 68    /// <summary>
 69    /// Descarga el archivo CSV BROU del período.
 70    /// GET /api/liquidacion/organismos/{periodoId}/brou
 71    /// </summary>
 72    [HttpGet("{periodoId}/brou")]
 73    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 74    [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
 75    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 76    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 77    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 78    public async Task<IActionResult> GetBrouCsv(long periodoId)
 79    {
 80        try
 81        {
 382            var periodo = await _periodoService.ObtenerPorIdAsync(periodoId);
 383            if (periodo == null)
 184                return NotFound(ApiResponse<string>.ErrorResult("Período no encontrado"));
 85
 286            if (periodo.Estado != Periodo.EstadoCerrada)
 187                return Conflict(ApiResponse<string>.ErrorResult(
 188                    "El período no está cerrado; los archivos para organismos solo están disponibles para períodos en es
 89
 190            var csvBytes = await _service.GenerarCsvBrouAsync(periodoId);
 91
 192            await _auditoriaService.LogAuditoriaAsync(
 193                _currentUser.UserId ?? 0,
 194                AccionEnum.GenerarArchivoBrou,
 195                ContextoEnum.Liquidaciones,
 196                _currentUser.Host,
 197                entidad: "ArchivoBrou",
 198                entidadId: periodoId,
 199                detalle: new { periodoId });
 100
 1101            var timestamp = DateTime.Now.ToString("yyyyMMddHHmm");
 1102            var fileName = $"brou_{periodo.Anio}_{periodo.Mes:D2}_{timestamp}.csv";
 1103            return File(csvBytes, "text/csv", fileName);
 104        }
 0105        catch (Exception ex)
 106        {
 0107            _logger.LogError(ex, "Error al generar CSV BROU del período {PeriodoId}", periodoId);
 0108            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 109        }
 3110    }
 111
 112    /// <summary>
 113    /// Retorna el resumen SIIF agrupado por programa × régimen.
 114    /// GET /api/liquidacion/organismos/{periodoId}/siif
 115    /// </summary>
 116    [HttpGet("{periodoId}/siif")]
 117    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 118    [ProducesResponseType(typeof(ApiResponse<SiifResumenDto>), StatusCodes.Status200OK)]
 119    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 120    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 121    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 122    public async Task<IActionResult> GetSiifResumen(long periodoId)
 123    {
 124        try
 125        {
 3126            var periodo = await _periodoService.ObtenerPorIdAsync(periodoId);
 3127            if (periodo == null)
 1128                return NotFound(ApiResponse<string>.ErrorResult("Período no encontrado"));
 129
 2130            if (periodo.Estado != Periodo.EstadoCerrada)
 1131                return Conflict(ApiResponse<string>.ErrorResult(
 1132                    "El período no está cerrado; los archivos para organismos solo están disponibles para períodos en es
 133
 1134            var resumen = await _service.ObtenerResumenSiifAsync(periodoId);
 1135            return Ok(ApiResponse<SiifResumenDto>.SuccessResult(resumen));
 136        }
 0137        catch (Exception ex)
 138        {
 0139            _logger.LogError(ex, "Error al obtener resumen SIIF del período {PeriodoId}", periodoId);
 0140            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 141        }
 3142    }
 143}