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:
@@ -1,4 +1,3 @@
|
||||
// src/pages/Reportes/ReporteListadoDistMensualPage.tsx
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Box, Typography, Paper, CircularProgress, Alert, Button,
|
||||
|
||||
@@ -1,116 +1,50 @@
|
||||
// src/pages/Reportes/ReporteDetalleDistribucionCanillasPage.tsx
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import {
|
||||
Box, Typography, Paper, CircularProgress, Alert, Button
|
||||
Box, Typography, Paper, CircularProgress, Alert, Button,
|
||||
TableContainer, Table, TableHead, TableRow, TableCell, TableBody
|
||||
} 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 type { ReporteDistribucionCanillasResponseDto } from '../../models/dtos/Reportes/ReporteDistribucionCanillasResponseDto';
|
||||
import SeleccionaReporteDetalleDistribucionCanillas from './SeleccionaReporteDetalleDistribucionCanillas';
|
||||
import type { ListadoDistribucionGeneralResponseDto } from '../../models/dtos/Reportes/ListadoDistribucionGeneralResponseDto';
|
||||
import SeleccionaReporteListadoDistribucionGeneral from './SeleccionaReporteListadoDistribucionGeneral';
|
||||
import * as XLSX from 'xlsx';
|
||||
import axios from 'axios';
|
||||
|
||||
interface TotalesComunes {
|
||||
totalCantSalida: number;
|
||||
totalCantEntrada: number;
|
||||
vendidos: number;
|
||||
totalRendir: number;
|
||||
}
|
||||
|
||||
const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
||||
const [reportData, setReportData] = useState<ReporteDistribucionCanillasResponseDto | null>(null);
|
||||
const ReporteListadoDistribucionGeneralPage: React.FC = () => {
|
||||
const [reportData, setReportData] = useState<ListadoDistribucionGeneralResponseDto | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingPdf, setLoadingPdf] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [apiErrorParams, setApiErrorParams] = useState<string | null>(null);
|
||||
const [showParamSelector, setShowParamSelector] = useState(true);
|
||||
const [currentParams, setCurrentParams] = useState<{
|
||||
fecha: string;
|
||||
idEmpresa: number;
|
||||
nombreEmpresa?: string;
|
||||
idPublicacion: number;
|
||||
fechaDesde: string; // Primer día del mes
|
||||
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);
|
||||
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: {
|
||||
fecha: string;
|
||||
idEmpresa: number;
|
||||
idPublicacion: number;
|
||||
fechaDesde: string;
|
||||
fechaHasta: string;
|
||||
}) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setApiErrorParams(null);
|
||||
|
||||
const empresaService = (await import('../../services/Distribucion/empresaService')).default;
|
||||
const empData = await empresaService.getEmpresaById(params.idEmpresa);
|
||||
|
||||
setCurrentParams({ ...params, nombreEmpresa: empData?.nombre });
|
||||
setReportData(null); // Limpiar datos antiguos
|
||||
|
||||
// Resetear totales
|
||||
setTotalesCanillas(initialTotals);
|
||||
setTotalesAccionistas(initialTotals);
|
||||
setTotalesTodos(initialTotals);
|
||||
setTotalesCanillasOtraFecha(initialTotals);
|
||||
setTotalesAccionistasOtraFecha(initialTotals);
|
||||
|
||||
// Para el nombre del archivo y título del PDF
|
||||
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, nombrePublicacion: pubData?.nombre, mesAnioParaNombreArchivo: mesAnioNombre });
|
||||
try {
|
||||
const data = await reportesService.getReporteDistribucionCanillas(params);
|
||||
|
||||
const addIds = <T extends Record<string, any>>(arr: T[] | undefined, prefix: string): Array<T & { id: string }> =>
|
||||
(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) {
|
||||
const data = await reportesService.getListadoDistribucionGeneral(params);
|
||||
setReportData(data);
|
||||
if ((!data.resumen || data.resumen.length === 0) && (!data.promediosPorDia || data.promediosPorDia.length === 0)) {
|
||||
setError("No se encontraron datos para los parámetros seleccionados.");
|
||||
}
|
||||
setShowParamSelector(false);
|
||||
@@ -134,96 +68,62 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
||||
}, []);
|
||||
|
||||
const handleExportToExcel = useCallback(() => {
|
||||
if (!reportData) {
|
||||
if (!reportData || (!reportData.resumen?.length && !reportData.promediosPorDia?.length)) {
|
||||
alert("No hay datos para exportar.");
|
||||
return;
|
||||
}
|
||||
const wb = XLSX.utils.book_new();
|
||||
|
||||
const formatAndSheet = (
|
||||
data: any[],
|
||||
sheetName: string,
|
||||
fields: Record<string, string>,
|
||||
totals?: TotalesComunes
|
||||
) => {
|
||||
if (data && data.length > 0) {
|
||||
let exportedData = data.map(item => {
|
||||
const row: Record<string, any> = {};
|
||||
const { id, ...itemData } = item; // Excluir el 'id' generado
|
||||
Object.keys(fields).forEach(key => {
|
||||
row[fields[key]] = (itemData as any)[key];
|
||||
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 (reportData.resumen?.length) {
|
||||
const resumenToExport = reportData.resumen.map(item => ({
|
||||
"Fecha": item.fecha ? new Date(item.fecha).toLocaleDateString('es-AR', { timeZone: 'UTC' }) : '-',
|
||||
"Tirada": item.cantidadTirada,
|
||||
"Sin Cargo": item.sinCargo,
|
||||
"Perdidos": item.perdidos,
|
||||
"Llevados": item.llevados,
|
||||
"Devueltos": item.devueltos,
|
||||
"Vendidos": item.vendidos,
|
||||
}));
|
||||
const wsResumen = XLSX.utils.json_to_sheet(resumenToExport);
|
||||
XLSX.utils.book_append_sheet(wb, wsResumen, "ResumenDiario");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (reportData.promediosPorDia?.length) {
|
||||
const promediosToExport = reportData.promediosPorDia.map(item => ({
|
||||
"Día Semana": item.dia,
|
||||
"Cant. Días": item.cantidadDias,
|
||||
"Prom. Tirada": item.promedioTirada,
|
||||
"Prom. Sin Cargo": item.promedioSinCargo,
|
||||
"Prom. Perdidos": item.promedioPerdidos,
|
||||
"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 ws = XLSX.utils.json_to_sheet(exportedData);
|
||||
const headers = Object.values(fields);
|
||||
ws['!cols'] = headers.map(h => {
|
||||
const maxLen = Math.max(...exportedData.map(row => (row[h]?.toString() ?? '').length), h.length);
|
||||
return { wch: maxLen + 2 };
|
||||
});
|
||||
ws['!freeze'] = { xSplit: 0, ySplit: 1 }; // Congelar primera fila
|
||||
XLSX.utils.book_append_sheet(wb, ws, sheetName);
|
||||
}
|
||||
};
|
||||
|
||||
const fieldsCanillaAccionista = { publicacion: "Publicación", canilla: "Canilla", totalCantSalida: "Llevados", totalCantEntrada: "Devueltos", vendidos: "Vendidos", totalRendir: "A Rendir" };
|
||||
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";
|
||||
let fileName = "ListadoDistribucionGeneral";
|
||||
if (currentParams) {
|
||||
fileName += `_${currentParams.nombreEmpresa?.replace(/\s+/g, '') ?? `Emp${currentParams.idEmpresa}`}`;
|
||||
fileName += `_${currentParams.fecha}`;
|
||||
fileName += `_${currentParams.nombrePublicacion?.replace(/\s+/g, '') ?? `Pub${currentParams.idPublicacion}`}`;
|
||||
fileName += `_${currentParams.mesAnioParaNombreArchivo?.replace('/', '-')}`;
|
||||
}
|
||||
fileName += ".xlsx";
|
||||
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) {
|
||||
setError("Primero debe generar el reporte en pantalla o seleccionar parámetros.");
|
||||
return;
|
||||
}
|
||||
setLoadingPdf(true);
|
||||
setError(null);
|
||||
setPdfSoloTotales(soloTotales);
|
||||
try {
|
||||
const blob = await reportesService.getReporteDistribucionCanillasPdf({
|
||||
...currentParams,
|
||||
soloTotales
|
||||
const blob = await reportesService.getListadoDistribucionGeneralPdf({
|
||||
idPublicacion: currentParams.idPublicacion,
|
||||
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") {
|
||||
const text = await blob.text();
|
||||
@@ -241,99 +141,13 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
||||
}
|
||||
}, [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) {
|
||||
return (
|
||||
<Box sx={{ p: 2, display: 'flex', justifyContent: 'center', mt: 2 }}>
|
||||
<Paper sx={{ width: '100%', maxWidth: 600 }} elevation={3}>
|
||||
<SeleccionaReporteDetalleDistribucionCanillas
|
||||
<SeleccionaReporteListadoDistribucionGeneral
|
||||
onGenerarReporte={handleGenerarReporte}
|
||||
onCancel={handleVolverAParametros} // Asumo que no se usa, ya que el selector no tiene botón de cancelar
|
||||
onCancel={handleVolverAParametros}
|
||||
isLoading={loading}
|
||||
apiErrorMessage={apiErrorParams}
|
||||
/>
|
||||
@@ -345,13 +159,10 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
||||
return (
|
||||
<Box sx={{ p: 2 }}>
|
||||
<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>
|
||||
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
|
||||
<Button onClick={() => handleGenerarYAbrirPdf(false)} variant="contained" disabled={loadingPdf || !reportData || !!error} size="small">
|
||||
{loadingPdf && !pdfSoloTotales ? <CircularProgress size={20} color="inherit" /> : "PDF Detalle"}
|
||||
</Button>
|
||||
<Button onClick={() => handleGenerarYAbrirPdf(true)} variant="contained" color="secondary" disabled={loadingPdf || !reportData || !!error} size="small">
|
||||
{loadingPdf && pdfSoloTotales ? <CircularProgress size={20} color="inherit" /> : "PDF Totales"}
|
||||
<Typography variant="h5">Reporte: Listado Distribución General</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<Button onClick={handleGenerarYAbrirPdf} variant="contained" disabled={loadingPdf || !reportData || !!error} size="small">
|
||||
{loadingPdf ? <CircularProgress size={20} color="inherit" /> : "Abrir PDF"}
|
||||
</Button>
|
||||
<Button onClick={handleExportToExcel} variant="outlined" disabled={!reportData || !!error} size="small">
|
||||
Exportar a Excel
|
||||
@@ -362,151 +173,80 @@ const ReporteDetalleDistribucionCanillasPage: React.FC = () => {
|
||||
</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>}
|
||||
|
||||
{!loading && !error && reportData && (
|
||||
<>
|
||||
{/* Canillitas (del día) */}
|
||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Canillitas (del día)</Typography>
|
||||
{rowsCanillas.length > 0 ? (
|
||||
<Paper sx={{ height: 400, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
||||
<DataGrid
|
||||
rows={rowsCanillas}
|
||||
columns={commonColumns}
|
||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
||||
density="compact"
|
||||
slots={{ footer: CustomFooterCanillas }}
|
||||
hideFooterSelectedRowCount
|
||||
/>
|
||||
</Paper>
|
||||
) : (<Typography sx={{ fontStyle: 'italic', mb:2 }}>No hay datos para canillitas (del día).</Typography>)}
|
||||
|
||||
{/* Accionistas (del día) */}
|
||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Accionistas (del día)</Typography>
|
||||
{rowsAccionistas.length > 0 ? (
|
||||
<Paper sx={{ height: 400, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
||||
<DataGrid
|
||||
rows={rowsAccionistas}
|
||||
columns={commonColumns}
|
||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
||||
density="compact"
|
||||
slots={{ footer: CustomFooterAccionistas }}
|
||||
hideFooterSelectedRowCount
|
||||
/>
|
||||
</Paper>
|
||||
) : (<Typography sx={{ fontStyle: 'italic', mb:2 }}>No hay datos para accionistas (del día).</Typography>)}
|
||||
|
||||
{/* Resumen por Tipo de Vendedor (del día) */}
|
||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Resumen por Tipo de Vendedor (del día)</Typography>
|
||||
{rowsTodos.length > 0 ? (
|
||||
<Paper sx={{ height: 300, width: '100%', mb: 3, '& .MuiDataGrid-footerContainer': { minHeight: '52px' } }}>
|
||||
<DataGrid
|
||||
rows={rowsTodos}
|
||||
columns={columnsTodos}
|
||||
localeText={esES.components.MuiDataGrid.defaultProps.localeText}
|
||||
density="compact"
|
||||
slots={{ footer: CustomFooterTodos }}
|
||||
hideFooterSelectedRowCount
|
||||
/>
|
||||
</Paper>
|
||||
) : (<Typography sx={{ fontStyle: 'italic', mb:2 }}>No hay datos para resumen por tipo de vendedor (del día).</Typography>)}
|
||||
|
||||
{/* Canillitas (Liquidados de Otras Fechas) */}
|
||||
{rowsCanillasOtraFecha.length > 0 && (
|
||||
<>
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Resumen Diario</Typography>
|
||||
{reportData.resumen && reportData.resumen.length > 0 ? (
|
||||
<TableContainer component={Paper} sx={{ maxHeight: '300px', mb: 3 }}>
|
||||
<Table stickyHeader size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Fecha</TableCell>
|
||||
<TableCell align="right">Tirada</TableCell>
|
||||
<TableCell align="right">Sin Cargo</TableCell>
|
||||
<TableCell align="right">Perdidos</TableCell>
|
||||
<TableCell align="right">Llevados</TableCell>
|
||||
<TableCell align="right">Devueltos</TableCell>
|
||||
<TableCell align="right">Vendidos</TableCell>
|
||||
</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>)}
|
||||
|
||||
<Typography variant="h6" gutterBottom sx={{ mt: 2 }}>Promedios por Día de Semana</Typography>
|
||||
{reportData.promediosPorDia && reportData.promediosPorDia.length > 0 ? (
|
||||
<TableContainer component={Paper} sx={{ maxHeight: '300px' }}>
|
||||
<Table stickyHeader size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Día</TableCell>
|
||||
<TableCell align="right">Cant. Días</TableCell>
|
||||
<TableCell align="right">Prom. Tirada</TableCell>
|
||||
<TableCell align="right">Prom. Sin Cargo</TableCell>
|
||||
<TableCell align="right">Prom. Perdidos</TableCell>
|
||||
<TableCell align="right">Prom. Llevados</TableCell>
|
||||
<TableCell align="right">Prom. Devueltos</TableCell>
|
||||
<TableCell align="right">Prom. Vendidos</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{reportData.promediosPorDia.map((row, idx) => (
|
||||
<TableRow key={`promedio-${idx}`}>
|
||||
<TableCell>{row.dia}</TableCell>
|
||||
<TableCell align="right">{row.cantidadDias.toLocaleString('es-AR')}</TableCell>
|
||||
<TableCell align="right">{row.promedioTirada.toLocaleString('es-AR')}</TableCell>
|
||||
<TableCell align="right">{row.promedioSinCargo.toLocaleString('es-AR')}</TableCell>
|
||||
<TableCell align="right">{row.promedioPerdidos.toLocaleString('es-AR')}</TableCell>
|
||||
<TableCell align="right">{row.promedioLlevados.toLocaleString('es-AR')}</TableCell>
|
||||
<TableCell align="right">{row.promedioDevueltos.toLocaleString('es-AR')}</TableCell>
|
||||
<TableCell align="right">{row.promedioVendidos.toLocaleString('es-AR')}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
) : (<Typography>No hay datos de promedios por día.</Typography>)}
|
||||
</>
|
||||
)}
|
||||
{!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>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReporteDetalleDistribucionCanillasPage;
|
||||
export default ReporteListadoDistribucionGeneralPage;
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Box, Typography, TextField, Button, CircularProgress, Alert,
|
||||
FormControl,
|
||||
ToggleButtonGroup, ToggleButton, RadioGroup, FormControlLabel, Radio
|
||||
Box, Typography, TextField, Button, CircularProgress, Alert,
|
||||
FormControl,
|
||||
ToggleButtonGroup, ToggleButton, RadioGroup, FormControlLabel, Radio
|
||||
} from '@mui/material';
|
||||
|
||||
export type TipoListadoDistMensual = 'diarios' | 'publicaciones';
|
||||
@@ -71,35 +71,79 @@ const SeleccionaReporteListadoDistMensual: React.FC<SeleccionaReporteListadoDist
|
||||
disabled={isLoading}
|
||||
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
|
||||
color="primary"
|
||||
<ToggleButtonGroup
|
||||
value={esAccionista ? 'accionistas' : 'canillitas'}
|
||||
exclusive
|
||||
onChange={(_, newValue) => {
|
||||
if (newValue !== null) setEsAccionista(newValue === 'accionistas');
|
||||
onChange={(_, value) => {
|
||||
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 value="accionistas">Accionistas</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
</FormControl>
|
||||
|
||||
<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>
|
||||
</FormControl>
|
||||
</Box>
|
||||
<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
|
||||
row
|
||||
aria-label="Variante del Reporte"
|
||||
name="tipoReporte"
|
||||
value={tipoReporte}
|
||||
onChange={(e) => setTipoReporte(e.target.value as TipoListadoDistMensual)}
|
||||
row
|
||||
aria-label="Variante del Reporte"
|
||||
name="tipoReporte"
|
||||
value={tipoReporte}
|
||||
onChange={(e) => setTipoReporte(e.target.value as TipoListadoDistMensual)}
|
||||
>
|
||||
<FormControlLabel value="publicaciones" control={<Radio size="small" />} label="Por Publicación" />
|
||||
<FormControlLabel value="diarios" control={<Radio size="small" />} label="Por Diarios (El Día/El Plata)" />
|
||||
<FormControlLabel value="publicaciones" control={<Radio size="small" />} label="Por Publicación" />
|
||||
<FormControlLabel value="diarios" control={<Radio size="small" />} label="Por Diarios (El Día/El Plata)" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Box, Typography, TextField, Button, CircularProgress, Alert,
|
||||
FormControl, InputLabel, Select, MenuItem,
|
||||
ToggleButtonGroup,
|
||||
ToggleButton
|
||||
Box, Typography, TextField, Button, CircularProgress, Alert,
|
||||
FormControl, InputLabel, Select, MenuItem,
|
||||
ToggleButtonGroup,
|
||||
ToggleButton
|
||||
} from '@mui/material';
|
||||
import type { PublicacionDto } from '../../models/dtos/Distribucion/PublicacionDto';
|
||||
import publicacionService from '../../services/Distribucion/publicacionService';
|
||||
@@ -90,7 +90,7 @@ const SeleccionaReporteListadoDistribucionCanillasImporte: React.FC<SeleccionaRe
|
||||
<MenuItem key={p.idPublicacion} value={p.idPublicacion}>{p.nombre}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{localErrors.idPublicacion && <Typography color="error" variant="caption" sx={{ml:1.5}}>{localErrors.idPublicacion}</Typography>}
|
||||
{localErrors.idPublicacion && <Typography color="error" variant="caption" sx={{ ml: 1.5 }}>{localErrors.idPublicacion}</Typography>}
|
||||
</FormControl>
|
||||
<TextField
|
||||
label="Fecha Desde"
|
||||
@@ -119,64 +119,64 @@ const SeleccionaReporteListadoDistribucionCanillasImporte: React.FC<SeleccionaRe
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
<Box sx={{ mt: 2, mb: 2, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||
<Typography variant="subtitle1" sx={{ mb: 1, fontWeight: 500 }}>
|
||||
Tipo de reporte
|
||||
</Typography>
|
||||
<ToggleButtonGroup
|
||||
value={esAccionista ? 'accionistas' : 'canillitas'}
|
||||
exclusive
|
||||
onChange={(_, value) => {
|
||||
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,
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
</Box>
|
||||
<Typography variant="subtitle1" sx={{ mb: 1, fontWeight: 500 }}>
|
||||
Tipo de Vendedor
|
||||
</Typography>
|
||||
<ToggleButtonGroup
|
||||
value={esAccionista ? 'accionistas' : 'canillitas'}
|
||||
exclusive
|
||||
onChange={(_, value) => {
|
||||
if (value !== null) setEsAccionista(value === 'accionistas');
|
||||
}}
|
||||
aria-label="Tipo de Vendedor"
|
||||
disabled={isLoading}
|
||||
color="primary"
|
||||
size="large"
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
boxShadow: 2,
|
||||
backgroundColor: '#f5f5f5',
|
||||
p: 0.5,
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
</Box>
|
||||
|
||||
{apiErrorMessage && <Alert severity="error" sx={{ mt: 2 }}>{apiErrorMessage}</Alert>}
|
||||
{localErrors.dropdowns && <Alert severity="warning" sx={{ mt: 1 }}>{localErrors.dropdowns}</Alert>}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// src/pages/Reportes/SeleccionaReporteListadoDistribucionGeneral.tsx
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Box, Typography, Button, CircularProgress, Alert,
|
||||
|
||||
Reference in New Issue
Block a user