< Summary

Information
Class: FAU.Logica.Services.ExporteMdnExcelService
Assembly: FAU.Logica
File(s): /home/runner/work/Sistema.Liquidacion.BE/Sistema.Liquidacion.BE/FAU.Logica/Services/ExporteMdnExcelService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 295
Coverable lines: 295
Total lines: 460
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 60
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
get_Cedula()100%210%
.ctor(...)100%210%
get_Cedula()100%210%
get_Apellido()100%210%
get_Nombre()100%210%
get_Escalafon()100%210%
get_Grado()100%210%
get_Situacion()100%210%
get_Programa()100%210%
get_PersonaId()100%210%
get_AniosServicioAnterior()100%210%
get_FechaInicio()100%210%
get_FechaFin()100%210%
get_FechaAscensoOficial()100%210%
.ctor(...)100%210%
get_PersonaId()100%210%
get_CantDisca()100%210%
get_DedHij100()100%210%
get_DedHij50()100%210%
.cctor()100%210%
OgACampoMdn(...)0%2040%
GenerarExcelAsync()100%210%
ObtenerCampoMdn(...)0%7280%
GenerarHojaLiquidacion(...)0%420200%
GenerarHojaPersonal(...)0%600240%
GenerarHojaControlPorcentual(...)0%2040%
Escribir()100%210%
ObtenerVersionMaximaAsync()100%210%

File(s)

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

#LineLine coverage
 1using ClosedXML.Excel;
 2using FAU.DataAccess;
 3using FAU.Entidades;
 4using FAU.Logica.DTOs;
 5using Microsoft.EntityFrameworkCore;
 6
 7namespace FAU.Logica.Services;
 8
 9public class ExporteMdnExcelService : IExporteMdnExcelService
 10{
 11    private readonly ApplicationDbContext _context;
 12    private readonly IReporteMDNService _reporteMdnService;
 13
 014    public ExporteMdnExcelService(ApplicationDbContext context, IReporteMDNService reporteMdnService)
 15    {
 016        _context = context;
 017        _reporteMdnService = reporteMdnService;
 018    }
 19
 20    // ═════════════════════════════════════════════════════════════════════════════
 21    // DTOs internos
 22    // ═════════════════════════════════════════════════════════════════════════════
 023    private sealed record ItemRaw(string Cedula, string CodigoConcepto, decimal Importe, string RubroContable);
 24
 025    private sealed record PersonaMdn(
 026        string Cedula,
 027        string Apellido,
 028        string Nombre,
 029        string Escalafon,
 030        string Grado,
 031        string Situacion,
 032        string Programa,
 033        long PersonaId,
 034        short? AniosServicioAnterior,
 035        DateTime? FechaInicio,
 036        DateTime? FechaFin,
 037        DateTime? FechaAscensoOficial);
 38
 039    private sealed record DedDep(
 040        long PersonaId,
 041        int CantDisca,
 042        int DedHij100,
 043        int DedHij50);
 44
 45    // ═════════════════════════════════════════════════════════════════════════════
 46    // Mapeo hardcode código de concepto → campo MDN legacy
 47    // Solo para los códigos que NO tienen OG asociado o tienen destino especial.
 48    // ═════════════════════════════════════════════════════════════════════════════
 49    /// <summary>
 50    /// Diccionario de excepciones: código de concepto → campo MDN legacy.
 51    /// Usado cuando el catálogo no tiene OG o el OG no mapea a un campo MDN legacy.
 52    /// </summary>
 053    private static readonly Dictionary<string, string> OverrideCodigoACampo = new()
 054    {
 055        // Fictos IRPF (no tienen OG en el legacy)
 056        ["370"] = "Boletos",
 057        ["372"] = "Comedor",
 058        ["374"] = "Alquiler",
 059        ["375"] = "Guarderia",
 060        ["376"] = "Ticket",
 061
 062        // Descuentos fictos IRPF
 063        ["607"] = "Boletos_2",
 064        ["608"] = "Comedor_2",
 065        ["609"] = "Alquiler_2",
 066        ["613"] = "Boletos_2",
 067        ["614"] = "Guarderia2",
 068        ["618"] = "Ticket_2",
 069
 070        // Códigos especiales del legacy → R_99_99
 071        ["9"] = "R_99_99",
 072        ["690"] = "R_99_99",
 073        ["691"] = "R_99_99",
 074        ["692"] = "R_99_99",
 075        ["693"] = "R_99_99",
 076        ["694"] = "R_99_99",
 077        ["695"] = "R_99_99",
 078        ["696"] = "R_99_99",
 079
 080        // Códigos de catálogo nuevo (5 dígitos) → campo MDN legacy
 081        // Cuando el OG del catálogo no coincide con el nombre de campo legacy.
 082        ["280"] = "R_234_002", // Rancho Metálico
 083        ["281"] = "R_234_000", // Viático de Traslado (legacy mapea aquí)
 084        ["300"] = "R_234_000", // Viático de Traslado (variante)
 085
 086        // IRPF — en el legacy el código 517 (IRPF Sueldo) → R_1_089
 087        ["517"] = "R_1_089",
 088        ["518"] = "R_1_104",
 089        ["519"] = "R_1_089", // IRPF Civil
 090
 091        // Sanidad militar por tramos — código legacy 5010/5011/5012
 092        ["5010"] = "R_5_010",
 093        ["5011"] = "R_5_011",
 094        ["5012"] = "R_5_012",
 095
 096        // FRL — no tiene OG claro en legacy
 097        ["FRL"] = "R_5_012",
 098    };
 99
 100    // Columnas exactas del legacy LIQ_MDN, en orden
 0101    private static readonly string[] ColumnasLiquidacionMdn =
 0102    {
 0103        "cedula_7", "apellido", "nombre", "esc", "grado", "situacion", "programa",
 0104        "R_011_000", "R_011_300", "R_015_000", "R_031_000", "R_041_003", "R_041_008",
 0105        "R_042_000", "R_042_012", "R_042_014", "R_042_019", "R_042_022", "R_042_025",
 0106        "R_042_067", "R_042_093", "R_042_103", "R_042_400", "R042_520_1", "R042_520_2",
 0107        "R042_520_3", "R_042_536", "R_042_610", "R_042_611", "R_043_003", "R_043_004",
 0108        "R_044_001", "R_047_500", "R_048_004", "R_048_009", "R_048_012", "R_048_015",
 0109        "R_048_017", "R_048_018", "R_048_023", "R_048_026", "R_048_032", "R_048_038",
 0110        "R_048_040", "R_048_042", "R_059_000", "R_066_000", "R_071_000", "R_072_000",
 0111        "R_073_000", "R_074_000", "R_079_001", "R_1_01", "R_1_03", "R_1_04",
 0112        "R_1_089", "R_1_104", "R_122_001", "R_234_000", "R_234_002", "R_4_01",
 0113        "R_5_01", "R_5_010", "R_5_011", "R_5_012", "R_5_03", "R_5_04",
 0114        "R_5_05", "R_5_08", "R_513_008", "R_9_064", "R_9_070", "R_9_071",
 0115        "R_9_074", "Boletos", "Boletos_2", "Comedor", "Comedor_2", "Alquiler",
 0116        "Alquiler_2", "Ticket", "Ticket_2", "Guarderia", "Guarderia2", "R_99_99",
 0117        "SuelPaIRPF", "ded_Sanid", "dedu_mont", "dedu_pasiv", "dedu_Hijos",
 0118        "dedu_Profe", "Cant_disca", "ded_hij100", "ded_hij_50"
 0119    };
 120
 121    /// <summary>
 122    /// Convierte un OG SIIF (ej. "042.012", "011.000") al nombre de campo MDN legacy (ej. "R_042_012").
 123    /// Null/empty → cadena vacía.
 124    /// </summary>
 125    private static string OgACampoMdn(string? og)
 126    {
 0127        if (string.IsNullOrWhiteSpace(og)) return "";
 0128        var parts = og.Split('.');
 0129        if (parts.Length != 2) return "";
 0130        return $"R_{parts[0]}_{parts[1]}";
 131    }
 132
 133    // ═════════════════════════════════════════════════════════════════════════════
 134    // API pública
 135    // ═════════════════════════════════════════════════════════════════════════════
 136
 137    public async Task<(byte[] Bytes, string FileName)> GenerarExcelAsync(long periodoId, long? regimenId = null)
 138    {
 0139        var periodo = await _context.PeriodosLiquidacion.AsNoTracking().FirstAsync(p => p.Id == periodoId);
 0140        var version = await ObtenerVersionMaximaAsync(periodoId);
 141
 142        // ── Items de liquidación ───────────────────────────────────────────────
 0143        var items = await _context.LiquidacionItems
 0144            .AsNoTracking()
 0145            .Where(i => i.PeriodoId == periodoId && i.Version == version)
 0146            .Select(i => new ItemRaw(i.Cedula, i.CodigoConcepto, i.Importe, i.RubroContable))
 0147            .ToListAsync();
 148
 149        // ── Catálogo para clasificación y resolución de OG ────────────────────
 0150        var catalogoItems = await _context.CatalogoItems
 0151            .AsNoTracking()
 0152            .Where(ci => items.Select(i => i.CodigoConcepto).Contains(ci.Codigo.ToString()))
 0153            .ToListAsync();
 154
 0155        var catalogoDict = catalogoItems.ToDictionary(ci => ci.Codigo.ToString(), ci => ci.ClasificacionSiif ?? "");
 0156        var catalogoTipoDict = catalogoItems.ToDictionary(ci => ci.Codigo.ToString(), ci => ci.Tipo);
 157
 0158        items = items.Where(i => catalogoTipoDict.GetValueOrDefault(i.CodigoConcepto) != "descuento_personal").ToList();
 0159        var cedulas = items.Select(i => i.Cedula).Distinct().ToList();
 160
 161        // ── Montepio por cédula (para columna dedu_mont) ───────────────────────
 0162        var montepioPorCedula = items
 0163            .Where(i => i.CodigoConcepto == "550")
 0164            .GroupBy(i => i.Cedula)
 0165            .ToDictionary(g => g.Key, g => Math.Abs(g.Sum(i => i.Importe)));
 166
 167        // ── Datos personales ──────────────────────────────────────────────────
 0168        var personasDict = await _context.RelacionesLaborales
 0169            .AsNoTracking()
 0170            .Where(r => cedulas.Contains(r.Persona.Cedula) && r.Estado == EstadoRelacion.Activo)
 0171            .Select(r => new PersonaMdn(
 0172                r.Persona.Cedula,
 0173                $"{r.Persona.PrimerApellido} {r.Persona.SegundoApellido}".Trim(),
 0174                $"{r.Persona.PrimerNombre} {r.Persona.SegundoNombre}".Trim(),
 0175                r.Escalafon.Denominacion,
 0176                r.Grado.Denominacion,
 0177                r.Situacion.Denominacion,
 0178                r.Programa.Denominacion,
 0179                r.PersonaId,
 0180                r.AniosServicioAnterior,
 0181                r.FechaInicio,
 0182                r.FechaFin,
 0183                r.FechaAscensoOficial))
 0184            .ToDictionaryAsync(x => x.Cedula);
 185
 0186        var personasCrudas = await _context.Personas
 0187            .AsNoTracking()
 0188            .Where(p => cedulas.Contains(p.Cedula))
 0189            .ToDictionaryAsync(p => p.Cedula);
 190
 191        // ── IRPF ───────────────────────────────────────────────────────────────
 0192        var personaIds = personasDict.Values.Select(p => p.PersonaId).Distinct().ToList();
 0193        var irpfDict = await _context.IrpfsMensual
 0194            .AsNoTracking()
 0195            .Where(i => i.LiquidacionId == periodoId && personaIds.Contains(i.PersonaId))
 0196            .ToDictionaryAsync(i => i.PersonaId);
 197
 198        // ── Dependientes ───────────────────────────────────────────────────────
 0199        var dedDict = await _context.Dependientes
 0200            .AsNoTracking()
 0201            .Where(d => personaIds.Contains(d.PersonaId) && d.Activo)
 0202            .GroupBy(d => d.PersonaId)
 0203            .Select(g => new DedDep(
 0204                g.Key,
 0205                g.Count(d => d.Tipo == "hijo_discapacidad"),
 0206                g.Count(d => d.Tipo.StartsWith("hijo") && d.PorcentajeDeduccion == 100),
 0207                g.Count(d => d.Tipo.StartsWith("hijo") && d.PorcentajeDeduccion == 50)))
 0208            .ToDictionaryAsync(x => x.PersonaId);
 209
 0210        using var wb = new XLWorkbook();
 211
 0212        GenerarHojaLiquidacion(wb, "Liquidacion_MDN", items, catalogoDict, personasDict, irpfDict, dedDict, montepioPorC
 0213        GenerarHojaPersonal(wb, "Personal_MDN", items, personasDict, personasCrudas);
 214
 0215        var control = await _reporteMdnService.ObtenerControlPorcentualAsync(periodoId, regimenId);
 0216        GenerarHojaControlPorcentual(wb, "Control_Porcentual", control);
 217
 0218        using var ms = new MemoryStream();
 0219        wb.SaveAs(ms);
 0220        var fileName = $"MDN_{periodo.Anio}_{periodo.Mes:D2}_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
 0221        return (ms.ToArray(), fileName);
 0222    }
 223
 224    // ═════════════════════════════════════════════════════════════════════════════
 225    // Mapeo principal: resuelve OG del catálogo como fallback, luego override
 226    // ═════════════════════════════════════════════════════════════════════════════
 227
 228    /// <summary>
 229    /// Determina el campo MDN legacy para un item de liquidación.
 230    /// 1. Si el item tiene RubroContable poblado → mapea por OG.
 231    /// 2. Si está vacío → busca el OG en el catálogo por CodigoConcepto.
 232    /// 3. Si aún sin OG → aplica override por código de concepto.
 233    /// </summary>
 234    private static string ObtenerCampoMdn(ItemRaw item, Dictionary<string, string> catalogoDict)
 235    {
 236        // Paso 1: intentar OG del item mismo
 0237        var og = item.RubroContable;
 0238        if (string.IsNullOrWhiteSpace(og))
 239        {
 240            // Paso 2: fallback al catálogo
 0241            catalogoDict.TryGetValue(item.CodigoConcepto, out og);
 242        }
 0243        if (!string.IsNullOrWhiteSpace(og))
 244        {
 0245            var campo = OgACampoMdn(og);
 0246            if (!string.IsNullOrEmpty(campo)) return campo;
 247        }
 248        // Paso 3: override por código
 0249        OverrideCodigoACampo.TryGetValue(item.CodigoConcepto, out var overrideCampo);
 0250        return overrideCampo ?? "";
 251    }
 252
 253    // ═════════════════════════════════════════════════════════════════════════════
 254    // Hoja 1 — Liquidacion_MDN
 255    // ═════════════════════════════════════════════════════════════════════════════
 256
 257    private static void GenerarHojaLiquidacion(
 258        XLWorkbook wb,
 259        string sheetName,
 260        List<ItemRaw> items,
 261        Dictionary<string, string> catalogoDict,
 262        Dictionary<string, PersonaMdn> personasDict,
 263        Dictionary<long, IrpfMensual> irpfDict,
 264        Dictionary<long, DedDep> dedDict,
 265        Dictionary<string, decimal> montepioPorCedula)
 266    {
 0267        var ws = wb.Worksheets.Add(sheetName);
 268
 0269        for (int c = 0; c < ColumnasLiquidacionMdn.Length; c++)
 0270            ws.Cell(1, c + 1).Value = ColumnasLiquidacionMdn[c];
 271
 0272        var acumuladoPorCedula = new Dictionary<string, Dictionary<string, decimal>>();
 0273        foreach (var item in items)
 274        {
 0275            var campo = ObtenerCampoMdn(item, catalogoDict);
 0276            if (string.IsNullOrEmpty(campo)) continue;
 0277            if (!acumuladoPorCedula.TryGetValue(item.Cedula, out var campos))
 278            {
 0279                campos = new Dictionary<string, decimal>();
 0280                acumuladoPorCedula[item.Cedula] = campos;
 281            }
 0282            campos[campo] = campos.GetValueOrDefault(campo) + item.Importe;
 283        }
 284
 0285        int row = 2;
 0286        foreach (var (cedula, campos) in acumuladoPorCedula.OrderBy(kv => kv.Key))
 287        {
 0288            if (!personasDict.TryGetValue(cedula, out var p)) continue;
 289
 0290            ws.Cell(row, 1).Value = cedula;
 0291            ws.Cell(row, 2).Value = p.Apellido;
 0292            ws.Cell(row, 3).Value = p.Nombre;
 0293            ws.Cell(row, 4).Value = p.Escalafon;
 0294            ws.Cell(row, 5).Value = p.Grado;
 0295            ws.Cell(row, 6).Value = p.Situacion;
 0296            ws.Cell(row, 7).Value = p.Programa;
 297
 0298            for (int c = 7; c < ColumnasLiquidacionMdn.Length; c++)
 299            {
 0300                var campo = ColumnasLiquidacionMdn[c];
 0301                if (campos.TryGetValue(campo, out var val))
 0302                    ws.Cell(row, c + 1).Value = val;
 303            }
 304
 0305            if (irpfDict.TryGetValue(p.PersonaId, out var irpf))
 306            {
 0307                var baseCol = ColumnasLiquidacionMdn.Length - 9;
 0308                var dedMontepio = montepioPorCedula.GetValueOrDefault(cedula);
 0309                ws.Cell(row, baseCol + 1).Value = irpf.IngresosGravados;                          // SuelPaIRPF
 0310                ws.Cell(row, baseCol + 2).Value = irpf.DeduccionAportes;                          // ded_Sanid
 0311                ws.Cell(row, baseCol + 3).Value = dedMontepio;                                    // dedu_mont
 0312                ws.Cell(row, baseCol + 4).Value = Math.Max(0m, irpf.DeduccionAportes - dedMontepio); // dedu_pasiv
 0313                ws.Cell(row, baseCol + 5).Value = irpf.DeduccionHijos;                            // dedu_Hijos
 0314                ws.Cell(row, baseCol + 6).Value = irpf.DeduccionProfesional;                      // dedu_Profe
 315            }
 316
 0317            if (dedDict.TryGetValue(p.PersonaId, out var dep))
 318            {
 0319                var baseCol = ColumnasLiquidacionMdn.Length - 3;
 0320                ws.Cell(row, baseCol + 1).Value = dep.CantDisca;   // Cant_disca
 0321                ws.Cell(row, baseCol + 2).Value = dep.DedHij100;   // ded_hij100
 0322                ws.Cell(row, baseCol + 3).Value = dep.DedHij50;    // ded_hij_50
 323            }
 324
 0325            row++;
 326        }
 327
 0328        ws.Columns().AdjustToContents();
 0329    }
 330
 331    // ═════════════════════════════════════════════════════════════════════════════
 332    // Hoja 2 — Personal_MDN
 333    // ═════════════════════════════════════════════════════════════════════════════
 334
 335    private static void GenerarHojaPersonal(
 336        XLWorkbook wb,
 337        string sheetName,
 338        List<ItemRaw> items,
 339        Dictionary<string, PersonaMdn> personasDict,
 340        Dictionary<string, Persona> personasCrudas)
 341    {
 0342        var ws = wb.Worksheets.Add(sheetName);
 343
 0344        string[] cols =
 0345        {
 0346            "cedula", "ape1_per", "ape2_per", "nom1_per", "nom2_per",
 0347            "situa_per", "unidad", "compania", "esc_per", "grado",
 0348            "anios_trop", "anios_adm", "fec_ing", "fec_retiro", "fec_ofi",
 0349            "fec_sub", "fec_ult_as", "programa", "nom_sit", "nom_grado", "antiguedad"
 0350        };
 351
 0352        for (int c = 0; c < cols.Length; c++)
 0353            ws.Cell(1, c + 1).Value = cols[c];
 354
 0355        var cedulasConLiq = items.Select(i => i.Cedula).Distinct().ToHashSet();
 356
 0357        int row = 2;
 0358        foreach (var (cedula, p) in personasDict.OrderBy(kv => kv.Key).Where(kv => cedulasConLiq.Contains(kv.Key)))
 359        {
 0360            personasCrudas.TryGetValue(cedula, out var pc);
 361
 0362            ws.Cell(row, 1).Value = cedula;
 0363            ws.Cell(row, 2).Value = pc?.PrimerApellido ?? p.Apellido;
 0364            ws.Cell(row, 3).Value = pc?.SegundoApellido ?? "";
 0365            ws.Cell(row, 4).Value = pc?.PrimerNombre ?? p.Nombre;
 0366            ws.Cell(row, 5).Value = pc?.SegundoNombre ?? "";
 0367            ws.Cell(row, 6).Value = p.Situacion;
 0368            ws.Cell(row, 7).Value = "";
 0369            ws.Cell(row, 8).Value = "";
 0370            ws.Cell(row, 9).Value = p.Escalafon;
 0371            ws.Cell(row, 10).Value = p.Grado;
 0372            ws.Cell(row, 11).Value = p.AniosServicioAnterior;
 0373            ws.Cell(row, 12).Value = 0;
 0374            ws.Cell(row, 13).Value = p.FechaInicio;
 0375            ws.Cell(row, 14).Value = p.FechaFin;
 0376            ws.Cell(row, 15).Value = p.FechaAscensoOficial;
 0377            ws.Cell(row, 16).Value = (DateTime?)null;
 0378            ws.Cell(row, 17).Value = (DateTime?)null;
 0379            ws.Cell(row, 18).Value = p.Programa;
 0380            ws.Cell(row, 19).Value = p.Situacion;
 0381            ws.Cell(row, 20).Value = p.Grado;
 0382            var ant = p.FechaInicio.HasValue
 0383                ? (int)((DateTime.Now - p.FechaInicio.Value).TotalDays / 365) + (p.AniosServicioAnterior ?? 0)
 0384                : p.AniosServicioAnterior ?? 0;
 0385            ws.Cell(row, 21).Value = ant;
 386
 0387            row++;
 388        }
 389
 0390        ws.Columns().AdjustToContents();
 0391    }
 392
 393    // ═════════════════════════════════════════════════════════════════════════════
 394    // Hoja 3 — Control_Porcentual
 395    // ═════════════════════════════════════════════════════════════════════════════
 396
 397    private static void GenerarHojaControlPorcentual(XLWorkbook wb, string sheetName, ControlPorcentualMdnDto dto)
 398    {
 0399        var ws = wb.Worksheets.Add(sheetName);
 0400        int row = 1;
 401
 0402        ws.Cell(row, 1).Value = "RESUMEN RETRIBUCIONES PERCIBIDAS — Porcentajes a cobrar sobre Líquido";
 0403        ws.Range(row, 1, row, 5).Merge();
 0404        row += 2;
 405
 0406        string[] headers = { "Cédula", "Nombre", "Grado", "Unidad", "Haberes Gravados",
 0407            "Haberes No Gravados", "Beneficios Sociales", "Descuentos Legales", "Líquido MDN",
 0408            "Cálculo 30%", "Porcentaje Real" };
 0409        for (int c = 0; c < headers.Length; c++)
 0410            ws.Cell(row, c + 1).Value = headers[c];
 0411        row++;
 412
 0413        foreach (var f in dto.Filas)
 414        {
 0415            ws.Cell(row, 1).Value = f.Cedula;
 0416            ws.Cell(row, 2).Value = f.Nombre;
 0417            ws.Cell(row, 3).Value = f.Grado;
 0418            ws.Cell(row, 4).Value = f.Unidad;
 0419            ws.Cell(row, 5).Value = f.HaberesGravados;
 0420            ws.Cell(row, 6).Value = f.HaberesNoGravados;
 0421            ws.Cell(row, 7).Value = f.BeneficiosSociales;
 0422            ws.Cell(row, 8).Value = f.DescuentosLegales;
 0423            ws.Cell(row, 9).Value = f.LiquidoMDN;
 0424            ws.Cell(row, 10).Value = f.Calculo30Porciento;
 0425            ws.Cell(row, 11).Value = f.PorcentajeReal;
 0426            row++;
 427        }
 428
 0429        row += 2;
 0430        ws.Cell(row, 1).Value = "RANGO";
 0431        ws.Cell(row, 2).Value = "CANTIDAD";
 0432        ws.Cell(row, 3).Value = "IMPORTE NOMINAL";
 0433        row++;
 434
 0435        var r = dto.Resumen;
 436        void Escribir(string rango, int cant, decimal imp)
 437        {
 0438            ws.Cell(row, 1).Value = rango;
 0439            ws.Cell(row, 2).Value = cant;
 0440            ws.Cell(row, 3).Value = imp;
 0441            row++;
 0442        }
 443
 0444        Escribir("> 50%", r.CantidadSuperior50, r.ImporteSuperior50);
 0445        Escribir("40% – 50%", r.CantidadEntre40Y50, r.ImporteEntre40Y50);
 0446        Escribir("30% – 40%", r.CantidadEntre30Y40, r.ImporteEntre30Y40);
 0447        Escribir("< 30% (insuficiente)", r.CantidadInferior30, r.ImporteInferior30);
 0448        Escribir("Total deudas no atendidas", 0, r.TotalDeudasNoAtendidas);
 449
 0450        ws.Columns().AdjustToContents();
 0451    }
 452
 453    private async Task<int> ObtenerVersionMaximaAsync(long periodoId)
 454    {
 0455        return await _context.LiquidacionItems
 0456            .AsNoTracking()
 0457            .Where(i => i.PeriodoId == periodoId)
 0458            .MaxAsync(i => (int?)i.Version) ?? 0;
 0459    }
 460}

Methods/Properties

.ctor(FAU.DataAccess.ApplicationDbContext,FAU.Logica.Services.IReporteMDNService)
get_Cedula()
.ctor(System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.Int64,System.Nullable`1<System.Int16>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>)
get_Cedula()
get_Apellido()
get_Nombre()
get_Escalafon()
get_Grado()
get_Situacion()
get_Programa()
get_PersonaId()
get_AniosServicioAnterior()
get_FechaInicio()
get_FechaFin()
get_FechaAscensoOficial()
.ctor(System.Int64,System.Int32,System.Int32,System.Int32)
get_PersonaId()
get_CantDisca()
get_DedHij100()
get_DedHij50()
.cctor()
OgACampoMdn(System.String)
GenerarExcelAsync()
ObtenerCampoMdn(FAU.Logica.Services.ExporteMdnExcelService/ItemRaw,System.Collections.Generic.Dictionary`2<System.String,System.String>)
GenerarHojaLiquidacion(ClosedXML.Excel.XLWorkbook,System.String,System.Collections.Generic.List`1<FAU.Logica.Services.ExporteMdnExcelService/ItemRaw>,System.Collections.Generic.Dictionary`2<System.String,System.String>,System.Collections.Generic.Dictionary`2<System.String,FAU.Logica.Services.ExporteMdnExcelService/PersonaMdn>,System.Collections.Generic.Dictionary`2<System.Int64,FAU.Entidades.IrpfMensual>,System.Collections.Generic.Dictionary`2<System.Int64,FAU.Logica.Services.ExporteMdnExcelService/DedDep>,System.Collections.Generic.Dictionary`2<System.String,System.Decimal>)
GenerarHojaPersonal(ClosedXML.Excel.XLWorkbook,System.String,System.Collections.Generic.List`1<FAU.Logica.Services.ExporteMdnExcelService/ItemRaw>,System.Collections.Generic.Dictionary`2<System.String,FAU.Logica.Services.ExporteMdnExcelService/PersonaMdn>,System.Collections.Generic.Dictionary`2<System.String,FAU.Entidades.Persona>)
GenerarHojaControlPorcentual(ClosedXML.Excel.XLWorkbook,System.String,FAU.Logica.DTOs.ControlPorcentualMdnDto)
Escribir()
ObtenerVersionMaximaAsync()