< Summary

Information
Class: FAU.API.Controllers.DescuentosPersonalesController
Assembly: FAU.API
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.API/Controllers/DescuentosPersonalesController.cs
Line coverage
76%
Covered lines: 86
Uncovered lines: 27
Coverable lines: 113
Total lines: 284
Line coverage: 76.1%
Branch coverage
28%
Covered branches: 8
Total branches: 28
Branch coverage: 28.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Crear()62.5%8880.64%
Listar()50%3250%
Editar()50%2257.14%
Eliminar()100%1150%
ConfirmarUno()100%1158.33%
Confirmar()50%2290%

File(s)

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

#LineLine coverage
 1using FAU.Entidades;
 2using FAU.Logica.DTOs;
 3using FAU.Logica.Services;
 4using Microsoft.AspNetCore.Authorization;
 5using Microsoft.AspNetCore.Mvc;
 6using System.ComponentModel.DataAnnotations;
 7
 8namespace FAU.API.Controllers;
 9
 10/// <summary>
 11/// Gestión de descuentos personales del período
 12/// </summary>
 13[ApiController]
 14[Route("api/descuentos-personales")]
 15[Authorize]
 16public class DescuentosPersonalesController : ControllerBase
 17{
 18    private readonly IDescuentoPersonalService _service;
 19    private readonly ICurrentUserContext _currentUser;
 20    private readonly ILogger<DescuentosPersonalesController> _logger;
 21
 1322    public DescuentosPersonalesController(
 1323        IDescuentoPersonalService service,
 1324        ICurrentUserContext currentUser,
 1325        ILogger<DescuentosPersonalesController> logger)
 26    {
 1327        _service = service;
 1328        _currentUser = currentUser;
 1329        _logger = logger;
 1330    }
 31
 32    /// <summary>
 33    /// Crear un descuento personal en borrador
 34    /// POST /api/descuentos-personales
 35    /// </summary>
 36    [HttpPost]
 37    [FAU.API.Security.RequirePermission(PermisoEnum.CrearDescuentosPersonales)]
 38    public async Task<IActionResult> Crear([FromBody] CrearDescuentoPersonalRequest request)
 39    {
 40        try
 41        {
 442            if (request.PeriodoId <= 0)
 043                return BadRequest(ApiResponse<string>.ErrorResult("periodoId es requerido"));
 444            if (string.IsNullOrWhiteSpace(request.CedulaTitular))
 045                return BadRequest(ApiResponse<string>.ErrorResult("cedulaTitular es requerida"));
 446            if (request.AcreedorId <= 0)
 047                return BadRequest(ApiResponse<string>.ErrorResult("acreedorId es requerido"));
 448            if (request.Importe <= 0)
 149                return BadRequest(ApiResponse<string>.ErrorResult("importe debe ser mayor a cero"));
 50
 351            var usuarioId = _currentUser.UserId ?? 0;
 352            var creado = await _service.CrearAsync(
 353                request.PeriodoId,
 354                request.CedulaTitular,
 355                request.CodigoConcepto,
 356                request.AcreedorId,
 357                request.Importe,
 358                request.Observaciones,
 359                usuarioId);
 60
 161            return CreatedAtAction(
 162                nameof(Listar),
 163                new { periodoId = request.PeriodoId },
 164                ApiResponse<object>.SuccessResult(
 165                    new { id = creado.Id, creado = true },
 166                    "Descuento personal creado exitosamente"));
 67        }
 168        catch (ArgumentException ex)
 69        {
 170            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 71        }
 172        catch (InvalidOperationException ex)
 73        {
 174            return Conflict(ApiResponse<string>.ErrorResult(ex.Message));
 75        }
 076        catch (Exception ex)
 77        {
 078            _logger.LogError(ex, "Error al crear descuento personal");
 079            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 80        }
 481    }
 82
 83    /// <summary>
 84    /// Listar descuentos personales del período
 85    /// GET /api/descuentos-personales?periodoId=...&cedulaTitular=...&codigoConcepto=...&estado=...
 86    /// </summary>
 87    [HttpGet]
 88    [FAU.API.Security.RequirePermission(PermisoEnum.VerDescuentosPersonales)]
 89    public async Task<IActionResult> Listar(
 90        [FromQuery] long periodoId,
 91        [FromQuery] string? cedulaTitular = null,
 92        [FromQuery] int? codigoConcepto = null,
 93        [FromQuery] string? estado = null)
 94    {
 95        try
 96        {
 197            if (periodoId <= 0)
 098                return BadRequest(ApiResponse<string>.ErrorResult("periodoId es requerido"));
 99
 1100            var items = await _service.ListarAsync(periodoId, cedulaTitular, codigoConcepto, estado);
 101
 1102            var response = items.Select(d => new
 1103            {
 1104                id = d.Id,
 1105                periodoId = d.PeriodoId,
 1106                personaId = d.PersonaId,
 1107                cedula = d.Persona?.Cedula,
 1108                nombreCompleto = d.Persona?.NombreCompleto,
 1109                acreedorId = d.AcreedorId,
 1110                acreedorCodigo = d.Acreedor?.Codigo,
 1111                acreedorNombre = d.Acreedor?.Nombre,
 1112                prioridadDeficit = d.Acreedor?.PrioridadDeficit,
 1113                catalogoItemId = d.CatalogoItemId,
 1114                codigoConcepto = d.CatalogoItem?.Codigo,
 1115                nombreConcepto = d.CatalogoItem?.Nombre,
 1116                importe = d.Importe,
 1117                estado = d.Estado,
 1118                observaciones = d.Observaciones,
 1119                fechaCreacion = d.FechaCreacion,
 1120                usuarioCreacionId = d.UsuarioCreacionId
 1121            });
 122
 1123            return Ok(ApiResponse<object>.SuccessResult(response));
 124        }
 0125        catch (Exception ex)
 126        {
 0127            _logger.LogError(ex, "Error al listar descuentos personales");
 0128            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 129        }
 1130    }
 131
 132    /// <summary>
 133    /// Editar un descuento personal en borrador
 134    /// PUT /api/descuentos-personales/{id}
 135    /// </summary>
 136    [HttpPut("{id}")]
 137    [FAU.API.Security.RequirePermission(PermisoEnum.ActualizarDescuentosPersonales)]
 138    public async Task<IActionResult> Editar(long id, [FromBody] EditarDescuentoPersonalRequest request)
 139    {
 140        try
 141        {
 2142            if (request.Importe <= 0)
 0143                return BadRequest(ApiResponse<string>.ErrorResult("importe debe ser mayor a cero"));
 144
 2145            var actualizado = await _service.EditarAsync(id, request.Importe, request.Observaciones);
 1146            return Ok(ApiResponse<object>.SuccessResult(
 1147                new { id = actualizado.Id, actualizado = true },
 1148                "Descuento personal actualizado exitosamente"));
 149        }
 0150        catch (ArgumentException ex)
 151        {
 0152            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 153        }
 1154        catch (InvalidOperationException ex)
 155        {
 1156            return Conflict(ApiResponse<string>.ErrorResult(ex.Message));
 157        }
 0158        catch (Exception ex)
 159        {
 0160            _logger.LogError(ex, "Error al actualizar descuento personal {Id}", id);
 0161            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 162        }
 2163    }
 164
 165    /// <summary>
 166    /// Eliminar un descuento personal en borrador
 167    /// DELETE /api/descuentos-personales/{id}
 168    /// </summary>
 169    [HttpDelete("{id}")]
 170    [FAU.API.Security.RequirePermission(PermisoEnum.ActualizarDescuentosPersonales)]
 171    public async Task<IActionResult> Eliminar(long id)
 172    {
 173        try
 174        {
 2175            await _service.EliminarAsync(id);
 1176            return NoContent();
 177        }
 0178        catch (ArgumentException ex)
 179        {
 0180            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 181        }
 1182        catch (InvalidOperationException ex)
 183        {
 1184            return Conflict(ApiResponse<string>.ErrorResult(ex.Message));
 185        }
 0186        catch (Exception ex)
 187        {
 0188            _logger.LogError(ex, "Error al eliminar descuento personal {Id}", id);
 0189            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 190        }
 2191    }
 192
 193    /// <summary>
 194    /// Confirmar un descuento personal en borrador
 195    /// POST /api/descuentos-personales/{id}/confirmar
 196    /// </summary>
 197    [HttpPost("{id}/confirmar")]
 198    [FAU.API.Security.RequirePermission(PermisoEnum.ConfirmarDescuentosPersonales)]
 199    public async Task<IActionResult> ConfirmarUno(long id)
 200    {
 201        try
 202        {
 2203            var confirmado = await _service.ConfirmarAsync(id);
 1204            return Ok(ApiResponse<object>.SuccessResult(
 1205                new { confirmado = true },
 1206                $"Descuento personal {confirmado.Id} confirmado exitosamente"));
 207        }
 0208        catch (ArgumentException ex)
 209        {
 0210            return NotFound(ApiResponse<string>.ErrorResult(ex.Message));
 211        }
 1212        catch (InvalidOperationException ex)
 213        {
 1214            return Conflict(ApiResponse<string>.ErrorResult(ex.Message));
 215        }
 0216        catch (Exception ex)
 217        {
 0218            _logger.LogError(ex, "Error al confirmar descuento personal {Id}", id);
 0219            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 220        }
 2221    }
 222
 223    /// <summary>
 224    /// Confirmar todos los borradores de un período
 225    /// POST /api/descuentos-personales/confirmar
 226    /// </summary>
 227    [HttpPost("confirmar")]
 228    [FAU.API.Security.RequirePermission(PermisoEnum.ConfirmarDescuentosPersonales)]
 229    public async Task<IActionResult> Confirmar([FromBody] ConfirmarDescuentosRequest request)
 230    {
 231        try
 232        {
 2233            if (request.PeriodoId <= 0)
 0234                return BadRequest(ApiResponse<string>.ErrorResult("periodoId es requerido"));
 235
 2236            var cantidad = await _service.ConfirmarBorradoresAsync(request.PeriodoId);
 1237            return Ok(ApiResponse<object>.SuccessResult(
 1238                new { confirmados = cantidad },
 1239                $"Se confirmaron {cantidad} descuento(s) personal(es)"));
 240        }
 1241        catch (Exception ex)
 242        {
 1243            _logger.LogError(ex, "Error al confirmar descuentos personales del período {PeriodoId}", request.PeriodoId);
 1244            return StatusCode(500, ApiResponse<string>.ErrorResult("Error interno del servidor"));
 245        }
 2246    }
 247}
 248
 249public class CrearDescuentoPersonalRequest
 250{
 251    [Required]
 252    public long PeriodoId { get; set; }
 253
 254    [Required]
 255    [MaxLength(12)]
 256    public string CedulaTitular { get; set; } = string.Empty;
 257
 258    [Required]
 259    public int CodigoConcepto { get; set; }
 260
 261    [Required]
 262    public long AcreedorId { get; set; }
 263
 264    [Required]
 265    public decimal Importe { get; set; }
 266
 267    [MaxLength(500)]
 268    public string? Observaciones { get; set; }
 269}
 270
 271public class EditarDescuentoPersonalRequest
 272{
 273    [Required]
 274    public decimal Importe { get; set; }
 275
 276    [MaxLength(500)]
 277    public string? Observaciones { get; set; }
 278}
 279
 280public class ConfirmarDescuentosRequest
 281{
 282    [Required]
 283    public long PeriodoId { get; set; }
 284}