diff --git a/Backend/GestionIntegral.Api/Controllers/Reportes/PdfTemplates/ListadoDistribucionCanillasDocument.cs b/Backend/GestionIntegral.Api/Controllers/Reportes/PdfTemplates/ListadoDistribucionCanillasDocument.cs
index f414595..8000a15 100644
--- a/Backend/GestionIntegral.Api/Controllers/Reportes/PdfTemplates/ListadoDistribucionCanillasDocument.cs
+++ b/Backend/GestionIntegral.Api/Controllers/Reportes/PdfTemplates/ListadoDistribucionCanillasDocument.cs
@@ -148,7 +148,7 @@ namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
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;
+ var porcDevolucion = item.Promedio_Llevados > 0 ? (decimal)item.Promedio_Devueltos * 100 / item.Promedio_Llevados : 0;
table.Cell().Border(1).Padding(3).Text(item.Dia);
table.Cell().Border(1).Padding(3).AlignRight().Text(item.Cant.ToString("N0"));
@@ -162,7 +162,6 @@ namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
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));
@@ -170,7 +169,7 @@ namespace GestionIntegral.Api.Controllers.Reportes.PdfTemplates
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));
+ table.Cell().Border(1).Padding(3).AlignRight().Text(text => text.Span(Model.PorcentajeDevolucionGeneral.ToString("F2") + "%").Style(boldStyle));
}
});
});
diff --git a/Backend/GestionIntegral.Api/Models/Dtos/Reportes/ViewModels/ListadoDistribucionCanillasViewModel.cs b/Backend/GestionIntegral.Api/Models/Dtos/Reportes/ViewModels/ListadoDistribucionCanillasViewModel.cs
index c662ec1..8731e83 100644
--- a/Backend/GestionIntegral.Api/Models/Dtos/Reportes/ViewModels/ListadoDistribucionCanillasViewModel.cs
+++ b/Backend/GestionIntegral.Api/Models/Dtos/Reportes/ViewModels/ListadoDistribucionCanillasViewModel.cs
@@ -13,7 +13,7 @@ namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
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
@@ -29,7 +29,23 @@ namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
};
}
}
-
+
+ public decimal PorcentajeDevolucionGeneral
+ {
+ get
+ {
+ if (PromediosPorDia == null || !PromediosPorDia.Any()) return 0;
+
+ var totalPonderadoLlevados = PromediosPorDia.Sum(p => p.Promedio_Llevados * p.Cant);
+ var totalPonderadoDevueltos = PromediosPorDia.Sum(p => p.Promedio_Devueltos * p.Cant);
+
+ if (totalPonderadoLlevados == 0) return 0;
+
+ // Calculamos el porcentaje usando los totales ponderados para máxima precisión como lo hace el frontend.
+ return (decimal)totalPonderadoDevueltos * 100 / totalPonderadoLlevados;
+ }
+ }
+
// --- PROPIEDAD PARA LA FILA "GENERAL" ---
public ListadoDistribucionCanillasPromedioDiaDto? PromedioGeneral
{
@@ -37,20 +53,27 @@ namespace GestionIntegral.Api.Dtos.Reportes.ViewModels
{
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);
+ // Sumamos los totales ponderados para cada columna
+ var totalPonderadoLlevados = PromediosPorDia.Sum(p => p.Promedio_Llevados * p.Cant);
+ var totalPonderadoDevueltos = PromediosPorDia.Sum(p => p.Promedio_Devueltos * p.Cant);
+ var totalPonderadoVentas = PromediosPorDia.Sum(p => p.Promedio_Ventas * p.Cant);
var totalDias = PromediosPorDia.Sum(p => p.Cant);
if (totalDias == 0) return null;
+ // Usamos Math.Round para un redondeo matemático estándar antes de la conversión.
+ // MidpointRounding.AwayFromZero asegura que .5 se redondee hacia arriba, igual que en JavaScript.
+ var promGeneralLlevados = (int)Math.Round((decimal)totalPonderadoLlevados / totalDias, MidpointRounding.AwayFromZero);
+ var promGeneralDevueltos = (int)Math.Round((decimal)totalPonderadoDevueltos / totalDias, MidpointRounding.AwayFromZero);
+ var promGeneralVentas = (int)Math.Round((decimal)totalPonderadoVentas / totalDias, MidpointRounding.AwayFromZero);
+
return new ListadoDistribucionCanillasPromedioDiaDto
{
Dia = "General",
Cant = totalDias,
- Promedio_Llevados = totalLlevados / totalDias,
- Promedio_Devueltos = totalDevueltos / totalDias,
- Promedio_Ventas = (totalLlevados - totalDevueltos) / totalDias
+ Promedio_Llevados = promGeneralLlevados,
+ Promedio_Devueltos = promGeneralDevueltos,
+ Promedio_Ventas = promGeneralVentas
};
}
}
diff --git a/Backend/GestionIntegral.Api/Program.cs b/Backend/GestionIntegral.Api/Program.cs
index 0815017..064ad81 100644
--- a/Backend/GestionIntegral.Api/Program.cs
+++ b/Backend/GestionIntegral.Api/Program.cs
@@ -187,7 +187,7 @@ builder.Services.AddCors(options =>
policy =>
{
policy.WithOrigins(
- "http://localhost:5174", // Para desarrollo local
+ "http://localhost:5173", // Para desarrollo local
"https://gestion.eldiaservicios.com" // Para producción
)
.AllowAnyHeader()
diff --git a/Frontend/src/pages/Reportes/ReporteListadoDistribucionCanillasPage.tsx b/Frontend/src/pages/Reportes/ReporteListadoDistribucionCanillasPage.tsx
index f485fb7..f996c79 100644
--- a/Frontend/src/pages/Reportes/ReporteListadoDistribucionCanillasPage.tsx
+++ b/Frontend/src/pages/Reportes/ReporteListadoDistribucionCanillasPage.tsx
@@ -69,8 +69,8 @@ const ReporteListadoDistribucionCanillasPage: React.FC = () => {
setReportData(null);
setDetalleDiarioCalculado([]);
setPromediosPorDiaCalculado([]);
- setTotalesDetalle({ llevados:0, devueltos:0, ventaNeta:0, promedioGeneralVentaNeta:0, porcentajeDevolucionGeneral:0 });
- setTotalesPromedios({ cantDias:0, promLlevados:0, promDevueltos:0, promVentas:0, porcentajeDevolucionGeneral:0});
+ setTotalesDetalle({ llevados: 0, devueltos: 0, ventaNeta: 0, promedioGeneralVentaNeta: 0, porcentajeDevolucionGeneral: 0 });
+ setTotalesPromedios({ cantDias: 0, promLlevados: 0, promDevueltos: 0, promVentas: 0, porcentajeDevolucionGeneral: 0 });
const pubService = (await import('../../services/Distribucion/publicacionService')).default;
@@ -89,7 +89,7 @@ const ReporteListadoDistribucionCanillasPage: React.FC = () => {
const llevados = item.llevados || 0;
const devueltos = item.devueltos || 0;
const ventaNeta = llevados - devueltos;
-
+
if (llevados > 0) {
diasConActividadDetalle++;
acumuladoVentaNeta += ventaNeta;
@@ -101,7 +101,7 @@ const ReporteListadoDistribucionCanillasPage: React.FC = () => {
...item,
id: `simple-can-${index}`, // o simple-dist-${index}
ventaNeta: ventaNeta,
- promedio: promedioActual,
+ promedio: promedioActual,
porcentajeDevolucion: llevados > 0 ? (devueltos / llevados) * 100 : 0, // Esto es % Devolución real
};
});
@@ -110,45 +110,44 @@ const ReporteListadoDistribucionCanillasPage: React.FC = () => {
const totalLlevadosDetalle = detalleCalculadoLocal.reduce((sum, item) => sum + (item.llevados || 0), 0);
const totalDevueltosDetalle = detalleCalculadoLocal.reduce((sum, item) => sum + (item.devueltos || 0), 0);
const totalVentaNetaDetalle = totalLlevadosDetalle - totalDevueltosDetalle;
-
+
setTotalesDetalle({
- llevados: totalLlevadosDetalle,
- devueltos: totalDevueltosDetalle,
- ventaNeta: totalVentaNetaDetalle,
- promedioGeneralVentaNeta: ultimoPromedioDetalle,
- porcentajeDevolucionGeneral: totalLlevadosDetalle > 0 ? (totalDevueltosDetalle / totalLlevadosDetalle) * 100 : 0
+ llevados: totalLlevadosDetalle,
+ devueltos: totalDevueltosDetalle,
+ ventaNeta: totalVentaNetaDetalle,
+ promedioGeneralVentaNeta: ultimoPromedioDetalle,
+ porcentajeDevolucionGeneral: totalLlevadosDetalle > 0 ? (totalDevueltosDetalle / totalLlevadosDetalle) * 100 : 0
});
// --- Cálculos para promedios y sus totales ---
const promediosCalculadoLocal = data.promediosPorDia.map((item, index) => {
const promLlevados = item.promedio_Llevados || 0;
+ const promDevueltos = item.promedio_Devueltos || 0;
const promVentas = item.promedio_Ventas || 0;
return {
...item,
- id: `prom-can-${index}`, // o prom-dist-${index}
- // LA COLUMNA EN EL PDF SE LLAMA "% Devolución" PERO PARECE SER "% VENTA"
+ id: `prom-can-${index}`,
porcentajeColumnaPDF: promLlevados > 0 ? (promVentas / promLlevados) * 100 : 0,
- porcentajeDevolucion: promLlevados > 0 ? (promVentas / promLlevados) * 100 : 0,
+ porcentajeDevolucion: promLlevados > 0 ? (promDevueltos / promLlevados) * 100 : 0,
};
});
setPromediosPorDiaCalculado(promediosCalculadoLocal);
-
+
const totalDiasProm = promediosCalculadoLocal.reduce((sum, item) => sum + (item.cant || 0), 0);
const totalPonderadoLlevados = promediosCalculadoLocal.reduce((sum, item) => sum + ((item.promedio_Llevados || 0) * (item.cant || 0)), 0);
- // const totalPonderadoDevueltos = promediosCalculadoLocal.reduce((sum, item) => sum + ((item.promedio_Devueltos || 0) * (item.cant || 0)), 0); // No se usa para el % del PDF
+ const totalPonderadoDevueltos = promediosCalculadoLocal.reduce((sum, item) => sum + ((item.promedio_Devueltos || 0) * (item.cant || 0)), 0);
const totalPonderadoVentas = promediosCalculadoLocal.reduce((sum, item) => sum + ((item.promedio_Ventas || 0) * (item.cant || 0)), 0);
+ const promGeneralLlevados = totalDiasProm > 0 ? totalPonderadoLlevados / totalDiasProm : 0;
+ const promGeneralDevueltos = totalDiasProm > 0 ? totalPonderadoDevueltos / totalDiasProm : 0;
+
setTotalesPromedios({
cantDias: totalDiasProm,
- promLlevados: totalDiasProm > 0 ? totalPonderadoLlevados / totalDiasProm : 0,
- promDevueltos: totalDiasProm > 0 ? promediosCalculadoLocal.reduce((sum, item) => sum + (item.promedio_Devueltos || 0), 0) / promediosCalculadoLocal.length :0, // Promedio simple para mostrar
+ promLlevados: promGeneralLlevados,
+ promDevueltos: promGeneralDevueltos,
promVentas: totalDiasProm > 0 ? totalPonderadoVentas / totalDiasProm : 0,
- // Para la fila "General" de promedios, el PDF usa (Total Prom. Ventas / Total Prom. Llevados) * 100
- // Usaremos los promedios generales calculados aquí
- porcentajeDevolucionGeneral: (totalDiasProm > 0 && (totalPonderadoLlevados / totalDiasProm) > 0)
- ? ((totalPonderadoVentas / totalDiasProm) / (totalPonderadoLlevados / totalDiasProm)) * 100
- : 0,
+ porcentajeDevolucionGeneral: promGeneralLlevados > 0 ? (promGeneralDevueltos / promGeneralLlevados) * 100 : 0,
});
setReportData({ detalleSimple: detalleCalculadoLocal, promediosPorDia: promediosCalculadoLocal });
@@ -280,16 +279,16 @@ const ReporteListadoDistribucionCanillasPage: React.FC = () => {
{/* Contenedor para tus totales */}
- General:
- {totalesDetalle.llevados.toLocaleString('es-AR')}
- {totalesDetalle.devueltos.toLocaleString('es-AR')}
- {totalesDetalle.ventaNeta.toLocaleString('es-AR')}
- {totalesDetalle.promedioGeneralVentaNeta.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
+ General:
+ {totalesDetalle.llevados.toLocaleString('es-AR')}
+ {totalesDetalle.devueltos.toLocaleString('es-AR')}
+ {totalesDetalle.ventaNeta.toLocaleString('es-AR')}
+ {totalesDetalle.promedioGeneralVentaNeta.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
{totalesDetalle.porcentajeDevolucionGeneral.toLocaleString('es-AR', { maximumFractionDigits: 2 })}%
);
-
+
// --- Custom Footer para Promedios por Día ---
const CustomFooterPromedios = () => (
@@ -297,11 +296,11 @@ const ReporteListadoDistribucionCanillasPage: React.FC = () => {
- General:
- {totalesPromedios.cantDias.toLocaleString('es-AR')}
- {totalesPromedios.promLlevados.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
- {totalesPromedios.promDevueltos.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
- {totalesPromedios.promVentas.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
+ General:
+ {totalesPromedios.cantDias.toLocaleString('es-AR')}
+ {totalesPromedios.promLlevados.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
+ {totalesPromedios.promDevueltos.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
+ {totalesPromedios.promVentas.toLocaleString('es-AR', { maximumFractionDigits: 0 })}
{totalesPromedios.porcentajeDevolucionGeneral.toLocaleString('es-AR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%
@@ -372,10 +371,10 @@ const ReporteListadoDistribucionCanillasPage: React.FC = () => {
density="compact"
slots={{ footer: CustomFooterPromedios }}
hideFooterSelectedRowCount
- sx={{
- '& .MuiTablePagination-root': { // Oculta el paginador por defecto
- display: 'none',
- },
+ sx={{
+ '& .MuiTablePagination-root': { // Oculta el paginador por defecto
+ display: 'none',
+ },
}}
/>