| | | 1 | | using ClosedXML.Excel; |
| | | 2 | | using FAU.DataAccess; |
| | | 3 | | using FAU.Entidades; |
| | | 4 | | using Microsoft.EntityFrameworkCore; |
| | | 5 | | |
| | | 6 | | namespace FAU.Logica.Services; |
| | | 7 | | |
| | | 8 | | public class AguinaldoReporteControlService : IAguinaldoReporteControlService |
| | | 9 | | { |
| | | 10 | | private readonly ApplicationDbContext _context; |
| | | 11 | | |
| | 0 | 12 | | public AguinaldoReporteControlService(ApplicationDbContext context) |
| | | 13 | | { |
| | 0 | 14 | | _context = context; |
| | 0 | 15 | | } |
| | | 16 | | |
| | | 17 | | public async Task<(byte[] Bytes, string FileName)> GenerarExcelAsync(int anio, int mes, string variante, bool esLeyV |
| | | 18 | | { |
| | 0 | 19 | | if (mes != 6 && mes != 12) |
| | 0 | 20 | | throw new ArgumentException("El mes debe ser 6 o 12.", nameof(mes)); |
| | | 21 | | |
| | 0 | 22 | | variante = variante.ToUpper(); |
| | 0 | 23 | | if (variante != "TODOS" && variante != "REVISTAN" && variante != "BAJAS") |
| | 0 | 24 | | throw new ArgumentException("La variante debe ser TODOS, REVISTAN o BAJAS.", nameof(variante)); |
| | | 25 | | |
| | 0 | 26 | | var semestre = (short)(mes == 6 ? 1 : 2); |
| | 0 | 27 | | var mesesSemestre = ObtenerMesesSemestre(anio, mes); |
| | 0 | 28 | | var filas = new List<FilaControl>(); |
| | | 29 | | |
| | 0 | 30 | | if (variante == "REVISTAN" || variante == "TODOS") |
| | | 31 | | { |
| | 0 | 32 | | var semestralData = await ( |
| | 0 | 33 | | from a in _context.Aguinaldos |
| | 0 | 34 | | where a.Anio == (short)anio && a.Semestre == semestre |
| | 0 | 35 | | join rl in _context.RelacionesLaborales on a.PersonaId equals rl.PersonaId |
| | 0 | 36 | | where rl.Estado == EstadoRelacion.Activo && rl.Regimen.EsLeyVieja == esLeyVieja |
| | 0 | 37 | | select new |
| | 0 | 38 | | { |
| | 0 | 39 | | a.PersonaId, |
| | 0 | 40 | | rl.Persona.Cedula, |
| | 0 | 41 | | rl.Persona.PrimerNombre, |
| | 0 | 42 | | rl.Persona.SegundoNombre, |
| | 0 | 43 | | rl.Persona.PrimerApellido, |
| | 0 | 44 | | rl.Persona.SegundoApellido, |
| | 0 | 45 | | GradoDenominacion = rl.Grado.Denominacion, |
| | 0 | 46 | | GradoOrden = rl.Grado.Orden, |
| | 0 | 47 | | SituacionCodigo = rl.Situacion.Codigo, |
| | 0 | 48 | | SituacionDenominacion = rl.Situacion.Denominacion, |
| | 0 | 49 | | ProgramaCodigo = rl.Programa.Codigo, |
| | 0 | 50 | | ProgramaDenominacion = rl.Programa.Denominacion, |
| | 0 | 51 | | FechaIngreso = rl.FechaInicio, |
| | 0 | 52 | | } |
| | 0 | 53 | | ).ToListAsync(); |
| | | 54 | | |
| | 0 | 55 | | var semestralIds = semestralData.Select(d => d.PersonaId).ToList(); |
| | 0 | 56 | | var historicoSemestral = await GetHistoricoDict(semestralIds, mesesSemestre); |
| | | 57 | | |
| | 0 | 58 | | foreach (var d in semestralData) |
| | | 59 | | { |
| | 0 | 60 | | var mesesData = GetMesesData(d.PersonaId, historicoSemestral, mesesSemestre, null); |
| | 0 | 61 | | var total = mesesData.Sum(); |
| | 0 | 62 | | filas.Add(new FilaControl( |
| | 0 | 63 | | d.PersonaId, |
| | 0 | 64 | | d.Cedula, |
| | 0 | 65 | | FormatApellidosNombres(d.PrimerApellido, d.SegundoApellido, d.PrimerNombre, d.SegundoNombre), |
| | 0 | 66 | | d.GradoDenominacion, |
| | 0 | 67 | | d.GradoOrden, |
| | 0 | 68 | | FormatFechaIngreso(d.FechaIngreso), |
| | 0 | 69 | | d.SituacionCodigo, |
| | 0 | 70 | | d.SituacionDenominacion, |
| | 0 | 71 | | d.ProgramaCodigo, |
| | 0 | 72 | | d.ProgramaDenominacion, |
| | 0 | 73 | | mesesData, |
| | 0 | 74 | | total, |
| | 0 | 75 | | Math.Round(total / 12m, 2), |
| | 0 | 76 | | false)); |
| | | 77 | | } |
| | 0 | 78 | | } |
| | | 79 | | |
| | 0 | 80 | | if (variante == "BAJAS" || variante == "TODOS") |
| | | 81 | | { |
| | 0 | 82 | | var bajaRecords = await _context.AguinaldosBaja |
| | 0 | 83 | | .Where(b => b.Anio == (short)anio && b.Semestre == semestre) |
| | 0 | 84 | | .ToListAsync(); |
| | | 85 | | |
| | 0 | 86 | | var bajaPersonaIds = bajaRecords.Select(b => b.PersonaId).Distinct().ToList(); |
| | | 87 | | |
| | 0 | 88 | | var relacionesBajaRaw = await _context.RelacionesLaborales |
| | 0 | 89 | | .Where(rl => bajaPersonaIds.Contains(rl.PersonaId) && rl.Regimen.EsLeyVieja == esLeyVieja) |
| | 0 | 90 | | .Select(rl => new |
| | 0 | 91 | | { |
| | 0 | 92 | | rl.PersonaId, |
| | 0 | 93 | | rl.FechaInicio, |
| | 0 | 94 | | GradoDenominacion = rl.Grado.Denominacion, |
| | 0 | 95 | | GradoOrden = rl.Grado.Orden, |
| | 0 | 96 | | SituacionCodigo = rl.Situacion.Codigo, |
| | 0 | 97 | | SituacionDenominacion = rl.Situacion.Denominacion, |
| | 0 | 98 | | ProgramaCodigo = rl.Programa.Codigo, |
| | 0 | 99 | | ProgramaDenominacion = rl.Programa.Denominacion, |
| | 0 | 100 | | PersFechaInicio = rl.FechaInicio |
| | 0 | 101 | | }) |
| | 0 | 102 | | .ToListAsync(); |
| | | 103 | | |
| | 0 | 104 | | var relacionesBajaDict = relacionesBajaRaw |
| | 0 | 105 | | .GroupBy(rl => rl.PersonaId) |
| | 0 | 106 | | .ToDictionary(g => g.Key, g => g.OrderByDescending(rl => rl.FechaInicio).First()); |
| | | 107 | | |
| | 0 | 108 | | var historicoBaja = await GetHistoricoDict(bajaPersonaIds, mesesSemestre); |
| | | 109 | | |
| | 0 | 110 | | var semestralPersonaIds = filas.Select(f => f.PersonaId).ToHashSet(); |
| | | 111 | | |
| | 0 | 112 | | foreach (var b in bajaRecords) |
| | | 113 | | { |
| | 0 | 114 | | if (variante == "TODOS" && semestralPersonaIds.Contains(b.PersonaId)) |
| | | 115 | | continue; |
| | | 116 | | |
| | 0 | 117 | | relacionesBajaDict.TryGetValue(b.PersonaId, out var rl); |
| | | 118 | | |
| | 0 | 119 | | var mesesData = GetMesesData(b.PersonaId, historicoBaja, mesesSemestre, b.FechaBaja); |
| | 0 | 120 | | var total = mesesData.Sum(); |
| | | 121 | | |
| | 0 | 122 | | filas.Add(new FilaControl( |
| | 0 | 123 | | b.PersonaId, |
| | 0 | 124 | | b.Cedula, |
| | 0 | 125 | | b.NombreCompleto + " (BAJA)", |
| | 0 | 126 | | rl?.GradoDenominacion ?? "", |
| | 0 | 127 | | rl?.GradoOrden ?? 0, |
| | 0 | 128 | | rl != null ? FormatFechaIngreso(rl.PersFechaInicio) : "", |
| | 0 | 129 | | rl?.SituacionCodigo ?? "", |
| | 0 | 130 | | rl?.SituacionDenominacion ?? "", |
| | 0 | 131 | | rl?.ProgramaCodigo ?? "", |
| | 0 | 132 | | rl?.ProgramaDenominacion ?? "", |
| | 0 | 133 | | mesesData, |
| | 0 | 134 | | total, |
| | 0 | 135 | | Math.Round(total / 12m, 2), |
| | 0 | 136 | | true)); |
| | | 137 | | } |
| | 0 | 138 | | } |
| | | 139 | | |
| | 0 | 140 | | var leyLabel = esLeyVieja ? "ley_vieja" : "ley_nueva"; |
| | 0 | 141 | | var bytes = GenerarExcel(filas, anio, mes, variante, esLeyVieja, mesesSemestre); |
| | 0 | 142 | | return (bytes, $"control_aguinaldo_{anio}_{mes:D2}_{variante.ToLower()}_{leyLabel}.xlsx"); |
| | 0 | 143 | | } |
| | | 144 | | |
| | | 145 | | private async Task<Dictionary<long, Dictionary<(short Anio, short Mes), decimal>>> GetHistoricoDict( |
| | | 146 | | List<long> personaIds, |
| | | 147 | | IReadOnlyList<(short Anio, short Mes)> mesesSemestre) |
| | | 148 | | { |
| | 0 | 149 | | if (personaIds.Count == 0) |
| | 0 | 150 | | return new Dictionary<long, Dictionary<(short Anio, short Mes), decimal>>(); |
| | | 151 | | |
| | 0 | 152 | | var aniosSemestre = mesesSemestre.Select(m => m.Anio).Distinct().ToList(); |
| | 0 | 153 | | var mesesIds = mesesSemestre.Select(m => m.Mes).Distinct().ToList(); |
| | | 154 | | |
| | 0 | 155 | | var historicos = await _context.HistoricoLiquidaciones |
| | 0 | 156 | | .Where(h => personaIds.Contains(h.PersonaId) |
| | 0 | 157 | | && aniosSemestre.Contains(h.Anio) |
| | 0 | 158 | | && mesesIds.Contains(h.Mes)) |
| | 0 | 159 | | .Select(h => new { h.PersonaId, h.Anio, h.Mes, h.HaberesGravados }) |
| | 0 | 160 | | .ToListAsync(); |
| | | 161 | | |
| | 0 | 162 | | var mesesSet = mesesSemestre.ToHashSet(); |
| | 0 | 163 | | return historicos |
| | 0 | 164 | | .Where(h => mesesSet.Contains((h.Anio, h.Mes))) |
| | 0 | 165 | | .GroupBy(h => h.PersonaId) |
| | 0 | 166 | | .ToDictionary( |
| | 0 | 167 | | g => g.Key, |
| | 0 | 168 | | g => g.ToDictionary(h => (h.Anio, h.Mes), h => h.HaberesGravados)); |
| | 0 | 169 | | } |
| | | 170 | | |
| | | 171 | | private static decimal[] GetMesesData( |
| | | 172 | | long personaId, |
| | | 173 | | Dictionary<long, Dictionary<(short Anio, short Mes), decimal>> dict, |
| | | 174 | | IReadOnlyList<(short Anio, short Mes)> mesesSemestre, |
| | | 175 | | DateTime? fechaBaja) |
| | | 176 | | { |
| | 0 | 177 | | var personaDict = dict.GetValueOrDefault(personaId) ?? new Dictionary<(short Anio, short Mes), decimal>(); |
| | 0 | 178 | | return mesesSemestre.Select(m => |
| | 0 | 179 | | { |
| | 0 | 180 | | if (fechaBaja.HasValue) |
| | 0 | 181 | | { |
| | 0 | 182 | | var mesDate = new DateTime(m.Anio, m.Mes, 1); |
| | 0 | 183 | | var bajaMonth = new DateTime(fechaBaja.Value.Year, fechaBaja.Value.Month, 1); |
| | 0 | 184 | | if (mesDate > bajaMonth) |
| | 0 | 185 | | return 0m; |
| | 0 | 186 | | } |
| | 0 | 187 | | return personaDict.GetValueOrDefault(m, 0m); |
| | 0 | 188 | | }).ToArray(); |
| | | 189 | | } |
| | | 190 | | |
| | | 191 | | private static IReadOnlyList<(short Anio, short Mes)> ObtenerMesesSemestre(int anio, int mes) |
| | | 192 | | { |
| | 0 | 193 | | if (mes == 6) |
| | 0 | 194 | | return new[] |
| | 0 | 195 | | { |
| | 0 | 196 | | ((short)(anio - 1), (short)12), |
| | 0 | 197 | | ((short)anio, (short)1), |
| | 0 | 198 | | ((short)anio, (short)2), |
| | 0 | 199 | | ((short)anio, (short)3), |
| | 0 | 200 | | ((short)anio, (short)4), |
| | 0 | 201 | | ((short)anio, (short)5) |
| | 0 | 202 | | }; |
| | | 203 | | |
| | 0 | 204 | | return new[] |
| | 0 | 205 | | { |
| | 0 | 206 | | ((short)anio, (short)6), |
| | 0 | 207 | | ((short)anio, (short)7), |
| | 0 | 208 | | ((short)anio, (short)8), |
| | 0 | 209 | | ((short)anio, (short)9), |
| | 0 | 210 | | ((short)anio, (short)10), |
| | 0 | 211 | | ((short)anio, (short)11) |
| | 0 | 212 | | }; |
| | | 213 | | } |
| | | 214 | | |
| | | 215 | | private static string[] GetMesHeaders(IReadOnlyList<(short Anio, short Mes)> meses) |
| | | 216 | | { |
| | 0 | 217 | | string[] nombres = ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"]; |
| | 0 | 218 | | return meses.Select(m => $"{nombres[m.Mes - 1]} {m.Anio}").ToArray(); |
| | | 219 | | } |
| | | 220 | | |
| | 0 | 221 | | private static string FormatFechaIngreso(DateTime fecha) => $"{fecha:MM/yyyy}"; |
| | | 222 | | |
| | | 223 | | private static string FormatApellidosNombres( |
| | | 224 | | string primerApellido, string? segundoApellido, |
| | | 225 | | string primerNombre, string? segundoNombre) |
| | | 226 | | { |
| | 0 | 227 | | var apellidos = primerApellido + (string.IsNullOrWhiteSpace(segundoApellido) ? "" : " " + segundoApellido); |
| | 0 | 228 | | var nombres = primerNombre + (string.IsNullOrWhiteSpace(segundoNombre) ? "" : " " + segundoNombre); |
| | 0 | 229 | | return $"{apellidos}, {nombres}"; |
| | | 230 | | } |
| | | 231 | | |
| | | 232 | | private static byte[] GenerarExcel( |
| | | 233 | | List<FilaControl> filas, |
| | | 234 | | int anio, int mes, string variante, bool esLeyVieja, |
| | | 235 | | IReadOnlyList<(short Anio, short Mes)> mesesSemestre) |
| | | 236 | | { |
| | 0 | 237 | | using var wb = new XLWorkbook(); |
| | 0 | 238 | | var ws = wb.Worksheets.Add("Control"); |
| | | 239 | | |
| | 0 | 240 | | var mesHeaders = GetMesHeaders(mesesSemestre); |
| | 0 | 241 | | var semNombre = mes == 6 ? "1er Semestre" : "2do Semestre"; |
| | 0 | 242 | | var leyNombre = esLeyVieja ? "Ley Vieja (14.157)" : "Ley Nueva (19.695)"; |
| | | 243 | | const int TotalCols = 12; |
| | | 244 | | const int RightCol = 10; |
| | 0 | 245 | | int row = 1; |
| | | 246 | | |
| | | 247 | | // ── Cabezal ────────────────────────────────────────────────────────── |
| | 0 | 248 | | ws.Cell(row, 1).Value = "F.A.U. Dirección de Economía y Finanzas"; |
| | 0 | 249 | | ws.Range(row, 1, row, RightCol - 1).Merge(); |
| | 0 | 250 | | ws.Cell(row, RightCol).Value = $"Fecha: {DateTime.Now:dd/MM/yyyy}"; |
| | 0 | 251 | | ws.Range(row, RightCol, row, TotalCols).Merge(); |
| | 0 | 252 | | ws.Cell(row, RightCol).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Right; |
| | 0 | 253 | | row++; |
| | | 254 | | |
| | 0 | 255 | | ws.Cell(row, 1).Value = "Departamento de Administración Presupuestal"; |
| | 0 | 256 | | ws.Range(row, 1, row, RightCol - 1).Merge(); |
| | 0 | 257 | | ws.Cell(row, RightCol).Value = $"Hora : {DateTime.Now:HH:mm:ss}"; |
| | 0 | 258 | | ws.Range(row, RightCol, row, TotalCols).Merge(); |
| | 0 | 259 | | ws.Cell(row, RightCol).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Right; |
| | 0 | 260 | | row++; |
| | | 261 | | |
| | 0 | 262 | | ws.Cell(row, 1).Value = $"{variante} | {leyNombre} | {semNombre} {anio}"; |
| | 0 | 263 | | ws.Range(row, 1, row, TotalCols).Merge(); |
| | 0 | 264 | | ws.Cell(row, 1).Style.Font.Bold = true; |
| | 0 | 265 | | ws.Cell(row, 1).Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; |
| | 0 | 266 | | row += 2; |
| | | 267 | | |
| | | 268 | | // ── Cabecera de columnas ────────────────────────────────────────────── |
| | 0 | 269 | | string[] headers = [ |
| | 0 | 270 | | "Ingreso FAU", "Grado", "Cédula", "Apellidos y Nombres", |
| | 0 | 271 | | mesHeaders[0], mesHeaders[1], mesHeaders[2], |
| | 0 | 272 | | mesHeaders[3], mesHeaders[4], mesHeaders[5], |
| | 0 | 273 | | "Total Semestral", "1/12" |
| | 0 | 274 | | ]; |
| | | 275 | | |
| | 0 | 276 | | for (int c = 0; c < headers.Length; c++) |
| | | 277 | | { |
| | 0 | 278 | | var cell = ws.Cell(row, c + 1); |
| | 0 | 279 | | cell.Value = headers[c]; |
| | 0 | 280 | | cell.Style.Font.Bold = true; |
| | 0 | 281 | | cell.Style.Fill.BackgroundColor = XLColor.FromHtml("#4472C4"); |
| | 0 | 282 | | cell.Style.Font.FontColor = XLColor.White; |
| | 0 | 283 | | cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; |
| | 0 | 284 | | cell.Style.Alignment.WrapText = true; |
| | | 285 | | } |
| | 0 | 286 | | int headerRow = row; |
| | 0 | 287 | | row++; |
| | | 288 | | |
| | 0 | 289 | | var totalGeneral = new decimal[8]; |
| | | 290 | | |
| | 0 | 291 | | var porPrograma = filas |
| | 0 | 292 | | .GroupBy(f => (f.ProgramaCodigo, f.ProgramaDenominacion)) |
| | 0 | 293 | | .OrderBy(g => g.Key.ProgramaCodigo); |
| | | 294 | | |
| | 0 | 295 | | foreach (var programaGroup in porPrograma) |
| | | 296 | | { |
| | 0 | 297 | | ws.Cell(row, 1).Value = $"Programa: {programaGroup.Key.ProgramaCodigo} - {programaGroup.Key.ProgramaDenomina |
| | 0 | 298 | | ws.Range(row, 1, row, TotalCols).Merge(); |
| | 0 | 299 | | ws.Cell(row, 1).Style.Font.Bold = true; |
| | 0 | 300 | | ws.Cell(row, 1).Style.Fill.BackgroundColor = XLColor.FromHtml("#D9E1F2"); |
| | 0 | 301 | | row++; |
| | | 302 | | |
| | 0 | 303 | | var totalPrograma = new decimal[8]; |
| | | 304 | | |
| | 0 | 305 | | var porSituacion = programaGroup |
| | 0 | 306 | | .GroupBy(f => (f.SituacionCodigo, f.SituacionDenominacion)) |
| | 0 | 307 | | .OrderBy(g => g.Key.SituacionCodigo); |
| | | 308 | | |
| | 0 | 309 | | foreach (var situacionGroup in porSituacion) |
| | | 310 | | { |
| | 0 | 311 | | ws.Cell(row, 1).Value = $" Situación: {situacionGroup.Key.SituacionCodigo} - {situacionGroup.Key.Situac |
| | 0 | 312 | | ws.Range(row, 1, row, TotalCols).Merge(); |
| | 0 | 313 | | ws.Cell(row, 1).Style.Font.Italic = true; |
| | 0 | 314 | | ws.Cell(row, 1).Style.Fill.BackgroundColor = XLColor.FromHtml("#EEF2F9"); |
| | 0 | 315 | | row++; |
| | | 316 | | |
| | 0 | 317 | | var totalSituacion = new decimal[8]; |
| | | 318 | | |
| | 0 | 319 | | foreach (var fila in situacionGroup.OrderBy(f => f.GradoOrden).ThenBy(f => f.NombreCompleto)) |
| | | 320 | | { |
| | 0 | 321 | | ws.Cell(row, 1).Value = fila.FechaIngreso; |
| | 0 | 322 | | ws.Cell(row, 2).Value = fila.GradoDenominacion; |
| | 0 | 323 | | ws.Cell(row, 3).Value = fila.Cedula; |
| | 0 | 324 | | ws.Cell(row, 4).Value = fila.NombreCompleto; |
| | 0 | 325 | | for (int i = 0; i < 6; i++) |
| | 0 | 326 | | ws.Cell(row, 5 + i).Value = fila.MesesData[i]; |
| | 0 | 327 | | ws.Cell(row, 11).Value = fila.TotalSemestral; |
| | 0 | 328 | | ws.Cell(row, 12).Value = fila.Duodecimo; |
| | | 329 | | |
| | 0 | 330 | | if (fila.EsBaja) |
| | 0 | 331 | | ws.Range(row, 1, row, TotalCols).Style.Font.Italic = true; |
| | | 332 | | |
| | 0 | 333 | | for (int i = 0; i < 6; i++) totalSituacion[i] += fila.MesesData[i]; |
| | 0 | 334 | | totalSituacion[6] += fila.TotalSemestral; |
| | 0 | 335 | | totalSituacion[7] += fila.Duodecimo; |
| | 0 | 336 | | row++; |
| | | 337 | | } |
| | | 338 | | |
| | 0 | 339 | | EscribirSubtotal(ws, row, TotalCols, |
| | 0 | 340 | | $"Subtotal {situacionGroup.Key.SituacionDenominacion}", totalSituacion, |
| | 0 | 341 | | XLColor.FromHtml("#EEF2F9")); |
| | 0 | 342 | | for (int i = 0; i < 8; i++) totalPrograma[i] += totalSituacion[i]; |
| | 0 | 343 | | row++; |
| | | 344 | | } |
| | | 345 | | |
| | 0 | 346 | | EscribirSubtotal(ws, row, TotalCols, |
| | 0 | 347 | | $"Subtotal Programa {programaGroup.Key.ProgramaCodigo}", totalPrograma, |
| | 0 | 348 | | XLColor.FromHtml("#D9E1F2")); |
| | 0 | 349 | | for (int i = 0; i < 8; i++) totalGeneral[i] += totalPrograma[i]; |
| | 0 | 350 | | row++; |
| | 0 | 351 | | row++; |
| | | 352 | | } |
| | | 353 | | |
| | 0 | 354 | | ws.Cell(row, 4).Value = "TOTAL GENERAL"; |
| | 0 | 355 | | ws.Cell(row, 4).Style.Font.Bold = true; |
| | 0 | 356 | | ws.Cell(row, 4).Style.Font.FontSize = 12; |
| | 0 | 357 | | for (int i = 0; i < 6; i++) |
| | 0 | 358 | | ws.Cell(row, 5 + i).Value = totalGeneral[i]; |
| | 0 | 359 | | ws.Cell(row, 11).Value = totalGeneral[6]; |
| | 0 | 360 | | ws.Cell(row, 12).Value = totalGeneral[7]; |
| | 0 | 361 | | ws.Range(row, 1, row, TotalCols).Style.Font.Bold = true; |
| | 0 | 362 | | ws.Range(row, 1, row, TotalCols).Style.Fill.BackgroundColor = XLColor.FromHtml("#4472C4"); |
| | 0 | 363 | | ws.Range(row, 1, row, TotalCols).Style.Font.FontColor = XLColor.White; |
| | | 364 | | |
| | 0 | 365 | | ws.Range(headerRow, 5, row, 12).Style.NumberFormat.Format = "#,##0.00"; |
| | 0 | 366 | | ws.Columns().AdjustToContents(); |
| | | 367 | | |
| | 0 | 368 | | using var ms = new MemoryStream(); |
| | 0 | 369 | | wb.SaveAs(ms); |
| | 0 | 370 | | return ms.ToArray(); |
| | 0 | 371 | | } |
| | | 372 | | |
| | | 373 | | private static void EscribirSubtotal(IXLWorksheet ws, int row, int totalCols, string etiqueta, decimal[] totales, XL |
| | | 374 | | { |
| | 0 | 375 | | ws.Cell(row, 4).Value = etiqueta; |
| | 0 | 376 | | for (int i = 0; i < 6; i++) |
| | 0 | 377 | | ws.Cell(row, 5 + i).Value = totales[i]; |
| | 0 | 378 | | ws.Cell(row, 11).Value = totales[6]; |
| | 0 | 379 | | ws.Cell(row, 12).Value = totales[7]; |
| | 0 | 380 | | ws.Range(row, 1, row, totalCols).Style.Font.Bold = true; |
| | 0 | 381 | | ws.Range(row, 1, row, totalCols).Style.Fill.BackgroundColor = bgColor; |
| | 0 | 382 | | } |
| | | 383 | | |
| | 0 | 384 | | private record FilaControl( |
| | 0 | 385 | | long PersonaId, |
| | 0 | 386 | | string Cedula, |
| | 0 | 387 | | string NombreCompleto, |
| | 0 | 388 | | string GradoDenominacion, |
| | 0 | 389 | | short GradoOrden, |
| | 0 | 390 | | string FechaIngreso, |
| | 0 | 391 | | string SituacionCodigo, |
| | 0 | 392 | | string SituacionDenominacion, |
| | 0 | 393 | | string ProgramaCodigo, |
| | 0 | 394 | | string ProgramaDenominacion, |
| | 0 | 395 | | decimal[] MesesData, |
| | 0 | 396 | | decimal TotalSemestral, |
| | 0 | 397 | | decimal Duodecimo, |
| | 0 | 398 | | bool EsBaja); |
| | | 399 | | } |