< 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: 144
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.API.Security;
 2using FAU.Entidades;
 3using FAU.Logica.DTOs;
 4using FAU.Logica.Services;
 5using Microsoft.AspNetCore.Authorization;
 6using Microsoft.AspNetCore.Http;
 7using Microsoft.AspNetCore.Mvc;
 8
 9namespace FAU.API.Controllers;
 10
 11[ApiController]
 12[Route("api/liquidacion/organismos")]
 13[Authorize]
 14[Produces("application/json")]
 15public class ArchivoOrganismoController : ControllerBase
 16{
 17    private readonly IArchivoOrganismoService _service;
 18    private readonly IPeriodoService _periodoService;
 19    private readonly IAuditoriaService _auditoriaService;
 20    private readonly ICurrentUserContext _currentUser;
 21    private readonly ILogger<ArchivoOrganismoController> _logger;
 22
 923    public ArchivoOrganismoController(
 924        IArchivoOrganismoService service,
 925        IPeriodoService periodoService,
 926        IAuditoriaService auditoriaService,
 927        ICurrentUserContext currentUser,
 928        ILogger<ArchivoOrganismoController> logger)
 29    {
 930        _service          = service;
 931        _periodoService   = periodoService;
 932        _auditoriaService = auditoriaService;
 933        _currentUser      = currentUser;
 934        _logger           = logger;
 935    }
 36
 37    /// <summary>
 38    /// Vista previa del archivo BROU: filas con cuenta y excepciones sin cuenta.
 39    /// GET /api/liquidacion/organismos/{periodoId}/brou/preview
 40    /// </summary>
 41    [HttpGet("{periodoId}/brou/preview")]
 42    [RequirePermission(PermisoEnum.VerArchivosOrganismo)]
 43    [ProducesResponseType(typeof(ApiResponse<BrouPreviewDto>), StatusCodes.Status200OK)]
 44    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 45    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 46    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 47    public async Task<IActionResult> GetBrouPreview(long periodoId)
 48    {
 49        try
 50        {
 351            var periodo = await _periodoService.ObtenerPorIdAsync(periodoId);
 352            if (periodo == null)
 153                return NotFound(ApiResponse<string>.ErrorResult("Período no encontrado"));
 54
 255            if (periodo.Estado != Periodo.EstadoCerrada)
 156                return Conflict(ApiResponse<string>.ErrorResult(
 157                    "El período no está cerrado; los archivos para organismos solo están disponibles para períodos en es
 58
 159            var preview = await _service.ObtenerPreviewBrouAsync(periodoId);
 160            return Ok(ApiResponse<BrouPreviewDto>.SuccessResult(preview));
 61        }
 062        catch (Exception ex)
 63        {
 064            _logger.LogError(ex, "Error al obtener preview BROU del período {PeriodoId}", periodoId);
 065            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 66        }
 367    }
 68
 69    /// <summary>
 70    /// Descarga el archivo CSV BROU del período.
 71    /// GET /api/liquidacion/organismos/{periodoId}/brou
 72    /// </summary>
 73    [HttpGet("{periodoId}/brou")]
 74    [RequirePermission(PermisoEnum.VerArchivosOrganismo)]
 75    [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)]
 76    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 77    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 78    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 79    public async Task<IActionResult> GetBrouCsv(long periodoId)
 80    {
 81        try
 82        {
 383            var periodo = await _periodoService.ObtenerPorIdAsync(periodoId);
 384            if (periodo == null)
 185                return NotFound(ApiResponse<string>.ErrorResult("Período no encontrado"));
 86
 287            if (periodo.Estado != Periodo.EstadoCerrada)
 188                return Conflict(ApiResponse<string>.ErrorResult(
 189                    "El período no está cerrado; los archivos para organismos solo están disponibles para períodos en es
 90
 191            var csvBytes = await _service.GenerarCsvBrouAsync(periodoId);
 92
 193            await _auditoriaService.LogAuditoriaAsync(
 194                _currentUser.UserId ?? 0,
 195                AccionEnum.GenerarArchivoBrou,
 196                ContextoEnum.Liquidaciones,
 197                _currentUser.Host,
 198                entidad: "ArchivoBrou",
 199                entidadId: periodoId,
 1100                detalle: new { periodoId });
 101
 1102            var timestamp = DateTime.Now.ToString("yyyyMMddHHmm");
 1103            var fileName = $"brou_{periodo.Anio}_{periodo.Mes:D2}_{timestamp}.csv";
 1104            return File(csvBytes, "text/csv", fileName);
 105        }
 0106        catch (Exception ex)
 107        {
 0108            _logger.LogError(ex, "Error al generar CSV BROU del período {PeriodoId}", periodoId);
 0109            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 110        }
 3111    }
 112
 113    /// <summary>
 114    /// Retorna el resumen SIIF agrupado por programa × régimen.
 115    /// GET /api/liquidacion/organismos/{periodoId}/siif
 116    /// </summary>
 117    [HttpGet("{periodoId}/siif")]
 118    [RequirePermission(PermisoEnum.VerArchivosOrganismo)]
 119    [ProducesResponseType(typeof(ApiResponse<SiifResumenDto>), StatusCodes.Status200OK)]
 120    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 121    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 122    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 123    public async Task<IActionResult> GetSiifResumen(long periodoId)
 124    {
 125        try
 126        {
 3127            var periodo = await _periodoService.ObtenerPorIdAsync(periodoId);
 3128            if (periodo == null)
 1129                return NotFound(ApiResponse<string>.ErrorResult("Período no encontrado"));
 130
 2131            if (periodo.Estado != Periodo.EstadoCerrada)
 1132                return Conflict(ApiResponse<string>.ErrorResult(
 1133                    "El período no está cerrado; los archivos para organismos solo están disponibles para períodos en es
 134
 1135            var resumen = await _service.ObtenerResumenSiifAsync(periodoId);
 1136            return Ok(ApiResponse<SiifResumenDto>.SuccessResult(resumen));
 137        }
 0138        catch (Exception ex)
 139        {
 0140            _logger.LogError(ex, "Error al obtener resumen SIIF del período {PeriodoId}", periodoId);
 0141            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 142        }
 3143    }
 144}