< Summary

Information
Class: FAU.Logica.Services.AguinaldoValidador
Assembly: FAU.Logica
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/AguinaldoValidador.cs
Line coverage
98%
Covered lines: 71
Uncovered lines: 1
Coverable lines: 72
Total lines: 119
Line coverage: 98.6%
Branch coverage
80%
Covered branches: 8
Total branches: 10
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ValidarHistoricoSemestralAsync()83.33%66100%
ObtenerMesesSemestre(...)75%4495.23%
FormatearMesAnio(...)100%11100%

File(s)

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

#LineLine coverage
 1using FAU.DataAccess;
 2using FAU.DataAccess.Repositories;
 3using FAU.Logica.DTOs;
 4using Microsoft.EntityFrameworkCore;
 5
 6namespace FAU.Logica.Services;
 7
 8public class AguinaldoValidador : IAguinaldoValidador
 9{
 10    private readonly IPersonalRepository _personalRepository;
 11    private readonly ApplicationDbContext _context;
 12
 613    public AguinaldoValidador(
 614        IPersonalRepository personalRepository,
 615        ApplicationDbContext context)
 16    {
 617        _personalRepository = personalRepository;
 618        _context = context;
 619    }
 20
 21    public async Task<AguinaldoValidacionDto> ValidarHistoricoSemestralAsync(CalcularAguinaldoSemestralRequest request)
 22    {
 623        var mesesSemestre = ObtenerMesesSemestre(request);
 624        var activos = (await _personalRepository.GetActivosAsync()).ToList();
 25
 1226        var personaIds = activos.Select(a => a.PersonaId).ToList();
 4227        var aniosSemestre = mesesSemestre.Select(m => m.Anio).Distinct().ToList();
 4228        var mesesIds = mesesSemestre.Select(m => m.Mes).Distinct().ToList();
 29
 30        // Fetch loose from DB (cross-year false positives filtered in memory)
 631        var mesesSet = mesesSemestre.ToHashSet();
 632        var registrosDb = await _context.HistoricoLiquidaciones
 633            .Where(h => personaIds.Contains(h.PersonaId)
 634                && aniosSemestre.Contains(h.Anio)
 635                && mesesIds.Contains(h.Mes))
 636            .Select(h => new { h.PersonaId, h.Anio, h.Mes })
 637            .ToListAsync();
 38
 639        var historicosPorPersona = registrosDb
 3140            .Where(h => mesesSet.Contains((h.Anio, h.Mes)))
 3141            .GroupBy(h => h.PersonaId)
 4942            .ToDictionary(g => g.Key, g => g.Select(h => (h.Anio, h.Mes)).ToHashSet());
 43
 644        var resultado = new AguinaldoValidacionDto
 645        {
 646            TotalPersonasActivas = activos.Count
 647        };
 48
 2449        foreach (var relacion in activos)
 50        {
 51            // Solo se exigen meses a partir del mes de ingreso del funcionario.
 52            // Un funcionario dado de alta en febrero no necesita diciembre ni enero.
 653            var inicioYearMonth = relacion.FechaInicio.Year * 12 + relacion.FechaInicio.Month;
 654            var mesesRequeridos = mesesSemestre
 3655                .Where(m => m.Anio * 12 + m.Mes >= inicioYearMonth)
 656                .ToList();
 57
 658            var mesesConHistorico = historicosPorPersona.TryGetValue(relacion.PersonaId, out var h)
 659                ? h
 660                : new HashSet<(short, short)>();
 61
 662            var faltantes = mesesRequeridos
 2963                .Where(m => !mesesConHistorico.Contains(m))
 664                .ToList();
 65
 666            if (faltantes.Any())
 67            {
 268                resultado.PersonasConHistoricoIncompleto++;
 269                resultado.Incidencias.Add(new AguinaldoIncidenciaDto
 270                {
 271                    Tipo = "HistoricoIncompleto",
 272                    Cedula = relacion.Persona.Cedula,
 273                    NombreCompleto = relacion.Persona.NombreCompleto,
 274                    MesesFaltantes = faltantes.Select(m => FormatearMesAnio(m.Anio, m.Mes)).ToList(),
 275                    Descripcion = "Faltan meses en el histórico de liquidaciones para el semestre seleccionado."
 276                });
 77            }
 78            else
 79            {
 480                resultado.PersonasListasParaCalcular++;
 81            }
 82        }
 83
 684        return resultado;
 685    }
 86
 87    private static IReadOnlyList<(short Anio, short Mes)> ObtenerMesesSemestre(CalcularAguinaldoSemestralRequest request
 88    {
 689        if (request.Mes == 6)
 90        {
 591            return new List<(short Anio, short Mes)>
 592            {
 593                ((short)(request.Anio - 1), (short)12),
 594                ((short)request.Anio, (short)1),
 595                ((short)request.Anio, (short)2),
 596                ((short)request.Anio, (short)3),
 597                ((short)request.Anio, (short)4),
 598                ((short)request.Anio, (short)5)
 599            };
 100        }
 101
 1102        if (request.Mes == 12)
 103        {
 1104            return new List<(short Anio, short Mes)>
 1105            {
 1106                ((short)request.Anio, (short)6),
 1107                ((short)request.Anio, (short)7),
 1108                ((short)request.Anio, (short)8),
 1109                ((short)request.Anio, (short)9),
 1110                ((short)request.Anio, (short)10),
 1111                ((short)request.Anio, (short)11)
 1112            };
 113        }
 114
 0115        throw new InvalidOperationException("El mes proporcionado no corresponde a un cierre de aguinaldo semestral.");
 116    }
 117
 2118    private static string FormatearMesAnio(short anio, short mes) => $"{mes:D2}/{anio:D4}";
 119}