< Summary

Information
Class: FAU.Logica.Services.TipoBeneficioService
Assembly: FAU.Logica
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/TipoBeneficioService.cs
Line coverage
100%
Covered lines: 143
Uncovered lines: 0
Coverable lines: 143
Total lines: 326
Line coverage: 100%
Branch coverage
95%
Covered branches: 69
Total branches: 72
Branch coverage: 95.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%
ObtenerPorIdAsync()100%11100%
ObtenerPaginadoAsync()87.5%88100%
CrearAsync()100%44100%
ActualizarAsync()100%3030100%
ActivarAsync()100%11100%
DesactivarAsync()100%11100%
EliminarAsync()100%66100%
CambiarEstadoAsync()100%44100%
RegistrarAuditoria(...)100%11100%
ValidarDatos(...)100%1212100%
EsViolacionCodigoDuplicado(...)75%88100%
MapearDto(...)100%11100%

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/TipoBeneficioService.cs

#LineLine coverage
 1using FAU.DataAccess.Repositories;
 2using FAU.Entidades;
 3using FAU.Logica.DTOs;
 4using Microsoft.EntityFrameworkCore;
 5
 6namespace FAU.Logica.Services;
 7
 8public class TipoBeneficioService : ITipoBeneficioService
 9{
 10    private readonly ITipoBeneficioRepository _tipoBeneficioRepository;
 11    private readonly IAuditoriaService _auditoriaService;
 12
 3013    public TipoBeneficioService(
 3014        ITipoBeneficioRepository tipoBeneficioRepository,
 3015        IAuditoriaService auditoriaService)
 16    {
 3017        _tipoBeneficioRepository = tipoBeneficioRepository;
 3018        _auditoriaService = auditoriaService;
 3019    }
 20
 21    public async Task<TipoBeneficio?> ObtenerPorIdAsync(long id)
 22    {
 123        return await _tipoBeneficioRepository.ObtenerPorIdAsync(id);
 124    }
 25
 26    public async Task<PagedResult<TipoBeneficioDto>> ObtenerPaginadoAsync(
 27        int pagina,
 28        int tamano,
 29        string? busqueda = null,
 30        bool? activo = null)
 31    {
 332        if (pagina < 1) pagina = 1;
 233        if (tamano < 1) tamano = 10;
 334        if (tamano > 100) tamano = 100;
 35
 236        var (items, totalCount) = await _tipoBeneficioRepository.ObtenerPaginadoAsync(pagina, tamano, busqueda, activo);
 37
 238        var itemsDto = items.Select(MapearDto).ToList();
 39
 240        return new PagedResult<TipoBeneficioDto>
 241        {
 242            Items = itemsDto,
 243            Page = pagina,
 244            PageSize = tamano,
 245            TotalCount = totalCount
 246        };
 247    }
 48
 49    public async Task<(bool Exito, TipoBeneficio? Resultado, string? Error)> CrearAsync(
 50        string codigo,
 51        string nombre,
 52        bool esMensual,
 53        bool permiteRetroactividad,
 54        short? plazoPresentacionDias,
 55        decimal? montoReferencia,
 56        long? catalogoItemId,
 57        bool activo,
 58        long usuarioId,
 59        string host)
 60    {
 61        try
 62        {
 863            var validacion = ValidarDatos(codigo, nombre, plazoPresentacionDias, montoReferencia);
 864            if (!string.IsNullOrEmpty(validacion))
 65            {
 466                return (false, null, validacion);
 67            }
 68
 469            var codigoNormalizado = codigo.Trim().ToUpperInvariant();
 470            if (await _tipoBeneficioRepository.ExisteCodigoAsync(codigoNormalizado))
 71            {
 172                return (false, null, "Ya existe un tipo de beneficio con ese codigo");
 73            }
 74
 375            var nuevoTipo = new TipoBeneficio
 376            {
 377                Codigo = codigoNormalizado,
 378                Nombre = nombre.Trim(),
 379                EsMensual = esMensual,
 380                PermiteRetroactividad = permiteRetroactividad,
 381                PlazoPresentacionDias = plazoPresentacionDias,
 382                MontoReferencia = montoReferencia,
 383                CatalogoItemId = catalogoItemId,
 384                Activo = activo
 385            };
 86
 387            var creado = await _tipoBeneficioRepository.CrearAsync(nuevoTipo);
 188            RegistrarAuditoria(usuarioId, (int)AccionEnum.CrearUsuario, host);
 89
 190            return (true, creado, null);
 91        }
 192        catch (DbUpdateException ex) when (EsViolacionCodigoDuplicado(ex))
 93        {
 194            return (false, null, "Ya existe un tipo de beneficio con ese codigo");
 95        }
 196        catch (Exception ex)
 97        {
 198            return (false, null, $"Error al crear tipo de beneficio: {ex.Message}");
 99        }
 8100    }
 101
 102    public async Task<(bool Exito, TipoBeneficio? Resultado, string? Error)> ActualizarAsync(
 103        long id,
 104        string? codigo,
 105        string? nombre,
 106        bool? esMensual,
 107        bool? permiteRetroactividad,
 108        short? plazoPresentacionDias,
 109        decimal? montoReferencia,
 110        long? catalogoItemId,
 111        long usuarioId,
 112        string host)
 113    {
 114        try
 115        {
 9116            var existente = await _tipoBeneficioRepository.ObtenerPorIdAsync(id);
 8117            if (existente == null)
 118            {
 1119                return (false, null, "Tipo de beneficio no encontrado");
 120            }
 121
 7122            if (codigo != null)
 123            {
 4124                if (string.IsNullOrWhiteSpace(codigo))
 125                {
 1126                    return (false, null, "El codigo es requerido");
 127                }
 128
 3129                var codigoNormalizado = codigo.Trim().ToUpperInvariant();
 3130                if (await _tipoBeneficioRepository.ExisteCodigoAsync(codigoNormalizado, id))
 131                {
 1132                    return (false, null, "Ya existe un tipo de beneficio con ese codigo");
 133                }
 134
 2135                existente.Codigo = codigoNormalizado;
 2136            }
 137
 5138            if (nombre != null)
 139            {
 2140                if (string.IsNullOrWhiteSpace(nombre))
 141                {
 1142                    return (false, null, "El nombre es requerido");
 143                }
 144
 1145                existente.Nombre = nombre.Trim();
 146            }
 147
 4148            if (plazoPresentacionDias.HasValue && plazoPresentacionDias.Value < 0)
 149            {
 1150                return (false, null, "El plazo de presentacion no puede ser negativo");
 151            }
 152
 3153            if (montoReferencia.HasValue && montoReferencia.Value < 0)
 154            {
 1155                return (false, null, "El monto de referencia no puede ser negativo");
 156            }
 157
 2158            if (esMensual.HasValue)
 159            {
 1160                existente.EsMensual = esMensual.Value;
 161            }
 162
 2163            if (permiteRetroactividad.HasValue)
 164            {
 1165                existente.PermiteRetroactividad = permiteRetroactividad.Value;
 166            }
 167
 2168            if (plazoPresentacionDias.HasValue)
 169            {
 1170                existente.PlazoPresentacionDias = plazoPresentacionDias;
 171            }
 172
 2173            if (montoReferencia.HasValue)
 174            {
 1175                existente.MontoReferencia = montoReferencia;
 176            }
 177
 2178            if (catalogoItemId.HasValue)
 179            {
 1180                existente.CatalogoItemId = catalogoItemId;
 181            }
 182
 2183            var actualizado = await _tipoBeneficioRepository.ActualizarAsync(existente);
 1184            RegistrarAuditoria(usuarioId, (int)AccionEnum.ActualizarUsuario, host);
 185
 1186            return (true, actualizado, null);
 187        }
 1188        catch (DbUpdateException ex) when (EsViolacionCodigoDuplicado(ex))
 189        {
 1190            return (false, null, "Ya existe un tipo de beneficio con ese codigo");
 191        }
 1192        catch (Exception ex)
 193        {
 1194            return (false, null, $"Error al actualizar tipo de beneficio: {ex.Message}");
 195        }
 9196    }
 197
 198    public async Task<(bool Exito, TipoBeneficio? Resultado, string? Error)> ActivarAsync(long id, long usuarioId, strin
 199    {
 3200        return await CambiarEstadoAsync(id, true, usuarioId, host);
 3201    }
 202
 203    public async Task<(bool Exito, TipoBeneficio? Resultado, string? Error)> DesactivarAsync(long id, long usuarioId, st
 204    {
 2205        return await CambiarEstadoAsync(id, false, usuarioId, host);
 2206    }
 207
 208    public async Task<(bool Exito, bool BajaLogica, string? Error)> EliminarAsync(long id, long usuarioId, string host)
 209    {
 210        try
 211        {
 5212            var existente = await _tipoBeneficioRepository.ObtenerPorIdAsync(id);
 4213            if (existente == null)
 214            {
 1215                return (false, false, "Tipo de beneficio no encontrado");
 216            }
 217
 3218            if (await _tipoBeneficioRepository.TieneLiquidacionesAbiertasAsync(id))
 219            {
 1220                return (false, false, "No se puede dar de baja porque existen liquidaciones abiertas relacionadas");
 221            }
 222
 2223            var tieneHistorico = await _tipoBeneficioRepository.TieneHistoricoBeneficiosAsync(id);
 2224            if (tieneHistorico)
 225            {
 1226                existente.Activo = false;
 1227                await _tipoBeneficioRepository.ActualizarAsync(existente);
 1228                RegistrarAuditoria(usuarioId, (int)AccionEnum.EliminarUsuario, host);
 1229                return (true, true, null);
 230            }
 231
 1232            await _tipoBeneficioRepository.EliminarAsync(id);
 1233            RegistrarAuditoria(usuarioId, (int)AccionEnum.EliminarUsuario, host);
 1234            return (true, false, null);
 235        }
 1236        catch (Exception ex)
 237        {
 1238            return (false, false, $"Error al eliminar tipo de beneficio: {ex.Message}");
 239        }
 5240    }
 241
 242    private async Task<(bool Exito, TipoBeneficio? Resultado, string? Error)> CambiarEstadoAsync(
 243        long id,
 244        bool nuevoEstado,
 245        long usuarioId,
 246        string host)
 247    {
 248        try
 249        {
 5250            var existente = await _tipoBeneficioRepository.ObtenerPorIdAsync(id);
 4251            if (existente == null)
 252            {
 1253                return (false, null, "Tipo de beneficio no encontrado");
 254            }
 255
 3256            if (await _tipoBeneficioRepository.TieneLiquidacionesAbiertasAsync(id))
 257            {
 1258                return (false, null, "No se puede cambiar el estado porque existen liquidaciones abiertas relacionadas")
 259            }
 260
 2261            existente.Activo = nuevoEstado;
 2262            var actualizado = await _tipoBeneficioRepository.ActualizarAsync(existente);
 2263            RegistrarAuditoria(usuarioId, (int)AccionEnum.ActualizarUsuario, host);
 264
 2265            return (true, actualizado, null);
 266        }
 1267        catch (Exception ex)
 268        {
 1269            return (false, null, $"Error al cambiar estado del tipo de beneficio: {ex.Message}");
 270        }
 5271    }
 272
 273    private void RegistrarAuditoria(long usuarioId, int accionId, string host)
 274    {
 6275        _auditoriaService.LogAuditoria(usuarioId, accionId, (int)ContextoEnum.Sistema, host);
 6276    }
 277
 278    private static string? ValidarDatos(string codigo, string nombre, short? plazoPresentacionDias, decimal? montoRefere
 279    {
 8280        if (string.IsNullOrWhiteSpace(codigo))
 281        {
 1282            return "El codigo es requerido";
 283        }
 284
 7285        if (string.IsNullOrWhiteSpace(nombre))
 286        {
 1287            return "El nombre es requerido";
 288        }
 289
 6290        if (plazoPresentacionDias.HasValue && plazoPresentacionDias.Value < 0)
 291        {
 1292            return "El plazo de presentacion no puede ser negativo";
 293        }
 294
 5295        if (montoReferencia.HasValue && montoReferencia.Value < 0)
 296        {
 1297            return "El monto de referencia no puede ser negativo";
 298        }
 299
 4300        return null;
 301    }
 302
 303    private static bool EsViolacionCodigoDuplicado(DbUpdateException ex)
 304    {
 2305        var mensaje = ex.InnerException?.Message ?? ex.Message;
 2306        return mensaje.Contains("ux_tipos_beneficio_codigo_upper", StringComparison.OrdinalIgnoreCase)
 2307               || mensaje.Contains("tipos_beneficio_codigo_key", StringComparison.OrdinalIgnoreCase)
 2308               || mensaje.Contains("duplicate key", StringComparison.OrdinalIgnoreCase);
 309    }
 310
 311    private static TipoBeneficioDto MapearDto(TipoBeneficio item)
 312    {
 1313        return new TipoBeneficioDto
 1314        {
 1315            Id = item.Id,
 1316            Codigo = item.Codigo,
 1317            Nombre = item.Nombre,
 1318            EsMensual = item.EsMensual,
 1319            PermiteRetroactividad = item.PermiteRetroactividad,
 1320            PlazoPresentacionDias = item.PlazoPresentacionDias,
 1321            MontoReferencia = item.MontoReferencia,
 1322            CatalogoItemId = item.CatalogoItemId,
 1323            Activo = item.Activo
 1324        };
 325    }
 326}