From 972749cee2fac2c8b06aa710c740de17c8f764c1 Mon Sep 17 00:00:00 2001 From: Pablinux Date: Sun, 28 Sep 2025 15:02:50 -0500 Subject: [PATCH] inicializacion del proyecto. --- README.md | 10 +- src/app.js | 4 + .../controlador_sincronizacion_docs.js | 106 ++++++++++++++++++ .../APP_SIGMA_NODE.postman_collection.json | 96 ++++++++++++++++ src/rutas/rt_apps.js | 72 ++++++++++++ src/rutas/rt_proyectos.js | 4 +- 6 files changed, 284 insertions(+), 8 deletions(-) create mode 100644 src/controladores/controlador_sincronizacion_docs.js diff --git a/README.md b/README.md index 034c72a..a6280d9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ### Modulos Requeridos para el funcionamiento ejs -mysql : se cambiara a mysql2 +mysql2 express-myconnection express express-session: necesario para controlar las ssiones @@ -16,18 +16,16 @@ nodemon express-fileupload cors jsonwebtoken - -npm install mysql2 - - +uuid ### recomendaciones previas npm install -s //-s para guardar los datos ### instalacion de modulos +Se recomienda usar `mysql2` en lugar de `mysql` por su soporte a Promises y mejor rendimiento. ```bash -npm install -s mysql express-myconnection express morgan telegraf nodemon ejs express-fileupload axios jsonwebtoken +npm install -s mysql2 express-myconnection express morgan telegraf nodemon ejs express-fileupload axios jsonwebtoken cors express-session uuid ``` ### Modulo control de origenes diff --git a/src/app.js b/src/app.js index 6fe8605..1f3f673 100644 --- a/src/app.js +++ b/src/app.js @@ -47,6 +47,10 @@ app.use(session({ resave: false,//no se guarde cada vez que se hace un cambio saveUninitialized: true,//guardar sesion aunque no haya datos cookie: { secure: global.config.sessionStorage.cookie }//true solo se envia por https + // FIX: La cookie de sesión debe ser segura en producción. + // Se establece dinámicamente en 'true' si el entorno es 'production'. + // Esto requiere que la app en producción se sirva sobre HTTPS. + //cookie: { secure: process.env.NODE_ENV === 'production' } })); //middlewares diff --git a/src/controladores/controlador_sincronizacion_docs.js b/src/controladores/controlador_sincronizacion_docs.js new file mode 100644 index 0000000..3159dcd --- /dev/null +++ b/src/controladores/controlador_sincronizacion_docs.js @@ -0,0 +1,106 @@ +// src/controladores/controlador_sincronizacion_docs.js +const mysql = require('mysql2/promise'); // Usamos la versión con promesas para async/await + +const controlador = {}; + +// Pool de conexión específico para la base de datos 'webControl' +const poolWebControl = mysql.createPool({ + host: process.env.DB_WEBCTRL_HOST || '192.168.10.150', // Asumiendo variables de entorno + user: process.env.DB_WEBCTRL_USER || 'admin', + password: process.env.DB_WEBCTRL_PASSWORD || 'Dx.1706%', + database: process.env.DB_WEBCTRL_NAME || 'webControl', // Nombre de la BD + waitForConnections: true, + connectionLimit: 10, + queueLimit: 0 +}); + +/** + * @description Crea un nuevo registro de documento electrónico. + * Espera los datos del documento en el cuerpo de la solicitud. + */ +controlador.crearDocumento = async (req, res) => { + const { + tipo_documento, + entidad_emisora, + entidad_receptora, + numero_autorizacion, + fecha_registrada + } = req.body; + + if (!tipo_documento || !entidad_emisora || !entidad_receptora || !numero_autorizacion || !fecha_registrada) { + return res.status(400).json({ error: 'Todos los campos son obligatorios: tipo_documento, entidad_emisora, entidad_receptora, numero_autorizacion, fecha_registrada.' }); + } + + try { + const sql = 'INSERT INTO ia_sincronizacion_documentos_electronicos SET ?'; + const nuevoDocumento = { + tipo_documento, + entidad_emisora, + entidad_receptora, + numero_autorizacion, + fecha_registrada, + estado_sincronizacion: 'pendiente' // Por defecto al crear + }; + + const [result] = await poolWebControl.query(sql, nuevoDocumento); + res.status(201).json({ message: 'Documento registrado para sincronización.', id: result.insertId }); + + } catch (error) { + console.error("Error al insertar el documento:", error); + if (error.code === 'ER_DUP_ENTRY') { + return res.status(409).json({ error: `El documento con autorización '${numero_autorizacion}' ya existe.` }); + } + return res.status(500).json({ error: 'Error al guardar el registro del documento.' }); + } +}; + +/** + * @description Obtiene una lista de documentos, con opción de filtrar por estado. + */ +controlador.listarDocumentos = async (req, res) => { + const { estado } = req.query; // Filtrar por ej: /api/documentos-electronicos?estado=pendiente + + try { + let sql = 'SELECT * FROM ia_sincronizacion_documentos_electronicos'; + const params = []; + + if (estado) { + sql += ' WHERE estado_sincronizacion = ?'; + params.push(estado); + } + sql += ' ORDER BY fecha_registrada DESC'; + + const [rows] = await poolWebControl.query(sql, params); + res.status(200).json(rows); + } catch (error) { + console.error("Error al consultar documentos:", error); + return res.status(500).json({ error: 'Error al obtener los documentos.' }); + } +}; + +/** + * @description Actualiza el estado de un documento electrónico por su ID. + */ +controlador.actualizarEstadoDocumento = async (req, res) => { + const { id } = req.params; + const { estado_sincronizacion } = req.body; + + if (!estado_sincronizacion || !['pendiente', 'procesado', 'error'].includes(estado_sincronizacion)) { + return res.status(400).json({ error: "El campo 'estado_sincronizacion' es obligatorio y debe ser 'pendiente', 'procesado' o 'error'." }); + } + + try { + const sql = 'UPDATE ia_sincronizacion_documentos_electronicos SET estado_sincronizacion = ? WHERE id = ?'; + const [result] = await poolWebControl.query(sql, [estado_sincronizacion, id]); + + if (result.affectedRows === 0) { + return res.status(404).json({ error: `No se encontró ningún documento con el ID ${id}.` }); + } + res.status(200).json({ message: 'Estado del documento actualizado correctamente.' }); + } catch (error) { + console.error("Error al actualizar el estado:", error); + return res.status(500).json({ error: 'Error al actualizar el estado del documento.' }); + } +}; + +module.exports = controlador; \ No newline at end of file diff --git a/src/data/APP_SIGMA_NODE.postman_collection.json b/src/data/APP_SIGMA_NODE.postman_collection.json index f29067c..dffb0a1 100644 --- a/src/data/APP_SIGMA_NODE.postman_collection.json +++ b/src/data/APP_SIGMA_NODE.postman_collection.json @@ -148,6 +148,102 @@ } }, "response": [] + }, + { + "name": "Sincronización Documentos Electrónicos", + "item": [ + { + "name": "Crear Documento", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"tipo_documento\": \"01\",\n \"entidad_emisora\": \"0992222222001\",\n \"entidad_receptora\": \"0701637498001\",\n \"numero_autorizacion\": \"1234567890123456789012345678901234567890123456789\",\n \"fecha_registrada\": \"2023-11-15T14:30:00Z\"\n}" + }, + "url": { + "raw": "http://localhost:3001/api/documentos-electronicos", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "3001", + "path": [ + "api", + "documentos-electronicos" + ] + }, + "description": "Registra un nuevo documento electrónico para ser procesado por el sistema. Ideal para ser llamado desde n8n." + }, + "response": [] + }, + { + "name": "Listar Documentos", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:3001/api/documentos-electronicos?estado=pendiente", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "3001", + "path": [ + "api", + "documentos-electronicos" + ], + "query": [ + { + "key": "estado", + "value": "pendiente", + "description": "Filtra por 'pendiente', 'procesado' o 'error'. Omitir para ver todos." + } + ] + }, + "description": "Obtiene una lista de todos los documentos electrónicos, con la opción de filtrar por su estado de sincronización." + }, + "response": [] + }, + { + "name": "Actualizar Estado de Documento", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"estado_sincronizacion\": \"procesado\"\n}" + }, + "url": { + "raw": "http://localhost:3001/api/documentos-electronicos/1/estado", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "3001", + "path": [ + "api", + "documentos-electronicos", + "1", + "estado" + ] + }, + "description": "Actualiza el estado de un documento específico por su ID. El estado puede ser 'procesado' o 'error'." + }, + "response": [] + } + ], + "description": "Endpoints para la gestión de documentos electrónicos sincronizados desde n8n." } ] } \ No newline at end of file diff --git a/src/rutas/rt_apps.js b/src/rutas/rt_apps.js index f707c60..cbd4c31 100644 --- a/src/rutas/rt_apps.js +++ b/src/rutas/rt_apps.js @@ -3,6 +3,7 @@ const rutas = express.Router(); const controlador_init = require('../controladores/controlador_Apps'); const controlador_videos = require('../controladores/controlador_videos'); // Controlador para videos +const controlador_sinc_docs = require('../controladores/controlador_sincronizacion_docs'); // NUEVO: Controlador para documentos electrónicos rutas.get('/app_restaurant', controlador_init.app_restaurant);//login testing css / dev //rutas.get('/usuarios', controlador_init.user);// @@ -24,4 +25,75 @@ rutas.get('/videos', controlador_videos.videos_v2);//videos sigma server rutas.get('/videos_upload', controlador_videos.upload_v2);//videos sigma server (version nueva) rutas.post('/videos_upload', controlador_videos.uploadVideo); // Nueva ruta para manejar la subida +// --- API para Sincronización de Documentos Electrónicos (desde n8n) --- + +/** + * @swagger + * /api/documentos-electronicos: + * post: + * summary: Registra un nuevo documento electrónico para ser procesado. + * tags: [Sincronización Documentos] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: [tipo_documento, entidad_emisora, entidad_receptora, numero_autorizacion, fecha_registrada] + * properties: + * tipo_documento: { type: string, example: "01" } + * entidad_emisora: { type: string, example: "RUC_EMISOR" } + * entidad_receptora: { type: string, example: "RUC_RECEPTOR" } + * numero_autorizacion: { type: string, example: "1234567890123456789012345678901234567890123456789" } + * fecha_registrada: { type: string, format: date-time, example: "2023-10-27T10:00:00Z" } + * responses: + * 201: { description: Documento registrado exitosamente. } + * 400: { description: Datos de entrada inválidos. } + * 409: { description: El documento ya existe (conflicto). } + * 500: { description: Error del servidor. } + * get: + * summary: Lista todos los documentos electrónicos registrados. + * tags: [Sincronización Documentos] + * parameters: + * - in: query + * name: estado + * schema: + * type: string + * enum: [pendiente, procesado, error] + * description: Filtra los documentos por su estado de sincronización. + * responses: + * 200: { description: Lista de documentos. } + * 500: { description: Error del servidor. } + */ +rutas.post('/api/documentos-electronicos', controlador_sinc_docs.crearDocumento); +rutas.get('/api/documentos-electronicos', controlador_sinc_docs.listarDocumentos); + +/** + * @swagger + * /api/documentos-electronicos/{id}/estado: + * put: + * summary: Actualiza el estado de sincronización de un documento. + * tags: [Sincronización Documentos] + * parameters: + * - in: path + * name: id + * required: true + * schema: { type: integer } + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: [estado_sincronizacion] + * properties: + * estado_sincronizacion: { type: string, enum: [pendiente, procesado, error], example: "procesado" } + * responses: + * 200: { description: Estado actualizado correctamente. } + * 400: { description: Estado inválido. } + * 404: { description: Documento no encontrado. } + * 500: { description: Error del servidor. } + */ +rutas.put('/api/documentos-electronicos/:id/estado', controlador_sinc_docs.actualizarEstadoDocumento); + module.exports = rutas; \ No newline at end of file diff --git a/src/rutas/rt_proyectos.js b/src/rutas/rt_proyectos.js index 78073b9..3fa478c 100644 --- a/src/rutas/rt_proyectos.js +++ b/src/rutas/rt_proyectos.js @@ -512,8 +512,8 @@ router.post('/api/proyectos/memorias-tecnicas/:memoriaId/mantenimiento', control * type: integer * description: ID del plan de mantenimiento a eliminar. * responses: - * 200: - * description: Plan de mantenimiento eliminado exitosamente. + * 204: + * description: Plan de mantenimiento eliminado exitosamente. No devuelve contenido. * 404: * description: Plan de mantenimiento no encontrado. * 500: