< Summary

Information
Class: FAU.API.Controllers.PersonalController
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/PersonalController.cs
Line coverage
84%
Covered lines: 70
Uncovered lines: 13
Coverable lines: 83
Total lines: 278
Line coverage: 84.3%
Branch coverage
57%
Covered branches: 37
Total branches: 64
Branch coverage: 57.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetPersonal()50%66100%
GetPersonalDetalle()100%22100%
CreatePersonal()91.66%1212100%
UpdatePersonal()87.5%88100%
RegistrarBaja()87.5%88100%
RegistrarAscenso()87.5%88100%
GetReporteMovimientos()0%420200%

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/PersonalController.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/// <summary>
 11/// Gestión de personal militar
 12/// </summary>
 13[ApiController]
 14[Route("api/[controller]")]
 15[Authorize]
 16[Produces("application/json")]
 17public class PersonalController : ControllerBase
 18{
 19    private readonly IPersonalService _personalService;
 20    private readonly ILogger<PersonalController> _logger;
 21
 2222    public PersonalController(
 2223        IPersonalService personalService,
 2224        ILogger<PersonalController> logger)
 25    {
 2226        _personalService = personalService;
 2227        _logger = logger;
 2228    }
 29
 30    /// <summary>
 31    /// Listar personal con filtros y paginación
 32    /// GET /api/personal?buscar=&amp;cargoId=&amp;estado=&amp;ley=&amp;page=&amp;pageSize=&amp;orderBy=&amp;sort=
 33    /// </summary>
 34    [HttpGet]
 35    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 36    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 37    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 38    public async Task<IActionResult> GetPersonal(
 39        [FromQuery] string? buscar = null,
 40        [FromQuery] long? cargoId = null,
 41        [FromQuery] string? estado = null,
 42        [FromQuery] string? ley = null,
 43        [FromQuery] int page = 1,
 44        [FromQuery] int pageSize = 25,
 45        [FromQuery] string? orderBy = null,
 46        [FromQuery] string sort = "asc")
 47    {
 48        try
 49        {
 50            // Validación de parámetros
 351            if (page < 1) page = 1;
 352            if (pageSize < 1) pageSize = 25;
 353            if (pageSize > 100) pageSize = 100;
 54
 355            var result = await _personalService.GetPersonalListAsync(
 356                buscar, cargoId, estado, ley, page, pageSize, orderBy, sort);
 57
 258            return Ok(ApiResponse<object>.SuccessResult(result));
 59        }
 160        catch (Exception ex)
 61        {
 162            _logger.LogError(ex, "Error al obtener listado de personal");
 163            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 64        }
 365    }
 66
 67    /// <summary>
 68    /// Obtener detalle completo de personal
 69    /// GET /api/personal/{id}
 70    /// Retorna: {id, datosPersonales, datosLaborales, historial}
 71    /// </summary>
 72    [HttpGet("{id}")]
 73    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 74    [ProducesResponseType(typeof(ApiResponse<PersonalDetalleDto>), StatusCodes.Status200OK)]
 75    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 76    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 77    public async Task<IActionResult> GetPersonalDetalle(long id)
 78    {
 79        try
 80        {
 381            var detalle = await _personalService.GetDetalleAsync(id);
 82
 283            if (detalle == null)
 84            {
 185                return NotFound(ApiResponse<string>.ErrorResult("Personal no encontrado"));
 86            }
 87
 188            return Ok(ApiResponse<PersonalDetalleDto>.SuccessResult(detalle));
 89        }
 190        catch (Exception ex)
 91        {
 192            _logger.LogError(ex, "Error al obtener detalle de personal {Id}", id);
 193            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 94        }
 395    }
 96
 97    /// <summary>
 98    /// Alta de personal
 99    /// POST /api/personal
 100    /// Body: { ci, nombre, apellido, fechaNacimiento, email, telefono, direccion, codigoPostal, departamento, localidad
 101    /// Response: { id, creado:true }
 102    /// </summary>
 103    [HttpPost]
 104    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 105    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status201Created)]
 106    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 107    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status409Conflict)]
 108    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 109    public async Task<IActionResult> CreatePersonal([FromBody] CreatePersonalRequest request)
 110    {
 111        try
 112        {
 4113            var (success, personalId, error) = await _personalService.CreatePersonalAsync(request);
 114
 3115            if (!success)
 116            {
 2117                if (error?.Contains("ya existe") == true || error?.Contains("única") == true)
 118                {
 1119                    return Conflict(ApiResponse<string>.ErrorResult(error));
 120                }
 1121                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al crear personal"));
 122            }
 123
 1124            return CreatedAtAction(
 1125                nameof(GetPersonalDetalle),
 1126                new { id = personalId },
 1127                ApiResponse<object>.SuccessResult(new { id = personalId, creado = true }));
 128        }
 1129        catch (Exception ex)
 130        {
 1131            _logger.LogError(ex, "Error al crear personal");
 1132            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 133        }
 4134    }
 135
 136    /// <summary>
 137    /// Modificar personal
 138    /// PUT /api/personal/{id}
 139    /// Body: { ...campos editables..., estado? }
 140    /// Response: { actualizado:true }
 141    /// </summary>
 142    [HttpPut("{id}")]
 143    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 144    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 145    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 146    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 147    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 148    public async Task<IActionResult> UpdatePersonal(long id, [FromBody] UpdatePersonalRequest request)
 149    {
 150        try
 151        {
 4152            var (success, error) = await _personalService.UpdatePersonalAsync(id, request);
 153
 3154            if (!success)
 155            {
 2156                if (error?.Contains("no encontrado") == true)
 157                {
 1158                    return NotFound(ApiResponse<string>.ErrorResult(error));
 159                }
 1160                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al actualizar personal"));
 161            }
 162
 1163            return Ok(ApiResponse<object>.SuccessResult(new { actualizado = true }));
 164        }
 1165        catch (Exception ex)
 166        {
 1167            _logger.LogError(ex, "Error al actualizar personal {Id}", id);
 1168            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 169        }
 4170    }
 171
 172    /// <summary>
 173    /// Registrar baja de personal
 174    /// DELETE /api/personal/{id}/baja
 175    /// Body: { motivoId, motivoBajaId, fechaBaja, observaciones }
 176    /// Response: { id, estado:'Inactivo' }
 177    /// </summary>
 178    [HttpDelete("{id}/baja")]
 179    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 180    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 181    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 182    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 183    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 184    public async Task<IActionResult> RegistrarBaja(long id, [FromBody] RegistrarBajaRequest request)
 185    {
 186        try
 187        {
 4188            var (success, error) = await _personalService.RegistrarBajaAsync(id, request);
 189
 3190            if (!success)
 191            {
 2192                if (error?.Contains("no encontrado") == true)
 193                {
 1194                    return NotFound(ApiResponse<string>.ErrorResult(error));
 195                }
 1196                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al registrar baja"));
 197            }
 198
 1199            return Ok(ApiResponse<object>.SuccessResult(
 1200                new { id = id, estado = "Inactivo" },
 1201                "Baja registrada exitosamente"));
 202        }
 1203        catch (Exception ex)
 204        {
 1205            _logger.LogError(ex, "Error al registrar baja de personal {Id}", id);
 1206            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 207        }
 4208    }
 209
 210    /// <summary>
 211    /// Registrar ascenso
 212    /// POST /api/personal/{id}/ascenso
 213    /// Body: { nuevoGradoId, fechaAscenso, Observacion, unidadId, leyId }
 214    /// Response: { id, gradoActualizado:true }
 215    /// </summary>
 216    [HttpPost("{id}/ascenso")]
 217    [Authorize(Roles = "Administrador,Supervisor,Usuario")]
 218    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 219    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 220    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status404NotFound)]
 221    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 222    public async Task<IActionResult> RegistrarAscenso(long id, [FromBody] FAU.Logica.DTOs.AscensoRequest request)
 223    {
 224        try
 225        {
 4226            var (success, error) = await _personalService.RegistrarAscensoAsync(id, request);
 227
 3228            if (!success)
 229            {
 2230                _logger.LogWarning("Error al registrar ascenso para PersonaId {Id}: {Error}", id, error);
 2231                if (error?.Contains("no encontrado") == true)
 232                {
 1233                    return NotFound(ApiResponse<string>.ErrorResult(error));
 234                }
 1235                return BadRequest(ApiResponse<string>.ErrorResult(error ?? "Error al registrar ascenso"));
 236            }
 237
 1238            return Ok(ApiResponse<object>.SuccessResult(new { id = id, gradoActualizado = true }, "Ascenso registrado ex
 239        }
 1240        catch (Exception ex)
 241        {
 1242            _logger.LogError(ex, "Error al registrar ascenso de personal {Id}", id);
 1243            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 244        }
 4245    }
 246
 247    /// GET /api/personal/reporte-movimientos?mes=5&amp;anio=2026&amp;tipo=todos
 248    [HttpGet("reporte-movimientos")]
 249    [Authorize(Roles = "Administrador,Supervisor")]
 250    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
 251    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status400BadRequest)]
 252    [ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status500InternalServerError)]
 253    public async Task<IActionResult> GetReporteMovimientos(
 254        [FromQuery] int mes,
 255        [FromQuery] int anio,
 256        [FromQuery] string? tipo = "todos")
 257    {
 0258        if (mes < 1 || mes > 12)
 0259            return BadRequest(ApiResponse<string>.ErrorResult("El mes debe estar entre 1 y 12"));
 0260        if (anio < 2000 || anio > 2100)
 0261            return BadRequest(ApiResponse<string>.ErrorResult("El año no es válido"));
 262
 0263        var tipoValido = tipo?.ToLower();
 0264        if (tipoValido != null && tipoValido != "todos" && tipoValido != "alta" && tipoValido != "baja" && tipoValido !=
 0265            return BadRequest(ApiResponse<string>.ErrorResult("El tipo debe ser: alta, baja, ascenso o todos"));
 266
 267        try
 268        {
 0269            var reporte = await _personalService.ObtenerReporteMovimientosAsync(mes, anio, tipoValido);
 0270            return Ok(ApiResponse<object>.SuccessResult(new { items = reporte, total = reporte.Count }));
 271        }
 0272        catch (Exception ex)
 273        {
 0274            _logger.LogError(ex, "Error al obtener reporte de movimientos mes={Mes} anio={Anio}", mes, anio);
 0275            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 276        }
 0277    }
 278}