Files
GestionIntegralWeb/Frontend/src/pages/Reportes/ReporteVentaMensualSecretariaPage.tsx

326 lines
16 KiB
TypeScript
Raw Normal View History

import React, { useState, useCallback } from 'react';
import {
Box, Typography, Paper, CircularProgress, Alert, Button,
TableContainer, Table, TableHead, TableRow, TableCell, TableBody
} from '@mui/material';
import reportesService from '../../services/Reportes/reportesService';
import type { VentaMensualSecretariaElDiaDto } from '../../models/dtos/Reportes/VentaMensualSecretariaElDiaDto';
import type { VentaMensualSecretariaElPlataDto } from '../../models/dtos/Reportes/VentaMensualSecretariaElPlataDto';
import type { VentaMensualSecretariaTirDevoDto } from '../../models/dtos/Reportes/VentaMensualSecretariaTirDevoDto';
import SeleccionaReporteVentaMensual, { type TipoReporteVentaMensual } from './SeleccionaReporteVentaMensual';
import * as XLSX from 'xlsx';
import axios from 'axios';
type ReportData = VentaMensualSecretariaElDiaDto[] | VentaMensualSecretariaElPlataDto[] | VentaMensualSecretariaTirDevoDto[];
const ReporteVentaMensualSecretariaPage: React.FC = () => {
const [reportData, setReportData] = useState<ReportData>([]);
const [currentReportType, setCurrentReportType] = useState<TipoReporteVentaMensual | 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<{
fechaDesde: string;
fechaHasta: string;
tipoReporte: TipoReporteVentaMensual;
} | null>(null);
const handleGenerarReporte = useCallback(async (params: {
fechaDesde: string;
fechaHasta: string;
tipoReporte: TipoReporteVentaMensual;
}) => {
setLoading(true);
setError(null);
setApiErrorParams(null);
setCurrentParams(params);
setCurrentReportType(params.tipoReporte);
setReportData([]);
try {
let data: ReportData = [];
if (params.tipoReporte === 'ElDia') {
data = await reportesService.getVentaMensualSecretariaElDia(params);
} else if (params.tipoReporte === 'ElPlata') {
data = await reportesService.getVentaMensualSecretariaElPlata(params);
} else if (params.tipoReporte === 'TirDevo') {
data = await reportesService.getVentaMensualSecretariaTirDevo(params);
}
setReportData(data);
if (data.length === 0) {
setError("No se encontraron datos para los parámetros seleccionados.");
}
setShowParamSelector(false);
} catch (err: any) {
const message = axios.isAxiosError(err) && err.response?.data?.message
? err.response.data.message
: 'Ocurrió un error al generar el reporte.';
setApiErrorParams(message);
} finally {
setLoading(false);
}
}, []);
const handleVolverAParametros = useCallback(() => {
setShowParamSelector(true);
setReportData([]);
setError(null);
setApiErrorParams(null);
setCurrentParams(null);
setCurrentReportType(null);
}, []);
const getReportTitle = () => {
if (!currentReportType) return "Venta Mensual Secretaría";
if (currentReportType === 'ElDia') return "Venta Mensual: El Día";
if (currentReportType === 'ElPlata') return "Venta Mensual: El Plata";
if (currentReportType === 'TirDevo') return "Venta Mensual: Tirada/Devolución";
return "Venta Mensual Secretaría";
};
const handleExportToExcel = useCallback(() => {
if (reportData.length === 0 || !currentReportType) {
alert("No hay datos para exportar.");
return;
}
let dataToExport: Record<string, any>[] = [];
let sheetName = "Reporte";
let fileNamePrefix = "ReporteVentaMensual";
if (currentReportType === 'ElDia') {
dataToExport = (reportData as VentaMensualSecretariaElDiaDto[]).map(item => ({
"Día": item.dia, "Canillitas": item.cantidadCanillas, "Tirajes": item.tirajes,
"Ventas": item.ventas, "Accionistas": item.accionistas, "Total Coop.": item.totalCooperativa,
"Total General": item.totalGeneral
}));
sheetName = "ElDia";
fileNamePrefix += "_ElDia";
} else if (currentReportType === 'ElPlata') {
dataToExport = (reportData as VentaMensualSecretariaElPlataDto[]).map(item => ({
"Día": item.dia, "Tirada Coop.": item.tiradaCoop, "Devol. Coop.": item.devolucionCoop,
"Venta Coop.": item.ventaCoop, "Tirada Can.": item.tiradaCan, "Venta Can.": item.ventaCan,
"Total": item.total
}));
sheetName = "ElPlata";
fileNamePrefix += "_ElPlata";
} else if (currentReportType === 'TirDevo') {
dataToExport = (reportData as VentaMensualSecretariaTirDevoDto[]).map(item => ({
"Día": item.dia, "Tir. Coop. (ED)": item.tiradaCoop, "Dev. Coop. (ED)": item.devolucionCoop,
"Vta. Coop. (ED)": item.ventaCoop, "Vta. Can. (ED)": item.ventaCan,
"Tir. Popular": item.tiradaPopular, "Dev. Popular": item.devolucionPopular, "Vta. Popular": item.ventaPopular,
"Tir. Clarín": item.tiradaClarin, "Dev. Clarín": item.devolucionClarin, "Vta. Clarín": item.ventaClarin,
"Tir. Nación": item.tiradaNacion, "Dev. Nación": item.devolucionNacion, "Vta. Nación": item.ventaNacion,
}));
sheetName = "TiradaDevolucion";
fileNamePrefix += "_TirDevo";
}
const ws = XLSX.utils.json_to_sheet(dataToExport);
const headers = Object.keys(dataToExport[0] || {});
ws['!cols'] = headers.map(h => {
const maxLen = Math.max(...dataToExport.map(row => (row[h]?.toString() ?? '').length), h.length);
return { wch: maxLen + 2 };
});
ws['!freeze'] = { xSplit: 0, ySplit: 1 };
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, sheetName);
let fileName = fileNamePrefix;
if (currentParams) {
fileName += `_${currentParams.fechaDesde}_a_${currentParams.fechaHasta}`;
}
fileName += ".xlsx";
XLSX.writeFile(wb, fileName);
}, [reportData, currentReportType, currentParams]);
const handleGenerarYAbrirPdf = useCallback(async () => {
if (!currentParams) {
setError("Primero debe generar el reporte en pantalla o seleccionar parámetros.");
return;
}
setLoadingPdf(true);
setError(null);
try {
let blob: Blob;
if (currentParams.tipoReporte === 'ElDia') {
blob = await reportesService.getVentaMensualSecretariaElDiaPdf(currentParams);
} else if (currentParams.tipoReporte === 'ElPlata') {
blob = await reportesService.getVentaMensualSecretariaElPlataPdf(currentParams);
} else if (currentParams.tipoReporte === 'TirDevo') {
blob = await reportesService.getVentaMensualSecretariaTirDevoPdf(currentParams);
} else {
setError("Tipo de reporte no válido para PDF.");
setLoadingPdf(false);
return;
}
if (blob.type === "application/json") {
const text = await blob.text();
const msg = JSON.parse(text).message ?? "Error inesperado al generar PDF.";
setError(msg);
} else {
const url = URL.createObjectURL(blob);
const w = window.open(url, '_blank');
if (!w) alert("Permite popups para ver el PDF.");
}
} catch {
setError('Ocurrió un error al generar el PDF.');
} finally {
setLoadingPdf(false);
}
}, [currentParams]);
const renderTable = () => {
if (!reportData || reportData.length === 0 || !currentReportType) return null;
if (currentReportType === 'ElDia') {
const data = reportData as VentaMensualSecretariaElDiaDto[];
return (
<TableContainer component={Paper} sx={{ maxHeight: 'calc(100vh - 280px)' }}>
<Table stickyHeader size="small">
<TableHead>
<TableRow>
<TableCell>Día</TableCell><TableCell align="right">Canillitas</TableCell>
<TableCell align="right">Tirajes</TableCell><TableCell align="right">Ventas</TableCell>
<TableCell align="right">Accionistas</TableCell><TableCell align="right">Total Coop.</TableCell>
<TableCell align="right">Total General</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map((row, idx) => (
<TableRow key={`eldia-${idx}`}>
<TableCell>{row.dia}</TableCell>
<TableCell align="right">{row.cantidadCanillas.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.tirajes.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventas.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.accionistas.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.totalCooperativa.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.totalGeneral.toLocaleString('es-AR')}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
} else if (currentReportType === 'ElPlata') {
const data = reportData as VentaMensualSecretariaElPlataDto[];
return (
<TableContainer component={Paper} sx={{ maxHeight: 'calc(100vh - 280px)' }}>
<Table stickyHeader size="small">
<TableHead>
<TableRow>
<TableCell>Día</TableCell><TableCell align="right">Tirada Coop.</TableCell>
<TableCell align="right">Devol. Coop.</TableCell><TableCell align="right">Venta Coop.</TableCell>
<TableCell align="right">Tirada Can.</TableCell><TableCell align="right">Venta Can.</TableCell>
<TableCell align="right">Total</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map((row, idx) => (
<TableRow key={`elplata-${idx}`}>
<TableCell>{row.dia}</TableCell>
<TableCell align="right">{row.tiradaCoop.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.devolucionCoop.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventaCoop.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.tiradaCan.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventaCan.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.total.toLocaleString('es-AR')}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
} else if (currentReportType === 'TirDevo') {
const data = reportData as VentaMensualSecretariaTirDevoDto[];
return (
<TableContainer component={Paper} sx={{ maxHeight: 'calc(100vh - 280px)' }}>
<Table stickyHeader size="small">
<TableHead>
<TableRow>
<TableCell rowSpan={2} sx={{verticalAlign: 'bottom'}}>Día</TableCell>
<TableCell colSpan={4} align="center" sx={{borderBottom: '1px solid rgba(224, 224, 224, 1)'}}>El Día</TableCell>
<TableCell colSpan={3} align="center" sx={{borderBottom: '1px solid rgba(224, 224, 224, 1)'}}>Popular</TableCell>
<TableCell colSpan={3} align="center" sx={{borderBottom: '1px solid rgba(224, 224, 224, 1)'}}>Clarín</TableCell>
<TableCell colSpan={3} align="center" sx={{borderBottom: '1px solid rgba(224, 224, 224, 1)'}}>Nación</TableCell>
</TableRow>
<TableRow>
<TableCell align="right">Tir. Coop.</TableCell><TableCell align="right">Dev. Coop.</TableCell>
<TableCell align="right">Vta. Coop.</TableCell><TableCell align="right">Vta. Can.</TableCell>
<TableCell align="right">Tirada</TableCell><TableCell align="right">Devol.</TableCell><TableCell align="right">Venta</TableCell>
<TableCell align="right">Tirada</TableCell><TableCell align="right">Devol.</TableCell><TableCell align="right">Venta</TableCell>
<TableCell align="right">Tirada</TableCell><TableCell align="right">Devol.</TableCell><TableCell align="right">Venta</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map((row, idx) => (
<TableRow key={`tirdevo-${idx}`}>
<TableCell>{row.dia}</TableCell>
<TableCell align="right">{row.tiradaCoop.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.devolucionCoop.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventaCoop.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventaCan.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.tiradaPopular.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.devolucionPopular.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventaPopular.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.tiradaClarin.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.devolucionClarin.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventaClarin.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.tiradaNacion.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.devolucionNacion.toLocaleString('es-AR')}</TableCell>
<TableCell align="right">{row.ventaNacion.toLocaleString('es-AR')}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
return null;
};
if (showParamSelector) {
return (
<Box sx={{ p: 2, display: 'flex', justifyContent: 'center', mt: 2 }}>
<Paper sx={{ width: '100%', maxWidth: 600 }} elevation={3}>
<SeleccionaReporteVentaMensual
onGenerarReporte={handleGenerarReporte}
onCancel={handleVolverAParametros} // Este podría navegar a /reportes
isLoading={loading}
apiErrorMessage={apiErrorParams}
/>
</Paper>
</Box>
);
}
return (
<Box sx={{ p: 2 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2, flexWrap: 'wrap', gap: 1 }}>
<Typography variant="h5">{getReportTitle()}</Typography>
<Box sx={{ display: 'flex', gap: 1 }}>
<Button onClick={handleGenerarYAbrirPdf} variant="contained" disabled={loadingPdf || reportData.length === 0 || !!error} size="small">
{loadingPdf ? <CircularProgress size={20} color="inherit" /> : "Abrir PDF"}
</Button>
<Button onClick={handleExportToExcel} variant="outlined" disabled={reportData.length === 0 || !!error} size="small">
Exportar a Excel
</Button>
<Button onClick={handleVolverAParametros} variant="outlined" color="secondary" size="small">
Nuevos Parámetros
</Button>
</Box>
</Box>
{loading && <Box sx={{ textAlign: 'center' }}><CircularProgress /></Box>}
{error && !loading && <Alert severity="error" sx={{ my: 2 }}>{error}</Alert>}
{!loading && !error && renderTable()}
{!loading && !error && reportData.length === 0 && (<Typography>No se encontraron datos para los criterios seleccionados.</Typography>)}
</Box>
);
};
export default ReporteVentaMensualSecretariaPage;