QuestPdf Implementado en la totalidad de reportes.
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 7m55s
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 7m55s
This commit is contained in:
@@ -0,0 +1,114 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ComparativaConsumoBobinasDocument : IDocument
|
||||||
|
{
|
||||||
|
public ComparativaConsumoBobinasViewModel Model { get; }
|
||||||
|
|
||||||
|
public ComparativaConsumoBobinasDocument(ComparativaConsumoBobinasViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(9));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("Reporte de Consumo de Bobinas - Comparativa Mensual").SemiBold().FontSize(14);
|
||||||
|
|
||||||
|
string subTitle = Model.EsConsolidado ? "Consolidado" : $"Planta: {Model.NombrePlanta}";
|
||||||
|
column.Item().AlignCenter().Text(subTitle).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
// Le damos una proporción menor al texto de la izquierda (que es corto y fijo).
|
||||||
|
row.RelativeItem(1).Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha del Reporte: ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaReporte);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Le damos una proporción mayor al texto de la derecha (que es largo y variable).
|
||||||
|
// El factor "2" significa que tendrá el doble de espacio disponible que el item con factor "1".
|
||||||
|
row.RelativeItem(2).AlignRight().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Meses: ").SemiBold().FontSize(12);
|
||||||
|
text.Span($"{Model.MesA} (Mes A) contra {Model.MesB} (Mes B)").FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(3); // Tipo Bobina
|
||||||
|
columns.RelativeColumn(1); columns.RelativeColumn(1); columns.RelativeColumn(1); // Grupo Cantidad
|
||||||
|
columns.RelativeColumn(1); columns.RelativeColumn(1); columns.RelativeColumn(1); // Grupo Kilos
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
// Fila 1 del Encabezado
|
||||||
|
header.Cell().RowSpan(2).Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignMiddle().Text("Tipo Bobina").SemiBold();
|
||||||
|
header.Cell().ColumnSpan(3).Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignCenter().Text("Cantidad Bobinas").SemiBold();
|
||||||
|
header.Cell().ColumnSpan(3).Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignCenter().Text("Kilos Utilizados").SemiBold();
|
||||||
|
|
||||||
|
// Fila 2 del Encabezado
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Mes A").SemiBold();
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Mes B").SemiBold();
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Diferencia").SemiBold();
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Kg Mes A").SemiBold();
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Kg Mes B").SemiBold();
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Diferencia").SemiBold();
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.Detalles.OrderBy(x => x.TipoBobina))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.TipoBobina);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.BobinasUtilizadasMesA.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.BobinasUtilizadasMesB.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.DiferenciaBobinasUtilizadas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.KilosUtilizadosMesA.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.KilosUtilizadosMesB.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.DiferenciaKilosUtilizados.ToString("N0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de Totales
|
||||||
|
var style = TextStyle.Default.SemiBold();
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span("Totales").Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.BobinasUtilizadasMesA).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.BobinasUtilizadasMesB).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.DiferenciaBobinasUtilizadas).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.KilosUtilizadosMesA).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.KilosUtilizadosMesB).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.DiferenciaKilosUtilizados).ToString("N0")).Style(style));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ConsumoBobinasPublicacionDocument : IDocument
|
||||||
|
{
|
||||||
|
public ConsumoBobinasPublicacionViewModel Model { get; }
|
||||||
|
|
||||||
|
public ConsumoBobinasPublicacionDocument(ConsumoBobinasPublicacionViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1.5f, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("Reporte de Consumo de Bobinas por Publicaciones").SemiBold().FontSize(14);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha del Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Periodo: ").SemiBold(); text.Span($"{Model.FechaDesde} - {Model.FechaHasta}"); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2); // Planta
|
||||||
|
columns.RelativeColumn(3); // Publicación
|
||||||
|
columns.RelativeColumn(1.5f); // Kilos
|
||||||
|
columns.RelativeColumn(1.5f); // Cant. Bobinas
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Planta");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Publicación");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Kilos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Cant. Bobinas");
|
||||||
|
});
|
||||||
|
|
||||||
|
var gruposPorPlanta = Model.Detalles.GroupBy(p => p.NombrePlanta);
|
||||||
|
|
||||||
|
foreach (var grupoPlanta in gruposPorPlanta)
|
||||||
|
{
|
||||||
|
var primeraFilaDePlanta = true;
|
||||||
|
foreach (var detalle in grupoPlanta.OrderBy(d => d.NombrePublicacion))
|
||||||
|
{
|
||||||
|
// Celda de Planta (solo en la primera fila del grupo)
|
||||||
|
if (primeraFilaDePlanta)
|
||||||
|
{
|
||||||
|
table.Cell().RowSpan((uint)grupoPlanta.Count()).Border(1).Padding(3).AlignTop().Text(grupoPlanta.Key).SemiBold();
|
||||||
|
primeraFilaDePlanta = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3).Text(detalle.NombrePublicacion);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(detalle.TotalKilos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(detalle.CantidadBobinas.ToString("N0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de Totales Generales
|
||||||
|
var totalGeneralKilos = Model.Detalles.Sum(d => d.TotalKilos);
|
||||||
|
var totalGeneralBobinas = Model.Detalles.Sum(d => d.CantidadBobinas);
|
||||||
|
|
||||||
|
table.Cell().ColumnSpan(2).BorderTop(1.5f).BorderColor(Colors.Black).Padding(3).AlignRight().Text("Totales").ExtraBold();
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).Padding(3).AlignRight().Text(t => t.Span(totalGeneralKilos.ToString("N0")).ExtraBold());
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).Padding(3).AlignRight().Text(t => t.Span(totalGeneralBobinas.ToString("N0")).ExtraBold());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes;
|
||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ConsumoBobinasSeccionDocument : IDocument
|
||||||
|
{
|
||||||
|
public ConsumoBobinasSeccionViewModel Model { get; }
|
||||||
|
|
||||||
|
public ConsumoBobinasSeccionDocument(ConsumoBobinasSeccionViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1.5f, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(9));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("Reporte de Consumo de Bobinas por Secciones").SemiBold().FontSize(14);
|
||||||
|
|
||||||
|
string subTitle = Model.EsConsolidado ? "Consolidado" : $"Planta: {Model.NombrePlanta}";
|
||||||
|
column.Item().AlignCenter().Text(subTitle).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha del Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Periodo: ").SemiBold(); text.Span($"{Model.FechaDesde} - {Model.FechaHasta}"); });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Encabezado de la tabla principal
|
||||||
|
column.Item().PaddingTop(10).BorderBottom(1.5f).BorderColor(Colors.Black).Padding(4).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem(1.5f).Text("Publicación").SemiBold();
|
||||||
|
row.RelativeItem(1.5f).Text("Sección").SemiBold();
|
||||||
|
row.RelativeItem(3).Text("Bobina").SemiBold();
|
||||||
|
row.RelativeItem(1).AlignRight().Text("Cant. Bobinas").SemiBold();
|
||||||
|
row.RelativeItem(1).AlignRight().Text("Kilos").SemiBold();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
var gruposPorPublicacion = Model.Detalles.GroupBy(p => p.NombrePublicacion);
|
||||||
|
|
||||||
|
foreach (var grupoPub in gruposPorPublicacion)
|
||||||
|
{
|
||||||
|
column.Item().Element(c => ComposePublicacionSection(c, grupoPub));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de Totales Generales al final
|
||||||
|
var totalGeneralBobinas = Model.Detalles.Sum(d => d.CantidadBobinas);
|
||||||
|
var totalGeneralKilos = Model.Detalles.Sum(d => d.TotalKilos);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(10).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem(6).AlignRight().Text("Total General").ExtraBold().FontSize(12);
|
||||||
|
row.RelativeItem(1).AlignRight().Text(totalGeneralBobinas.ToString("N0")).ExtraBold().FontSize(12);
|
||||||
|
row.RelativeItem(1).AlignRight().Text(totalGeneralKilos.ToString("N0")).ExtraBold().FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- COMPONENTE PARA UNA PUBLICACIÓN ENTERA ---
|
||||||
|
void ComposePublicacionSection(IContainer container, IGrouping<string, ConsumoBobinasSeccionDto> grupoPub)
|
||||||
|
{
|
||||||
|
container.Row(row =>
|
||||||
|
{
|
||||||
|
// Columna 1: Nombre de la Publicación
|
||||||
|
row.RelativeItem(1.5f).BorderBottom(1).BorderLeft(1).BorderRight(1).BorderColor(Colors.Grey.Medium).Padding(3).Text(grupoPub.Key).SemiBold();
|
||||||
|
|
||||||
|
// Columna 2: Contiene todas las sub-tablas de secciones
|
||||||
|
row.RelativeItem(6.5f).Column(seccionesColumn =>
|
||||||
|
{
|
||||||
|
var gruposPorSeccion = grupoPub.GroupBy(s => s.NombreSeccion);
|
||||||
|
foreach(var grupoSec in gruposPorSeccion)
|
||||||
|
{
|
||||||
|
seccionesColumn.Item().Element(c => ComposeSeccionTable(c, grupoSec));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- COMPONENTE PARA LA TABLA DE UNA SECCIÓN ---
|
||||||
|
void ComposeSeccionTable(IContainer container, IGrouping<string, ConsumoBobinasSeccionDto> grupoSec)
|
||||||
|
{
|
||||||
|
container.Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(1.5f); // Sección
|
||||||
|
columns.RelativeColumn(3); // Bobina
|
||||||
|
columns.RelativeColumn(1); // Cantidad
|
||||||
|
columns.RelativeColumn(1); // Kilos
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filas de detalle
|
||||||
|
foreach (var detalle in grupoSec.OrderBy(d => d.NombreBobina))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Medium).Padding(3).Text(grupoSec.Key);
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Medium).Padding(3).Text(detalle.NombreBobina);
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Medium).Padding(3).AlignRight().Text(detalle.CantidadBobinas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Medium).Padding(3).AlignRight().Text(detalle.TotalKilos.ToString("N0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de total de la sección
|
||||||
|
var totalCantSeccion = grupoSec.Sum(d => d.CantidadBobinas);
|
||||||
|
var totalKilosSeccion = grupoSec.Sum(d => d.TotalKilos);
|
||||||
|
|
||||||
|
table.Cell().ColumnSpan(2).Border(1).BorderColor(Colors.Grey.Medium).AlignRight().Padding(3).Text("Total Sección").SemiBold();
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Medium).Padding(3).AlignRight().Text(t => t.Span(totalCantSeccion.ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Medium).Padding(3).AlignRight().Text(t => t.Span(totalKilosSeccion.ToString("N0")).SemiBold());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ControlDevolucionesDocument : IDocument
|
||||||
|
{
|
||||||
|
public ControlDevolucionesViewModel Model { get; }
|
||||||
|
|
||||||
|
public ControlDevolucionesDocument(ControlDevolucionesViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
public DocumentSettings GetSettings() => DocumentSettings.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Roboto").FontSize(11));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("Control de Devoluciones").SemiBold().FontSize(16);
|
||||||
|
column.Item().AlignCenter().Text("Canillas / Accionistas").FontSize(13);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(15);
|
||||||
|
|
||||||
|
column.Item().Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha Consultada: ").SemiBold();
|
||||||
|
text.Span(Model.FechaConsultada);
|
||||||
|
});
|
||||||
|
row.RelativeItem().AlignRight().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Cantidad Canillas: ").SemiBold();
|
||||||
|
text.Span(Model.CantidadCanillas.ToString());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5).Border(1).Background(Colors.Grey.Lighten3).AlignCenter().Padding(2).Text(Model.NombreEmpresa).SemiBold();
|
||||||
|
|
||||||
|
column.Item().Border(1).Padding(10).Column(innerCol =>
|
||||||
|
{
|
||||||
|
innerCol.Spacing(5);
|
||||||
|
|
||||||
|
// Fila de "Ingresados por Remito" con borde inferior sólido.
|
||||||
|
innerCol.Item().BorderBottom(1, Unit.Point).BorderColor(Colors.Grey.Medium).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text("Ingresados por Remito:").SemiBold();
|
||||||
|
row.RelativeItem().AlignRight().Text(Model.TotalIngresadosPorRemito.ToString("N0"));
|
||||||
|
}); // <-- SOLUCIÓN: Borde sólido simple.
|
||||||
|
|
||||||
|
foreach (var item in Model.Detalles)
|
||||||
|
{
|
||||||
|
var totalSeccion = item.Devueltos - item.Llevados;
|
||||||
|
innerCol.Item().PaddingTop(5).Row(row =>
|
||||||
|
{
|
||||||
|
row.ConstantItem(100).Text(item.Tipo).SemiBold();
|
||||||
|
|
||||||
|
row.RelativeItem().Column(sub =>
|
||||||
|
{
|
||||||
|
sub.Spacing(2);
|
||||||
|
sub.Item().Row(r => {
|
||||||
|
r.RelativeItem().Text("Llevados");
|
||||||
|
r.RelativeItem().AlignRight().Text($"-{item.Llevados:N0}");
|
||||||
|
});
|
||||||
|
sub.Item().Row(r => {
|
||||||
|
r.RelativeItem().Text("Devueltos");
|
||||||
|
r.RelativeItem().AlignRight().Text($"{item.Devueltos:N0}");
|
||||||
|
});
|
||||||
|
sub.Item().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(2).Row(r => {
|
||||||
|
r.RelativeItem().Text(t => t.Span("Total").SemiBold());
|
||||||
|
r.RelativeItem().AlignRight().Text(t => t.Span(totalSeccion.ToString("N0")).SemiBold());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
column.Item().PaddingTop(10).Column(finalCol =>
|
||||||
|
{
|
||||||
|
finalCol.Spacing(2);
|
||||||
|
|
||||||
|
Action<RowDescriptor, string, string, bool> AddTotalRow = (row, label, value, isBold) =>
|
||||||
|
{
|
||||||
|
var text = row.RelativeItem().Text(label);
|
||||||
|
if (isBold) text.SemiBold();
|
||||||
|
|
||||||
|
var valueText = row.ConstantItem(80).AlignRight().Text(value);
|
||||||
|
if (isBold) valueText.SemiBold();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Usamos bordes superiores para separar las líneas de total
|
||||||
|
finalCol.Item().BorderTop(2f).BorderColor(Colors.Black).PaddingTop(2).Row(row => AddTotalRow(row, "Total Devolución a la Fecha", Model.TotalDevolucionALaFecha.ToString("N0"), false));
|
||||||
|
finalCol.Item().BorderTop(1).BorderColor(Colors.Grey.Lighten2).PaddingTop(2).Row(row => AddTotalRow(row, "Total Devolución Días Anteriores", Model.TotalDevolucionDiasAnteriores.ToString("N0"), false));
|
||||||
|
finalCol.Item().BorderTop(1).BorderColor(Colors.Grey.Lighten2).PaddingTop(2).Row(row => AddTotalRow(row, "Total Devolución", Model.TotalDevolucionGeneral.ToString("N0"), false));
|
||||||
|
finalCol.Item().BorderTop(2f).BorderColor(Colors.Black).PaddingTop(5).Row(row => AddTotalRow(row, "Sin Cargo", Model.TotalSinCargo.ToString("N0"), false));
|
||||||
|
finalCol.Item().BorderTop(1).BorderColor(Colors.Grey.Lighten2).PaddingTop(2).Row(row => AddTotalRow(row, "Sobrantes", $"-{Model.TotalSobrantes.ToString("N0")}", false));
|
||||||
|
finalCol.Item().BorderTop(1).BorderColor(Colors.Grey.Lighten2).BorderBottom(1).BorderColor(Colors.Grey.Lighten2).PaddingTop(5).Row(row => AddTotalRow(row, "Diferencia", Model.DiferenciaFinal.ToString("N0"), true));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class CuentasDistribuidorDocument : IDocument
|
||||||
|
{
|
||||||
|
public CuentasDistribuidorViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR", false)
|
||||||
|
{
|
||||||
|
NumberFormat = { CurrencySymbol = "$" }
|
||||||
|
};
|
||||||
|
|
||||||
|
public CuentasDistribuidorDocument(CuentasDistribuidorViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
public DocumentSettings GetSettings() => DocumentSettings.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(9));
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); x.Span(" de "); x.TotalPages(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text($"Fecha de Reporte {Model.FechaReporte}");
|
||||||
|
row.RelativeItem().AlignCenter().Text("Cuenta De Distribuidor").SemiBold().FontSize(14);
|
||||||
|
row.RelativeItem();
|
||||||
|
});
|
||||||
|
|
||||||
|
column.Item().AlignCenter().Text(Model.NombreDistribuidor).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(2, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem(2);
|
||||||
|
row.RelativeItem(8).AlignCenter().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha Consultada: Desde ").SemiBold();
|
||||||
|
text.Span(Model.FechaDesde);
|
||||||
|
text.Span(" Hasta ").SemiBold();
|
||||||
|
text.Span(Model.FechaHasta);
|
||||||
|
});
|
||||||
|
row.RelativeItem(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(20);
|
||||||
|
|
||||||
|
if (Model.Movimientos.Any()) column.Item().Element(ComposeMovimientosTable);
|
||||||
|
if (Model.Pagos.Any()) column.Item().Element(ComposePagosTable);
|
||||||
|
if (Model.DebitosCreditos.Any()) column.Item().Element(ComposeDebCredTable);
|
||||||
|
|
||||||
|
column.Item().Element(ComposeResumenPeriodo);
|
||||||
|
column.Item().Element(ComposeSaldoFinal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeMovimientosTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(5).Text("Movimientos").SemiBold().FontSize(11);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(60);
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
columns.ConstantColumn(50);
|
||||||
|
columns.ConstantColumn(50);
|
||||||
|
columns.RelativeColumn(1.5f);
|
||||||
|
columns.RelativeColumn(1.5f);
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Fecha");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Publicacion");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Remito");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Cantidad");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Debe");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Haber");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Saldo");
|
||||||
|
});
|
||||||
|
|
||||||
|
decimal saldoAcumulado = 0; // Inicia en CERO
|
||||||
|
foreach (var item in Model.Movimientos.OrderBy(m => m.Fecha))
|
||||||
|
{
|
||||||
|
saldoAcumulado += (item.Debe - item.Haber);
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Fecha.ToString("dd/MM/yyyy"));
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Publicacion);
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Remito);
|
||||||
|
table.Cell().Border(1).Padding(2).AlignCenter().Text(item.Cantidad.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.Debe.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.Haber.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(saldoAcumulado.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Cell().ColumnSpan(4).Border(1).AlignRight().Padding(2).Text(t => t.Span("Totales").SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(Model.Movimientos.Sum(x => x.Debe).ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(Model.Movimientos.Sum(x => x.Haber).ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(saldoAcumulado.ToString("C", CultureAr)).SemiBold());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposePagosTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(5).Text("Pagos").SemiBold().FontSize(12);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(60);
|
||||||
|
columns.RelativeColumn(1.5f);
|
||||||
|
columns.ConstantColumn(50);
|
||||||
|
columns.RelativeColumn(1.5f);
|
||||||
|
columns.RelativeColumn(1.5f);
|
||||||
|
columns.RelativeColumn(1.5f);
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Fecha");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Recibo");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Tipo");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Debe");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Haber");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Saldo");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Detalle");
|
||||||
|
});
|
||||||
|
|
||||||
|
decimal saldoAcumulado = Model.TotalMovimientos;
|
||||||
|
foreach (var item in Model.Pagos.OrderBy(p => p.Fecha).ThenBy(p => p.Recibo))
|
||||||
|
{
|
||||||
|
saldoAcumulado += (item.Debe - item.Haber);
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Fecha.ToString("dd/MM/yyyy"));
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Recibo.ToString());
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Tipo);
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.Debe.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.Haber.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(saldoAcumulado.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Detalle);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Cell().ColumnSpan(3).Border(1).AlignRight().Padding(2).Text(t => t.Span("Totales").SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(Model.Pagos.Sum(x => x.Debe).ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(Model.Pagos.Sum(x => x.Haber).ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(saldoAcumulado.ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().Border(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeDebCredTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(5).Text("Débitos / Créditos").SemiBold().FontSize(12);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(65);
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
columns.RelativeColumn(1);
|
||||||
|
columns.RelativeColumn(1);
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Fecha");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Referencia");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Debe");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Haber");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Saldo");
|
||||||
|
});
|
||||||
|
|
||||||
|
decimal saldoAcumulado = Model.TotalMovimientos + Model.TotalPagos;
|
||||||
|
foreach (var item in Model.DebitosCreditos.OrderBy(dc => dc.Fecha))
|
||||||
|
{
|
||||||
|
saldoAcumulado += (item.Debe - item.Haber);
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Fecha.ToString("dd/MM/yyyy"));
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Referencia);
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.Debe.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.Haber.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(saldoAcumulado.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Cell().ColumnSpan(2).Border(1).AlignRight().Padding(2).Text(t => t.Span("Totales").SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(Model.DebitosCreditos.Sum(x => x.Debe).ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(Model.DebitosCreditos.Sum(x => x.Haber).ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().Border(1).AlignRight().Padding(2).Text(t => t.Span(saldoAcumulado.ToString("C", CultureAr)).SemiBold());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeResumenPeriodo(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).AlignLeft().Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().Border(1).Padding(5).Width(300, Unit.Point).Column(col =>
|
||||||
|
{
|
||||||
|
col.Spacing(5);
|
||||||
|
col.Item().Text("Datos totales del periodo consultado").SemiBold();
|
||||||
|
Action<RowDescriptor, string, decimal> AddResumenRow = (row, label, value) =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(label);
|
||||||
|
row.ConstantItem(120).AlignRight().Text(value.ToString("C", CultureAr));
|
||||||
|
};
|
||||||
|
col.Item().Row(row => AddResumenRow(row, "Movimientos", Model.TotalMovimientos));
|
||||||
|
col.Item().Row(row => AddResumenRow(row, "Débitos/Créditos", Model.TotalDebitosCreditos));
|
||||||
|
col.Item().Row(row => AddResumenRow(row, "Pagos", Model.TotalPagos));
|
||||||
|
col.Item().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(5).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text("Total").SemiBold();
|
||||||
|
row.ConstantItem(120).AlignRight().Text(t => t.Span(Model.TotalPeriodo.ToString("C", CultureAr)).SemiBold());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeSaldoFinal(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).AlignLeft().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span($"Saldo Total del Distribuidor al {Model.FechaReporte} ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.SaldoDeCuenta.ToString("C", CultureAr)).SemiBold().FontSize(12);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
// --- REEMPLAZAR ARCHIVO: Controllers/Reportes/PdfTemplates/DistribucionCanillasDocument.cs ---
|
||||||
|
using GestionIntegral.Api.Dtos.Reportes;
|
||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class DistribucionCanillasDocument : IDocument
|
||||||
|
{
|
||||||
|
public DistribucionCanillasViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR");
|
||||||
|
|
||||||
|
public DistribucionCanillasDocument(DistribucionCanillasViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(9));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().Row(row => {
|
||||||
|
row.RelativeItem().Text("Listado de Distribución: Canillas / Accionistas").FontSize(12);
|
||||||
|
row.RelativeItem().AlignRight().Text(text => {
|
||||||
|
text.Span("Fecha Consultada ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaConsultada).FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
column.Item().PaddingTop(5).Row(row => {
|
||||||
|
row.RelativeItem().Text(text => {
|
||||||
|
text.Span("Fecha de Generación del Reporte ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaReporte);
|
||||||
|
});
|
||||||
|
row.RelativeItem().AlignRight().Text(text => {
|
||||||
|
text.Span("Empresa ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.Empresa).FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(15);
|
||||||
|
|
||||||
|
if(Model.Canillas.Any())
|
||||||
|
column.Item().Element(c => ComposeTablaDetallada(c, "Canillas", Model.Canillas));
|
||||||
|
|
||||||
|
if(Model.CanillasAccionistas.Any())
|
||||||
|
column.Item().Element(c => ComposeTablaDetallada(c, "Accionistas", Model.CanillasAccionistas));
|
||||||
|
|
||||||
|
if(Model.CanillasLiquidadasOtraFecha.Any())
|
||||||
|
column.Item().Element(c => ComposeTablaLiquidacion(c, "Liquidación de movimientos de otras fechas canillas", Model.CanillasLiquidadasOtraFecha));
|
||||||
|
|
||||||
|
if(Model.CanillasAccionistasLiquidadasOtraFecha.Any())
|
||||||
|
column.Item().Element(c => ComposeTablaLiquidacion(c, "Liquidación de movimientos de otras fechas accionistas", Model.CanillasAccionistasLiquidadasOtraFecha));
|
||||||
|
|
||||||
|
if(Model.CanillasTodos.Any())
|
||||||
|
column.Item().Element(c => ComposeTablaTotales(c, "Recuento de Publicaciones", Model.CanillasTodos));
|
||||||
|
|
||||||
|
if(Model.RemitoIngresado > 0)
|
||||||
|
column.Item().Element(ComposeResumenDevoluciones);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeTablaDetallada(IContainer container, string title, IEnumerable<DetalleDistribucionCanillaDto> data)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(4).Text(title).SemiBold().FontSize(11);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(3); columns.RelativeColumn(3);
|
||||||
|
columns.RelativeColumn(1); columns.RelativeColumn(1);
|
||||||
|
columns.RelativeColumn(1); columns.RelativeColumn(1.2f);
|
||||||
|
});
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Vendedor");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Publicación");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Vendidos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("A Rendir");
|
||||||
|
});
|
||||||
|
foreach (var grupoCanilla in data.GroupBy(c => c.Canilla))
|
||||||
|
{
|
||||||
|
var primeraFila = true;
|
||||||
|
// El RowSpan es el número de publicaciones + la fila de total
|
||||||
|
var totalFilasGrupo = grupoCanilla.Count() + 1;
|
||||||
|
foreach (var item in grupoCanilla.OrderBy(p => p.Publicacion))
|
||||||
|
{
|
||||||
|
if (primeraFila)
|
||||||
|
{
|
||||||
|
table.Cell().RowSpan((uint)totalFilasGrupo).Border(1).Padding(2).AlignTop().Text(item.Canilla);
|
||||||
|
primeraFila = false;
|
||||||
|
}
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Publicacion);
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantSalida.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantEntrada.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text((item.TotalCantSalida - item.TotalCantEntrada).ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalRendir.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
// Subtotal por canilla
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text("Totales").SemiBold();
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(t => t.Span(grupoCanilla.Sum(i => i.TotalCantSalida).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(t => t.Span(grupoCanilla.Sum(i => i.TotalCantEntrada).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(t => t.Span(grupoCanilla.Sum(i => i.TotalCantSalida - i.TotalCantEntrada).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(t => t.Span(grupoCanilla.Sum(i => i.TotalRendir).ToString("C", CultureAr)).SemiBold());
|
||||||
|
}
|
||||||
|
|
||||||
|
var boldStyle = TextStyle.Default.ExtraBold();
|
||||||
|
table.Cell().ColumnSpan(2).BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span("Total " + title).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantSalida).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantSalida - i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalRendir).ToString("C", CultureAr)).Style(boldStyle));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeTablaLiquidacion(IContainer container, string title, IEnumerable<DetalleDistribucionCanillaDto> data)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(4).Text(title).SemiBold().FontSize(11);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(3); columns.RelativeColumn(1.5f);
|
||||||
|
columns.RelativeColumn(3); columns.RelativeColumn(1);
|
||||||
|
columns.RelativeColumn(1); columns.RelativeColumn(1);
|
||||||
|
columns.RelativeColumn(1.2f);
|
||||||
|
});
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Vendedor");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Fecha");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Publicación");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Vendidos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("A Rendir");
|
||||||
|
});
|
||||||
|
foreach(var item in data.OrderBy(d => d.Canilla).ThenBy(d => d.Fecha))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Canilla);
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Fecha?.ToString("dd/MM/yyyy") ?? "");
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Publicacion);
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantSalida.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantEntrada.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text((item.TotalCantSalida - item.TotalCantEntrada).ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalRendir.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
var boldStyle = TextStyle.Default.ExtraBold();
|
||||||
|
table.Cell().ColumnSpan(3).BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span("Total").Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantSalida).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantSalida - i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalRendir).ToString("C", CultureAr)).Style(boldStyle));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeTablaTotales(IContainer container, string title, IEnumerable<DetalleDistribucionCanillaAllDto> data)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(4).Text(title).SemiBold().FontSize(11);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2); columns.RelativeColumn(3);
|
||||||
|
columns.RelativeColumn(1.2f); columns.RelativeColumn(1.2f);
|
||||||
|
columns.RelativeColumn(1.2f); columns.RelativeColumn(1.5f);
|
||||||
|
});
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Tipo Vendedor");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Publicación");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Vendidos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("A Rendir");
|
||||||
|
});
|
||||||
|
foreach(var item in data.OrderBy(d => d.TipoVendedor).ThenBy(d => d.Publicacion))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.TipoVendedor);
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Publicacion);
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantSalida.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantEntrada.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text((item.TotalCantSalida-item.TotalCantEntrada).ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalRendir.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
var boldStyle = TextStyle.Default.ExtraBold();
|
||||||
|
table.Cell().ColumnSpan(2).BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span("Total General").Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantSalida).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalCantSalida - i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(data.Sum(i => i.TotalRendir).ToString("C", CultureAr)).Style(boldStyle));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeResumenDevoluciones(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5).Column(column => {
|
||||||
|
column.Item().Row(row => {
|
||||||
|
row.Spacing(15);
|
||||||
|
row.AutoItem().Text(text => { text.Span("Remito: ").SemiBold().FontSize(11); text.Span(Model.RemitoIngresado.ToString("N0")).FontSize(11); });
|
||||||
|
row.AutoItem().Text(text => { text.Span("Devolución: ").SemiBold().FontSize(11); text.Span(Model.DevolucionTotal.ToString("N0")).FontSize(11); });
|
||||||
|
row.AutoItem().Text(text => { text.Span("Venta: ").SemiBold().FontSize(11); text.Span(Model.VentaTotal.ToString("N0")).FontSize(11); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class DistribucionCanillasTotalesDocument : IDocument
|
||||||
|
{
|
||||||
|
public DistribucionCanillasViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR");
|
||||||
|
|
||||||
|
public DistribucionCanillasTotalesDocument(DistribucionCanillasViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().Row(row => {
|
||||||
|
row.RelativeItem().Text("Listado de Distribución: Canillas / Accionistas (Totales)").FontSize(12);
|
||||||
|
row.RelativeItem().AlignRight().Text(text => {
|
||||||
|
text.Span("Fecha Consultada ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaConsultada).FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
column.Item().PaddingTop(5).Row(row => {
|
||||||
|
row.RelativeItem().Text(text => {
|
||||||
|
text.Span("Fecha de Generación del Reporte ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaReporte).FontSize(12);
|
||||||
|
});
|
||||||
|
row.RelativeItem().AlignRight().Text(text => {
|
||||||
|
text.Span("Empresa ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.Empresa).FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(15);
|
||||||
|
|
||||||
|
if(Model.CanillasTodos.Any())
|
||||||
|
column.Item().Element(ComposeTablaTotales);
|
||||||
|
|
||||||
|
if(Model.RemitoIngresado > 0)
|
||||||
|
column.Item().Element(ComposeResumenDevoluciones);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeTablaTotales(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(4).Text("Recuento de Publicaciones").SemiBold().FontSize(11);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2); columns.RelativeColumn(3);
|
||||||
|
columns.RelativeColumn(1.2f); columns.RelativeColumn(1.2f);
|
||||||
|
columns.RelativeColumn(1.2f); columns.RelativeColumn(1.5f);
|
||||||
|
});
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Tipo Vendedor");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).Text("Publicación");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("Vendidos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(2).AlignRight().Text("A Rendir");
|
||||||
|
});
|
||||||
|
foreach(var item in Model.CanillasTodos.OrderBy(d => d.TipoVendedor).ThenBy(d => d.Publicacion))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.TipoVendedor);
|
||||||
|
table.Cell().Border(1).Padding(2).Text(item.Publicacion);
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantSalida.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalCantEntrada.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text((item.TotalCantSalida-item.TotalCantEntrada).ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(2).AlignRight().Text(item.TotalRendir.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
var boldStyle = TextStyle.Default.ExtraBold();
|
||||||
|
table.Cell().ColumnSpan(2).BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span("Total General").Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(Model.CanillasTodos.Sum(i => i.TotalCantSalida).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(Model.CanillasTodos.Sum(i => i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(Model.CanillasTodos.Sum(i => i.TotalCantSalida - i.TotalCantEntrada).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).Padding(2).AlignRight().Text(t => t.Span(Model.CanillasTodos.Sum(i => i.TotalRendir).ToString("C", CultureAr)).Style(boldStyle));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeResumenDevoluciones(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(10).Column(column => {
|
||||||
|
column.Item().Row(row => {
|
||||||
|
row.Spacing(15);
|
||||||
|
row.AutoItem().Text(text => { text.Span("Remito: ").SemiBold(); text.Span(Model.RemitoIngresado.ToString("N0")); });
|
||||||
|
row.AutoItem().Text(text => { text.Span("Devolución: ").SemiBold(); text.Span(Model.DevolucionTotal.ToString("N0")); });
|
||||||
|
row.AutoItem().Text(text => { text.Span("Venta: ").SemiBold(); text.Span(Model.VentaTotal.ToString("N0")); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
|||||||
container
|
container
|
||||||
.Page(page =>
|
.Page(page =>
|
||||||
{
|
{
|
||||||
page.Margin(1.5f, Unit.Centimetre);
|
page.Margin(1, Unit.Centimetre);
|
||||||
page.PageColor(Colors.White);
|
page.PageColor(Colors.White);
|
||||||
page.DefaultTextStyle(x => x.FontFamily("Roboto").FontSize(10));
|
page.DefaultTextStyle(x => x.FontFamily("Roboto").FontSize(10));
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
|||||||
container
|
container
|
||||||
.Page(page =>
|
.Page(page =>
|
||||||
{
|
{
|
||||||
page.Margin(1.5f, Unit.Centimetre);
|
page.Margin(1, Unit.Centimetre);
|
||||||
page.PageColor(Colors.White);
|
page.PageColor(Colors.White);
|
||||||
page.DefaultTextStyle(x => x.FontFamily("Roboto").FontSize(10));
|
page.DefaultTextStyle(x => x.FontFamily("Roboto").FontSize(10));
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class LiquidacionCanillaDocument : IDocument
|
||||||
|
{
|
||||||
|
public LiquidacionCanillaViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR");
|
||||||
|
|
||||||
|
public LiquidacionCanillaDocument(LiquidacionCanillaViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
// CORRECCIÓN: El método GetSettings ya no es necesario para este diseño.
|
||||||
|
// La configuración por defecto es suficiente.
|
||||||
|
// public DocumentSettings GetSettings() => DocumentSettings.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Size(PageSizes.A5);
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(9));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().Text("EL DIA S.A.I.C. y F.");
|
||||||
|
column.Item().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Liquidación venta de diarios del: ");
|
||||||
|
text.Span(Model.FechaLiquidacion);
|
||||||
|
});
|
||||||
|
column.Item().PaddingTop(5).Text($"Vendedor: {Model.NombreVendedor}").SemiBold();
|
||||||
|
column.Item().PaddingTop(10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(15);
|
||||||
|
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
columns.RelativeColumn(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.Detalles.OrderBy(d => d.Publicacion))
|
||||||
|
{
|
||||||
|
var vendidos = item.TotalCantSalida - item.TotalCantEntrada;
|
||||||
|
|
||||||
|
table.Cell().ColumnSpan(3).Text(item.Publicacion).SemiBold();
|
||||||
|
|
||||||
|
table.Cell();
|
||||||
|
table.Cell().Text("Retirados");
|
||||||
|
table.Cell().AlignRight().Text(item.TotalCantSalida.ToString("N0"));
|
||||||
|
|
||||||
|
table.Cell();
|
||||||
|
table.Cell().Text("Devueltos");
|
||||||
|
table.Cell().AlignRight().Text(item.TotalCantEntrada.ToString("N0"));
|
||||||
|
|
||||||
|
table.Cell();
|
||||||
|
table.Cell().Text("Vendidos");
|
||||||
|
table.Cell().AlignRight().Text(vendidos.ToString("N0"));
|
||||||
|
|
||||||
|
table.Cell();
|
||||||
|
table.Cell().Text("Precio Unitario");
|
||||||
|
table.Cell().AlignRight().Text(item.PrecioEjemplar.ToString("C", CultureAr));
|
||||||
|
|
||||||
|
table.Cell();
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(2).Text(t => t.Span("Importe Vendido").SemiBold());
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(2).AlignRight().Text(t => t.Span(item.TotalRendir.ToString("C", CultureAr)).SemiBold());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
column.Item().BorderTop(2).BorderColor(Colors.Black).PaddingTop(4).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text("Total A Rendir").SemiBold().FontSize(10);
|
||||||
|
row.RelativeItem().AlignRight().Text(text => text.Span(Model.TotalARendir.ToString("C", CultureAr)).SemiBold().FontSize(10));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!Model.EsAccionista && Model.Ganancias.Any())
|
||||||
|
{
|
||||||
|
column.Item().PaddingTop(10).Element(ComposeGananciasTable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeGananciasTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().Text("Comisiones Acreditadas").SemiBold().FontSize(11);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2);
|
||||||
|
columns.RelativeColumn(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.Ganancias)
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Lighten2).Padding(3).Text(item.Publicacion);
|
||||||
|
table.Cell().Border(1).BorderColor(Colors.Grey.Lighten2).Padding(3).AlignRight().Text(item.TotalRendir.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).Padding(3).Text("Total Comisiones").SemiBold();
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).Padding(3).AlignRight().Text(t => t.Span(Model.TotalComisiones.ToString("C", CultureAr)).SemiBold());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ListadoDistCanMensualDiariosDocument : IDocument
|
||||||
|
{
|
||||||
|
public ListadoDistCanMensualDiariosViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR");
|
||||||
|
|
||||||
|
public ListadoDistCanMensualDiariosDocument(ListadoDistCanMensualDiariosViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(9));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text($"Ventas por {Model.TipoDestinatario} desde el {Model.FechaDesde} hasta el {Model.FechaHasta}").SemiBold().FontSize(12);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
// APLICAMOS LA SOLUCIÓN AQUÍ: .AlignTop()
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).AlignTop().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(3); // Nombre
|
||||||
|
columns.ConstantColumn(50); // El Día
|
||||||
|
columns.ConstantColumn(50); // El Plata
|
||||||
|
columns.ConstantColumn(60); // Vendidos
|
||||||
|
columns.RelativeColumn(1.5f); // Imp. El Día
|
||||||
|
columns.RelativeColumn(1.5f); // Imp. El Plata
|
||||||
|
columns.RelativeColumn(1.5f); // Importe Total
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().BorderBottom(1).BorderColor(Colors.Grey.Medium).Padding(4).Text("Nombre").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1).BorderColor(Colors.Grey.Medium).Padding(4).AlignCenter().Text("El Día").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1).BorderColor(Colors.Grey.Medium).Padding(4).AlignCenter().Text("El Plata").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1).BorderColor(Colors.Grey.Medium).Padding(4).AlignCenter().Text("Vendidos").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1).BorderColor(Colors.Grey.Medium).Padding(4).AlignRight().Text("Imp. El Día").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1).BorderColor(Colors.Grey.Medium).Padding(4).AlignRight().Text("Imp. El Plata").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1).BorderColor(Colors.Grey.Medium).Padding(4).AlignRight().Text("Importe Total").SemiBold();
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.Detalles.OrderBy(d => d.Canilla))
|
||||||
|
{
|
||||||
|
table.Cell().Padding(3).PaddingRight(10).Text(item.Canilla);
|
||||||
|
table.Cell().Padding(3).AlignCenter().Text(item.ElDia?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Padding(3).AlignCenter().Text(item.ElPlata?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Padding(3).AlignCenter().Text(item.Vendidos?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Padding(3).AlignRight().Text(item.ImporteElDia?.ToString("C", CultureAr) ?? "$ 0.00");
|
||||||
|
table.Cell().Padding(3).AlignRight().Text(item.ImporteElPlata?.ToString("C", CultureAr) ?? "$ 0.00");
|
||||||
|
table.Cell().Padding(3).AlignRight().Text(item.ImporteTotal?.ToString("C", CultureAr) ?? "$ 0.00");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de Totales
|
||||||
|
var totalElDia = Model.Detalles.Sum(x => x.ElDia ?? 0);
|
||||||
|
var totalElPlata = Model.Detalles.Sum(x => x.ElPlata ?? 0);
|
||||||
|
var totalVendidos = Model.Detalles.Sum(x => x.Vendidos ?? 0);
|
||||||
|
var totalImpElDia = Model.Detalles.Sum(x => x.ImporteElDia ?? 0);
|
||||||
|
var totalImpElPlata = Model.Detalles.Sum(x => x.ImporteElPlata ?? 0);
|
||||||
|
var totalImpTotal = Model.Detalles.Sum(x => x.ImporteTotal ?? 0);
|
||||||
|
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(4).Text("Totales").SemiBold();
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(4).AlignCenter().Text(t => t.Span(totalElDia.ToString("N0")).SemiBold());
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(4).AlignCenter().Text(t => t.Span(totalElPlata.ToString("N0")).SemiBold());
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(4).AlignCenter().Text(t => t.Span(totalVendidos.ToString("N0")).SemiBold());
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(4).AlignRight().Text(t => t.Span(totalImpElDia.ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(4).AlignRight().Text(t => t.Span(totalImpElPlata.ToString("C", CultureAr)).SemiBold());
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).PaddingTop(4).AlignRight().Text(t => t.Span(totalImpTotal.ToString("C", CultureAr)).SemiBold());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ListadoDistCanMensualDocument : IDocument
|
||||||
|
{
|
||||||
|
public ListadoDistCanMensualViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR");
|
||||||
|
|
||||||
|
public ListadoDistCanMensualDocument(ListadoDistCanMensualViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1.5f, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("Listado de Distribución Mensual").SemiBold().FontSize(14);
|
||||||
|
column.Item().AlignCenter().Text(Model.TipoDestinatario).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha de Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Periodo: ").SemiBold(); text.Span($"{Model.FechaDesde} - {Model.FechaHasta}"); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(10);
|
||||||
|
|
||||||
|
// Agrupamos los datos por Canilla
|
||||||
|
var gruposPorCanilla = Model.Detalles.GroupBy(d => d.Canilla);
|
||||||
|
|
||||||
|
// Creamos una tabla principal que contendrá todo
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2.5f); // Canilla / Publicación
|
||||||
|
columns.RelativeColumn(); // Llevados
|
||||||
|
columns.RelativeColumn(); // Devueltos
|
||||||
|
columns.RelativeColumn(1.2f); // Importe
|
||||||
|
});
|
||||||
|
|
||||||
|
// Encabezado principal de la tabla
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().BorderBottom(1.5f).BorderColor(Colors.Black).Padding(4).Text("Canilla / Publicación").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1.5f).BorderColor(Colors.Black).Padding(4).AlignRight().Text("Llevados").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1.5f).BorderColor(Colors.Black).Padding(4).AlignRight().Text("Devueltos").SemiBold();
|
||||||
|
header.Cell().BorderBottom(1.5f).BorderColor(Colors.Black).Padding(4).AlignRight().Text("Importe").SemiBold();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Iteramos sobre cada grupo de canilla
|
||||||
|
foreach (var grupo in gruposPorCanilla)
|
||||||
|
{
|
||||||
|
// Fila del nombre del Canilla
|
||||||
|
table.Cell().ColumnSpan(4).PaddingTop(8).Text(grupo.Key).SemiBold();
|
||||||
|
|
||||||
|
// Filas de detalle para ese canilla
|
||||||
|
foreach (var detalle in grupo)
|
||||||
|
{
|
||||||
|
table.Cell().PaddingLeft(15).Padding(2).Text(detalle.Publicacion);
|
||||||
|
table.Cell().Padding(2).AlignRight().Text(detalle.TotalCantSalida?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Padding(2).AlignRight().Text(detalle.TotalCantEntrada?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Padding(2).AlignRight().Text(detalle.TotalRendir?.ToString("C", CultureAr) ?? "$ 0.00");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de total por canilla
|
||||||
|
var totalRendirCanilla = grupo.Sum(d => d.TotalRendir ?? 0);
|
||||||
|
table.Cell().ColumnSpan(3).BorderTop(1.5f).BorderColor(Colors.Black).AlignRight().Padding(2).Text("A Rendir").SemiBold();
|
||||||
|
table.Cell().BorderTop(1.5f).BorderColor(Colors.Black).AlignRight().Padding(2).Text(t => t.Span(totalRendirCanilla.ToString("C", CultureAr)).SemiBold());
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Fila de TOTALES GENERALES ---
|
||||||
|
var totalGeneralLlevados = Model.Detalles.Sum(d => d.TotalCantSalida ?? 0);
|
||||||
|
var totalGeneralDevueltos = Model.Detalles.Sum(d => d.TotalCantEntrada ?? 0);
|
||||||
|
var totalGeneralRendir = Model.Detalles.Sum(d => d.TotalRendir ?? 0);
|
||||||
|
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).PaddingTop(5).Text("TOTALES").ExtraBold();
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).PaddingTop(5).AlignRight().Text(t => t.Span(totalGeneralLlevados.ToString("N0")).ExtraBold());
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).PaddingTop(5).AlignRight().Text(t => t.Span(totalGeneralDevueltos.ToString("N0")).ExtraBold());
|
||||||
|
table.Cell().BorderTop(2).BorderColor(Colors.Black).PaddingTop(5).AlignRight().Text(t => t.Span(totalGeneralRendir.ToString("C", CultureAr)).ExtraBold());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ListadoDistCanillasImporteDocument : IDocument
|
||||||
|
{
|
||||||
|
public ListadoDistCanillasImporteViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR");
|
||||||
|
|
||||||
|
public ListadoDistCanillasImporteDocument(ListadoDistCanillasImporteViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1.5f, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("Listado de Distribución con Importes").SemiBold().FontSize(14);
|
||||||
|
column.Item().AlignCenter().Text(Model.TipoDestinatario).FontSize(12);
|
||||||
|
column.Item().AlignCenter().Text(Model.NombrePublicacion).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha de Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Periodo: ").SemiBold(); text.Span($"{Model.FechaDesde} - {Model.FechaHasta}"); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(); // Fecha
|
||||||
|
columns.RelativeColumn(); // Llevados
|
||||||
|
columns.RelativeColumn(); // Devueltos
|
||||||
|
columns.RelativeColumn(); // Vendidos
|
||||||
|
columns.RelativeColumn(1.5f); // Importe Publicación
|
||||||
|
columns.RelativeColumn(1.5f); // A Rendir
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Fecha");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Vendidos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Imp. Publicación");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("A Rendir");
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.Detalles)
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Fecha);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Llevados.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Devueltos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Vendidos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.TotalRendirPublicacion.ToString("C", CultureAr));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.TotalRendirGeneral.ToString("C", CultureAr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de Totales
|
||||||
|
var totalLlevados = Model.Detalles.Sum(x => x.Llevados);
|
||||||
|
var totalDevueltos = Model.Detalles.Sum(x => x.Devueltos);
|
||||||
|
var totalVendidos = Model.Detalles.Sum(x => x.Vendidos);
|
||||||
|
var totalRendirPub = Model.Detalles.Sum(x => x.TotalRendirPublicacion);
|
||||||
|
var totalRendirGral = Model.Detalles.Sum(x => x.TotalRendirGeneral);
|
||||||
|
|
||||||
|
var boldStyle = TextStyle.Default.SemiBold();
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3); // Celda vacía
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(totalLlevados.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(totalDevueltos.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(totalVendidos.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(totalRendirPub.ToString("C", CultureAr)).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(totalRendirGral.ToString("C", CultureAr)).Style(boldStyle));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ListadoDistribucionCanillasDocument : IDocument
|
||||||
|
{
|
||||||
|
public ListadoDistribucionCanillasViewModel Model { get; }
|
||||||
|
|
||||||
|
public ListadoDistribucionCanillasDocument(ListadoDistribucionCanillasViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("Listado de Distribución - Canillitas").SemiBold().FontSize(14);
|
||||||
|
column.Item().AlignCenter().Text(Model.NombrePublicacion).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha de Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Periodo: ").SemiBold(); text.Span($"{Model.FechaDesde} - {Model.FechaHasta}"); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(8, Unit.Millimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(15);
|
||||||
|
|
||||||
|
column.Item().Text("Distribución").SemiBold().FontSize(12);
|
||||||
|
column.Item().Element(ComposeDetalleDiarioTable);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre);
|
||||||
|
|
||||||
|
column.Item().Text("Promedios").SemiBold().FontSize(12);
|
||||||
|
column.Item().Element(ComposePromediosTable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeDetalleDiarioTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(50); // Día
|
||||||
|
columns.RelativeColumn(); // Llevados
|
||||||
|
columns.RelativeColumn(); // Devueltos
|
||||||
|
columns.RelativeColumn(); // Venta Neta
|
||||||
|
columns.RelativeColumn(2); // Promedio (columna vacía en el original)
|
||||||
|
columns.RelativeColumn(2); // % Devolución
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Día");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Venta Neta");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Promedio");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("% Devolución");
|
||||||
|
});
|
||||||
|
|
||||||
|
decimal ventaNetaAcumulada = 0;
|
||||||
|
int conteoDias = 0;
|
||||||
|
|
||||||
|
foreach (var item in Model.DetalleDiario.OrderBy(x => x.Dia))
|
||||||
|
{
|
||||||
|
var ventaNetaDia = item.Llevados - item.Devueltos;
|
||||||
|
ventaNetaAcumulada += ventaNetaDia;
|
||||||
|
conteoDias++;
|
||||||
|
var promedio = ventaNetaAcumulada / conteoDias;
|
||||||
|
var porcDevolucion = item.Llevados > 0 ? (decimal)item.Devueltos * 100 / item.Llevados : 0;
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Dia.ToString());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Llevados.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Devueltos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(ventaNetaDia.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(promedio.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(porcDevolucion.ToString("F2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalVentaNeta = Model.TotalesDetalleDiario.Llevados - Model.TotalesDetalleDiario.Devueltos;
|
||||||
|
var totalPorcDevolucion = Model.TotalesDetalleDiario.Llevados > 0 ? (decimal)Model.TotalesDetalleDiario.Devueltos * 100 / Model.TotalesDetalleDiario.Llevados : 0;
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3); // Celda vacía
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.TotalesDetalleDiario.Llevados.ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.TotalesDetalleDiario.Devueltos.ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(totalVentaNeta.ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span((ventaNetaAcumulada / (conteoDias > 0 ? conteoDias : 1)).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(totalPorcDevolucion.ToString("F2")).SemiBold());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposePromediosTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingBottom(5).Text("Promedios por Día de Semana").SemiBold().FontSize(11);
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(1.5f);
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn(1.2f);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Día Semana");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Cant. Días");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Ventas");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("% Devolución");
|
||||||
|
});
|
||||||
|
|
||||||
|
var dayOrder = new Dictionary<string, int> { { "Lunes", 1 }, { "Martes", 2 }, { "Miércoles", 3 }, { "Jueves", 4 }, { "Viernes", 5 }, { "Sábado", 6 }, { "Domingo", 7 } };
|
||||||
|
|
||||||
|
foreach (var item in Model.PromediosPorDia.OrderBy(d => dayOrder.GetValueOrDefault(d.Dia, 99)))
|
||||||
|
{
|
||||||
|
var porcDevolucion = item.Llevados > 0 ? (decimal)item.Devueltos * 100 / item.Llevados : 0;
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Dia);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Cant.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Promedio_Llevados.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Promedio_Devueltos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Promedio_Ventas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(porcDevolucion.ToString("F2") + "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- SECCIÓN AÑADIDA PARA LA FILA "GENERAL" ---
|
||||||
|
var general = Model.PromedioGeneral;
|
||||||
|
if (general != null)
|
||||||
|
{
|
||||||
|
var porcDevolucionGeneral = general.Promedio_Llevados > 0 ? (decimal)general.Promedio_Devueltos * 100 / general.Promedio_Llevados : 0;
|
||||||
|
var boldStyle = TextStyle.Default.SemiBold();
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3).Text(text => text.Span(general.Dia).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.Cant.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.Promedio_Llevados.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.Promedio_Devueltos.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.Promedio_Ventas.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(porcDevolucionGeneral.ToString("F2") + "%").Style(boldStyle));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ListadoDistribucionDistribuidoresDocument : IDocument
|
||||||
|
{
|
||||||
|
public ListadoDistribucionDistribuidoresViewModel Model { get; }
|
||||||
|
|
||||||
|
public ListadoDistribucionDistribuidoresDocument(ListadoDistribucionDistribuidoresViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("Listado de Distribución").SemiBold().FontSize(14);
|
||||||
|
column.Item().AlignCenter().Text(Model.NombreDistribuidor).FontSize(12);
|
||||||
|
column.Item().AlignCenter().Text(Model.NombrePublicacion).FontSize(11);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha de Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Periodo: ").SemiBold(); text.Span($"{Model.FechaDesde} - {Model.FechaHasta}"); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(8, Unit.Millimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(15);
|
||||||
|
column.Item().Text("Distribución").SemiBold().FontSize(12);
|
||||||
|
column.Item().Element(ComposeDetalleDiarioTable);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre);
|
||||||
|
|
||||||
|
column.Item().Text("Promedios").SemiBold().FontSize(12);
|
||||||
|
column.Item().Element(ComposePromediosTable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeDetalleDiarioTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(50); columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn(); columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn(2); columns.RelativeColumn(2);
|
||||||
|
});
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Día");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Venta Neta");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Promedio");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("% Devolución");
|
||||||
|
});
|
||||||
|
|
||||||
|
decimal ventaNetaAcumulada = 0;
|
||||||
|
int conteoDias = 0;
|
||||||
|
|
||||||
|
foreach (var item in Model.DetalleDiario.OrderBy(x => x.Dia))
|
||||||
|
{
|
||||||
|
var llevados = item.Llevados ?? 0;
|
||||||
|
var devueltos = item.Devueltos ?? 0;
|
||||||
|
var ventaNetaDia = llevados - devueltos;
|
||||||
|
if(llevados > 0)
|
||||||
|
{
|
||||||
|
ventaNetaAcumulada += ventaNetaDia;
|
||||||
|
conteoDias++;
|
||||||
|
}
|
||||||
|
var promedio = conteoDias > 0 ? ventaNetaAcumulada / conteoDias : 0;
|
||||||
|
var porcDevolucion = llevados > 0 ? (decimal)devueltos * 100 / llevados : 0;
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Dia.ToString());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(llevados.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(devueltos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(ventaNetaDia.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(promedio.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(porcDevolucion.ToString("F2") + "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalLlevados = Model.DetalleDiario.Sum(i => i.Llevados ?? 0);
|
||||||
|
var totalDevueltos = Model.DetalleDiario.Sum(i => i.Devueltos ?? 0);
|
||||||
|
var totalVentaNeta = totalLlevados - totalDevueltos;
|
||||||
|
var totalPorcDevolucion = totalLlevados > 0 ? (decimal)totalDevueltos * 100 / totalLlevados : 0;
|
||||||
|
|
||||||
|
var boldStyle = TextStyle.Default.SemiBold();
|
||||||
|
table.Cell().Border(1).Padding(3);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(totalLlevados.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(totalDevueltos.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(totalVentaNeta.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span((ventaNetaAcumulada / (conteoDias > 0 ? conteoDias : 1)).ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(totalPorcDevolucion.ToString("F2") + "%").Style(boldStyle));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposePromediosTable(IContainer container)
|
||||||
|
{
|
||||||
|
var dayOrder = new Dictionary<string, int> { { "Lunes", 1 }, { "Martes", 2 }, { "Miércoles", 3 }, { "Jueves", 4 }, { "Viernes", 5 }, { "Sábado", 6 }, { "Domingo", 7 }};
|
||||||
|
|
||||||
|
container.Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(1.5f); columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn(); columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn(); columns.RelativeColumn(1.2f);
|
||||||
|
});
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Día");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Cant. Días");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Ventas");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("% Devolución");
|
||||||
|
});
|
||||||
|
foreach (var item in Model.PromediosPorDia.Where(p => p.Dia != "General").OrderBy(d => dayOrder.GetValueOrDefault(d.Dia, 99)))
|
||||||
|
{
|
||||||
|
var llevados = item.Promedio_Llevados ?? 0;
|
||||||
|
var devueltos = item.Promedio_Devueltos ?? 0;
|
||||||
|
var porcDevolucion = llevados > 0 ? (decimal)devueltos * 100 / llevados : 0;
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Dia);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Cant?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(llevados.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(devueltos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Promedio_Ventas?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(porcDevolucion.ToString("F2") + "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FILA GENERAL ---
|
||||||
|
var general = Model.PromedioGeneral;
|
||||||
|
if (general != null)
|
||||||
|
{
|
||||||
|
var boldStyle = TextStyle.Default.SemiBold();
|
||||||
|
var llevadosGeneral = general.Llevados ?? 0; // Usamos el total para el %
|
||||||
|
var devueltosGeneral = general.Devueltos ?? 0; // Usamos el total para el %
|
||||||
|
var porcDevolucionGeneral = llevadosGeneral > 0 ? (decimal)devueltosGeneral * 100 / llevadosGeneral : 0;
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3).Text(t => t.Span(general.Dia).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(general.Cant?.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(general.Promedio_Llevados?.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(general.Promedio_Devueltos?.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(general.Promedio_Ventas?.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(porcDevolucionGeneral.ToString("F2") + "%").Style(boldStyle));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class ListadoDistribucionGeneralDocument : IDocument
|
||||||
|
{
|
||||||
|
public ListadoDistribucionGeneralViewModel Model { get; }
|
||||||
|
|
||||||
|
public ListadoDistribucionGeneralDocument(ListadoDistribucionGeneralViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("Listado de Distribución General Mensual").SemiBold().FontSize(14);
|
||||||
|
column.Item().AlignCenter().Text(Model.NombrePublicacion).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(1, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha de Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Mes Consultado: ").SemiBold(); text.Span(Model.MesConsultado); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Millimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(20);
|
||||||
|
|
||||||
|
if (Model.ResumenMensual.Any())
|
||||||
|
{
|
||||||
|
column.Item().Element(ComposeResumenTable);
|
||||||
|
}
|
||||||
|
if (Model.PromediosPorDia.Any())
|
||||||
|
{
|
||||||
|
column.Item().Element(ComposePromediosTable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeResumenTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(40);
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Día");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Tirada");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Sin Cargo");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Perdidos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Vendidos");
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.ResumenMensual.OrderBy(x => x.Fecha))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Fecha.Day.ToString());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.CantidadTirada.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.SinCargo.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Perdidos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Llevados.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Devueltos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Vendidos.ToString("N0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(3);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.ResumenMensual.Sum(x => x.CantidadTirada).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.ResumenMensual.Sum(x => x.SinCargo).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.ResumenMensual.Sum(x => x.Perdidos).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.ResumenMensual.Sum(x => x.Llevados).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.ResumenMensual.Sum(x => x.Devueltos).ToString("N0")).SemiBold());
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(t => t.Span(Model.ResumenMensual.Sum(x => x.Vendidos).ToString("N0")).SemiBold());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposePromediosTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
// --- TÍTULO DE LA TABLA DE PROMEDIOS ---
|
||||||
|
column.Item().PaddingBottom(5).AlignCenter().Text("Promedios Diarios de Distribución").SemiBold();
|
||||||
|
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(1.2f);
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
columns.RelativeColumn();
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Día");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Cant. Días");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Tirada");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Sin Cargo");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Perdidos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Llevados");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Devueltos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Vendidos");
|
||||||
|
});
|
||||||
|
|
||||||
|
var dayOrder = new Dictionary<string, int> { { "Lunes", 1 }, { "Martes", 2 }, { "Miércoles", 3 }, { "Jueves", 4 }, { "Viernes", 5 }, { "Sábado", 6 }, { "Domingo", 7 } };
|
||||||
|
|
||||||
|
// Mostramos los promedios por día de la semana
|
||||||
|
foreach (var item in Model.PromediosPorDia.OrderBy(d => dayOrder.GetValueOrDefault(d.Dia, 99)))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Dia);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.CantidadDias.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.PromedioTirada.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.PromedioSinCargo.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.PromedioPerdidos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.PromedioLlevados.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.PromedioDevueltos.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.PromedioVendidos.ToString("N0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FILA GENERAL CON DATOS CALCULADOS DEL VIEWMODEL ---
|
||||||
|
var general = Model.PromedioGeneral;
|
||||||
|
if (general != null)
|
||||||
|
{
|
||||||
|
var boldStyle = TextStyle.Default.SemiBold();
|
||||||
|
table.Cell().Border(1).Padding(3).Text(text => text.Span(general.Dia).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.CantidadDias.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.PromedioTirada.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.PromedioSinCargo.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.PromedioPerdidos.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.PromedioLlevados.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.PromedioDevueltos.ToString("N0")).Style(boldStyle));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(general.PromedioVendidos.ToString("N0")).Style(boldStyle));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class MovimientoBobinasDocument : IDocument
|
||||||
|
{
|
||||||
|
public MovimientoBobinasViewModel Model { get; }
|
||||||
|
|
||||||
|
public MovimientoBobinasDocument(MovimientoBobinasViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
public DocumentSettings GetSettings() => DocumentSettings.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container
|
||||||
|
.Page(page =>
|
||||||
|
{
|
||||||
|
// Configuramos la página en modo apaisado (landscape)
|
||||||
|
page.Size(PageSizes.A4.Landscape());
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Roboto").FontSize(9)); // Un poco más pequeño por la cantidad de columnas
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
|
||||||
|
page.Footer()
|
||||||
|
.AlignCenter()
|
||||||
|
.Text(x =>
|
||||||
|
{
|
||||||
|
x.Span("Página ");
|
||||||
|
x.CurrentPageNumber();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("Reporte de Movimiento de Bobinas").SemiBold().FontSize(14);
|
||||||
|
column.Item().AlignCenter().Text($"Planta: {Model.NombrePlanta}").FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(2, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Column(col =>
|
||||||
|
{
|
||||||
|
col.Item().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha del Reporte: ").SemiBold();
|
||||||
|
text.Span(Model.FechaReporte);
|
||||||
|
});
|
||||||
|
col.Item().Text($"Periodo Consultado: Desde {Model.FechaDesde} Hasta {Model.FechaHasta}");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Table(table =>
|
||||||
|
{
|
||||||
|
// Definimos 11 columnas. Usamos una combinación de relativas y constantes
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2.5f); // Tipo
|
||||||
|
columns.ConstantColumn(50); // Cant. Inicial
|
||||||
|
columns.ConstantColumn(60); // Kg Iniciales
|
||||||
|
columns.ConstantColumn(50); // Compradas
|
||||||
|
columns.ConstantColumn(60); // Kg Comprados
|
||||||
|
columns.ConstantColumn(50); // Consumidas
|
||||||
|
columns.ConstantColumn(60); // Kg Consumidos
|
||||||
|
columns.ConstantColumn(50); // Dañadas
|
||||||
|
columns.ConstantColumn(60); // Kg Dañados
|
||||||
|
columns.ConstantColumn(50); // Cant. Final
|
||||||
|
columns.ConstantColumn(60); // Kg Final
|
||||||
|
});
|
||||||
|
|
||||||
|
// Encabezado de la tabla
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
// Celda por celda para control total
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).Text("Tipo");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Cant. Inicial");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Kg Inicial");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Compradas");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Kg Comprados");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Consumidas");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Kg Consumidos");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Dañadas");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Kg Dañados");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Cant. Final");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(2).AlignCenter().Text("Kg Final");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filas de datos
|
||||||
|
foreach (var item in Model.Movimientos)
|
||||||
|
{
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).Text(item.TipoBobina);
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.BobinasIniciales.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.KilosIniciales.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.BobinasCompradas.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.KilosComprados.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.BobinasConsumidas.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.KilosConsumidos.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.BobinasDaniadas.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.KilosDaniados.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.BobinasFinales.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(2).AlignCenter().Text(item.KilosFinales.ToString("N0"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class MovimientoBobinasEstadoDocument : IDocument
|
||||||
|
{
|
||||||
|
public MovimientoBobinasEstadoViewModel Model { get; }
|
||||||
|
|
||||||
|
public MovimientoBobinasEstadoDocument(MovimientoBobinasEstadoViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
public DocumentSettings GetSettings() => DocumentSettings.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container
|
||||||
|
.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Roboto").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
|
||||||
|
page.Footer()
|
||||||
|
.AlignCenter()
|
||||||
|
.Text(x =>
|
||||||
|
{
|
||||||
|
x.Span("Página ");
|
||||||
|
x.CurrentPageNumber();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("Reporte de Movimiento de Bobinas por Estados").SemiBold().FontSize(14);
|
||||||
|
column.Item().AlignCenter().Text($"Planta: {Model.NombrePlanta}").FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(2, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Column(col =>
|
||||||
|
{
|
||||||
|
col.Item().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha del Reporte: ").SemiBold();
|
||||||
|
text.Span(Model.FechaReporte);
|
||||||
|
});
|
||||||
|
col.Item().Text($"Periodo Consultado: Desde {Model.FechaDesde} Hasta {Model.FechaHasta}");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Column(column =>
|
||||||
|
{
|
||||||
|
// Primera tabla: Detalle de Movimientos
|
||||||
|
column.Item().Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(3); // Tipo Bobina
|
||||||
|
columns.RelativeColumn(2); // Remito
|
||||||
|
columns.ConstantColumn(80); // Fecha
|
||||||
|
columns.ConstantColumn(60); // Cantidad
|
||||||
|
columns.RelativeColumn(2); // Tipo Movimiento
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).Text("Tipo Bobina");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).Text("N° Remito");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).AlignCenter().Text("Fecha Mov.");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Cantidad");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).Text("Tipo Movimiento");
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.Detalles)
|
||||||
|
{
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).Text(item.TipoBobina);
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).Text(item.NumeroRemito);
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).AlignCenter().Text(item.FechaMovimiento.ToString("dd/MM/yyyy"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).AlignRight().Text(item.Cantidad.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).Text(item.TipoMovimiento);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Espacio entre tablas
|
||||||
|
column.Item().PaddingTop(1, Unit.Centimetre);
|
||||||
|
|
||||||
|
// Segunda tabla: Totales
|
||||||
|
column.Item().AlignLeft().Table(table => // Alineamos la tabla a la izquierda para que no ocupe todo el ancho
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(120); // Tipo Movimiento
|
||||||
|
columns.ConstantColumn(80); // Total Bobinas
|
||||||
|
columns.ConstantColumn(80); // Total Kilos
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).Text("Totales por Movimiento");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Total Bobinas");
|
||||||
|
header.Cell().Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Total Kilos");
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var total in Model.Totales)
|
||||||
|
{
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).Text(total.TipoMovimiento);
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).AlignRight().Text(total.TotalBobinas.ToString("N0"));
|
||||||
|
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2).Padding(4).AlignRight().Text(total.TotalKilos.ToString("N0"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class NovedadesCanillasDocument : IDocument
|
||||||
|
{
|
||||||
|
public NovedadesCanillasViewModel Model { get; }
|
||||||
|
private static readonly CultureInfo CultureAr = new CultureInfo("es-AR");
|
||||||
|
|
||||||
|
public NovedadesCanillasDocument(NovedadesCanillasViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1.5f, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(10));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("Listado de Novedades - Canillas").SemiBold().FontSize(16);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha de Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Periodo: ").SemiBold(); text.Span($"{Model.FechaDesde} - {Model.FechaHasta}"); });
|
||||||
|
});
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5).Border(1).Background(Colors.Grey.Lighten3).AlignCenter().Padding(2).Text(Model.NombreEmpresa).SemiBold();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(1, Unit.Centimetre).Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(20);
|
||||||
|
|
||||||
|
if (Model.ResumenCanillas.Any())
|
||||||
|
{
|
||||||
|
column.Item().Element(ComposeResumenTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Model.DetallesNovedades.Any())
|
||||||
|
{
|
||||||
|
column.Item().Element(ComposeDetallesNovedadesTable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeResumenTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(3); // Canilla
|
||||||
|
columns.RelativeColumn(1); // Legajo
|
||||||
|
columns.RelativeColumn(1); // Faltas
|
||||||
|
columns.RelativeColumn(1); // Francos
|
||||||
|
columns.RelativeColumn(1.5f); // Comisiones
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Canilla");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Legajo");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignCenter().Text("Faltas");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignCenter().Text("Francos");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Comisiones");
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.ResumenCanillas.OrderBy(x => x.Canilla))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Canilla);
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.Legajo?.ToString() ?? "-");
|
||||||
|
table.Cell().Border(1).Padding(3).AlignCenter().Text(item.Faltas?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Border(1).Padding(3).AlignCenter().Text(item.Francos?.ToString("N0") ?? "0");
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.TotalRendir?.ToString("C", CultureAr) ?? "$ 0.00");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de Totales
|
||||||
|
table.Cell().ColumnSpan(4).Border(1).Padding(3).AlignRight().Text("Total").SemiBold();
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.ResumenCanillas.Sum(x => x.TotalRendir ?? 0).ToString("C", CultureAr)).SemiBold());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeDetallesNovedadesTable(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().PaddingTop(10).Text("Otras Novedades").SemiBold().FontSize(12);
|
||||||
|
column.Item().PaddingTop(5).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2); // Nombre
|
||||||
|
columns.ConstantColumn(80); // Fecha
|
||||||
|
columns.RelativeColumn(4); // Detalle
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Nombre");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Fecha");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Detalle");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Agrupamos por canillita para mostrar su nombre una sola vez
|
||||||
|
foreach (var grupo in Model.DetallesNovedades.GroupBy(x => x.NomApe))
|
||||||
|
{
|
||||||
|
// Celda con el nombre del canillita, abarcando todas las filas de sus novedades
|
||||||
|
table.Cell().RowSpan((uint)grupo.Count()).Border(1).Padding(3).Text(grupo.Key);
|
||||||
|
|
||||||
|
// Iteramos sobre las novedades del grupo
|
||||||
|
foreach (var detalle in grupo.OrderBy(d => d.Fecha))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(3).Text(detalle.Fecha.ToString("dd/MM/yyyy"));
|
||||||
|
table.Cell().Border(1).Padding(3).Text(detalle.Detalle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class TiradasPublicacionesSeccionesDocument : IDocument
|
||||||
|
{
|
||||||
|
public TiradasPublicacionesSeccionesViewModel Model { get; }
|
||||||
|
|
||||||
|
public TiradasPublicacionesSeccionesDocument(TiradasPublicacionesSeccionesViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(9));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("Reporte de Tiradas por Publicación Mensual").SemiBold().FontSize(14);
|
||||||
|
|
||||||
|
// Título secundario dinámico
|
||||||
|
string subTitle = Model.EsConsolidado
|
||||||
|
? $"Consolidado - Publicación: {Model.NombrePublicacion}"
|
||||||
|
: $"Planta: {Model.NombrePlanta} - Publicación: {Model.NombrePublicacion}";
|
||||||
|
column.Item().AlignCenter().Text(subTitle).FontSize(12);
|
||||||
|
|
||||||
|
column.Item().PaddingTop(5, Unit.Millimetre).Row(row =>
|
||||||
|
{
|
||||||
|
row.RelativeItem().Text(text => { text.Span("Fecha del Reporte: ").SemiBold(); text.Span(Model.FechaReporte); });
|
||||||
|
row.RelativeItem().AlignRight().Text(text => { text.Span("Mes Consultado: ").SemiBold(); text.Span(Model.MesConsultado); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.RelativeColumn(2.5f); // Nombre Seccion
|
||||||
|
columns.RelativeColumn(1.5f); // Páginas Impresas
|
||||||
|
columns.RelativeColumn(1); // Total Ediciones
|
||||||
|
columns.RelativeColumn(1.5f); // Pág. Por Edición
|
||||||
|
columns.RelativeColumn(1.2f); // Total Ejemplares
|
||||||
|
columns.RelativeColumn(1.5f); // Pág. Ejemplar
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).Text("Nombre Sección");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Páginas Impresas");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Total Ediciones");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Pág/Edición");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Total Ejemplares");
|
||||||
|
header.Cell().Border(1).Background(Colors.Grey.Lighten3).Padding(4).AlignRight().Text("Prom. Pág/Ejemplar");
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.Detalles.OrderBy(x => x.NombreSeccion))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(3).Text(item.NombreSeccion);
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.TotalPaginasImpresas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.CantidadTiradas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.TotalPaginasEjemplares.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.TotalEjemplares.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(item.PromedioPaginasPorEjemplar.ToString("N0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fila de Totales
|
||||||
|
var style = TextStyle.Default.SemiBold();
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span("Totales").Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.TotalPaginasImpresas).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.CantidadTiradas).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.TotalPaginasEjemplares).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.TotalEjemplares).ToString("N0")).Style(style));
|
||||||
|
table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.Detalles.Sum(x => x.PromedioPaginasPorEjemplar).ToString("N0")).Style(style));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class VentaMensualSecretariaElDiaDocument : IDocument
|
||||||
|
{
|
||||||
|
public VentaMensualSecretariaElDiaViewModel Model { get; }
|
||||||
|
|
||||||
|
public VentaMensualSecretariaElDiaDocument(VentaMensualSecretariaElDiaViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(11));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("VENTA DIARIO EL DÍA").SemiBold().FontSize(16);
|
||||||
|
|
||||||
|
column.Item().AlignCenter().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha Consultada: Desde ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaDesde).FontSize(12);
|
||||||
|
text.Span(" Hasta ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaHasta).FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(50); // Día
|
||||||
|
columns.RelativeColumn(); // Canillas
|
||||||
|
columns.RelativeColumn(); // Tirajes
|
||||||
|
columns.RelativeColumn(); // Ventas
|
||||||
|
columns.RelativeColumn(); // Accionistas
|
||||||
|
columns.RelativeColumn(); // Total Coop.
|
||||||
|
columns.RelativeColumn(); // Total Gral.
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("DÍA").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("CANILLAS").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("TIRAJES").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("VENTAS").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("ACCIONISTAS").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("TOTAL COOPERATIVA").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("TOTAL").FontColor(Colors.White).SemiBold());
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.VentasDiarias.OrderBy(x => x.Dia))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.Dia.ToString());
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.CantidadCanillas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.Tirajes.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.Ventas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.Accionistas.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.TotalCooperativa.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(t => t.Span(item.TotalGeneral.ToString("N0")).SemiBold());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class VentaMensualSecretariaElPlataDocument : IDocument
|
||||||
|
{
|
||||||
|
public VentaMensualSecretariaElPlataViewModel Model { get; }
|
||||||
|
|
||||||
|
public VentaMensualSecretariaElPlataDocument(VentaMensualSecretariaElPlataViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(11));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Spacing(5);
|
||||||
|
column.Item().AlignCenter().Text("VENTA DIARIO EL PLATA").SemiBold().FontSize(16);
|
||||||
|
|
||||||
|
column.Item().AlignCenter().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha Consultada: Desde ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaDesde).FontSize(12);
|
||||||
|
text.Span(" Hasta ").SemiBold().FontSize(12);
|
||||||
|
text.Span(Model.FechaHasta).FontSize(12);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(50); // Día
|
||||||
|
columns.RelativeColumn(); // Tirada Coop
|
||||||
|
columns.RelativeColumn(); // Devolución Coop
|
||||||
|
columns.RelativeColumn(); // Venta Coop
|
||||||
|
columns.RelativeColumn(); // Tirada Canillas
|
||||||
|
columns.RelativeColumn(); // Venta Canillas
|
||||||
|
columns.RelativeColumn(); // Total
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("DÍA").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("TIRADA COOP.").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("DEVOLUCIÓN COOP.").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("VENTA COOP.").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("TIRADA CANILLAS").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("VENTA CANILLAS (TOTAL)").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().Background(Colors.Black).Border(1).BorderColor(Colors.White).Padding(4).AlignCenter().Text(text => text.Span("TOTAL").FontColor(Colors.White).SemiBold());
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var item in Model.VentasDiarias.OrderBy(x => x.Dia))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.Dia.ToString());
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.TiradaCoop.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.DevolucionCoop.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.VentaCoop.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.TiradaCan.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.VentaCan.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(t => t.Span(item.Total.ToString("N0")).SemiBold());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
using GestionIntegral.Api.Dtos.Reportes.ViewModels;
|
||||||
|
using QuestPDF.Elements.Table;
|
||||||
|
using QuestPDF.Fluent;
|
||||||
|
using QuestPDF.Helpers;
|
||||||
|
using QuestPDF.Infrastructure;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
|
||||||
|
{
|
||||||
|
public class VentaMensualSecretariaTirDevoDocument : IDocument
|
||||||
|
{
|
||||||
|
public VentaMensualSecretariaTirDevoViewModel Model { get; }
|
||||||
|
|
||||||
|
public VentaMensualSecretariaTirDevoDocument(VentaMensualSecretariaTirDevoViewModel model)
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DocumentMetadata GetMetadata() => DocumentMetadata.Default;
|
||||||
|
|
||||||
|
public void Compose(IDocumentContainer container)
|
||||||
|
{
|
||||||
|
container.Page(page =>
|
||||||
|
{
|
||||||
|
// CORRECCIÓN: Se aplica Landscape() al tamaño de página.
|
||||||
|
page.Size(PageSizes.A4.Landscape());
|
||||||
|
page.Margin(1, Unit.Centimetre);
|
||||||
|
page.DefaultTextStyle(x => x.FontFamily("Arial").FontSize(12));
|
||||||
|
|
||||||
|
page.Header().Element(ComposeHeader);
|
||||||
|
page.Content().Element(ComposeContent);
|
||||||
|
page.Footer().AlignCenter().Text(x => { x.Span("Página "); x.CurrentPageNumber(); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeHeader(IContainer container)
|
||||||
|
{
|
||||||
|
container.Column(column =>
|
||||||
|
{
|
||||||
|
column.Item().AlignCenter().Text("TIRADA Y DEVOLUCIÓN").SemiBold().FontSize(18);
|
||||||
|
column.Item().AlignCenter().Text(text =>
|
||||||
|
{
|
||||||
|
text.Span("Fecha Consultada: Desde ").SemiBold().FontSize(14);
|
||||||
|
text.Span(Model.FechaDesde).FontSize(14);
|
||||||
|
text.Span(" Hasta ").SemiBold().FontSize(14);
|
||||||
|
text.Span(Model.FechaHasta).FontSize(14);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComposeContent(IContainer container)
|
||||||
|
{
|
||||||
|
container.PaddingTop(5, Unit.Millimetre).Table(table =>
|
||||||
|
{
|
||||||
|
table.ColumnsDefinition(columns =>
|
||||||
|
{
|
||||||
|
columns.ConstantColumn(40);
|
||||||
|
columns.RelativeColumn(); columns.RelativeColumn(); columns.RelativeColumn(); // EL DÍA
|
||||||
|
columns.RelativeColumn(); columns.RelativeColumn(); columns.RelativeColumn(); // POPULAR
|
||||||
|
columns.RelativeColumn(); columns.RelativeColumn(); columns.RelativeColumn(); // CLARÍN
|
||||||
|
columns.RelativeColumn(); columns.RelativeColumn(); columns.RelativeColumn(); // LA NACIÓN
|
||||||
|
});
|
||||||
|
|
||||||
|
table.Header(header =>
|
||||||
|
{
|
||||||
|
// CORRECCIÓN: La sintaxis de VerticalAlign es un método.
|
||||||
|
header.Cell().RowSpan(2).Border(1).Background(Colors.Black).AlignCenter().AlignMiddle().Text(text => text.Span("Día").FontColor(Colors.White).SemiBold());
|
||||||
|
|
||||||
|
header.Cell().ColumnSpan(3).Border(1).Background(Colors.Black).AlignCenter().Text(text => text.Span("EL DÍA").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().ColumnSpan(3).Border(1).Background(Colors.Black).AlignCenter().Text(text => text.Span("POPULAR").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().ColumnSpan(3).Border(1).Background(Colors.Black).AlignCenter().Text(text => text.Span("CLARÍN").FontColor(Colors.White).SemiBold());
|
||||||
|
header.Cell().ColumnSpan(3).Border(1).Background(Colors.Black).AlignCenter().Text(text => text.Span("LA NACIÓN").FontColor(Colors.White).SemiBold());
|
||||||
|
|
||||||
|
// CORRECCIÓN: Se define una función local para crear y estilizar las celdas del sub-encabezado.
|
||||||
|
// Esto evita el error de "multiple child elements".
|
||||||
|
void SubHeaderCell(ITableCellContainer cell, string text)
|
||||||
|
{
|
||||||
|
cell.Border(1)
|
||||||
|
.Background(Colors.Black)
|
||||||
|
.AlignCenter()
|
||||||
|
.Text(txt => txt.Span(text).FontColor(Colors.White).SemiBold());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var _ in Enumerable.Range(0, 4))
|
||||||
|
{
|
||||||
|
SubHeaderCell(header.Cell(), "TIRADA");
|
||||||
|
SubHeaderCell(header.Cell(), "DEVOLUC");
|
||||||
|
SubHeaderCell(header.Cell(), "VENTA");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filas de datos (sin cambios)
|
||||||
|
foreach (var item in Model.VentasDiarias.OrderBy(x => x.Dia))
|
||||||
|
{
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.Dia.ToString());
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.TiradaCoop.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.DevolucionCoop.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(t => t.Span(item.VentaCoop.ToString("N0")).SemiBold());
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.TiradaPopular.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.DevolucionPopular.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(t => t.Span(item.VentaPopular.ToString("N0")).SemiBold());
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.TiradaClarin.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.DevolucionClarin.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(t => t.Span(item.VentaClarin.ToString("N0")).SemiBold());
|
||||||
|
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.TiradaNacion.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(item.DevolucionNacion.ToString("N0"));
|
||||||
|
table.Cell().Border(1).Padding(4).AlignCenter().Text(t => t.Span(item.VentaNacion.ToString("N0")).SemiBold());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -19,29 +19,4 @@
|
|||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.9.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!--
|
|
||||||
<PropertyGroup>
|
|
||||||
<EnableDefaultContentItems>false</EnableDefaultContentItems>
|
|
||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
|
||||||
<PreserveCompilationReferences>true</PreserveCompilationReferences>
|
|
||||||
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
|
|
||||||
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
|
||||||
<RazorCompileOnPublish>false</RazorCompileOnPublish>
|
|
||||||
<CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="Controllers/Reportes/Templates/**/*.cshtml">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="appsettings.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
-->
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ComparativaConsumoBobinasViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ComparativaConsumoBobinasDto> Detalles { get; set; } = new List<ComparativaConsumoBobinasDto>();
|
||||||
|
|
||||||
|
public string? NombrePlanta { get; set; }
|
||||||
|
public string MesA { get; set; } = string.Empty;
|
||||||
|
public string MesB { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
public bool EsConsolidado => string.IsNullOrEmpty(NombrePlanta);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ConsumoBobinasPublicacionViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ConsumoBobinasPublicacionDto> Detalles { get; set; } = new List<ConsumoBobinasPublicacionDto>();
|
||||||
|
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ConsumoBobinasSeccionViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ConsumoBobinasSeccionDto> Detalles { get; set; } = new List<ConsumoBobinasSeccionDto>();
|
||||||
|
|
||||||
|
public string? NombrePlanta { get; set; }
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
public bool EsConsolidado => string.IsNullOrEmpty(NombrePlanta);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ControlDevolucionesViewModel
|
||||||
|
{
|
||||||
|
// --- Datos de entrada ---
|
||||||
|
public IEnumerable<ControlDevolucionesReporteDto> Detalles { get; set; } = new List<ControlDevolucionesReporteDto>();
|
||||||
|
public int TotalDevolucionDiasAnteriores { get; set; }
|
||||||
|
|
||||||
|
// --- Parámetros del reporte ---
|
||||||
|
public string NombreEmpresa { get; set; } = string.Empty;
|
||||||
|
public string FechaConsultada { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
// --- Propiedades calculadas (corregidas para ser de solo lectura) ---
|
||||||
|
public int CantidadCanillas => Detalles?.FirstOrDefault()?.TotalNoAccionistas ?? 0;
|
||||||
|
public int TotalIngresadosPorRemito => Detalles?.FirstOrDefault()?.Ingresados ?? 0;
|
||||||
|
public int TotalSobrantes => Detalles?.FirstOrDefault()?.Sobrantes ?? 0;
|
||||||
|
public int TotalSinCargo => Detalles?.FirstOrDefault()?.SinCargo ?? 0;
|
||||||
|
|
||||||
|
public int TotalLlevados => Detalles?.Sum(d => d.Llevados) ?? 0;
|
||||||
|
public int TotalDevueltosFecha => Detalles?.Sum(d => d.Devueltos) ?? 0;
|
||||||
|
|
||||||
|
public decimal TotalDevolucionALaFecha => (decimal)(TotalIngresadosPorRemito - TotalLlevados + TotalDevueltosFecha);
|
||||||
|
public decimal TotalDevolucionGeneral => TotalDevolucionALaFecha + TotalDevolucionDiasAnteriores;
|
||||||
|
public decimal DiferenciaFinal => TotalDevolucionALaFecha - TotalSobrantes - TotalSinCargo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class CuentasDistribuidorViewModel
|
||||||
|
{
|
||||||
|
// --- Datos de entrada ---
|
||||||
|
public IEnumerable<BalanceCuentaDistDto> Movimientos { get; set; } = new List<BalanceCuentaDistDto>();
|
||||||
|
public IEnumerable<BalanceCuentaPagosDto> Pagos { get; set; } = new List<BalanceCuentaPagosDto>();
|
||||||
|
public IEnumerable<BalanceCuentaDebCredDto> DebitosCreditos { get; set; } = new List<BalanceCuentaDebCredDto>();
|
||||||
|
|
||||||
|
// Saldo real de la cuenta, se muestra al final sin usarse en cálculos intermedios.
|
||||||
|
public decimal SaldoDeCuenta { get; set; }
|
||||||
|
|
||||||
|
// --- Parámetros del reporte ---
|
||||||
|
public string NombreDistribuidor { get; set; } = string.Empty;
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
// --- Propiedades para el resumen final ---
|
||||||
|
public decimal TotalMovimientos => Movimientos.Sum(m => m.Debe - m.Haber);
|
||||||
|
public decimal TotalPagos => Pagos.Sum(p => p.Debe - p.Haber);
|
||||||
|
public decimal TotalDebitosCreditos => DebitosCreditos.Sum(d => d.Debe - d.Haber);
|
||||||
|
public decimal TotalPeriodo => TotalMovimientos + TotalPagos + TotalDebitosCreditos;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class DistribucionCanillasViewModel
|
||||||
|
{
|
||||||
|
// --- Datos de entrada ---
|
||||||
|
public IEnumerable<DetalleDistribucionCanillaDto> Canillas { get; set; } = new List<DetalleDistribucionCanillaDto>();
|
||||||
|
public IEnumerable<DetalleDistribucionCanillaDto> CanillasAccionistas { get; set; } = new List<DetalleDistribucionCanillaDto>();
|
||||||
|
public IEnumerable<DetalleDistribucionCanillaAllDto> CanillasTodos { get; set; } = new List<DetalleDistribucionCanillaAllDto>();
|
||||||
|
public IEnumerable<DetalleDistribucionCanillaDto> CanillasLiquidadasOtraFecha { get; set; } = new List<DetalleDistribucionCanillaDto>();
|
||||||
|
public IEnumerable<DetalleDistribucionCanillaDto> CanillasAccionistasLiquidadasOtraFecha { get; set; } = new List<DetalleDistribucionCanillaDto>();
|
||||||
|
public IEnumerable<ControlDevolucionesReporteDto> ControlDevolucionesDetalle { get; set; } = new List<ControlDevolucionesReporteDto>();
|
||||||
|
public int RemitoIngresado { get; set; }
|
||||||
|
|
||||||
|
// --- Parámetros del reporte ---
|
||||||
|
public string Empresa { get; set; } = string.Empty;
|
||||||
|
public string FechaConsultada { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
// Propiedades calculadas para el resumen final
|
||||||
|
public int VentaTotal => (ControlDevolucionesDetalle?.Sum(d => d.Llevados) ?? 0) - (ControlDevolucionesDetalle?.Sum(d => d.Devueltos) ?? 0);
|
||||||
|
public int DevolucionTotal => RemitoIngresado - VentaTotal;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class LiquidacionCanillaViewModel
|
||||||
|
{
|
||||||
|
// --- Datos de entrada ---
|
||||||
|
public IEnumerable<LiquidacionCanillaDetalleDto> Detalles { get; set; } = new List<LiquidacionCanillaDetalleDto>();
|
||||||
|
public IEnumerable<LiquidacionCanillaGananciaDto> Ganancias { get; set; } = new List<LiquidacionCanillaGananciaDto>();
|
||||||
|
|
||||||
|
// --- Parámetros del reporte ---
|
||||||
|
public string FechaLiquidacion { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
// Propiedades calculadas para un acceso más fácil y limpio en la plantilla
|
||||||
|
public string NombreVendedor => Detalles.FirstOrDefault()?.Canilla ?? "N/A";
|
||||||
|
public decimal TotalARendir => Detalles.Sum(d => d.TotalRendir);
|
||||||
|
public decimal TotalComisiones => Ganancias.Sum(g => g.TotalRendir);
|
||||||
|
|
||||||
|
// Propiedad para el título del reporte
|
||||||
|
public string TituloReporte => EsAccionista ? "Liquidación de Accionistas" : "Liquidación Venta de Diarios";
|
||||||
|
public bool EsAccionista { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ListadoDistCanMensualDiariosViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ListadoDistCanMensualDiariosDto> Detalles { get; set; } = new List<ListadoDistCanMensualDiariosDto>();
|
||||||
|
|
||||||
|
public string TipoDestinatario { get; set; } = string.Empty; // "Canillitas" o "Accionistas"
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ListadoDistCanMensualViewModel
|
||||||
|
{
|
||||||
|
// Usamos el DTO existente que ya tiene la estructura que necesitamos.
|
||||||
|
public IEnumerable<ListadoDistCanMensualPubDto> Detalles { get; set; } = new List<ListadoDistCanMensualPubDto>();
|
||||||
|
|
||||||
|
// Parámetros para el encabezado
|
||||||
|
public string TipoDestinatario { get; set; } = string.Empty; // "Canillitas" o "Accionistas"
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ListadoDistCanillasImporteViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ListadoDistribucionCanillasImporteDto> Detalles { get; set; } = new List<ListadoDistribucionCanillasImporteDto>();
|
||||||
|
|
||||||
|
public string NombrePublicacion { get; set; } = string.Empty;
|
||||||
|
public string TipoDestinatario { get; set; } = string.Empty; // "Canillitas" o "Accionistas"
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ListadoDistribucionCanillasViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ListadoDistribucionCanillasSimpleDto> DetalleDiario { get; set; } = new List<ListadoDistribucionCanillasSimpleDto>();
|
||||||
|
public IEnumerable<ListadoDistribucionCanillasPromedioDiaDto> PromediosPorDia { get; set; } = new List<ListadoDistribucionCanillasPromedioDiaDto>();
|
||||||
|
|
||||||
|
public string NombrePublicacion { get; set; } = string.Empty;
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
public ListadoDistribucionCanillasSimpleDto TotalesDetalleDiario
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (DetalleDiario == null || !DetalleDiario.Any())
|
||||||
|
{
|
||||||
|
return new ListadoDistribucionCanillasSimpleDto();
|
||||||
|
}
|
||||||
|
return new ListadoDistribucionCanillasSimpleDto
|
||||||
|
{
|
||||||
|
Llevados = DetalleDiario.Sum(d => d.Llevados),
|
||||||
|
Devueltos = DetalleDiario.Sum(d => d.Devueltos)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PROPIEDAD PARA LA FILA "GENERAL" ---
|
||||||
|
public ListadoDistribucionCanillasPromedioDiaDto? PromedioGeneral
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (PromediosPorDia == null || !PromediosPorDia.Any()) return null;
|
||||||
|
|
||||||
|
// Sumamos los totales, no promediamos los promedios
|
||||||
|
var totalLlevados = PromediosPorDia.Sum(p => p.Llevados);
|
||||||
|
var totalDevueltos = PromediosPorDia.Sum(p => p.Devueltos);
|
||||||
|
var totalDias = PromediosPorDia.Sum(p => p.Cant);
|
||||||
|
|
||||||
|
if (totalDias == 0) return null;
|
||||||
|
|
||||||
|
return new ListadoDistribucionCanillasPromedioDiaDto
|
||||||
|
{
|
||||||
|
Dia = "General",
|
||||||
|
Cant = totalDias,
|
||||||
|
Promedio_Llevados = totalLlevados / totalDias,
|
||||||
|
Promedio_Devueltos = totalDevueltos / totalDias,
|
||||||
|
Promedio_Ventas = (totalLlevados - totalDevueltos) / totalDias
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ListadoDistribucionDistribuidoresViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ListadoDistribucionDistSimpleDto> DetalleDiario { get; set; } = new List<ListadoDistribucionDistSimpleDto>();
|
||||||
|
public IEnumerable<ListadoDistribucionDistPromedioDiaDto> PromediosPorDia { get; set; } = new List<ListadoDistribucionDistPromedioDiaDto>();
|
||||||
|
|
||||||
|
public string NombrePublicacion { get; set; } = string.Empty;
|
||||||
|
public string NombreDistribuidor { get; set; } = string.Empty;
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
// --- PROPIEDAD CALCULADA PARA LA FILA "GENERAL" ---
|
||||||
|
public ListadoDistribucionDistPromedioDiaDto? PromedioGeneral
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (DetalleDiario == null || !DetalleDiario.Any())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var diasConDatos = DetalleDiario.Count(d => (d.Llevados ?? 0) > 0);
|
||||||
|
if (diasConDatos == 0) return null;
|
||||||
|
|
||||||
|
var totalLlevados = DetalleDiario.Sum(d => d.Llevados ?? 0);
|
||||||
|
var totalDevueltos = DetalleDiario.Sum(d => d.Devueltos ?? 0);
|
||||||
|
|
||||||
|
return new ListadoDistribucionDistPromedioDiaDto
|
||||||
|
{
|
||||||
|
Dia = "General",
|
||||||
|
Cant = diasConDatos,
|
||||||
|
Promedio_Llevados = totalLlevados / diasConDatos,
|
||||||
|
Promedio_Devueltos = totalDevueltos / diasConDatos,
|
||||||
|
Promedio_Ventas = (totalLlevados - totalDevueltos) / diasConDatos,
|
||||||
|
Llevados = totalLlevados, // Guardamos el total para el cálculo del %
|
||||||
|
Devueltos = totalDevueltos // Guardamos el total para el cálculo del %
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq; // Necesario para .Any() y .Sum()
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class ListadoDistribucionGeneralViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<ListadoDistribucionGeneralResumenDto> ResumenMensual { get; set; } = new List<ListadoDistribucionGeneralResumenDto>();
|
||||||
|
public IEnumerable<ListadoDistribucionGeneralPromedioDiaDto> PromediosPorDia { get; set; } = new List<ListadoDistribucionGeneralPromedioDiaDto>();
|
||||||
|
|
||||||
|
public string NombrePublicacion { get; set; } = string.Empty;
|
||||||
|
public string MesConsultado { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
// --- PROPIEDAD PARA LOS TOTALES GENERALES DE PROMEDIOS ---
|
||||||
|
// Esta propiedad calcula los promedios generales basados en los datos del resumen mensual.
|
||||||
|
public ListadoDistribucionGeneralPromedioDiaDto? PromedioGeneral
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (ResumenMensual == null || !ResumenMensual.Any())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contar solo los días con tirada > 0 para promediar correctamente
|
||||||
|
var diasConTirada = ResumenMensual.Count(d => d.CantidadTirada > 0);
|
||||||
|
if (diasConTirada == 0) return null;
|
||||||
|
|
||||||
|
return new ListadoDistribucionGeneralPromedioDiaDto
|
||||||
|
{
|
||||||
|
Dia = "General",
|
||||||
|
CantidadDias = diasConTirada,
|
||||||
|
PromedioTirada = (int)ResumenMensual.Average(r => r.CantidadTirada),
|
||||||
|
PromedioSinCargo = (int)ResumenMensual.Average(r => r.SinCargo),
|
||||||
|
PromedioPerdidos = (int)ResumenMensual.Average(r => r.Perdidos),
|
||||||
|
PromedioLlevados = (int)ResumenMensual.Average(r => r.Llevados),
|
||||||
|
PromedioDevueltos = (int)ResumenMensual.Average(r => r.Devueltos),
|
||||||
|
PromedioVendidos = (int)ResumenMensual.Average(r => r.Vendidos)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class MovimientoBobinasEstadoViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<MovimientoBobinaEstadoDetalleDto> Detalles { get; set; } = new List<MovimientoBobinaEstadoDetalleDto>();
|
||||||
|
public IEnumerable<MovimientoBobinaEstadoTotalDto> Totales { get; set; } = new List<MovimientoBobinaEstadoTotalDto>();
|
||||||
|
public string NombrePlanta { get; set; } = string.Empty;
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class MovimientoBobinasViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<MovimientoBobinasDto> Movimientos { get; set; } = new List<MovimientoBobinasDto>();
|
||||||
|
public string NombrePlanta { get; set; } = string.Empty;
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class NovedadesCanillasViewModel
|
||||||
|
{
|
||||||
|
// Resumen de ganancias, faltas y francos por canilla
|
||||||
|
public IEnumerable<CanillaGananciaReporteDto> ResumenCanillas { get; set; } = new List<CanillaGananciaReporteDto>();
|
||||||
|
|
||||||
|
// Detalle de las novedades textuales
|
||||||
|
public IEnumerable<NovedadesCanillasReporteDto> DetallesNovedades { get; set; } = new List<NovedadesCanillasReporteDto>();
|
||||||
|
|
||||||
|
// Parámetros para el encabezado
|
||||||
|
public string NombreEmpresa { get; set; } = string.Empty;
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class TiradasPublicacionesSeccionesViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<TiradasPublicacionesSeccionesDto> Detalles { get; set; } = new List<TiradasPublicacionesSeccionesDto>();
|
||||||
|
|
||||||
|
public string NombrePublicacion { get; set; } = string.Empty;
|
||||||
|
public string MesConsultado { get; set; } = string.Empty;
|
||||||
|
public string FechaReporte { get; set; } = DateTime.Now.ToString("dd/MM/yyyy");
|
||||||
|
|
||||||
|
// Será nulo o vacío para la versión consolidada.
|
||||||
|
public string? NombrePlanta { get; set; }
|
||||||
|
|
||||||
|
// Propiedad calculada para simplificar la lógica en la plantilla.
|
||||||
|
public bool EsConsolidado => string.IsNullOrEmpty(NombrePlanta);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class VentaMensualSecretariaElDiaViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<VentaMensualSecretariaElDiaDto> VentasDiarias { get; set; } = new List<VentaMensualSecretariaElDiaDto>();
|
||||||
|
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class VentaMensualSecretariaElPlataViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<VentaMensualSecretariaElPlataDto> VentasDiarias { get; set; } = new List<VentaMensualSecretariaElPlataDto>();
|
||||||
|
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
|
||||||
|
{
|
||||||
|
public class VentaMensualSecretariaTirDevoViewModel
|
||||||
|
{
|
||||||
|
public IEnumerable<VentaMensualSecretariaTirDevoDto> VentasDiarias { get; set; } = new List<VentaMensualSecretariaTirDevoDto>();
|
||||||
|
|
||||||
|
public string FechaDesde { get; set; } = string.Empty;
|
||||||
|
public string FechaHasta { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -238,6 +238,9 @@ namespace GestionIntegral.Api.Services.Reportes
|
|||||||
ctrlDevolucionesOtrosDiasTask
|
ctrlDevolucionesOtrosDiasTask
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var detallesOriginales = await ctrlDevolucionesParaDistCanTask ?? Enumerable.Empty<ControlDevolucionesReporteDto>();
|
||||||
|
var detallesOrdenados = detallesOriginales.OrderBy(d => d.Tipo).ToList();
|
||||||
|
|
||||||
Func<IEnumerable<DetalleDistribucionCanillaDto>, IEnumerable<DetalleDistribucionCanillaDto>> toUtc =
|
Func<IEnumerable<DetalleDistribucionCanillaDto>, IEnumerable<DetalleDistribucionCanillaDto>> toUtc =
|
||||||
items => items?.Select(c => { if (c.Fecha.HasValue) c.Fecha = DateTime.SpecifyKind(c.Fecha.Value.Date, DateTimeKind.Utc); return c; }).ToList()
|
items => items?.Select(c => { if (c.Fecha.HasValue) c.Fecha = DateTime.SpecifyKind(c.Fecha.Value.Date, DateTimeKind.Utc); return c; }).ToList()
|
||||||
?? Enumerable.Empty<DetalleDistribucionCanillaDto>();
|
?? Enumerable.Empty<DetalleDistribucionCanillaDto>();
|
||||||
@@ -249,7 +252,7 @@ namespace GestionIntegral.Api.Services.Reportes
|
|||||||
toUtc(await canillasFechaLiqTask),
|
toUtc(await canillasFechaLiqTask),
|
||||||
toUtc(await canillasAccFechaLiqTask),
|
toUtc(await canillasAccFechaLiqTask),
|
||||||
await ctrlDevolucionesRemitosTask ?? Enumerable.Empty<ObtenerCtrlDevolucionesDto>(),
|
await ctrlDevolucionesRemitosTask ?? Enumerable.Empty<ObtenerCtrlDevolucionesDto>(),
|
||||||
await ctrlDevolucionesParaDistCanTask ?? Enumerable.Empty<ControlDevolucionesReporteDto>(),
|
detallesOrdenados,
|
||||||
await ctrlDevolucionesOtrosDiasTask ?? Enumerable.Empty<DevueltosOtrosDiasDto>(),
|
await ctrlDevolucionesOtrosDiasTask ?? Enumerable.Empty<DevueltosOtrosDiasDto>(),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// src/pages/Reportes/ReporteListadoDistMensualPage.tsx
|
|
||||||
import React, { useState, useCallback, useMemo } from 'react';
|
import React, { useState, useCallback, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
Box, Typography, Paper, CircularProgress, Alert, Button,
|
Box, Typography, Paper, CircularProgress, Alert, Button,
|
||||||
|
|||||||
@@ -1,116 +1,50 @@
|
|||||||
// src/pages/Reportes/ReporteDetalleDistribucionCanillasPage.tsx
|
import React, { useState, useCallback } from 'react';
|
||||||
import React, { useState, useCallback, useMemo } from 'react';
|
|
||||||
import {
|
import {
|
||||||
Box, Typography, Paper, CircularProgress, Alert, Button
|
Box, Typography, Paper, CircularProgress, Alert, Button,
|
||||||
|
TableContainer, Table, TableHead, TableRow, TableCell, TableBody
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { DataGrid, type GridColDef, GridFooterContainer, GridFooter } from '@mui/x-data-grid';
|
|
||||||
import { esES } from '@mui/x-data-grid/locales';
|
|
||||||
import reportesService from '../../services/Reportes/reportesService';
|
import reportesService from '../../services/Reportes/reportesService';
|
||||||
import type { ReporteDistribucionCanillasResponseDto } from '../../models/dtos/Reportes/ReporteDistribucionCanillasResponseDto';
|
import type { ListadoDistribucionGeneralResponseDto } from '../../models/dtos/Reportes/ListadoDistribucionGeneralResponseDto';
|
||||||
import SeleccionaReporteDetalleDistribucionCanillas from './SeleccionaReporteDetalleDistribucionCanillas';
|
import SeleccionaReporteListadoDistribucionGeneral from './SeleccionaReporteListadoDistribucionGeneral';
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
interface TotalesComunes {
|
const ReporteListadoDistribucionGeneralPage: React.FC = () => {
|
||||||
totalCantSalida: number;
|
const [reportData, setReportData] = useState<ListadoDistribucionGeneralResponseDto | null>(null);
|
||||||
totalCantEntrada: number;
|
|
||||||
vendidos: number;
|
|
||||||
totalRendir: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
|
||||||
const [reportData, setReportData] = useState<ReporteDistribucionCanillasResponseDto | null>(null);
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [loadingPdf, setLoadingPdf] = useState(false);
|
const [loadingPdf, setLoadingPdf] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [apiErrorParams, setApiErrorParams] = useState<string | null>(null);
|
const [apiErrorParams, setApiErrorParams] = useState<string | null>(null);
|
||||||
const [showParamSelector, setShowParamSelector] = useState(true);
|
const [showParamSelector, setShowParamSelector] = useState(true);
|
||||||
const [currentParams, setCurrentParams] = useState<{
|
const [currentParams, setCurrentParams] = useState<{
|
||||||
fecha: string;
|
idPublicacion: number;
|
||||||
idEmpresa: number;
|
fechaDesde: string; // Primer día del mes
|
||||||
nombreEmpresa?: string;
|
fechaHasta: string; // Último día del mes
|
||||||
|
nombrePublicacion?: string; // Para el nombre del archivo
|
||||||
|
mesAnioParaNombreArchivo?: string; // Para el nombre del archivo (ej. YYYY-MM)
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
const [pdfSoloTotales, setPdfSoloTotales] = useState(false);
|
|
||||||
|
|
||||||
// Estados para los totales de cada sección
|
|
||||||
const initialTotals: TotalesComunes = { totalCantSalida: 0, totalCantEntrada: 0, vendidos: 0, totalRendir: 0 };
|
|
||||||
const [totalesCanillas, setTotalesCanillas] = useState<TotalesComunes>(initialTotals);
|
|
||||||
const [totalesAccionistas, setTotalesAccionistas] = useState<TotalesComunes>(initialTotals);
|
|
||||||
const [totalesTodos, setTotalesTodos] = useState<TotalesComunes>(initialTotals);
|
|
||||||
const [totalesCanillasOtraFecha, setTotalesCanillasOtraFecha] = useState<TotalesComunes>(initialTotals);
|
|
||||||
const [totalesAccionistasOtraFecha, setTotalesAccionistasOtraFecha] = useState<TotalesComunes>(initialTotals);
|
|
||||||
|
|
||||||
// --- Formateadores ---
|
|
||||||
const currencyFormatter = (value: number | null | undefined) =>
|
|
||||||
value != null ? value.toLocaleString('es-AR', { style: 'currency', currency: 'ARS' }) : '';
|
|
||||||
const numberFormatter = (value: number | null | undefined) =>
|
|
||||||
value != null ? Number(value).toLocaleString('es-AR') : '';
|
|
||||||
|
|
||||||
const calculateAndSetTotals = (dataArray: Array<any> | undefined, setTotalsFunc: React.Dispatch<React.SetStateAction<TotalesComunes>>) => {
|
|
||||||
if (dataArray && dataArray.length > 0) {
|
|
||||||
const totals = dataArray.reduce((acc, item) => {
|
|
||||||
acc.totalCantSalida += Number(item.totalCantSalida) || 0;
|
|
||||||
acc.totalCantEntrada += Number(item.totalCantEntrada) || 0;
|
|
||||||
acc.totalRendir += Number(item.totalRendir) || 0;
|
|
||||||
return acc;
|
|
||||||
}, { totalCantSalida: 0, totalCantEntrada: 0, totalRendir: 0 });
|
|
||||||
totals.vendidos = totals.totalCantSalida - totals.totalCantEntrada;
|
|
||||||
setTotalsFunc(totals);
|
|
||||||
} else {
|
|
||||||
setTotalsFunc(initialTotals);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleGenerarReporte = useCallback(async (params: {
|
const handleGenerarReporte = useCallback(async (params: {
|
||||||
fecha: string;
|
idPublicacion: number;
|
||||||
idEmpresa: number;
|
fechaDesde: string;
|
||||||
|
fechaHasta: string;
|
||||||
}) => {
|
}) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
setApiErrorParams(null);
|
setApiErrorParams(null);
|
||||||
|
|
||||||
const empresaService = (await import('../../services/Distribucion/empresaService')).default;
|
// Para el nombre del archivo y título del PDF
|
||||||
const empData = await empresaService.getEmpresaById(params.idEmpresa);
|
const pubService = (await import('../../services/Distribucion/publicacionService')).default;
|
||||||
|
const pubData = await pubService.getPublicacionById(params.idPublicacion);
|
||||||
|
const mesAnioParts = params.fechaDesde.split('-'); // YYYY-MM-DD -> [YYYY, MM, DD]
|
||||||
|
const mesAnioNombre = `${mesAnioParts[1]}/${mesAnioParts[0]}`;
|
||||||
|
|
||||||
setCurrentParams({ ...params, nombreEmpresa: empData?.nombre });
|
|
||||||
setReportData(null); // Limpiar datos antiguos
|
|
||||||
|
|
||||||
// Resetear totales
|
|
||||||
setTotalesCanillas(initialTotals);
|
|
||||||
setTotalesAccionistas(initialTotals);
|
|
||||||
setTotalesTodos(initialTotals);
|
|
||||||
setTotalesCanillasOtraFecha(initialTotals);
|
|
||||||
setTotalesAccionistasOtraFecha(initialTotals);
|
|
||||||
|
|
||||||
|
setCurrentParams({...params, nombrePublicacion: pubData?.nombre, mesAnioParaNombreArchivo: mesAnioNombre });
|
||||||
try {
|
try {
|
||||||
const data = await reportesService.getReporteDistribucionCanillas(params);
|
const data = await reportesService.getListadoDistribucionGeneral(params);
|
||||||
|
setReportData(data);
|
||||||
const addIds = <T extends Record<string, any>>(arr: T[] | undefined, prefix: string): Array<T & { id: string }> =>
|
if ((!data.resumen || data.resumen.length === 0) && (!data.promediosPorDia || data.promediosPorDia.length === 0)) {
|
||||||
(arr || []).map((item, index) => ({ ...item, id: `${prefix}-${item.publicacion || item.tipoVendedor || 'item'}-${index}-${Math.random().toString(36).substring(7)}` }));
|
|
||||||
|
|
||||||
const processedData = {
|
|
||||||
canillas: addIds(data.canillas, 'can'),
|
|
||||||
canillasAccionistas: addIds(data.canillasAccionistas, 'acc'),
|
|
||||||
canillasTodos: addIds(data.canillasTodos, 'all'),
|
|
||||||
canillasLiquidadasOtraFecha: addIds(data.canillasLiquidadasOtraFecha, 'canliq'),
|
|
||||||
canillasAccionistasLiquidadasOtraFecha: addIds(data.canillasAccionistasLiquidadasOtraFecha, 'accliq'),
|
|
||||||
controlDevolucionesDetalle: addIds(data.controlDevolucionesDetalle, 'cdd'),
|
|
||||||
controlDevolucionesRemitos: addIds(data.controlDevolucionesRemitos, 'cdr'),
|
|
||||||
controlDevolucionesOtrosDias: addIds(data.controlDevolucionesOtrosDias, 'cdo')
|
|
||||||
};
|
|
||||||
setReportData(processedData);
|
|
||||||
|
|
||||||
// Calcular y setear totales para cada sección
|
|
||||||
calculateAndSetTotals(processedData.canillas, setTotalesCanillas);
|
|
||||||
calculateAndSetTotals(processedData.canillasAccionistas, setTotalesAccionistas);
|
|
||||||
calculateAndSetTotals(processedData.canillasTodos, setTotalesTodos);
|
|
||||||
calculateAndSetTotals(processedData.canillasLiquidadasOtraFecha, setTotalesCanillasOtraFecha);
|
|
||||||
calculateAndSetTotals(processedData.canillasAccionistasLiquidadasOtraFecha, setTotalesAccionistasOtraFecha);
|
|
||||||
|
|
||||||
const noData = (!data.canillas || data.canillas.length === 0) &&
|
|
||||||
(!data.canillasAccionistas || data.canillasAccionistas.length === 0) &&
|
|
||||||
(!data.canillasTodos || data.canillasTodos.length === 0); // Podrías añadir más chequeos si es necesario
|
|
||||||
if (noData) {
|
|
||||||
setError("No se encontraron datos para los parámetros seleccionados.");
|
setError("No se encontraron datos para los parámetros seleccionados.");
|
||||||
}
|
}
|
||||||
setShowParamSelector(false);
|
setShowParamSelector(false);
|
||||||
@@ -134,96 +68,62 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleExportToExcel = useCallback(() => {
|
const handleExportToExcel = useCallback(() => {
|
||||||
if (!reportData) {
|
if (!reportData || (!reportData.resumen?.length && !reportData.promediosPorDia?.length)) {
|
||||||
alert("No hay datos para exportar.");
|
alert("No hay datos para exportar.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const wb = XLSX.utils.book_new();
|
const wb = XLSX.utils.book_new();
|
||||||
|
|
||||||
const formatAndSheet = (
|
if (reportData.resumen?.length) {
|
||||||
data: any[],
|
const resumenToExport = reportData.resumen.map(item => ({
|
||||||
sheetName: string,
|
"Fecha": item.fecha ? new Date(item.fecha).toLocaleDateString('es-AR', { timeZone: 'UTC' }) : '-',
|
||||||
fields: Record<string, string>,
|
"Tirada": item.cantidadTirada,
|
||||||
totals?: TotalesComunes
|
"Sin Cargo": item.sinCargo,
|
||||||
) => {
|
"Perdidos": item.perdidos,
|
||||||
if (data && data.length > 0) {
|
"Llevados": item.llevados,
|
||||||
let exportedData = data.map(item => {
|
"Devueltos": item.devueltos,
|
||||||
const row: Record<string, any> = {};
|
"Vendidos": item.vendidos,
|
||||||
const { id, ...itemData } = item; // Excluir el 'id' generado
|
}));
|
||||||
Object.keys(fields).forEach(key => {
|
const wsResumen = XLSX.utils.json_to_sheet(resumenToExport);
|
||||||
row[fields[key]] = (itemData as any)[key];
|
XLSX.utils.book_append_sheet(wb, wsResumen, "ResumenDiario");
|
||||||
if (key === 'fecha' && (itemData as any)[key]) {
|
|
||||||
row[fields[key]] = new Date((itemData as any)[key]).toLocaleDateString('es-AR', { timeZone: 'UTC' });
|
|
||||||
}
|
|
||||||
if ((key === 'totalRendir') && (itemData as any)[key] != null) {
|
|
||||||
row[fields[key]] = parseFloat((itemData as any)[key]); // Mantener como número para suma en Excel
|
|
||||||
}
|
|
||||||
if (key === 'vendidos' && itemData.totalCantSalida != null && itemData.totalCantEntrada != null) {
|
|
||||||
row[fields[key]] = itemData.totalCantSalida - itemData.totalCantEntrada;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return row;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (totals) {
|
|
||||||
const totalRow: Record<string, any> = {};
|
|
||||||
const fieldKeys = Object.keys(fields);
|
|
||||||
totalRow[fields[fieldKeys[0]]] = "TOTALES"; // Título en la primera columna
|
|
||||||
if (fields.totalCantSalida) totalRow[fields.totalCantSalida] = totals.totalCantSalida;
|
|
||||||
if (fields.totalCantEntrada) totalRow[fields.totalCantEntrada] = totals.totalCantEntrada;
|
|
||||||
if (fields.vendidos) totalRow[fields.vendidos] = totals.vendidos;
|
|
||||||
if (fields.totalRendir) totalRow[fields.totalRendir] = totals.totalRendir;
|
|
||||||
exportedData.push(totalRow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ws = XLSX.utils.json_to_sheet(exportedData);
|
if (reportData.promediosPorDia?.length) {
|
||||||
const headers = Object.values(fields);
|
const promediosToExport = reportData.promediosPorDia.map(item => ({
|
||||||
ws['!cols'] = headers.map(h => {
|
"Día Semana": item.dia,
|
||||||
const maxLen = Math.max(...exportedData.map(row => (row[h]?.toString() ?? '').length), h.length);
|
"Cant. Días": item.cantidadDias,
|
||||||
return { wch: maxLen + 2 };
|
"Prom. Tirada": item.promedioTirada,
|
||||||
});
|
"Prom. Sin Cargo": item.promedioSinCargo,
|
||||||
ws['!freeze'] = { xSplit: 0, ySplit: 1 }; // Congelar primera fila
|
"Prom. Perdidos": item.promedioPerdidos,
|
||||||
XLSX.utils.book_append_sheet(wb, ws, sheetName);
|
"Prom. Llevados": item.promedioLlevados,
|
||||||
|
"Prom. Devueltos": item.promedioDevueltos,
|
||||||
|
"Prom. Vendidos": item.promedioVendidos,
|
||||||
|
}));
|
||||||
|
const wsPromedios = XLSX.utils.json_to_sheet(promediosToExport);
|
||||||
|
XLSX.utils.book_append_sheet(wb, wsPromedios, "PromediosPorDia");
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const fieldsCanillaAccionista = { publicacion: "Publicación", canilla: "Canilla", totalCantSalida: "Llevados", totalCantEntrada: "Devueltos", vendidos: "Vendidos", totalRendir: "A Rendir" };
|
let fileName = "ListadoDistribucionGeneral";
|
||||||
const fieldsCanillaAccionistaFechaLiq = { publicacion: "Publicación", canilla: "Canilla", fecha:"Fecha Mov.", totalCantSalida: "Llevados", totalCantEntrada: "Devueltos", vendidos: "Vendidos", totalRendir: "A Rendir" };
|
|
||||||
const fieldsTodos = { publicacion: "Publicación", tipoVendedor: "Tipo", totalCantSalida: "Llevados", totalCantEntrada: "Devueltos", vendidos: "Vendidos", totalRendir: "A Rendir" };
|
|
||||||
const fieldsCtrlDevDetalle = { ingresados: "Ingresados", sobrantes: "Sobrantes", sinCargo: "Sin Cargo", publicacion: "Publicación", llevados: "Llevados", devueltos: "Devueltos", tipo: "Tipo" };
|
|
||||||
const fieldsCtrlDevRemitos = { remito: "Remito Ingresado" };
|
|
||||||
const fieldsCtrlDevOtrosDias = { devueltos: "Devueltos Otros Días" };
|
|
||||||
|
|
||||||
formatAndSheet(reportData.canillas, "Canillitas_Dia", fieldsCanillaAccionista, totalesCanillas);
|
|
||||||
formatAndSheet(reportData.canillasAccionistas, "Accionistas_Dia", fieldsCanillaAccionista, totalesAccionistas);
|
|
||||||
formatAndSheet(reportData.canillasTodos, "Resumen_Dia", fieldsTodos, totalesTodos);
|
|
||||||
formatAndSheet(reportData.canillasLiquidadasOtraFecha, "Canillitas_OtrasFechas", fieldsCanillaAccionistaFechaLiq, totalesCanillasOtraFecha);
|
|
||||||
formatAndSheet(reportData.canillasAccionistasLiquidadasOtraFecha, "Accionistas_OtrasFechas", fieldsCanillaAccionistaFechaLiq, totalesAccionistasOtraFecha);
|
|
||||||
formatAndSheet(reportData.controlDevolucionesDetalle, "CtrlDev_Detalle", fieldsCtrlDevDetalle); // Sin totales para estos
|
|
||||||
formatAndSheet(reportData.controlDevolucionesRemitos, "CtrlDev_Remitos", fieldsCtrlDevRemitos);
|
|
||||||
formatAndSheet(reportData.controlDevolucionesOtrosDias, "CtrlDev_OtrosDias", fieldsCtrlDevOtrosDias);
|
|
||||||
|
|
||||||
let fileName = "ReporteDetalleDistribucionCanillitas";
|
|
||||||
if (currentParams) {
|
if (currentParams) {
|
||||||
fileName += `_${currentParams.nombreEmpresa?.replace(/\s+/g, '') ?? `Emp${currentParams.idEmpresa}`}`;
|
fileName += `_${currentParams.nombrePublicacion?.replace(/\s+/g, '') ?? `Pub${currentParams.idPublicacion}`}`;
|
||||||
fileName += `_${currentParams.fecha}`;
|
fileName += `_${currentParams.mesAnioParaNombreArchivo?.replace('/', '-')}`;
|
||||||
}
|
}
|
||||||
fileName += ".xlsx";
|
fileName += ".xlsx";
|
||||||
XLSX.writeFile(wb, fileName);
|
XLSX.writeFile(wb, fileName);
|
||||||
}, [reportData, currentParams, totalesCanillas, totalesAccionistas, totalesTodos, totalesCanillasOtraFecha, totalesAccionistasOtraFecha]);
|
}, [reportData, currentParams]);
|
||||||
|
|
||||||
const handleGenerarYAbrirPdf = useCallback(async (soloTotales: boolean) => {
|
const handleGenerarYAbrirPdf = useCallback(async () => {
|
||||||
if (!currentParams) {
|
if (!currentParams) {
|
||||||
setError("Primero debe generar el reporte en pantalla o seleccionar parámetros.");
|
setError("Primero debe generar el reporte en pantalla o seleccionar parámetros.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoadingPdf(true);
|
setLoadingPdf(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
setPdfSoloTotales(soloTotales);
|
|
||||||
try {
|
try {
|
||||||
const blob = await reportesService.getReporteDistribucionCanillasPdf({
|
const blob = await reportesService.getListadoDistribucionGeneralPdf({
|
||||||
...currentParams,
|
idPublicacion: currentParams.idPublicacion,
|
||||||
soloTotales
|
fechaDesde: currentParams.fechaDesde, // El servicio y SP esperan fechaDesde para el mes/año
|
||||||
|
fechaHasta: currentParams.fechaHasta // El SP no usa esta, pero el servicio de reporte sí para el nombre
|
||||||
});
|
});
|
||||||
if (blob.type === "application/json") {
|
if (blob.type === "application/json") {
|
||||||
const text = await blob.text();
|
const text = await blob.text();
|
||||||
@@ -241,99 +141,13 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [currentParams]);
|
}, [currentParams]);
|
||||||
|
|
||||||
// Definiciones de columnas
|
|
||||||
const commonColumns: GridColDef[] = [
|
|
||||||
{ field: 'publicacion', headerName: 'Publicación', width: 200, flex: 1.2 },
|
|
||||||
{ field: 'canilla', headerName: 'Canillita', width: 220, flex: 1.3 },
|
|
||||||
{ field: 'totalCantSalida', headerName: 'Llevados', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (value) => numberFormatter(Number(value)) },
|
|
||||||
{ field: 'totalCantEntrada', headerName: 'Devueltos', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (value) => numberFormatter(Number(value)) },
|
|
||||||
{ field: 'vendidos', headerName: 'Vendidos', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueGetter: (_value, row) => (row.totalCantSalida || 0) - (row.totalCantEntrada || 0), valueFormatter: (value) => numberFormatter(Number(value)) },
|
|
||||||
{ field: 'totalRendir', headerName: 'A Rendir', type: 'number', width: 150, align: 'right', headerAlign: 'right', valueFormatter: (value) => currencyFormatter(Number(value)) },
|
|
||||||
];
|
|
||||||
|
|
||||||
const commonColumnsWithFecha: GridColDef[] = [
|
|
||||||
{ field: 'publicacion', headerName: 'Publicación', width: 200, flex: 1 },
|
|
||||||
{ field: 'canilla', headerName: 'Canillita', width: 220, flex: 1.1 },
|
|
||||||
{ field: 'fecha', headerName: 'Fecha Mov.', width: 120, flex: 0.7, valueFormatter: (value) => value ? new Date(value as string).toLocaleDateString('es-AR', { timeZone: 'UTC' }) : '-' },
|
|
||||||
{ field: 'totalCantSalida', headerName: 'Llevados', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (value) => numberFormatter(Number(value)) },
|
|
||||||
{ field: 'totalCantEntrada', headerName: 'Devueltos', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (value) => numberFormatter(Number(value))},
|
|
||||||
{ field: 'vendidos', headerName: 'Vendidos', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueGetter: (_value, row) => (row.totalCantSalida || 0) - (row.totalCantEntrada || 0), valueFormatter: (value) => numberFormatter(Number(value)) },
|
|
||||||
{ field: 'totalRendir', headerName: 'A Rendir', type: 'number', width: 150, align: 'right', headerAlign: 'right', valueFormatter: (value) => currencyFormatter(Number(value)) },
|
|
||||||
];
|
|
||||||
|
|
||||||
const columnsTodos: GridColDef[] = [
|
|
||||||
{ field: 'publicacion', headerName: 'Publicación', width: 200, flex: 1.2 },
|
|
||||||
{ field: 'tipoVendedor', headerName: 'Tipo Vendedor', width: 150, flex: 0.8 },
|
|
||||||
{ field: 'totalCantSalida', headerName: 'Llevados', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (value) => numberFormatter(Number(value)) },
|
|
||||||
{ field: 'totalCantEntrada', headerName: 'Devueltos', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (value) => numberFormatter(Number(value))},
|
|
||||||
{ field: 'vendidos', headerName: 'Vendidos', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueGetter: (_value, row) => (row.totalCantSalida || 0) - (row.totalCantEntrada || 0), valueFormatter: (value) => numberFormatter(Number(value)) },
|
|
||||||
{ field: 'totalRendir', headerName: 'A Rendir', type: 'number', width: 150, align: 'right', headerAlign: 'right', valueFormatter: (value) => currencyFormatter(Number(value)) },
|
|
||||||
];
|
|
||||||
|
|
||||||
const columnsCtrlDevDetalle: GridColDef[] = [
|
|
||||||
{ field: 'publicacion', headerName: 'Publicación', width: 200, flex: 1.5 },
|
|
||||||
{ field: 'tipo', headerName: 'Tipo', width: 100, flex: 0.8 },
|
|
||||||
{ field: 'ingresados', headerName: 'Ingresados', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (v) => numberFormatter(Number(v))},
|
|
||||||
{ field: 'sobrantes', headerName: 'Sobrantes', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (v) => numberFormatter(Number(v))},
|
|
||||||
{ field: 'sinCargo', headerName: 'Sin Cargo', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (v) => numberFormatter(Number(v))},
|
|
||||||
{ field: 'llevados', headerName: 'Llevados', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (v) => numberFormatter(Number(v))},
|
|
||||||
{ field: 'devueltos', headerName: 'Devueltos', type: 'number', width: 100, align: 'right', headerAlign: 'right', valueFormatter: (v) => numberFormatter(Number(v))},
|
|
||||||
];
|
|
||||||
|
|
||||||
const columnsCtrlDevRemitos: GridColDef[] = [
|
|
||||||
{ field: 'remito', headerName: 'Remito Ingresado', flex: 1 },
|
|
||||||
];
|
|
||||||
|
|
||||||
const columnsCtrlDevOtrosDias: GridColDef[] = [
|
|
||||||
{ field: 'devueltos', headerName: 'Devueltos Otros Días', flex: 1 },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Memoizar filas (los IDs ya se añaden en handleGenerarReporte)
|
|
||||||
const rowsCanillas = useMemo(() => reportData?.canillas ?? [], [reportData]);
|
|
||||||
const rowsAccionistas = useMemo(() => reportData?.canillasAccionistas ?? [], [reportData]);
|
|
||||||
const rowsTodos = useMemo(() => reportData?.canillasTodos ?? [], [reportData]);
|
|
||||||
const rowsCanillasOtraFecha = useMemo(() => reportData?.canillasLiquidadasOtraFecha ?? [], [reportData]);
|
|
||||||
const rowsAccionistasOtraFecha = useMemo(() => reportData?.canillasAccionistasLiquidadasOtraFecha ?? [], [reportData]);
|
|
||||||
const rowsCtrlDevDetalle = useMemo(() => reportData?.controlDevolucionesDetalle ?? [], [reportData]);
|
|
||||||
const rowsCtrlDevRemitos = useMemo(() => reportData?.controlDevolucionesRemitos ?? [], [reportData]);
|
|
||||||
const rowsCtrlDevOtrosDias = useMemo(() => reportData?.controlDevolucionesOtrosDias ?? [], [reportData]);
|
|
||||||
|
|
||||||
// --- Custom Footers ---
|
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
const createCustomFooter = (totals: TotalesComunes, columns: GridColDef[]) => () => (
|
|
||||||
<GridFooterContainer sx={{ justifyContent: 'space-between', alignItems: 'center', width: '100%' }}>
|
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', flexShrink: 0, minWidth: '300px' }}>
|
|
||||||
<GridFooter sx={{ borderTop: 'none' }} />
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ p: 1, display: 'flex', alignItems: 'center', fontWeight: 'bold', marginLeft: 'auto', whiteSpace: 'nowrap', overflowX: 'auto' }}>
|
|
||||||
<Typography variant="subtitle2" sx={{ flex: columns[0].flex, width: columns[0].width, textAlign: 'right', fontWeight: 'bold' }}>TOTALES:</Typography>
|
|
||||||
{columns[1].field !== 'tipoVendedor' && <Typography variant="subtitle2" sx={{ flex: columns[1].flex, width: columns[1].width, textAlign: 'right', fontWeight: 'bold', pr:1 }}></Typography> /* Placeholder for Canilla/Tipo */ }
|
|
||||||
{columns[1].field === 'tipoVendedor' && <Typography variant="subtitle2" sx={{ flex: columns[1].flex, width: columns[1].width, textAlign: 'right', fontWeight: 'bold', pr:1 }}></Typography> /* Placeholder for Canilla/Tipo */ }
|
|
||||||
|
|
||||||
{columns.find(c => c.field === 'fecha') && <Typography variant="subtitle2" sx={{ flex: columns.find(c=>c.field === 'fecha')?.flex, width: columns.find(c=>c.field === 'fecha')?.width, textAlign: 'right', fontWeight: 'bold', pr:1 }}></Typography> /* Placeholder for Fecha */}
|
|
||||||
|
|
||||||
<Typography variant="subtitle2" sx={{ width: columns.find(c=>c.field === 'totalCantSalida')?.width, textAlign: 'right', fontWeight: 'bold', pr:1 }}>{numberFormatter(totals.totalCantSalida)}</Typography>
|
|
||||||
<Typography variant="subtitle2" sx={{ width: columns.find(c=>c.field === 'totalCantEntrada')?.width, textAlign: 'right', fontWeight: 'bold', pr:1 }}>{numberFormatter(totals.totalCantEntrada)}</Typography>
|
|
||||||
<Typography variant="subtitle2" sx={{ width: columns.find(c=>c.field === 'vendidos')?.width, textAlign: 'right', fontWeight: 'bold', pr:1 }}>{numberFormatter(totals.vendidos)}</Typography>
|
|
||||||
<Typography variant="subtitle2" sx={{ width: columns.find(c=>c.field === 'totalRendir')?.width, textAlign: 'right', fontWeight: 'bold' }}>{currencyFormatter(totals.totalRendir)}</Typography>
|
|
||||||
</Box>
|
|
||||||
</GridFooterContainer>
|
|
||||||
);
|
|
||||||
|
|
||||||
const CustomFooterCanillas = useMemo(() => createCustomFooter(totalesCanillas, commonColumns), [totalesCanillas]);
|
|
||||||
const CustomFooterAccionistas = useMemo(() => createCustomFooter(totalesAccionistas, commonColumns), [totalesAccionistas]);
|
|
||||||
const CustomFooterTodos = useMemo(() => createCustomFooter(totalesTodos, columnsTodos), [totalesTodos]);
|
|
||||||
const CustomFooterCanillasOtraFecha = useMemo(() => createCustomFooter(totalesCanillasOtraFecha, commonColumnsWithFecha), [totalesCanillasOtraFecha]);
|
|
||||||
const CustomFooterAccionistasOtraFecha = useMemo(() => createCustomFooter(totalesAccionistasOtraFecha, commonColumnsWithFecha), [totalesAccionistasOtraFecha]);
|
|
||||||
|
|
||||||
|
|
||||||
if (showParamSelector) {
|
if (showParamSelector) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ p: 2, display: 'flex', justifyContent: 'center', mt: 2 }}>
|
<Box sx={{ p: 2, display: 'flex', justifyContent: 'center', mt: 2 }}>
|
||||||
<Paper sx={{ width: '100%', maxWidth: 600 }} elevation={3}>
|
<Paper sx={{ width: '100%', maxWidth: 600 }} elevation={3}>
|
||||||
<SeleccionaReporteDetalleDistribucionCanillas
|
<SeleccionaReporteListadoDistribucionGeneral
|
||||||
onGenerarReporte={handleGenerarReporte}
|
onGenerarReporte={handleGenerarReporte}
|
||||||
onCancel={handleVolverAParametros} // Asumo que no se usa, ya que el selector no tiene botón de cancelar
|
onCancel={handleVolverAParametros}
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
apiErrorMessage={apiErrorParams}
|
apiErrorMessage={apiErrorParams}
|
||||||
/>
|
/>
|
||||||
@@ -345,13 +159,10 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<Box sx={{ p: 2 }}>
|
<Box sx={{ p: 2 }}>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2, flexWrap: 'wrap', gap: 1 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2, flexWrap: 'wrap', gap: 1 }}>
|
||||||
<Typography variant="h5">Reporte: Detalle Distribución Canillitas ({currentParams?.nombreEmpresa}) - {currentParams?.fecha}</Typography>
|
<Typography variant="h5">Reporte: Listado Distribución General</Typography>
|
||||||
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
|
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||||
<Button onClick={() => handleGenerarYAbrirPdf(false)} variant="contained" disabled={loadingPdf || !reportData || !!error} size="small">
|
<Button onClick={handleGenerarYAbrirPdf} variant="contained" disabled={loadingPdf || !reportData || !!error} size="small">
|
||||||
{loadingPdf && !pdfSoloTotales ? <CircularProgress size={20} color="inherit" /> : "PDF Detalle"}
|
{loadingPdf ? <CircularProgress size={20} color="inherit" /> : "Abrir PDF"}
|
||||||
</Button>
|
|
||||||
<Button onClick={() => handleGenerarYAbrirPdf(true)} variant="contained" color="secondary" disabled={loadingPdf || !reportData || !!error} size="small">
|
|
||||||
{loadingPdf && pdfSoloTotales ? <CircularProgress size={20} color="inherit" /> : "PDF Totales"}
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleExportToExcel} variant="outlined" disabled={!reportData || !!error} size="small">
|
<Button onClick={handleExportToExcel} variant="outlined" disabled={!reportData || !!error} size="small">
|
||||||
Exportar a Excel
|
Exportar a Excel
|
||||||
@@ -362,151 +173,80 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{loading && <Box sx={{ textAlign: 'center', my:2 }}><CircularProgress /></Box>}
|
{loading && <Box sx={{ textAlign: 'center' }}><CircularProgress /></Box>}
|
||||||
{error && !loading && <Alert severity="error" sx={{ my: 2 }}>{error}</Alert>}
|
{error && !loading && <Alert severity="error" sx={{ my: 2 }}>{error}</Alert>}
|
||||||
|
|
||||||
{!loading && !error && reportData && (
|
{!loading && !error && reportData && (
|
||||||
<>
|
<>
|
||||||
{/* Canillitas (del día) */}
|
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Resumen Diario</Typography>
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Canillitas (del día)</Typography>
|
{reportData.resumen && reportData.resumen.length > 0 ? (
|
||||||
{rowsCanillas.length > 0 ? (
|
<TableContainer component={Paper} sx={{ maxHeight: '300px', mb: 3 }}>
|
||||||
<Paper sx={{ height: 400, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
<Table stickyHeader size="small">
|
||||||
<DataGrid
|
<TableHead>
|
||||||
rows={rowsCanillas}
|
<TableRow>
|
||||||
columns={commonColumns}
|
<TableCell>Fecha</TableCell>
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
<TableCell align="right">Tirada</TableCell>
|
||||||
density="compact"
|
<TableCell align="right">Sin Cargo</TableCell>
|
||||||
slots={{ footer: CustomFooterCanillas }}
|
<TableCell align="right">Perdidos</TableCell>
|
||||||
hideFooterSelectedRowCount
|
<TableCell align="right">Llevados</TableCell>
|
||||||
/>
|
<TableCell align="right">Devueltos</TableCell>
|
||||||
</Paper>
|
<TableCell align="right">Vendidos</TableCell>
|
||||||
) : (<Typography sx={{ fontStyle: 'italic', mb:2 }}>No hay datos para canillitas (del día).</Typography>)}
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{reportData.resumen.map((row, idx) => (
|
||||||
|
<TableRow key={`resumen-${idx}`}>
|
||||||
|
<TableCell>{row.fecha ? new Date(row.fecha).toLocaleDateString('es-AR', { timeZone: 'UTC' }) : '-'}</TableCell>
|
||||||
|
<TableCell align="right">{row.cantidadTirada.toLocaleString('es-AR')}</TableCell>
|
||||||
|
<TableCell align="right">{row.sinCargo.toLocaleString('es-AR')}</TableCell>
|
||||||
|
<TableCell align="right">{row.perdidos.toLocaleString('es-AR')}</TableCell>
|
||||||
|
<TableCell align="right">{row.llevados.toLocaleString('es-AR')}</TableCell>
|
||||||
|
<TableCell align="right">{row.devueltos.toLocaleString('es-AR')}</TableCell>
|
||||||
|
<TableCell align="right">{row.vendidos.toLocaleString('es-AR')}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
) : (<Typography>No hay datos de resumen diario.</Typography>)}
|
||||||
|
|
||||||
{/* Accionistas (del día) */}
|
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Promedios por Día de Semana</Typography>
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Accionistas (del día)</Typography>
|
{reportData.promediosPorDia && reportData.promediosPorDia.length > 0 ? (
|
||||||
{rowsAccionistas.length > 0 ? (
|
<TableContainer component={Paper} sx={{ maxHeight: '300px' }}>
|
||||||
<Paper sx={{ height: 400, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
<Table stickyHeader size="small">
|
||||||
<DataGrid
|
<TableHead>
|
||||||
rows={rowsAccionistas}
|
<TableRow>
|
||||||
columns={commonColumns}
|
<TableCell>Día</TableCell>
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
<TableCell align="right">Cant. Días</TableCell>
|
||||||
density="compact"
|
<TableCell align="right">Prom. Tirada</TableCell>
|
||||||
slots={{ footer: CustomFooterAccionistas }}
|
<TableCell align="right">Prom. Sin Cargo</TableCell>
|
||||||
hideFooterSelectedRowCount
|
<TableCell align="right">Prom. Perdidos</TableCell>
|
||||||
/>
|
<TableCell align="right">Prom. Llevados</TableCell>
|
||||||
</Paper>
|
<TableCell align="right">Prom. Devueltos</TableCell>
|
||||||
) : (<Typography sx={{ fontStyle: 'italic', mb:2 }}>No hay datos para accionistas (del día).</Typography>)}
|
<TableCell align="right">Prom. Vendidos</TableCell>
|
||||||
|
</TableRow>
|
||||||
{/* Resumen por Tipo de Vendedor (del día) */}
|
</TableHead>
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Resumen por Tipo de Vendedor (del día)</Typography>
|
<TableBody>
|
||||||
{rowsTodos.length > 0 ? (
|
{reportData.promediosPorDia.map((row, idx) => (
|
||||||
<Paper sx={{ height: 300, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
<TableRow key={`promedio-${idx}`}>
|
||||||
<DataGrid
|
<TableCell>{row.dia}</TableCell>
|
||||||
rows={rowsTodos}
|
<TableCell align="right">{row.cantidadDias.toLocaleString('es-AR')}</TableCell>
|
||||||
columns={columnsTodos}
|
<TableCell align="right">{row.promedioTirada.toLocaleString('es-AR')}</TableCell>
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
<TableCell align="right">{row.promedioSinCargo.toLocaleString('es-AR')}</TableCell>
|
||||||
density="compact"
|
<TableCell align="right">{row.promedioPerdidos.toLocaleString('es-AR')}</TableCell>
|
||||||
slots={{ footer: CustomFooterTodos }}
|
<TableCell align="right">{row.promedioLlevados.toLocaleString('es-AR')}</TableCell>
|
||||||
hideFooterSelectedRowCount
|
<TableCell align="right">{row.promedioDevueltos.toLocaleString('es-AR')}</TableCell>
|
||||||
/>
|
<TableCell align="right">{row.promedioVendidos.toLocaleString('es-AR')}</TableCell>
|
||||||
</Paper>
|
</TableRow>
|
||||||
) : (<Typography sx={{ fontStyle: 'italic', mb:2 }}>No hay datos para resumen por tipo de vendedor (del día).</Typography>)}
|
))}
|
||||||
|
</TableBody>
|
||||||
{/* Canillitas (Liquidados de Otras Fechas) */}
|
</Table>
|
||||||
{rowsCanillasOtraFecha.length > 0 && (
|
</TableContainer>
|
||||||
<>
|
) : (<Typography>No hay datos de promedios por día.</Typography>)}
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Canillitas (Liquidados de Otras Fechas)</Typography>
|
|
||||||
<Paper sx={{ height: 300, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
|
||||||
<DataGrid
|
|
||||||
rows={rowsCanillasOtraFecha}
|
|
||||||
columns={commonColumnsWithFecha}
|
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
|
||||||
density="compact"
|
|
||||||
slots={{ footer: CustomFooterCanillasOtraFecha }}
|
|
||||||
hideFooterSelectedRowCount
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Accionistas (Liquidados de Otras Fechas) */}
|
|
||||||
{rowsAccionistasOtraFecha.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Accionistas (Liquidados de Otras Fechas)</Typography>
|
|
||||||
<Paper sx={{ height: 300, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
|
||||||
<DataGrid
|
|
||||||
rows={rowsAccionistasOtraFecha}
|
|
||||||
columns={commonColumnsWithFecha}
|
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
|
||||||
density="compact"
|
|
||||||
slots={{ footer: CustomFooterAccionistasOtraFecha }}
|
|
||||||
hideFooterSelectedRowCount
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Control Devoluciones - Detalle */}
|
|
||||||
{rowsCtrlDevDetalle.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Control Devoluciones - Detalle</Typography>
|
|
||||||
<Paper sx={{ height: 300, width: '100%', mb: 3 }}>
|
|
||||||
<DataGrid
|
|
||||||
rows={rowsCtrlDevDetalle}
|
|
||||||
columns={columnsCtrlDevDetalle}
|
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
|
||||||
density="compact"
|
|
||||||
hideFooterSelectedRowCount // Sin footer personalizado para estos
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Control Devoluciones - Remitos */}
|
|
||||||
{rowsCtrlDevRemitos.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Control Devoluciones - Remitos Ingresados</Typography>
|
|
||||||
<Paper sx={{ height: 200, width: '100%', mb: 3 }}>
|
|
||||||
<DataGrid
|
|
||||||
rows={rowsCtrlDevRemitos}
|
|
||||||
columns={columnsCtrlDevRemitos}
|
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
|
||||||
density="compact"
|
|
||||||
autoHeight
|
|
||||||
hideFooterSelectedRowCount
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Control Devoluciones - Otros Días */}
|
|
||||||
{rowsCtrlDevOtrosDias.length > 0 && (
|
|
||||||
<>
|
|
||||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Control Devoluciones - Otros Días</Typography>
|
|
||||||
<Paper sx={{ height: 200, width: '100%', mb: 3 }}>
|
|
||||||
<DataGrid
|
|
||||||
rows={rowsCtrlDevOtrosDias}
|
|
||||||
columns={columnsCtrlDevOtrosDias}
|
|
||||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
|
||||||
density="compact"
|
|
||||||
autoHeight
|
|
||||||
hideFooterSelectedRowCount
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{!loading && !error && (!reportData ||
|
|
||||||
(rowsCanillas.length === 0 && rowsAccionistas.length === 0 && rowsTodos.length === 0 &&
|
|
||||||
rowsCanillasOtraFecha.length === 0 && rowsAccionistasOtraFecha.length === 0 &&
|
|
||||||
rowsCtrlDevDetalle.length === 0 && rowsCtrlDevRemitos.length === 0 && rowsCtrlDevOtrosDias.length === 0
|
|
||||||
)) &&
|
|
||||||
(<Typography>No se encontraron datos para los criterios seleccionados.</Typography>)
|
|
||||||
}
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ReporteDetalleDistribucionCanillasPage;
|
export default ReporteListadoDistribucionGeneralPage;
|
||||||
@@ -71,24 +71,68 @@ const SeleccionaReporteListadoDistMensual: React.FC<SeleccionaReporteListadoDist
|
|||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
/>
|
/>
|
||||||
|
<Box sx={{ mt: 2, mb: 2, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<Typography variant="subtitle1" sx={{ mb: 0, fontWeight: 500 }}>
|
||||||
|
Tipo de Vendedor
|
||||||
|
</Typography>
|
||||||
|
<FormControl component="fieldset" margin="normal" fullWidth disabled={isLoading} sx={{ mt: 2, mb: 2, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
|
||||||
<FormControl component="fieldset" margin="normal" fullWidth disabled={isLoading}>
|
|
||||||
<Typography component="legend" variant="subtitle2" sx={{mb:0.5, color: 'rgba(0, 0, 0, 0.6)'}}>Tipo de Vendedor</Typography>
|
|
||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
color="primary"
|
|
||||||
value={esAccionista ? 'accionistas' : 'canillitas'}
|
value={esAccionista ? 'accionistas' : 'canillitas'}
|
||||||
exclusive
|
exclusive
|
||||||
onChange={(_, newValue) => {
|
onChange={(_, value) => {
|
||||||
if (newValue !== null) setEsAccionista(newValue === 'accionistas');
|
if (value !== null) setEsAccionista(value === 'accionistas');
|
||||||
|
}}
|
||||||
|
aria-label="Tipo de reporte"
|
||||||
|
disabled={isLoading}
|
||||||
|
color="primary"
|
||||||
|
size="large"
|
||||||
|
sx={{
|
||||||
|
borderRadius: 2,
|
||||||
|
boxShadow: 2,
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
p: 0.5,
|
||||||
}}
|
}}
|
||||||
aria-label="Tipo de Vendedor"
|
|
||||||
size="small"
|
|
||||||
>
|
>
|
||||||
<ToggleButton value="canillitas">Canillitas</ToggleButton>
|
<ToggleButton
|
||||||
<ToggleButton value="accionistas">Accionistas</ToggleButton>
|
value="canillitas"
|
||||||
|
aria-label="Canillitas"
|
||||||
|
sx={{
|
||||||
|
fontWeight: esAccionista ? 400 : 700,
|
||||||
|
bgcolor: !esAccionista ? 'primary.main' : 'background.paper',
|
||||||
|
color: !esAccionista ? 'primary.contrastText' : 'text.primary',
|
||||||
|
'&.Mui-selected': {
|
||||||
|
bgcolor: 'primary.main',
|
||||||
|
color: 'primary.contrastText',
|
||||||
|
},
|
||||||
|
minWidth: 140,
|
||||||
|
borderRadius: 2,
|
||||||
|
mx: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Canillitas
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton
|
||||||
|
value="accionistas"
|
||||||
|
aria-label="Accionistas"
|
||||||
|
sx={{
|
||||||
|
fontWeight: esAccionista ? 700 : 400,
|
||||||
|
bgcolor: esAccionista ? 'primary.main' : 'background.paper',
|
||||||
|
color: esAccionista ? 'primary.contrastText' : 'text.primary',
|
||||||
|
'&.Mui-selected': {
|
||||||
|
bgcolor: 'primary.main',
|
||||||
|
color: 'primary.contrastText',
|
||||||
|
},
|
||||||
|
minWidth: 140,
|
||||||
|
borderRadius: 2,
|
||||||
|
mx: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Accionistas
|
||||||
|
</ToggleButton>
|
||||||
</ToggleButtonGroup>
|
</ToggleButtonGroup>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
</Box>
|
||||||
<FormControl component="fieldset" margin="normal" fullWidth disabled={isLoading}>
|
<FormControl component="fieldset" margin="normal" fullWidth disabled={isLoading}>
|
||||||
<Typography component="legend" variant="subtitle2" sx={{ mb: 0.5, color: 'rgba(0, 0, 0, 0.6)' }}>Variante del Reporte</Typography>
|
<Typography component="legend" variant="subtitle2" sx={{ mb: 0.5, color: 'rgba(0, 0, 0, 0.6)' }}>Variante del Reporte</Typography>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ const SeleccionaReporteListadoDistribucionCanillasImporte: React.FC<SeleccionaRe
|
|||||||
/>
|
/>
|
||||||
<Box sx={{ mt: 2, mb: 2, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
<Box sx={{ mt: 2, mb: 2, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
<Typography variant="subtitle1" sx={{ mb: 1, fontWeight: 500 }}>
|
<Typography variant="subtitle1" sx={{ mb: 1, fontWeight: 500 }}>
|
||||||
Tipo de reporte
|
Tipo de Vendedor
|
||||||
</Typography>
|
</Typography>
|
||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
value={esAccionista ? 'accionistas' : 'canillitas'}
|
value={esAccionista ? 'accionistas' : 'canillitas'}
|
||||||
@@ -128,7 +128,7 @@ const SeleccionaReporteListadoDistribucionCanillasImporte: React.FC<SeleccionaRe
|
|||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
if (value !== null) setEsAccionista(value === 'accionistas');
|
if (value !== null) setEsAccionista(value === 'accionistas');
|
||||||
}}
|
}}
|
||||||
aria-label="Tipo de reporte"
|
aria-label="Tipo de Vendedor"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
color="primary"
|
color="primary"
|
||||||
size="large"
|
size="large"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// src/pages/Reportes/SeleccionaReporteListadoDistribucionGeneral.tsx
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
Box, Typography, Button, CircularProgress, Alert,
|
Box, Typography, Button, CircularProgress, Alert,
|
||||||
|
|||||||
Reference in New Issue
Block a user