< Summary

Information
Class: FAU.API.Controllers.RemuneracionesGradoController
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/RemuneracionesGradoController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 111
Coverable lines: 111
Total lines: 234
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 14
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%
GetTablaSalarial()100%210%
Get()0%620%
Put()0%2040%
ToUtcDate()100%210%
Post()0%7280%
ToUtcDate()100%210%

File(s)

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

#LineLine coverage
 1using FAU.DataAccess;
 2using FAU.Entidades;
 3using FAU.Logica.DTOs;
 4using Microsoft.AspNetCore.Authorization;
 5using Microsoft.AspNetCore.Mvc;
 6using Microsoft.EntityFrameworkCore;
 7
 8namespace FAU.API.Controllers;
 9
 10[ApiController]
 11[Route("api/remuneraciones-grado")]
 12[Authorize(Roles = "Administrador")]
 13public class RemuneracionesGradoController : ControllerBase
 14{
 15    private readonly ApplicationDbContext _context;
 16    private readonly ILogger<RemuneracionesGradoController> _logger;
 17
 018    public RemuneracionesGradoController(
 019        ApplicationDbContext context,
 020        ILogger<RemuneracionesGradoController> logger)
 21    {
 022        _context = context;
 023        _logger = logger;
 024    }
 25
 26    // GET /api/remuneraciones-grado/tabla-salarial
 27    // Returns ALL remuneraciones_grado entries for 'por_grado' catalog items,
 28    // including the catalog item name and SIIF code for each.
 29    // Used by the admin UI to display the full salary instructivo table.
 30    [HttpGet("tabla-salarial")]
 31    public async Task<IActionResult> GetTablaSalarial()
 32    {
 33        try
 34        {
 035            var items = await _context.RemuneracionesGrado
 036                .AsNoTracking()
 037                .Include(r => r.Item)
 038                .Include(r => r.Grado)
 039                .Where(r => r.Item.FormulaCalculo == "por_grado" && r.Item.Vigente)
 040                .OrderBy(r => r.Item.OrdenCalculo)
 041                .ThenBy(r => r.Grado.Orden)
 042                .ThenBy(r => r.VigenteDesde)
 043                .Select(r => new TablaSalarialItemDto
 044                {
 045                    Id = r.Id,
 046                    GradoId = r.GradoId,
 047                    GradoCodigo = r.Grado.Codigo,
 048                    GradoNombre = r.Grado.Denominacion,
 049                    ClasificacionSiif = r.Item.ClasificacionSiif!,
 050                    NombreOg = r.Item.Nombre,
 051                    OrdenOg = r.Item.OrdenCalculo,
 052                    Monto = r.Monto,
 053                    VigenteDesde = r.VigenteDesde,
 054                    VigenteHasta = r.VigenteHasta
 055                })
 056                .ToListAsync();
 57
 058            return Ok(ApiResponse<IEnumerable<TablaSalarialItemDto>>.SuccessResult(items));
 59        }
 060        catch (Exception ex)
 61        {
 062            _logger.LogError(ex, "Error al obtener tabla salarial completa");
 063            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 64        }
 065    }
 66
 67    // GET /api/remuneraciones-grado?siif=015.000
 68    [HttpGet]
 69    public async Task<IActionResult> Get([FromQuery] string siif)
 70    {
 071        if (string.IsNullOrWhiteSpace(siif))
 072            return BadRequest(ApiResponse<string>.ErrorResult("El parámetro 'siif' es obligatorio."));
 73
 74        try
 75        {
 076            var items = await _context.RemuneracionesGrado
 077                .AsNoTracking()
 078                .Include(r => r.Item)
 079                .Include(r => r.Grado)
 080                .Where(r => r.Item.ClasificacionSiif == siif)
 081                .OrderBy(r => r.Grado.Orden)
 082                .ThenBy(r => r.VigenteDesde)
 083                .Select(r => new RemuneracionGradoDto
 084                {
 085                    Id = r.Id,
 086                    GradoId = r.GradoId,
 087                    GradoCodigo = r.Grado.Codigo,
 088                    GradoNombre = r.Grado.Denominacion,
 089                    ClasificacionSiif = r.Item.ClasificacionSiif!,
 090                    Monto = r.Monto,
 091                    VigenteDesde = r.VigenteDesde,
 092                    VigenteHasta = r.VigenteHasta
 093                })
 094                .ToListAsync();
 95
 096            return Ok(ApiResponse<IEnumerable<RemuneracionGradoDto>>.SuccessResult(items));
 97        }
 098        catch (Exception ex)
 99        {
 0100            _logger.LogError(ex, "Error al obtener remuneraciones por grado para SIIF {Siif}", siif);
 0101            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 102        }
 0103    }
 104
 105    // PUT /api/remuneraciones-grado/{id}
 106    [HttpPut("{id:long}")]
 107    public async Task<IActionResult> Put(long id, [FromBody] ActualizarRemuneracionGradoRequest request)
 108    {
 109        try
 110        {
 0111            var entidad = await _context.RemuneracionesGrado.FindAsync(id);
 0112            if (entidad is null)
 0113                return NotFound(ApiResponse<string>.ErrorResult("Remuneración no encontrada."));
 114
 115            static DateTime ToUtcDate(DateTime d) =>
 0116                DateTime.SpecifyKind(d.Date, DateTimeKind.Utc);
 117
 0118            entidad.Monto = request.Monto;
 0119            entidad.VigenteDesde = ToUtcDate(request.VigenteDesde);
 0120            entidad.VigenteHasta = request.VigenteHasta.HasValue ? ToUtcDate(request.VigenteHasta.Value) : null;
 121
 0122            await _context.SaveChangesAsync();
 123
 0124            return Ok(ApiResponse<string>.SuccessResult("ok", "Remuneración actualizada correctamente."));
 125        }
 0126        catch (Exception ex)
 127        {
 0128            _logger.LogError(ex, "Error al actualizar remuneración {Id}", id);
 0129            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 130        }
 0131    }
 132
 133    // POST /api/remuneraciones-grado
 134    [HttpPost]
 135    public async Task<IActionResult> Post([FromBody] CrearRemuneracionGradoRequest request)
 136    {
 0137        if (string.IsNullOrWhiteSpace(request.ClasificacionSiif))
 0138            return BadRequest(ApiResponse<string>.ErrorResult("ClasificacionSiif es obligatorio."));
 139
 140        try
 141        {
 0142            var item = await _context.CatalogoItems
 0143                .AsNoTracking()
 0144                .Where(c => c.ClasificacionSiif == request.ClasificacionSiif && c.Vigente)
 0145                .OrderBy(c => c.OrdenCalculo)
 0146                .FirstOrDefaultAsync();
 147
 0148            if (item is null)
 0149                return BadRequest(ApiResponse<string>.ErrorResult(
 0150                    $"No existe ítem de catálogo vigente con clasificación SIIF '{request.ClasificacionSiif}'."));
 151
 0152            var gradoExiste = await _context.Grados.AnyAsync(g => g.Id == request.GradoId);
 0153            if (!gradoExiste)
 0154                return BadRequest(ApiResponse<string>.ErrorResult(
 0155                    $"No existe el grado {request.GradoId}."));
 156
 157            static DateTime ToUtcDate(DateTime d) =>
 0158                DateTime.SpecifyKind(d.Date, DateTimeKind.Utc);
 159
 0160            var entidad = new RemuneracionGrado
 0161            {
 0162                GradoId = request.GradoId,
 0163                ItemId = item.Id,
 0164                Monto = request.Monto,
 0165                VigenteDesde = ToUtcDate(request.VigenteDesde),
 0166                VigenteHasta = request.VigenteHasta.HasValue ? ToUtcDate(request.VigenteHasta.Value) : null
 0167            };
 168
 0169            _context.RemuneracionesGrado.Add(entidad);
 0170            await _context.SaveChangesAsync();
 171
 0172            var dto = new RemuneracionGradoDto
 0173            {
 0174                Id = entidad.Id,
 0175                GradoId = entidad.GradoId,
 0176                ClasificacionSiif = request.ClasificacionSiif,
 0177                Monto = entidad.Monto,
 0178                VigenteDesde = entidad.VigenteDesde,
 0179                VigenteHasta = entidad.VigenteHasta
 0180            };
 181
 0182            return Ok(ApiResponse<RemuneracionGradoDto>.SuccessResult(dto, "Remuneración por grado registrada correctame
 183        }
 0184        catch (Exception ex)
 185        {
 0186            _logger.LogError(ex, "Error al registrar remuneración por grado");
 0187            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 188        }
 0189    }
 190}
 191
 192// ── DTOs ────────────────────────────────────────────────────────────────────
 193
 194public class ActualizarRemuneracionGradoRequest
 195{
 196    public decimal Monto { get; set; }
 197    public DateTime VigenteDesde { get; set; }
 198    public DateTime? VigenteHasta { get; set; }
 199}
 200
 201public class CrearRemuneracionGradoRequest
 202{
 203    public string ClasificacionSiif { get; set; } = string.Empty; // ej. "015.000"
 204    public long GradoId { get; set; }
 205    public decimal Monto { get; set; }
 206    public DateTime VigenteDesde { get; set; }
 207    public DateTime? VigenteHasta { get; set; }
 208}
 209
 210public class RemuneracionGradoDto
 211{
 212    public long Id { get; set; }
 213    public long GradoId { get; set; }
 214    public string GradoCodigo { get; set; } = string.Empty;
 215    public string GradoNombre { get; set; } = string.Empty;
 216    public string ClasificacionSiif { get; set; } = string.Empty;
 217    public decimal Monto { get; set; }
 218    public DateTime VigenteDesde { get; set; }
 219    public DateTime? VigenteHasta { get; set; }
 220}
 221
 222public class TablaSalarialItemDto
 223{
 224    public long Id { get; set; }
 225    public long GradoId { get; set; }
 226    public string GradoCodigo { get; set; } = string.Empty;
 227    public string GradoNombre { get; set; } = string.Empty;
 228    public string ClasificacionSiif { get; set; } = string.Empty;
 229    public string NombreOg { get; set; } = string.Empty;
 230    public int OrdenOg { get; set; }
 231    public decimal Monto { get; set; }
 232    public DateTime VigenteDesde { get; set; }
 233    public DateTime? VigenteHasta { get; set; }
 234}