| | | 1 | | using FAU.DataAccess; |
| | | 2 | | using FAU.Entidades; |
| | | 3 | | using FAU.Logica.DTOs; |
| | | 4 | | using Microsoft.EntityFrameworkCore; |
| | | 5 | | |
| | | 6 | | namespace FAU.Logica.Services; |
| | | 7 | | |
| | | 8 | | public class InsumosPeriodoLoader : IInsumosPeriodoLoader |
| | | 9 | | { |
| | | 10 | | private readonly ApplicationDbContext _context; |
| | | 11 | | |
| | 1 | 12 | | public InsumosPeriodoLoader(ApplicationDbContext context) |
| | | 13 | | { |
| | 1 | 14 | | _context = context; |
| | 1 | 15 | | } |
| | | 16 | | |
| | | 17 | | public async Task<InsumosPeriodo> CargarAsync(long periodoId) |
| | | 18 | | { |
| | 1 | 19 | | var periodo = await _context.PeriodosLiquidacion |
| | 1 | 20 | | .AsNoTracking() |
| | 1 | 21 | | .FirstOrDefaultAsync(p => p.Id == periodoId && p.Activo); |
| | | 22 | | |
| | 1 | 23 | | if (periodo is null) |
| | | 24 | | { |
| | 0 | 25 | | throw new InvalidOperationException($"Periodo de liquidación {periodoId} no encontrado o no está activo."); |
| | | 26 | | } |
| | | 27 | | |
| | 1 | 28 | | var periodoDate = new DateTime(periodo.Anio, periodo.Mes, 1); |
| | | 29 | | |
| | 1 | 30 | | var parametros = await _context.ParametrosPeriodo |
| | 1 | 31 | | .AsNoTracking() |
| | 1 | 32 | | .FirstOrDefaultAsync(pp => pp.Anio == periodo.Anio && pp.Mes == periodo.Mes); |
| | | 33 | | |
| | 1 | 34 | | if (parametros is null) |
| | | 35 | | { |
| | 0 | 36 | | throw new InvalidOperationException($"Parámetros de período para {periodo.Anio}/{periodo.Mes} no encontrados |
| | | 37 | | } |
| | | 38 | | |
| | 1 | 39 | | var catalogoItems = await _context.CatalogoItems |
| | 1 | 40 | | .AsNoTracking() |
| | 1 | 41 | | .ToListAsync(); |
| | | 42 | | |
| | 1 | 43 | | var remuneraciones = await _context.RemuneracionesGrado |
| | 1 | 44 | | .AsNoTracking() |
| | 1 | 45 | | .Include(r => r.Item) |
| | 1 | 46 | | .Where(r => r.VigenteDesde <= periodoDate && (r.VigenteHasta == null || r.VigenteHasta >= periodoDate)) |
| | 1 | 47 | | .ToListAsync(); |
| | | 48 | | |
| | 1 | 49 | | var permanencias = await _context.Set<TablaPermanencia>() |
| | 1 | 50 | | .AsNoTracking() |
| | 1 | 51 | | .Where(t => t.VigenteDesde <= periodoDate && (t.VigenteHasta == null || t.VigenteHasta >= periodoDate)) |
| | 1 | 52 | | .ToListAsync(); |
| | | 53 | | |
| | 1 | 54 | | var franjasIrpf = await _context.FranjasIrpf |
| | 1 | 55 | | .AsNoTracking() |
| | 1 | 56 | | .Where(f => f.VigenteDesde <= periodoDate && (f.VigenteHasta == null || f.VigenteHasta >= periodoDate)) |
| | 1 | 57 | | .OrderBy(f => f.NumeroFranja) |
| | 1 | 58 | | .ToListAsync(); |
| | | 59 | | |
| | 1 | 60 | | var beneficios = await _context.BeneficiosSociales |
| | 1 | 61 | | .AsNoTracking() |
| | 1 | 62 | | .Where(b => b.Estado == "activo" && b.VigenteDesde <= periodoDate && (b.VigenteHasta == null || b.VigenteHas |
| | 1 | 63 | | .ToListAsync(); |
| | | 64 | | |
| | 1 | 65 | | var tiposBeneficio = await _context.TiposBeneficio |
| | 1 | 66 | | .AsNoTracking() |
| | 1 | 67 | | .ToDictionaryAsync(t => t.Id); |
| | | 68 | | |
| | 4 | 69 | | foreach (var b in beneficios) |
| | | 70 | | { |
| | 1 | 71 | | if (tiposBeneficio.TryGetValue(b.TipoBeneficioId, out var tipo)) |
| | 0 | 72 | | b.TipoBeneficio = tipo; |
| | | 73 | | } |
| | | 74 | | |
| | | 75 | | // Cargar hijos registrados para beneficios de tipo Asignación Familiar |
| | 1 | 76 | | var idsAsigFamiliar = beneficios |
| | 1 | 77 | | .Where(b => b.TipoBeneficio is not null && |
| | 1 | 78 | | (b.TipoBeneficio.Codigo == "ASIGNACION_FAMILIAR" || |
| | 1 | 79 | | b.TipoBeneficio.Codigo.StartsWith("300") || |
| | 1 | 80 | | b.TipoBeneficio.Nombre.ToUpperInvariant().Contains("ASIGNACION FAMILIAR") || |
| | 1 | 81 | | b.TipoBeneficio.Nombre.ToUpperInvariant().Contains("ASIGNACIÓN FAMILIAR"))) |
| | 0 | 82 | | .Select(b => b.Id) |
| | 1 | 83 | | .ToHashSet(); |
| | | 84 | | |
| | 1 | 85 | | var beneficiariosAsigFam = idsAsigFamiliar.Count > 0 |
| | 1 | 86 | | ? await _context.BeneficioSocialBeneficiarios |
| | 1 | 87 | | .AsNoTracking() |
| | 1 | 88 | | .Where(bh => idsAsigFamiliar.Contains(bh.BeneficioId) && |
| | 1 | 89 | | bh.Activo && |
| | 1 | 90 | | bh.VigenteDesde <= periodoDate && |
| | 1 | 91 | | (bh.VigenteHasta == null || bh.VigenteHasta >= periodoDate)) |
| | 1 | 92 | | .ToListAsync() |
| | 1 | 93 | | : []; |
| | | 94 | | |
| | 1 | 95 | | var beneficiariosPorBeneficio = beneficiariosAsigFam |
| | 0 | 96 | | .GroupBy(bh => bh.BeneficioId) |
| | 1 | 97 | | .ToDictionary(g => g.Key, g => (IReadOnlyList<BeneficioSocialBeneficiario>)g.ToList()); |
| | | 98 | | |
| | 1 | 99 | | var compensaciones = await _context.ItemsLoteCompensacion |
| | 1 | 100 | | .AsNoTracking() |
| | 1 | 101 | | .Include(i => i.LoteCompensacion) |
| | 1 | 102 | | .Where(i => i.LoteCompensacion.Estado == "aprobado" |
| | 1 | 103 | | && i.LoteCompensacion.Periodo.Year == periodo.Anio |
| | 1 | 104 | | && i.LoteCompensacion.Periodo.Month == periodo.Mes) |
| | 1 | 105 | | .ToListAsync(); |
| | | 106 | | |
| | 1 | 107 | | var novedadesConfirmadas = await _context.NovedadesPeriodo |
| | 1 | 108 | | .AsNoTracking() |
| | 1 | 109 | | .Where(n => n.PeriodoId == periodoId && n.Estado == "confirmada") |
| | 1 | 110 | | .ToListAsync(); |
| | | 111 | | |
| | 1 | 112 | | var remuneracionesPorGrado = remuneraciones |
| | 1 | 113 | | .GroupBy(r => r.GradoId) |
| | 1 | 114 | | .ToDictionary( |
| | 1 | 115 | | g => g.Key, |
| | 2 | 116 | | g => (IReadOnlyDictionary<int, RemuneracionGrado>)g |
| | 1 | 117 | | .GroupBy(r => r.Item.Codigo) |
| | 2 | 118 | | .ToDictionary( |
| | 1 | 119 | | gg => gg.Key, |
| | 4 | 120 | | gg => gg.OrderByDescending(r => r.VigenteDesde).First())); |
| | | 121 | | |
| | 1 | 122 | | var permanenciasPorEscalafon = permanencias |
| | 1 | 123 | | .GroupBy(t => t.EscalafonId) |
| | 4 | 124 | | .ToDictionary(g => g.Key, g => (IReadOnlyList<TablaPermanencia>)g.OrderBy(t => t.AniosDesde).ToList()); |
| | | 125 | | |
| | 1 | 126 | | var beneficiosPorPersona = beneficios |
| | 1 | 127 | | .GroupBy(b => b.PersonaId) |
| | 3 | 128 | | .ToDictionary(g => g.Key, g => (IReadOnlyList<BeneficioSocial>)g.ToList()); |
| | | 129 | | |
| | 1 | 130 | | var compensacionesPorPersona = compensaciones |
| | 1 | 131 | | .GroupBy(i => i.PersonaId) |
| | 3 | 132 | | .ToDictionary(g => g.Key, g => (IReadOnlyList<ItemLoteCompensacion>)g.ToList()); |
| | | 133 | | |
| | 1 | 134 | | var novedadesPorPersona = novedadesConfirmadas |
| | 3 | 135 | | .ToDictionary(n => n.PersonaId, n => (NovedadPeriodo?)n); |
| | | 136 | | |
| | | 137 | | // Instructivo Asignación Familiar: fila más reciente por tipo_franja |
| | 1 | 138 | | var instructivoAsigFamiliarRaw = await _context.InstructivosAsigFamiliar |
| | 1 | 139 | | .AsNoTracking() |
| | 1 | 140 | | .Where(i => i.VigenteDesde <= periodoDate) |
| | 1 | 141 | | .ToListAsync(); |
| | | 142 | | |
| | 1 | 143 | | var instructivoAsigFamiliar = instructivoAsigFamiliarRaw |
| | 0 | 144 | | .GroupBy(i => i.TipoFranja) |
| | 1 | 145 | | .ToDictionary( |
| | 0 | 146 | | g => g.Key, |
| | 1 | 147 | | g => g.OrderByDescending(i => i.VigenteDesde).First()); |
| | | 148 | | |
| | | 149 | | // Instructivo PSF: fila más reciente por numero_categoria |
| | 1 | 150 | | var instructivoPsfRaw = await _context.InstructivosPsf |
| | 1 | 151 | | .AsNoTracking() |
| | 1 | 152 | | .Where(i => i.VigenteDesde <= periodoDate) |
| | 1 | 153 | | .ToListAsync(); |
| | | 154 | | |
| | 1 | 155 | | var instructivoPsf = instructivoPsfRaw |
| | 0 | 156 | | .GroupBy(i => (int)i.NumeroCategoria) |
| | 1 | 157 | | .ToDictionary( |
| | 0 | 158 | | g => g.Key, |
| | 1 | 159 | | g => g.OrderByDescending(i => i.VigenteDesde).First()); |
| | | 160 | | |
| | | 161 | | // Tabla Hogar: tramos vigentes, ordenados ASC con NULL al final |
| | 1 | 162 | | var tablaPorHogarRaw = await _context.TablasHogarConstituido |
| | 1 | 163 | | .AsNoTracking() |
| | 1 | 164 | | .Where(t => t.VigenteDesde <= periodoDate) |
| | 1 | 165 | | .ToListAsync(); |
| | | 166 | | |
| | 1 | 167 | | var tablaPorHogar = tablaPorHogarRaw |
| | 0 | 168 | | .GroupBy(t => t.HastaHaberes) |
| | 0 | 169 | | .Select(g => g.OrderByDescending(t => t.VigenteDesde).First()) |
| | 0 | 170 | | .OrderBy(t => t.HastaHaberes.HasValue ? 0 : 1) |
| | 0 | 171 | | .ThenBy(t => t.HastaHaberes ?? decimal.MaxValue) |
| | 1 | 172 | | .ToList(); |
| | | 173 | | |
| | 1 | 174 | | var aguinaldos = await _context.Set<Aguinaldo>() |
| | 1 | 175 | | .AsNoTracking() |
| | 1 | 176 | | .Where(a => a.Anio == periodo.Anio) |
| | 1 | 177 | | .ToListAsync(); |
| | | 178 | | |
| | 1 | 179 | | var aguinaldosPorPersona = aguinaldos |
| | 0 | 180 | | .GroupBy(a => a.PersonaId) |
| | 1 | 181 | | .ToDictionary(g => g.Key, g => (IReadOnlyList<Aguinaldo>)g.ToList()); |
| | | 182 | | |
| | 1 | 183 | | return new InsumosPeriodo |
| | 1 | 184 | | { |
| | 1 | 185 | | PeriodoId = periodoId, |
| | 1 | 186 | | ParametroPeriodo = parametros, |
| | 1 | 187 | | CatalogoItems = catalogoItems, |
| | 1 | 188 | | RemuneracionesPorGrado = remuneracionesPorGrado, |
| | 1 | 189 | | PermanenciasPorEscalafon = permanenciasPorEscalafon, |
| | 1 | 190 | | FranjasIrpf = franjasIrpf, |
| | 1 | 191 | | BeneficiosPorPersona = beneficiosPorPersona, |
| | 1 | 192 | | CompensacionesPorPersona = compensacionesPorPersona, |
| | 1 | 193 | | NovedadesPorPersona = novedadesPorPersona, |
| | 1 | 194 | | BeneficiariosPorBeneficio = beneficiariosPorBeneficio, |
| | 1 | 195 | | InstructivoAsigFamiliar = instructivoAsigFamiliar, |
| | 1 | 196 | | InstructivoPsf = instructivoPsf, |
| | 1 | 197 | | TablaPorHogar = tablaPorHogar, |
| | 1 | 198 | | AguinaldosPorPersona = aguinaldosPorPersona |
| | 1 | 199 | | }; |
| | 1 | 200 | | } |
| | | 201 | | } |