< Summary

Information
Class: FAU.DataAccess.Repositories.CompensacionRepository
Assembly: FAU.DataAccess
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.DataAccess/Repositories/CompensacionRepository.cs
Line coverage
61%
Covered lines: 121
Uncovered lines: 75
Coverable lines: 196
Total lines: 332
Line coverage: 61.7%
Branch coverage
50%
Covered branches: 21
Total branches: 42
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.DataAccess/Repositories/CompensacionRepository.cs

#LineLine coverage
 1using FAU.Entidades;
 2using Microsoft.EntityFrameworkCore;
 3
 4namespace FAU.DataAccess.Repositories;
 5
 6public class CompensacionRepository : ICompensacionRepository
 7{
 8    private readonly ApplicationDbContext _context;
 9
 5110    public CompensacionRepository(ApplicationDbContext context)
 11    {
 5112        _context = context;
 5113    }
 14
 15    // ── Tipos ────────────────────────────────────────────────────────────────
 16
 17    public async Task<IEnumerable<TipoCompensacion>> GetTiposAsync(bool? activo = null)
 18    {
 419        var query = _context.TiposCompensacion.AsQueryable();
 420        if (activo.HasValue)
 221            query = query.Where(t => t.Vigente == activo.Value);
 422        return await query.OrderBy(t => t.Nombre).ToListAsync();
 423    }
 24
 25    public async Task<TipoCompensacion?> GetTipoByIdAsync(long id)
 226        => await _context.TiposCompensacion.FindAsync(id);
 27
 28    public async Task<TipoCompensacion?> GetTipoByCodigoAsync(string codigo)
 229        => await _context.TiposCompensacion.FirstOrDefaultAsync(t => t.Codigo == codigo);
 30
 31    public async Task<TipoCompensacion> CreateTipoAsync(TipoCompensacion tipo)
 32    {
 133        _context.TiposCompensacion.Add(tipo);
 134        await _context.SaveChangesAsync();
 135        return tipo;
 136    }
 37
 38    public async Task<TipoCompensacion> UpdateTipoAsync(TipoCompensacion tipo)
 39    {
 140        _context.TiposCompensacion.Update(tipo);
 141        await _context.SaveChangesAsync();
 142        return tipo;
 143    }
 44
 45    public async Task DeleteTipoAsync(long id)
 46    {
 247        var tipo = await _context.TiposCompensacion.FindAsync(id);
 248        if (tipo != null)
 49        {
 150            _context.TiposCompensacion.Remove(tipo);
 151            await _context.SaveChangesAsync();
 52        }
 253    }
 54
 55    public async Task<bool> TieneConfiguracionesAsync(long tipoId)
 256        => await _context.ConfigCompensaciones.AnyAsync(c => c.TipoCompensacionId == tipoId);
 57
 58    public async Task<bool> TieneLotesAsync(long tipoId)
 259        => await _context.LotesCompensacion.AnyAsync(l => l.TipoCompensacionId == tipoId);
 60
 61    // ── Configs ──────────────────────────────────────────────────────────────
 62
 63    public async Task<IEnumerable<ConfigCompensacion>> GetConfigsAsync(
 64        long? tipoId = null, long? regimenId = null, long? gradoId = null, bool? activo = null)
 65    {
 466        var query = _context.ConfigCompensaciones
 467            .Include(c => c.TipoCompensacion)
 468            .Include(c => c.Regimen)
 469            .Include(c => c.Grado)
 470            .Include(c => c.Escalafon)
 471            .AsQueryable();
 72
 573        if (tipoId.HasValue) query = query.Where(c => c.TipoCompensacionId == tipoId.Value);
 474        if (regimenId.HasValue) query = query.Where(c => c.RegimenId == regimenId.Value);
 475        if (gradoId.HasValue) query = query.Where(c => c.GradoId == gradoId.Value);
 676        if (activo.HasValue) query = query.Where(c => c.Activo == activo.Value);
 77
 478        return await query.OrderBy(c => c.TipoCompensacionId).ThenBy(c => c.VigenteDesde).ToListAsync();
 479    }
 80
 81    public async Task<ConfigCompensacion?> GetConfigByIdAsync(long id)
 282        => await _context.ConfigCompensaciones
 283            .Include(c => c.TipoCompensacion)
 284            .Include(c => c.Regimen)
 285            .Include(c => c.Grado)
 286            .Include(c => c.Escalafon)
 287            .FirstOrDefaultAsync(c => c.Id == id);
 88
 89    public async Task<ConfigCompensacion?> GetConfigVigenteAsync(long tipoId, DateTime periodo)
 90    {
 591        return await _context.ConfigCompensaciones
 592            .Where(c => c.TipoCompensacionId == tipoId
 593                     && c.Activo
 594                     && c.VigenteDesde <= periodo
 595                     && (c.VigenteHasta == null || c.VigenteHasta >= periodo))
 596            .OrderByDescending(c => c.VigenteDesde)
 597            .FirstOrDefaultAsync();
 598    }
 99
 100    public async Task<bool> EsUnicaConfigActivaAsync(long configId, long tipoId)
 2101        => !await _context.ConfigCompensaciones
 2102            .AnyAsync(c => c.TipoCompensacionId == tipoId && c.Activo && c.Id != configId);
 103
 104    public async Task DesactivarConfigsActivasAsync(long tipoId)
 105    {
 1106        await _context.ConfigCompensaciones
 1107            .Where(c => c.TipoCompensacionId == tipoId && c.Activo)
 1108            .ExecuteUpdateAsync(s => s.SetProperty(c => c.Activo, false));
 0109    }
 110
 111    public async Task<ConfigCompensacion> CreateConfigAsync(ConfigCompensacion config)
 112    {
 1113        _context.ConfigCompensaciones.Add(config);
 1114        await _context.SaveChangesAsync();
 1115        return config;
 1116    }
 117
 118    public async Task<ConfigCompensacion> UpdateConfigAsync(ConfigCompensacion config)
 119    {
 0120        _context.ConfigCompensaciones.Update(config);
 0121        await _context.SaveChangesAsync();
 0122        return config;
 0123    }
 124
 125    public async Task DeleteConfigAsync(long id)
 126    {
 1127        var config = await _context.ConfigCompensaciones.FindAsync(id);
 1128        if (config != null)
 129        {
 1130            _context.ConfigCompensaciones.Remove(config);
 1131            await _context.SaveChangesAsync();
 132        }
 1133    }
 134
 135    // ── Lotes ────────────────────────────────────────────────────────────────
 136
 137    public async Task<(IEnumerable<LoteCompensacion> Items, int TotalCount)> GetLotesPagedAsync(
 138        int page, int pageSize, long? tipoId = null, long? periodoId = null, string? estado = null)
 139    {
 3140        var query = _context.LotesCompensacion
 3141            .Include(l => l.TipoCompensacion)
 3142            .Include(l => l.Periodo)
 3143            .Include(l => l.AprobadorUsuario)
 3144            .AsQueryable();
 145
 3146        if (tipoId.HasValue)    query = query.Where(l => l.TipoCompensacionId == tipoId.Value);
 3147        if (periodoId.HasValue) query = query.Where(l => l.PeriodoId == periodoId.Value);
 3148        if (!string.IsNullOrWhiteSpace(estado)) query = query.Where(l => l.Estado == estado);
 149
 3150        var totalCount = await query.CountAsync();
 3151        var items = await query
 3152            .OrderByDescending(l => l.PeriodoId)
 3153            .ThenBy(l => l.TipoCompensacionId)
 3154            .Skip((page - 1) * pageSize)
 3155            .Take(pageSize)
 3156            .ToListAsync();
 157
 158        // Batch count y suma de montos sin cargar los items completos
 6159        var ids = items.Select(l => l.Id).ToList();
 3160        var stats = await _context.ItemsLoteCompensacion
 3161            .Where(i => ids.Contains(i.LoteCompensacionId))
 3162            .GroupBy(i => i.LoteCompensacionId)
 3163            .Select(g => new { LoteId = g.Key, Count = g.Count(), Total = g.Sum(i => i.Monto ?? 0) })
 7164            .ToDictionaryAsync(x => x.LoteId, x => x);
 165
 12166        foreach (var lote in items)
 167        {
 3168            lote.ItemCount  = stats.TryGetValue(lote.Id, out var s) ? s.Count : 0;
 3169            lote.TotalMonto = stats.TryGetValue(lote.Id, out s)     ? s.Total : 0;
 170        }
 171
 3172        return (items, totalCount);
 3173    }
 174
 175    public async Task<LoteCompensacion?> GetLoteByIdWithItemsAsync(long id)
 0176        => await _context.LotesCompensacion
 0177            .Include(l => l.Periodo)
 0178            .Include(l => l.TipoCompensacion)
 0179            .Include(l => l.AprobadorUsuario)
 0180            .Include(l => l.Items)
 0181                .ThenInclude(i => i.Persona)
 0182            .Include(l => l.Items)
 0183                .ThenInclude(i => i.SnapshotGrado)
 0184            .Include(l => l.Items)
 0185                .ThenInclude(i => i.SnapshotSituacion)
 0186            .Include(l => l.Items)
 0187                .ThenInclude(i => i.SnapshotUnidad)
 0188            .FirstOrDefaultAsync(l => l.Id == id);
 189
 190    public async Task<LoteCompensacion?> GetLoteByIdAsync(long id)
 0191        => await _context.LotesCompensacion
 0192            .Include(l => l.Periodo)
 0193            .FirstOrDefaultAsync(l => l.Id == id);
 194
 195    public async Task<bool> ExisteLoteActivoAsync(long tipoId, long periodoId)
 4196        => await _context.LotesCompensacion.AnyAsync(l =>
 4197            l.TipoCompensacionId == tipoId &&
 4198            l.PeriodoId == periodoId &&
 4199            l.Estado != "rechazado");
 200
 201    public async Task<LoteCompensacion> CreateLoteAsync(LoteCompensacion lote)
 202    {
 1203        _context.LotesCompensacion.Add(lote);
 1204        await _context.SaveChangesAsync();
 1205        return lote;
 1206    }
 207
 208    public async Task<LoteCompensacion> UpdateLoteAsync(LoteCompensacion lote)
 209    {
 210        // Marcar solo propiedades editables como modificadas para evitar problemas con DateTime Kind
 0211        var entry = _context.Entry(lote);
 212
 213        // Solo marcar como modificado si el valor es diferente del original
 0214        if (entry.Property(x => x.Estado).CurrentValue != entry.Property(x => x.Estado).OriginalValue)
 0215            entry.Property(x => x.Estado).IsModified = true;
 216
 0217        if (entry.Property(x => x.Fuente).CurrentValue != entry.Property(x => x.Fuente).OriginalValue)
 0218            entry.Property(x => x.Fuente).IsModified = true;
 219
 0220        if (entry.Property(x => x.NombreArchivo).CurrentValue != entry.Property(x => x.NombreArchivo).OriginalValue)
 0221            entry.Property(x => x.NombreArchivo).IsModified = true;
 222
 0223        if (entry.Property(x => x.HashArchivo).CurrentValue != entry.Property(x => x.HashArchivo).OriginalValue)
 0224            entry.Property(x => x.HashArchivo).IsModified = true;
 225
 0226        if (entry.Property(x => x.AprobadoPor).CurrentValue != entry.Property(x => x.AprobadoPor).OriginalValue)
 0227            entry.Property(x => x.AprobadoPor).IsModified = true;
 228
 0229        if (entry.Property(x => x.AprobadoEn).CurrentValue != entry.Property(x => x.AprobadoEn).OriginalValue)
 0230            entry.Property(x => x.AprobadoEn).IsModified = true;
 231
 0232        await _context.SaveChangesAsync();
 0233        return lote;
 0234    }
 235
 236    public async Task DeleteLoteAsync(LoteCompensacion lote)
 237    {
 0238        _context.LotesCompensacion.Remove(lote);
 0239        await _context.SaveChangesAsync();
 0240    }
 241
 242    public async Task DeleteAllItemsAsync(long loteId)
 243    {
 1244        var items = await _context.ItemsLoteCompensacion
 1245            .Where(i => i.LoteCompensacionId == loteId)
 1246            .ToListAsync();
 1247        _context.ItemsLoteCompensacion.RemoveRange(items);
 1248        await _context.SaveChangesAsync();
 1249    }
 250
 251    // ── Items ────────────────────────────────────────────────────────────────
 252
 253    public async Task<(IEnumerable<ItemLoteCompensacion> Items, int TotalCount)> GetItemsPagedAsync(
 254        long loteId, int page, int pageSize)
 255    {
 0256        var query = _context.ItemsLoteCompensacion
 0257            .Include(i => i.Persona)
 0258            .Include(i => i.SnapshotGrado)
 0259            .Include(i => i.SnapshotSituacion)
 0260            .Include(i => i.SnapshotUnidad)
 0261            .Where(i => i.LoteCompensacionId == loteId);
 262
 0263        var totalCount = await query.CountAsync();
 0264        var items = await query
 0265            .OrderBy(i => i.Id)
 0266            .Skip((page - 1) * pageSize)
 0267            .Take(pageSize)
 0268            .ToListAsync();
 269
 0270        return (items, totalCount);
 0271    }
 272
 273    public async Task<ItemLoteCompensacion?> GetItemByIdAsync(long id)
 2274        => await _context.ItemsLoteCompensacion
 2275            .Include(i => i.Persona)
 2276            .FirstOrDefaultAsync(i => i.Id == id);
 277
 278    public async Task<bool> ExistePersonaEnLoteAsync(long loteId, long personaId)
 2279        => await _context.ItemsLoteCompensacion
 2280            .AnyAsync(i => i.LoteCompensacionId == loteId && i.PersonaId == personaId);
 281
 282    public async Task<decimal> GetMontoTotalItemsAsync(long loteId)
 3283        => await _context.ItemsLoteCompensacion
 3284            .Where(i => i.LoteCompensacionId == loteId)
 3285            .SumAsync(i => i.Monto ?? 0m);
 286
 287    public async Task<int> GetItemCountAsync(long loteId)
 2288        => await _context.ItemsLoteCompensacion
 2289            .CountAsync(i => i.LoteCompensacionId == loteId);
 290
 291    public async Task<int> GetItemsEnErrorCountAsync(long loteId)
 2292        => await _context.ItemsLoteCompensacion
 2293            .CountAsync(i => i.LoteCompensacionId == loteId && i.Estado == "error");
 294
 295    public async Task<TarifaPorCategoria?> GetTarifaCategoriaAsync(long catalogoItemId, string categoria, DateTime perio
 0296        => await _context.TarifasPorCategoria
 0297            .Where(t => t.ItemId == catalogoItemId
 0298                     && t.Categoria == categoria
 0299                     && t.VigenteDesde <= periodo
 0300                     && (t.VigenteHasta == null || t.VigenteHasta >= periodo))
 0301            .OrderByDescending(t => t.VigenteDesde)
 0302            .FirstOrDefaultAsync();
 303
 304    public async Task<RemuneracionGrado?> GetTarifaGradoAsync(long catalogoItemId, long gradoId, DateTime periodo)
 0305        => await _context.RemuneracionesGrado
 0306            .Where(r => r.ItemId == catalogoItemId
 0307                     && r.GradoId == gradoId
 0308                     && r.VigenteDesde <= periodo
 0309                     && (r.VigenteHasta == null || r.VigenteHasta >= periodo))
 0310            .OrderByDescending(r => r.VigenteDesde)
 0311            .FirstOrDefaultAsync();
 312
 313    public async Task<ItemLoteCompensacion> CreateItemAsync(ItemLoteCompensacion item)
 314    {
 1315        _context.ItemsLoteCompensacion.Add(item);
 1316        await _context.SaveChangesAsync();
 1317        return item;
 1318    }
 319
 320    public async Task<ItemLoteCompensacion> UpdateItemAsync(ItemLoteCompensacion item)
 321    {
 0322        _context.ItemsLoteCompensacion.Update(item);
 0323        await _context.SaveChangesAsync();
 0324        return item;
 0325    }
 326
 327    public async Task DeleteItemAsync(ItemLoteCompensacion item)
 328    {
 0329        _context.ItemsLoteCompensacion.Remove(item);
 0330        await _context.SaveChangesAsync();
 0331    }
 332}