Final de creación de Módulos de Reportes. Se procede a testeos y ordenamientos...
This commit is contained in:
		| @@ -0,0 +1,209 @@ | ||||
| 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 { TiradasPublicacionesSeccionesDto } from '../../models/dtos/Reportes/TiradasPublicacionesSeccionesDto'; | ||||
| import SeleccionaReporteTiradasPublicacionesSecciones from './SeleccionaReporteTiradasPublicacionesSecciones'; | ||||
| import * as XLSX from 'xlsx'; | ||||
| import axios from 'axios'; | ||||
|  | ||||
| const ReporteTiradasPublicacionesSeccionesPage: React.FC = () => { | ||||
|   const [reportData, setReportData] = useState<TiradasPublicacionesSeccionesDto[]>([]); | ||||
|   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<{ | ||||
|     idPublicacion: number; | ||||
|     fechaDesde: string; | ||||
|     fechaHasta: string; | ||||
|     idPlanta?: number | null; | ||||
|     consolidado: boolean; | ||||
|     nombrePublicacion?: string; | ||||
|     nombrePlanta?: string; | ||||
|     mesAnioParaNombreArchivo?: string; | ||||
|   } | null>(null); | ||||
|  | ||||
|   const handleGenerarReporte = useCallback(async (params: { | ||||
|     idPublicacion: number; | ||||
|     fechaDesde: string; | ||||
|     fechaHasta: string; | ||||
|     idPlanta?: number | null; | ||||
|     consolidado: boolean; | ||||
|   }) => { | ||||
|     setLoading(true); | ||||
|     setError(null); | ||||
|     setApiErrorParams(null); | ||||
|     setReportData([]); | ||||
|  | ||||
|     const pubService = (await import('../../services/Distribucion/publicacionService')).default; | ||||
|     const pubData = await pubService.getPublicacionById(params.idPublicacion); | ||||
|     let plantaNombre = "Consolidado"; | ||||
|     if (!params.consolidado && params.idPlanta) { | ||||
|         const plantaService = (await import('../../services/Impresion/plantaService')).default; | ||||
|         const plantaData = await plantaService.getPlantaById(params.idPlanta); | ||||
|         plantaNombre = plantaData?.nombre ?? "N/A"; | ||||
|     } | ||||
|     const mesAnioParts = params.fechaDesde.split('-'); | ||||
|     const mesAnioNombre = `${mesAnioParts[1]}/${mesAnioParts[0]}`; | ||||
|  | ||||
|     setCurrentParams({...params, nombrePublicacion: pubData?.nombre, nombrePlanta: plantaNombre, mesAnioParaNombreArchivo: mesAnioNombre}); | ||||
|      | ||||
|     try { | ||||
|       const data = await reportesService.getTiradasPublicacionesSecciones(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); | ||||
|   }, []); | ||||
|  | ||||
|   const handleExportToExcel = useCallback(() => { | ||||
|     if (reportData.length === 0) { | ||||
|       alert("No hay datos para exportar."); | ||||
|       return; | ||||
|     } | ||||
|     const dataToExport = reportData.map(item => ({ | ||||
|       "Nombre Sección": item.nombreSeccion, | ||||
|       "Total Páginas Impresas": item.totalPaginasImpresas, | ||||
|       "Cantidad Ediciones": item.cantidadTiradas, | ||||
|       "Total Páginas x Edición": item.totalPaginasEjemplares, | ||||
|       "Total Ejemplares": item.totalEjemplares, | ||||
|       "Prom. Pág./Ejemplar": item.promedioPaginasPorEjemplar, | ||||
|     })); | ||||
|  | ||||
|     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 as any)[h]?.toString().length ?? 0), 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, "TiradasSecciones"); | ||||
|  | ||||
|     let fileName = "ReporteTiradasSecciones"; | ||||
|     if (currentParams) { | ||||
|       fileName += `_${currentParams.nombrePublicacion?.replace(/\s+/g, '') ?? `Pub${currentParams.idPublicacion}`}`; | ||||
|       if (!currentParams.consolidado) fileName += `_Planta${currentParams.idPlanta}`; | ||||
|       else fileName += "_Consolidado"; | ||||
|       fileName += `_${currentParams.mesAnioParaNombreArchivo?.replace('/', '-')}`; | ||||
|     } | ||||
|     fileName += ".xlsx"; | ||||
|     XLSX.writeFile(wb, fileName); | ||||
|   }, [reportData, 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 { | ||||
|       const blob = await reportesService.getTiradasPublicacionesSeccionesPdf(currentParams); | ||||
|       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]); | ||||
|  | ||||
|   if (showParamSelector) { | ||||
|     return ( | ||||
|       <Box sx={{ p: 2, display: 'flex', justifyContent: 'center', mt: 2 }}> | ||||
|         <Paper sx={{ width: '100%', maxWidth: 600 }} elevation={3}> | ||||
|           <SeleccionaReporteTiradasPublicacionesSecciones | ||||
|             onGenerarReporte={handleGenerarReporte} | ||||
|             onCancel={handleVolverAParametros} | ||||
|             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">Reporte: Tiradas por Publicación y Secciones</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 && reportData.length > 0 && ( | ||||
|         <TableContainer component={Paper} sx={{ maxHeight: 'calc(100vh - 240px)' }}> | ||||
|           <Table stickyHeader size="small"> | ||||
|             <TableHead> | ||||
|               <TableRow> | ||||
|                 <TableCell>Nombre Sección</TableCell> | ||||
|                 <TableCell align="right">Total Páginas Imp.</TableCell> | ||||
|                 <TableCell align="right">Cant. Ediciones</TableCell> | ||||
|                 <TableCell align="right">Total Pág. x Edición</TableCell> | ||||
|                 <TableCell align="right">Total Ejemplares</TableCell> | ||||
|                 <TableCell align="right">Prom. Pág./Ejemplar</TableCell> | ||||
|               </TableRow> | ||||
|             </TableHead> | ||||
|             <TableBody> | ||||
|               {reportData.map((row, idx) => ( | ||||
|                 <TableRow key={`${row.nombreSeccion}-${idx}`}> | ||||
|                   <TableCell>{row.nombreSeccion}</TableCell> | ||||
|                   <TableCell align="right">{row.totalPaginasImpresas.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.cantidadTiradas.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.totalPaginasEjemplares.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.totalEjemplares.toLocaleString('es-AR')}</TableCell> | ||||
|                   <TableCell align="right">{row.promedioPaginasPorEjemplar.toLocaleString('es-AR')}</TableCell> | ||||
|                 </TableRow> | ||||
|               ))} | ||||
|             </TableBody> | ||||
|           </Table> | ||||
|         </TableContainer> | ||||
|       )} | ||||
|       {!loading && !error && reportData.length === 0 && (<Typography>No se encontraron datos para los criterios seleccionados.</Typography>)} | ||||
|     </Box> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| export default ReporteTiradasPublicacionesSeccionesPage; | ||||
		Reference in New Issue
	
	Block a user