From a4d10da48b8b3d773a08c289bfa2552534fd4dab Mon Sep 17 00:00:00 2001 From: Elliot Axel Noriega Date: Fri, 1 Nov 2024 15:11:42 -0600 Subject: [PATCH 1/2] Funcionalidad de reportes --- cosiap_api/dynamic_tables/urls.py | 3 +- cosiap_api/dynamic_tables/views.py | 2 +- cosiap_api/solicitudes/urls.py | 4 - cosiap_frontend/src/api.js | 8 +- .../SolicitudesAdmin/MenuColumnas.jsx | 8 +- .../SolicitudesAdmin/MenuReportes.jsx | 54 +++ .../SolicitudesAdmin/Solicitudes.jsx | 388 ++++++++++++++++-- 7 files changed, 427 insertions(+), 40 deletions(-) diff --git a/cosiap_api/dynamic_tables/urls.py b/cosiap_api/dynamic_tables/urls.py index ff997cc..196d335 100644 --- a/cosiap_api/dynamic_tables/urls.py +++ b/cosiap_api/dynamic_tables/urls.py @@ -1,8 +1,9 @@ from django.urls import path -from .views import ReporteAPIView +from .views import ReporteAPIView, Exportar_CSV app_name = 'dynamic-tables' urlpatterns = [ path('', ReporteAPIView.as_view(), name='reportes'), path('/', ReporteAPIView.as_view(), name='reportes_pk'), + path('exportar//', Exportar_CSV.as_view(), name='exportar_pk'), ] \ No newline at end of file diff --git a/cosiap_api/dynamic_tables/views.py b/cosiap_api/dynamic_tables/views.py index 0186b54..4b33266 100644 --- a/cosiap_api/dynamic_tables/views.py +++ b/cosiap_api/dynamic_tables/views.py @@ -397,7 +397,7 @@ class Exportar_CSV(BasePermissionAPIView): print(configuracion.filters) print(configuracion.model_name) print(configuracion.columns) - reporte = DynamicTableDynamicForm(instance=configuracion, model_class=self.model_class) + reporte = DynamicTableDynamicForm(instance=configuracion, model_class='Solicitud') data = reporte.get_data(configuracion) print(data) response = reporte.export_to_csv_and_zip(data) diff --git a/cosiap_api/solicitudes/urls.py b/cosiap_api/solicitudes/urls.py index 308d00f..1e07f71 100644 --- a/cosiap_api/solicitudes/urls.py +++ b/cosiap_api/solicitudes/urls.py @@ -11,10 +11,6 @@ urlpatterns = [ path('solicitar//', views.SolicitarAPIView.as_view(), name='ver_editar_solicitud'), # se envía el pk de la solicitud a ver o a editar. path('historial/', views.HistorialAPIVIew.as_view(), name='historial'), path('historial//', views.HistorialAPIVIew.as_view(), name='historial_pk'), - path('reportes/', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes'), - path('reportes//', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes_pk'), - path('reportes/exportar/', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes'), - path('reportes/exportar//', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes_pk'), path('calificar//', views.CalificarDocumento.as_view(), name='calificar_documentos'), path('subir-convenio//', views.SubirConvenio.as_view(), name='subir_convenio_pk'), path('subir-convenio/', views.SubirConvenio.as_view(), name='subir_convenio'), diff --git a/cosiap_frontend/src/api.js b/cosiap_frontend/src/api.js index c357def..4dc8d67 100644 --- a/cosiap_frontend/src/api.js +++ b/cosiap_frontend/src/api.js @@ -128,10 +128,6 @@ const api = { update: (id,data) => ax.put(`api/solicitudes/subir-convenio/${id}/`, data), get: () => ax.get('api/solicitudes/subir-convenio/') }, - reportes: { - get: () => ax.get('api/solicitudes/reportes'), - getById: (id) => ax.get(`api/solicitudes/reportes/${id}`), - }, solicitar:{ post: (data) => ax.post('api/solicitudes/solicitar/', data), update: (id,data) => ax.put(`api/solicitudes/solicitar/${id}/`, data) @@ -141,7 +137,9 @@ const api = { get: () => ax.get('api/dynamic-tables'), post: (data) => ax.post('api/dynamic-tables/', data), getById: (id) => ax.get(`api/dynamic-tables/${id}`), - update: (id, data) => ax.put(`api/dynamic-tables/${id}`, data), + update: (id, data) => ax.put(`api/dynamic-tables/${id}/`, data), + delete: (id) => ax.delete(`api/dynamic-tables/${id}`), + exportar: (id, params) => ax.get(`api/dynamic-tables/exportar/${id}`, params) }, dynamicForms: { opciones: { diff --git a/cosiap_frontend/src/components/SolicitudesAdmin/MenuColumnas.jsx b/cosiap_frontend/src/components/SolicitudesAdmin/MenuColumnas.jsx index 5bfb386..e148010 100644 --- a/cosiap_frontend/src/components/SolicitudesAdmin/MenuColumnas.jsx +++ b/cosiap_frontend/src/components/SolicitudesAdmin/MenuColumnas.jsx @@ -27,22 +27,22 @@ export default function MenuColumnas( {columnas, columnasOcultas, setColumnasOcu
{Object.entries(columnas).map(([key, value], index) => ( diff --git a/cosiap_frontend/src/components/SolicitudesAdmin/MenuReportes.jsx b/cosiap_frontend/src/components/SolicitudesAdmin/MenuReportes.jsx index e69de29..6981037 100644 --- a/cosiap_frontend/src/components/SolicitudesAdmin/MenuReportes.jsx +++ b/cosiap_frontend/src/components/SolicitudesAdmin/MenuReportes.jsx @@ -0,0 +1,54 @@ + +export default function MenuReportes( {reportes, reporteAplicado, enableSectionReportes, setEnableSectionReportes, setReporteAplicado, menuRef, setViewMenu} ){ + const handleActionCreateReport = () => { + setViewMenu(false); //Ocultamo este menu + setEnableSectionReportes(true); //Mostramos la sección de reportes + setReporteAplicado(null) + }; + + return ( + <> +
+
+
+
+ {reportes.length === 0 ? ( + + No hay reportes registrados. Crea uno nuevo. + + + ) : ( + reportes.map((reporte, key) => ( +
{setReporteAplicado(reporte), setViewMenu(false)}} + > + + settings + + + {reporte.nombre} + +
+ )) + )} +
+
+
+ + add + + + Nuevo Reporte + + +
+
+
+ + ); +} \ No newline at end of file diff --git a/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx b/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx index ab9022f..81227cf 100644 --- a/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx +++ b/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx @@ -6,6 +6,8 @@ import MenuColumnas from "./MenuColumnas"; import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; import MenuFiltros from "./MenuFiltros"; import Alert from "../common/ui/Alert"; +import MenuReportes from "./MenuReportes"; +import ModalConfirmation from "../common/ui/Modals/ModalConfirmation"; export default function Solicitudes( {setViewPageLoader} ){ const [solicitudes, setSolicitudes] = useState([]); @@ -14,6 +16,8 @@ export default function Solicitudes( {setViewPageLoader} ){ const [filtros, setFiltros] = useState([]); const [solicitudesOriginales, setSolicitudesOriginales] = useState([]); const [filtrosAplicados, setFiltrosAplicados] = useState([]); + const [reportes, setReportes] = useState([]); + const [reporteAplicado, setReporteAplicado] = useState(null); const [searchTerm, setSearchTerm] = useState(''); //Estados para la edición de campos @@ -28,16 +32,22 @@ export default function Solicitudes( {setViewPageLoader} ){ //Estados para alertas const [showAlertSuccesful, setShowAlertSuccesful] = useState(false); const [showAlertError, setShowAlertError] = useState(false); + //Variable para el mensaje de la alerta + const [alertMessage, setAlertMessage] = useState(''); //Vistas de columnas y filtros const [viewMenuColumnas, setViewMenuColumnas] = useState(false) const [viewMenuFiltros, setViewMenuFiltros] = useState(false) + const [viewMenuReportes, setViewMenuReportes] = useState(false); + const [enableSectionReportes, setEnableSectionReportes] = useState(false); //Ref para ventanas y botones de los filtros y columnas const menuColumnasRef = useRef(null); const buttonMenuColumnasRef = useRef(null); const menuFiltrosRef = useRef(null); const buttonMenuFiltrosRef = useRef(null); + const menuReportesRef = useRef(null); + const buttonMenuReportesRef = useRef(null); const [sortConfig, setSortConfig] = useState({ key: null, direction: 'ascending' }); @@ -74,18 +84,7 @@ export default function Solicitudes( {setViewPageLoader} ){ // Función para manejar la búsqueda const handleSearch = (event) => { - const searchTerm = event.target.value.toLowerCase(); // Convertimos a minúsculas para hacer la búsqueda insensible a mayúsculas - setSearchTerm(searchTerm); - - // Filtramos las solicitudes originales según el término de búsqueda - const filteredSolicitudes = solicitudesOriginales.filter(solicitud => { - // Buscamos en todas las columnas. - return Object.values(solicitud).some(value => - value?.toString().toLowerCase().includes(searchTerm) - ); - }); - - setSolicitudes(filteredSolicitudes); + setSearchTerm(event.target.value); }; @@ -100,11 +99,25 @@ export default function Solicitudes( {setViewPageLoader} ){ setSolicitudesOriginales(response.data.data); setColumnas(response.data.available_columns); setFiltros(response.data.available_filters); - console.log('Columnas', response.data.available_columns) - console.log('Filtros', response.data.available_filters) - console.log('Solicitudes', response.data.data) + // console.log('Columnas', response.data.available_columns) + // console.log('Filtros', response.data.available_filters) + // console.log('Solicitudes', response.data.data) } catch (error) { - console.log('Extraccion de solicitudes fallida', error) + console.error('Extraccion de solicitudes fallida', error) + }finally{ + setViewPageLoader(false) + } + }; + + const obtenerReportes = async () => { + try { + setViewPageLoader(true) + //Obtenemos los reportes + const response = await api.dynamicTables.get(); + console.log('Extraccion de reportes exitosa', response) + setReportes(response.data); + } catch (error) { + console.error('Extraccion de reportes fallida', error) }finally{ setViewPageLoader(false) } @@ -123,6 +136,11 @@ export default function Solicitudes( {setViewPageLoader} ){ buttonMenuFiltrosRef.current && !buttonMenuFiltrosRef.current.contains(event.target)){ setViewMenuFiltros(false); } + // Cierra el menú de los reportes si se hace clic fuera de él y de su botón de toggle + if (menuReportesRef.current && !menuReportesRef.current.contains(event.target) && + buttonMenuReportesRef.current && !buttonMenuReportesRef.current.contains(event.target)){ + setViewMenuReportes(false); + } } // Añade el event listener para detectar clics fuera de los elementos @@ -134,9 +152,10 @@ export default function Solicitudes( {setViewPageLoader} ){ }; }, []); - //Cada renderizacion del componente, se obtendran las solicitudes + //Cada renderizacion del componente, se obtendran las solicitudes y los reportes useEffect(() => { obtenerSolicitudes() + obtenerReportes() }, []) const sortSolicitudes = (key) => { @@ -279,7 +298,7 @@ export default function Solicitudes( {setViewPageLoader} ){ } - //Funcion para filtrar las solicitudes en base a los filtros + //Funcion para filtrar las solicitudes en base a los filtros y la cadena de busqueda const filtrarSolicitudes = () => { // Clonamos las solicitudes originales para no mutarlas let solicitudesFiltradas = [...solicitudesOriginales]; @@ -338,6 +357,14 @@ export default function Solicitudes( {setViewPageLoader} ){ } } }); + // Aplicamos el término de búsqueda a todos los campos de cada solicitud + if (searchTerm !== '') { + solicitudesFiltradas = solicitudesFiltradas.filter(solicitud => { + return Object.values(solicitud).some(value => + value?.toString().toLowerCase().includes(searchTerm.toLowerCase()) + ); + }); + } setSolicitudes(solicitudesFiltradas); // Actualizamos las solicitudes filtradas setFiltrosAplicados(nuevosFiltrosAplicados); // Actualizamos los filtros aplicados @@ -451,7 +478,7 @@ export default function Solicitudes( {setViewPageLoader} ){ //Añadi que tambien dependiera de las solicitudes originales para que se actualice de inmediato cuando se edita un campo y hay filtros aplicados useEffect(() => { filtrarSolicitudes() - }, [solicitudesOriginales,filtros]) + }, [solicitudesOriginales, searchTerm,filtros]) // Evento de teclado para guardar cambios al presionar Enter const handleKeyDown = (e) => { @@ -484,6 +511,7 @@ export default function Solicitudes( {setViewPageLoader} ){ //Filtramos las solicitudes si es que hay filtros aplicados filtrarSolicitudes() + setAlertMessage('¡Los cambios han sido guardados de manera correcta!'); //Mostramos alerta de exito setShowAlertSuccesful(true); @@ -491,6 +519,8 @@ export default function Solicitudes( {setViewPageLoader} ){ setEditingField(null); setEditingValue(""); } catch (error) { + console.error('Error al guardar cambios', error); + setAlertMessage('¡Ha ocurrido un error al guardar los cambios! Vuelve a intentarlo'); setShowAlertError(true); } finally { setViewPageLoader(false); @@ -520,11 +550,183 @@ export default function Solicitudes( {setViewPageLoader} ){ ); }; + //Variable para crear un reporte + const handleCrearReporte = async (nombre) => { + try { + setViewPageLoader(true) + //formamos el data con los filtros, nombre, columnas etc + const data = { + nombre: nombre, + model_name: 'Solicitud', + columns: columnas, + exclude_columns: columnasOcultas, + search_query: searchTerm, + filters: filtros, + } + + //enviamos el data a la api para la creacion del reporte + const response = await api.dynamicTables.post(data); + console.log('Creación de reporte exitosa ', response) + //Cerramos la seccion de reporter + setEnableSectionReportes(false); + //Obtenemos de nuevo los reportes + obtenerReportes() + setAlertMessage('¡Creación de reporte exitosa!'); + setShowAlertSuccesful(true) + } catch (error) { + console.error(error) + //Definimos el mensaje de la alerta + setAlertMessage('¡Ha ocurrido un error inesperado! Vuelve a intentarlo'); + setShowAlertError(true) + }finally{ + setViewPageLoader(false); + } + }; + + //Variable para crear un reporte + const handleActualizarReporte = async (id, nombre) => { + try { + setViewPageLoader(true) + //formamos el data con los filtros, nombre, columnas etc + const data = { + nombre: nombre, + model_name: 'Solicitud', + columns: columnas, + exclude_columns: columnasOcultas, + search_query: searchTerm, + filters: filtros, + } + + //enviamos el data a la api para la actualización del reporte + const response = await api.dynamicTables.update(id, data); + console.log('Actualización de reporte exitosa ', response) + //Cerramos la seccion de reporter + setEnableSectionReportes(false); + //Obtenemos de nuevo los reportes + obtenerReportes() + //Definimos el mensaje de la alerta + setAlertMessage('Actualización de reporte exitosa!'); + setShowAlertSuccesful(true) + } catch (error) { + console.error(error) + //Definimos el mensaje de la alerta + setAlertMessage('¡Ha ocurrido un error inesperado! Vuelve a intentarlo'); + setShowAlertError(true) + }finally{ + setViewPageLoader(false); + } + }; + + //Variable para crear un reporte + const handleBorrarReporte = async (id) => { + try { + setViewPageLoader(true) + //hacemos la petición a la api para la eliminación del reporte + const response = await api.dynamicTables.delete(id); + console.log('Eliminación de reporte exitosa ', response) + //Cerramos la seccion de reporter + setEnableSectionReportes(false); + //Obtenemos de nuevo los reportes + obtenerReportes() + //Definimos el mensaje de la alerta + setAlertMessage('¡Eliminacion de reporte exitosa!'); + setShowAlertSuccesful(true) + } catch (error) { + console.error(error) + //Definimos el mensaje de la alerta + setAlertMessage('¡Ha ocurrido un error inesperado! Vuelve a intentarlo'); + setShowAlertError(true) + }finally{ + setViewPageLoader(false); + } + }; + + // Función para descargar y guardar el archivo ZIP + const downloadZipReport = (response) => { + try { + // Extraer el tipo de contenido desde los headers + const contentType = response.headers['content-type']; + console.log('Content Type:', contentType); + + // Asegúrate de que response.data sea un ArrayBuffer + console.log('Tamaño de datos:', response.data.byteLength); // Verifica el tamaño de los datos + + // Crear un Blob con el tipo de contenido de la respuesta y convertir `response.data` + const blob = new Blob([response.data], { type: contentType }); + + // Crear una URL para el Blob y enlazarla para descarga + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'reporte.zip'); // Nombre del archivo descargado + + // Agregar el enlace al DOM, hacer clic y luego eliminarlo + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + // Revocar la URL para liberar memoria + window.URL.revokeObjectURL(url); + + console.log("Archivo descargado con éxito."); + } catch (error) { + console.error("Error al descargar el archivo:", error); + } + }; + + // Función para exportar un reporte específico + const handleExportarReporte = async (id) => { + try { + setViewPageLoader(true); + + // Llamada a la API para exportar el reporte + const response = await api.dynamicTables.exportar(id, { + responseType: 'blob', // Asegura recibir datos binarios + }); + + console.log('Exportación de reporte exitosa', response); + + // Llama a la función de descarga del ZIP + downloadZipReport(response); + + // Actualiza el estado de la UI + setEnableSectionReportes(false); + obtenerReportes(); + setAlertMessage('Exportación de reporte exitosa!'); + setShowAlertSuccesful(true); + + } catch (error) { + console.error("Error al exportar el reporte:", error); + setAlertMessage('¡Ha ocurrido un error inesperado! Vuelve a intentarlo'); + setShowAlertError(true); + + } finally { + setViewPageLoader(false); + } + }; + + useEffect((() => { + if(reporteAplicado !== null){//Comprobamos que si se seteo un reporte + //Establecemos las columnas del reporte + setColumnas(reporteAplicado.columns); + //Las excluidas + setColumnasOcultas(reporteAplicado.exclude_columns); + //Los filtros + setFiltros(reporteAplicado.filters); + //Aplicamos los filtros + filtrarSolicitudes(); + //Establecemos la cadena de busqueda + setSearchTerm(reporteAplicado.search_query); + //Habilitamos la seccion de reportes + setEnableSectionReportes(true); + } + }),[reporteAplicado]) + return ( <> {showAlertSuccesful && ( )} + + {viewMenuReportes && ( + + )}
@@ -561,15 +767,16 @@ export default function Solicitudes( {setViewPageLoader} ){ placeholder="Search" className="relative z-0 border-0 px-3 py-2 font-semibold placeholder-gray-600 bg-white rounded-full text-base shadow-lg focus:ring-2 focus:ring-[var(--principal-f)] w-full pl-10" onChange={handleSearch} + value={searchTerm} />
-
-
- -
+ {enableSectionReportes && ( + + )}
@@ -745,4 +952,135 @@ const ShowFilters = ({filtrosAplicados, setFiltrosAplicados, deleteFilter}) => { )} ); +} + +function SectionReportes( {reporteAplicado, setReporteAplicado, enableSection, setEnableSection, handleCrearReporte, handleActualizarReporte, handleBorrarReporte, handleExportarReporte} ){ + const [name, setName] = useState(""); + const [showModal, setShowModal] = useState(false); + + useEffect((() => { + setName(reporteAplicado ? reporteAplicado.nombre : ""); + }),[reporteAplicado]) + + const handleNameChange = (e) => { + setName(e.target.value); + }; + + const handleCreate = () => { + if (name===""){ + alert("Debes ingresar un nombre para el reporte"); + }else{ + handleCrearReporte(name); + } + }; + + const handleCancel = () => { + setReporteAplicado(null) + setEnableSection(false); + }; + + const handleDelete = () => { + handleBorrarReporte(reporteAplicado.id); + setEnableSection(false); + setReporteAplicado(null) + }; + + // Si se ha declarado un reporte aplicado, significa que se selecciono un reporte de reportes existente + // Si no se ha declarado un reporte aplicado, significa que se selecciono la creación de uno nuevo + return ( + <> + {showModal && ( + + + + + + )} +
+
+ + {reporteAplicado === null ? "Crear reporte" : "Modificar reporte"} + +
+
+ + close + +
+
+
+
+ +
+
+ {reporteAplicado === null ? ( + <> +
+ + save + + + Guardar + +
+ + ) : ( + <> +
handleActualizarReporte(reporteAplicado.id, name)} + > + + system_update_alt + + + Actualizar + +
+
setShowModal(true)} + > + + delete + +
+
+
+ + ); } \ No newline at end of file -- GitLab From 429056e7e9154bbd8f4cd4b94a0570ddc8c5fab9 Mon Sep 17 00:00:00 2001 From: Elliot Axel Noriega Date: Fri, 1 Nov 2024 16:12:27 -0600 Subject: [PATCH 2/2] Reportes --- cosiap_api/dynamic_tables/urls.py | 2 +- cosiap_api/dynamic_tables/views.py | 3 ++- cosiap_api/solicitudes/urls.py | 4 ++++ cosiap_api/temp_export/reporte.csv | 3 +++ cosiap_frontend/src/api.js | 4 +++- .../src/components/SolicitudesAdmin/Solicitudes.jsx | 5 ++++- 6 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 cosiap_api/temp_export/reporte.csv diff --git a/cosiap_api/dynamic_tables/urls.py b/cosiap_api/dynamic_tables/urls.py index 196d335..821c286 100644 --- a/cosiap_api/dynamic_tables/urls.py +++ b/cosiap_api/dynamic_tables/urls.py @@ -5,5 +5,5 @@ app_name = 'dynamic-tables' urlpatterns = [ path('', ReporteAPIView.as_view(), name='reportes'), path('/', ReporteAPIView.as_view(), name='reportes_pk'), - path('exportar//', Exportar_CSV.as_view(), name='exportar_pk'), + path('exportar/', Exportar_CSV.as_view(), name='exportar_pk'), ] \ No newline at end of file diff --git a/cosiap_api/dynamic_tables/views.py b/cosiap_api/dynamic_tables/views.py index 4b33266..2dbd55a 100644 --- a/cosiap_api/dynamic_tables/views.py +++ b/cosiap_api/dynamic_tables/views.py @@ -397,7 +397,8 @@ class Exportar_CSV(BasePermissionAPIView): print(configuracion.filters) print(configuracion.model_name) print(configuracion.columns) - reporte = DynamicTableDynamicForm(instance=configuracion, model_class='Solicitud') + reporte = DynamicTableDynamicForm(instance=configuracion, model_class=self.model_class) + print('Reporte', reporte) data = reporte.get_data(configuracion) print(data) response = reporte.export_to_csv_and_zip(data) diff --git a/cosiap_api/solicitudes/urls.py b/cosiap_api/solicitudes/urls.py index 1e07f71..308d00f 100644 --- a/cosiap_api/solicitudes/urls.py +++ b/cosiap_api/solicitudes/urls.py @@ -11,6 +11,10 @@ urlpatterns = [ path('solicitar//', views.SolicitarAPIView.as_view(), name='ver_editar_solicitud'), # se envía el pk de la solicitud a ver o a editar. path('historial/', views.HistorialAPIVIew.as_view(), name='historial'), path('historial//', views.HistorialAPIVIew.as_view(), name='historial_pk'), + path('reportes/', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes'), + path('reportes//', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes_pk'), + path('reportes/exportar/', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes'), + path('reportes/exportar//', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes_pk'), path('calificar//', views.CalificarDocumento.as_view(), name='calificar_documentos'), path('subir-convenio//', views.SubirConvenio.as_view(), name='subir_convenio_pk'), path('subir-convenio/', views.SubirConvenio.as_view(), name='subir_convenio'), diff --git a/cosiap_api/temp_export/reporte.csv b/cosiap_api/temp_export/reporte.csv new file mode 100644 index 0000000..f3941de --- /dev/null +++ b/cosiap_api/temp_export/reporte.csv @@ -0,0 +1,3 @@ +status,monto_solicitado,monto_aprobado,solicitante__nombre,solicitante__curp,solicitante__email +Aprobado,10000.0,8000.0,Elliot,NOXE020729HNERXLA3,elliotnoriega@gmail.com +Pendiente,10000.0,9000.0,Elliot,NOXE020729HNERXLA3,elliotnoriega@gmail.com diff --git a/cosiap_frontend/src/api.js b/cosiap_frontend/src/api.js index 4dc8d67..3d170c3 100644 --- a/cosiap_frontend/src/api.js +++ b/cosiap_frontend/src/api.js @@ -131,6 +131,9 @@ const api = { solicitar:{ post: (data) => ax.post('api/solicitudes/solicitar/', data), update: (id,data) => ax.put(`api/solicitudes/solicitar/${id}/`, data) + }, + reportes:{ + exportar: (params) => ax.get(`api/solicitudes/reportes/exportar`, params) } }, dynamicTables: { @@ -139,7 +142,6 @@ const api = { getById: (id) => ax.get(`api/dynamic-tables/${id}`), update: (id, data) => ax.put(`api/dynamic-tables/${id}/`, data), delete: (id) => ax.delete(`api/dynamic-tables/${id}`), - exportar: (id, params) => ax.get(`api/dynamic-tables/exportar/${id}`, params) }, dynamicForms: { opciones: { diff --git a/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx b/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx index 81227cf..454570f 100644 --- a/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx +++ b/cosiap_frontend/src/components/SolicitudesAdmin/Solicitudes.jsx @@ -680,8 +680,11 @@ export default function Solicitudes( {setViewPageLoader} ){ setViewPageLoader(true); // Llamada a la API para exportar el reporte - const response = await api.dynamicTables.exportar(id, { + const response = await api.solicitudes.reportes.exportar({ responseType: 'blob', // Asegura recibir datos binarios + params: { + reporte_id: id // Aquí se pasan los parámetros de la API + }, }); console.log('Exportación de reporte exitosa', response); -- GitLab