| | | 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 AguinaldoPadronService : IAguinaldoPadronService |
| | | 9 | | { |
| | | 10 | | private readonly ApplicationDbContext _context; |
| | | 11 | | |
| | 0 | 12 | | public AguinaldoPadronService(ApplicationDbContext context) |
| | | 13 | | { |
| | 0 | 14 | | _context = context; |
| | 0 | 15 | | } |
| | | 16 | | |
| | | 17 | | public async Task<(byte[] Bytes, string FileName)> GenerarPadronExcelAsync(int anio, int mes) |
| | | 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 | | var semestre = (short)(mes == 6 ? 1 : 2); |
| | | 23 | | |
| | 0 | 24 | | var rawData = await ( |
| | 0 | 25 | | from a in _context.Aguinaldos |
| | 0 | 26 | | where a.Anio == (short)anio && a.Semestre == semestre |
| | 0 | 27 | | join rl in _context.RelacionesLaborales on a.PersonaId equals rl.PersonaId |
| | 0 | 28 | | where rl.Estado == EstadoRelacion.Activo |
| | 0 | 29 | | select new |
| | 0 | 30 | | { |
| | 0 | 31 | | rl.Persona.Cedula, |
| | 0 | 32 | | rl.Persona.PrimerNombre, |
| | 0 | 33 | | rl.Persona.SegundoNombre, |
| | 0 | 34 | | rl.Persona.PrimerApellido, |
| | 0 | 35 | | rl.Persona.SegundoApellido, |
| | 0 | 36 | | Grado = rl.Grado.Denominacion, |
| | 0 | 37 | | Unidad = rl.Unidad.Denominacion, |
| | 0 | 38 | | Situacion = rl.Situacion.Denominacion, |
| | 0 | 39 | | Nominal = a.Nominal ?? 0m, |
| | 0 | 40 | | Irpf = a.IrpfAguinaldo, |
| | 0 | 41 | | Montepio = a.Montepio ?? 0m, |
| | 0 | 42 | | Sanidad = a.Sanidad ?? 0m, |
| | 0 | 43 | | TotalDescuentos = a.TotalDescuentos ?? 0m, |
| | 0 | 44 | | Liquido = a.Liquido ?? 0m, |
| | 0 | 45 | | }).ToListAsync(); |
| | | 46 | | |
| | 0 | 47 | | var filas = rawData |
| | 0 | 48 | | .Select(d => new FilaPadron( |
| | 0 | 49 | | d.Cedula, |
| | 0 | 50 | | FormatNombre(d.PrimerNombre, d.SegundoNombre, d.PrimerApellido, d.SegundoApellido), |
| | 0 | 51 | | d.Grado, |
| | 0 | 52 | | d.Unidad, |
| | 0 | 53 | | d.Situacion, |
| | 0 | 54 | | d.Nominal, |
| | 0 | 55 | | d.Irpf, |
| | 0 | 56 | | d.Montepio, |
| | 0 | 57 | | d.Sanidad, |
| | 0 | 58 | | d.TotalDescuentos, |
| | 0 | 59 | | d.Liquido)) |
| | 0 | 60 | | .OrderBy(f => f.NombreCompleto) |
| | 0 | 61 | | .ToList(); |
| | | 62 | | |
| | 0 | 63 | | var bytes = GenerarExcel(filas, anio, mes); |
| | 0 | 64 | | return (bytes, $"padron_aguinaldo_{anio}_{mes:D2}.xlsx"); |
| | 0 | 65 | | } |
| | | 66 | | |
| | | 67 | | private static byte[] GenerarExcel(List<FilaPadron> filas, int anio, int mes) |
| | | 68 | | { |
| | 0 | 69 | | using var wb = new XLWorkbook(); |
| | 0 | 70 | | var ws = wb.Worksheets.Add("Padrón"); |
| | | 71 | | |
| | 0 | 72 | | int row = 1; |
| | | 73 | | |
| | 0 | 74 | | var tituloSemestre = mes == 6 ? "1er Semestre (Junio)" : "2do Semestre (Diciembre)"; |
| | 0 | 75 | | ws.Cell(row, 1).Value = $"Padrón Aguinaldo Semestral - Año {anio} - {tituloSemestre}"; |
| | 0 | 76 | | ws.Range(row, 1, row, 11).Merge().Style.Font.Bold = true; |
| | 0 | 77 | | ws.Range(row, 1, row, 11).Style.Font.FontSize = 14; |
| | 0 | 78 | | row += 2; |
| | | 79 | | |
| | 0 | 80 | | string[] headers = ["Cédula", "Nombres y Apellidos", "Grado", "Unidad", "Situación", "Nominal", "IRPF", "Montepi |
| | 0 | 81 | | for (int c = 0; c < headers.Length; c++) |
| | | 82 | | { |
| | 0 | 83 | | var cell = ws.Cell(row, c + 1); |
| | 0 | 84 | | cell.Value = headers[c]; |
| | 0 | 85 | | cell.Style.Font.Bold = true; |
| | 0 | 86 | | cell.Style.Fill.BackgroundColor = XLColor.LightGray; |
| | 0 | 87 | | cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; |
| | | 88 | | } |
| | 0 | 89 | | row++; |
| | | 90 | | |
| | 0 | 91 | | foreach (var f in filas) |
| | | 92 | | { |
| | 0 | 93 | | ws.Cell(row, 1).Value = f.Cedula; |
| | 0 | 94 | | ws.Cell(row, 2).Value = f.NombreCompleto; |
| | 0 | 95 | | ws.Cell(row, 3).Value = f.Grado; |
| | 0 | 96 | | ws.Cell(row, 4).Value = f.Unidad; |
| | 0 | 97 | | ws.Cell(row, 5).Value = f.Situacion; |
| | 0 | 98 | | ws.Cell(row, 6).Value = f.Nominal; |
| | 0 | 99 | | ws.Cell(row, 7).Value = f.Irpf; |
| | 0 | 100 | | ws.Cell(row, 8).Value = f.Montepio; |
| | 0 | 101 | | ws.Cell(row, 9).Value = f.Sanidad; |
| | 0 | 102 | | ws.Cell(row, 10).Value = f.TotalDescuentos; |
| | 0 | 103 | | ws.Cell(row, 11).Value = f.Liquido; |
| | 0 | 104 | | row++; |
| | | 105 | | } |
| | 0 | 106 | | row++; |
| | | 107 | | |
| | 0 | 108 | | EscribirFilaTotales(ws, ref row, $"TOTAL FUNCIONARIOS: {filas.Count}", filas); |
| | 0 | 109 | | row++; |
| | | 110 | | |
| | 0 | 111 | | EscribirSeccionSubtotales(ws, ref row, "Totales por Situación", filas, f => f.Situacion); |
| | 0 | 112 | | row++; |
| | | 113 | | |
| | 0 | 114 | | EscribirSeccionSubtotales(ws, ref row, "Totales por Unidad", filas, f => f.Unidad); |
| | 0 | 115 | | row++; |
| | | 116 | | |
| | 0 | 117 | | EscribirSeccionSubtotales(ws, ref row, "Totales por Grado", filas, f => f.Grado); |
| | | 118 | | |
| | 0 | 119 | | ws.Range(1, 6, row, 11).Style.NumberFormat.Format = "#,##0.00"; |
| | 0 | 120 | | ws.Columns().AdjustToContents(); |
| | | 121 | | |
| | 0 | 122 | | using var ms = new MemoryStream(); |
| | 0 | 123 | | wb.SaveAs(ms); |
| | 0 | 124 | | return ms.ToArray(); |
| | 0 | 125 | | } |
| | | 126 | | |
| | | 127 | | private static void EscribirFilaTotales(IXLWorksheet ws, ref int row, string etiqueta, IEnumerable<FilaPadron> filas |
| | | 128 | | { |
| | 0 | 129 | | var list = filas.ToList(); |
| | 0 | 130 | | ws.Cell(row, 1).Value = etiqueta; |
| | 0 | 131 | | ws.Cell(row, 6).Value = list.Sum(f => f.Nominal); |
| | 0 | 132 | | ws.Cell(row, 7).Value = list.Sum(f => f.Irpf); |
| | 0 | 133 | | ws.Cell(row, 8).Value = list.Sum(f => f.Montepio); |
| | 0 | 134 | | ws.Cell(row, 9).Value = list.Sum(f => f.Sanidad); |
| | 0 | 135 | | ws.Cell(row, 10).Value = list.Sum(f => f.TotalDescuentos); |
| | 0 | 136 | | ws.Cell(row, 11).Value = list.Sum(f => f.Liquido); |
| | 0 | 137 | | for (int c = 1; c <= 11; c++) |
| | 0 | 138 | | ws.Cell(row, c).Style.Font.Bold = true; |
| | 0 | 139 | | row++; |
| | 0 | 140 | | } |
| | | 141 | | |
| | | 142 | | private static void EscribirSeccionSubtotales(IXLWorksheet ws, ref int row, string titulo, List<FilaPadron> filas, F |
| | | 143 | | { |
| | 0 | 144 | | ws.Cell(row, 1).Value = titulo; |
| | 0 | 145 | | ws.Cell(row, 1).Style.Font.Bold = true; |
| | 0 | 146 | | ws.Cell(row, 1).Style.Font.Italic = true; |
| | 0 | 147 | | row++; |
| | | 148 | | |
| | 0 | 149 | | foreach (var grupo in filas.GroupBy(getKey).OrderBy(g => g.Key)) |
| | | 150 | | { |
| | 0 | 151 | | var list = grupo.ToList(); |
| | 0 | 152 | | ws.Cell(row, 1).Value = grupo.Key; |
| | 0 | 153 | | ws.Cell(row, 2).Value = list.Count; |
| | 0 | 154 | | ws.Cell(row, 6).Value = list.Sum(f => f.Nominal); |
| | 0 | 155 | | ws.Cell(row, 7).Value = list.Sum(f => f.Irpf); |
| | 0 | 156 | | ws.Cell(row, 8).Value = list.Sum(f => f.Montepio); |
| | 0 | 157 | | ws.Cell(row, 9).Value = list.Sum(f => f.Sanidad); |
| | 0 | 158 | | ws.Cell(row, 10).Value = list.Sum(f => f.TotalDescuentos); |
| | 0 | 159 | | ws.Cell(row, 11).Value = list.Sum(f => f.Liquido); |
| | 0 | 160 | | row++; |
| | | 161 | | } |
| | 0 | 162 | | } |
| | | 163 | | |
| | | 164 | | private static string FormatNombre(string primerNombre, string? segundoNombre, string primerApellido, string? segund |
| | 0 | 165 | | => $"{primerNombre}{(string.IsNullOrWhiteSpace(segundoNombre) ? "" : " " + segundoNombre)} {primerApellido}{(str |
| | | 166 | | |
| | 0 | 167 | | private record FilaPadron( |
| | 0 | 168 | | string Cedula, |
| | 0 | 169 | | string NombreCompleto, |
| | 0 | 170 | | string Grado, |
| | 0 | 171 | | string Unidad, |
| | 0 | 172 | | string Situacion, |
| | 0 | 173 | | decimal Nominal, |
| | 0 | 174 | | decimal Irpf, |
| | 0 | 175 | | decimal Montepio, |
| | 0 | 176 | | decimal Sanidad, |
| | 0 | 177 | | decimal TotalDescuentos, |
| | 0 | 178 | | decimal Liquido); |
| | | 179 | | } |