Creacion de rutas de registro de visitas de miembros

This commit is contained in:
Pablinux
2025-06-07 22:29:00 -05:00
parent 4966aaabc6
commit ba83c866e6
4 changed files with 367 additions and 3 deletions

View File

@@ -0,0 +1,342 @@
// src/controladores/controlador_Clientes_MiembrosVisitas.js
// NO NECESITARÁS 'moment-timezone' NI CÁLCULOS MANUALES COMPLEJOS
// const moment = require('moment-timezone');
// ¡IMPORTANTE: Cambia el nombre de esta constante para que coincida con la importación en rt_clientes.js!
const controlador_Clientes_MiembrosVisitas = {
/**
* @function registrarVisita
* @description Registra una nueva visita de miembro en la tabla clientes_miembros_visitas.
* @param {Object} req - Objeto de solicitud de Express.
* @param {Object} res - Objeto de respuesta de Express.
*/
registrarVisita: (req, res) => {
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para registrar visita:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const {
id_miembro,
matricula_registrada,
nombre_area_acceso,
estado_acceso, // 'CONCEDIDO' o 'DENEGADO'
motivo_denegacion,
registrado_por,
observaciones
} = req.body;
// Validación básica de los campos requeridos
if (!id_miembro || !matricula_registrada || !nombre_area_acceso || !estado_acceso) {
return res.status(400).json({ mensaje: 'Faltan campos obligatorios para registrar la visita (id_miembro, matricula_registrada, nombre_area_acceso, estado_acceso).' });
}
// Asegúrate de que estado_acceso sea uno de los valores ENUM permitidos
if (!['CONCEDIDO', 'DENEGADO'].includes(estado_acceso.toUpperCase())) {
return res.status(400).json({ mensaje: 'El estado de acceso debe ser "CONCEDIDO" o "DENEGADO".' });
}
// --- SIMPLIFICACIÓN: Usar la fecha nativa de JavaScript ---
const now = new Date(); // Esto obtendrá la fecha y hora local del servidor (Quito)
// Formatear la fecha y hora a 'YYYY-MM-DD HH:mm:ss' para MySQL
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // getMonth() es 0-indexado
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const fecha_hora_visita = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
// ---------------------------------------------------
const query = `
INSERT INTO clientes_miembros_visitas
(id_miembro, matricula_registrada, fecha_hora_visita, nombre_area_acceso, estado_acceso, motivo_denegacion, registrado_por, observaciones)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`;
const values = [
id_miembro,
matricula_registrada,
fecha_hora_visita, // Usa la fecha formateada
nombre_area_acceso,
estado_acceso.toUpperCase(), // Asegura que se guarde en mayúsculas
motivo_denegacion || null,
registrado_por || null,
observaciones || null
];
connection.query(query, values, (err, result) => {
if (err) {
console.error('Error al registrar visita:', err);
if (err.code === 'ER_NO_REFERENCED_ROW_2' || err.code === 'ER_NO_REFERENCED_ROW') {
return res.status(400).json({ mensaje: 'El ID de miembro especificado no existe. Asegúrate de que el miembro esté registrado en el sistema.', error: err.message });
}
return res.status(500).json({ mensaje: 'Error interno del servidor al registrar la visita', error: err.message });
}
if (result.affectedRows === 1) {
res.status(201).json({
mensaje: 'Visita registrada exitosamente.',
id_visita: result.insertId,
datos_visita: {
id_miembro,
matricula_registrada,
nombre_area_acceso,
estado_acceso,
fecha_hora_visita // Devuelve la fecha formateada
}
});
} else {
res.status(500).json({ mensaje: 'Error al registrar la visita: no se afectó ninguna fila.' });
}
});
});
},
/**
* @function listarVisitas
* @description Lista todos los registros de visitas.
* @param {Object} req - Objeto de solicitud de Express.
* @param {Object} res - Objeto de respuesta de Express.
*/
listarVisitas: (req, res) => {
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar visitas:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cv.id_visita,
cv.id_miembro,
cm.matricula AS matricula_miembro,
cli.client_nombre AS nombre_cliente,
cv.matricula_registrada,
cv.fecha_hora_visita,
cv.nombre_area_acceso,
cv.estado_acceso,
cv.motivo_denegacion,
cv.registrado_por,
cv.observaciones,
cv.fecha_creacion
FROM
clientes_miembros_visitas cv
JOIN
clientes_miembros cm ON cv.id_miembro = cm.id_miembro
JOIN
clientes cli ON cm.client_id = cli.client_id
ORDER BY cv.fecha_hora_visita DESC
`;
connection.query(query, (err, rows) => {
if (err) {
console.error('Error al listar visitas:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar visitas', error: err.message });
}
res.json(rows);
});
});
},
/**
* @function obtenerVisitaPorId
* @description Obtiene una visita específica por su ID.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_visita).
* @param {Object} res - Objeto de respuesta de Express.
*/
obtenerVisitaPorId: (req, res) => {
const { id_visita } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para visita por ID:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cv.id_visita,
cv.id_miembro,
cm.matricula AS matricula_miembro,
cli.client_nombre AS nombre_cliente,
cv.matricula_registrada,
cv.fecha_hora_visita,
cv.nombre_area_acceso,
cv.estado_acceso,
cv.motivo_denegacion,
cv.registrado_por,
cv.observaciones,
cv.fecha_creacion
FROM
clientes_miembros_visitas cv
JOIN
clientes_miembros cm ON cv.id_miembro = cm.id_miembro
JOIN
clientes cli ON cm.client_id = cli.client_id
WHERE cv.id_visita = ?
`;
connection.query(query, [id_visita], (err, rows) => {
if (err) {
console.error('Error al obtener visita por ID:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener visita', error: err.message });
}
if (rows.length === 0) {
return res.status(404).json({ mensaje: 'Visita no encontrada' });
}
res.json(rows[0]);
});
});
},
/**
* @function listarVisitasPorMiembro
* @description Lista el historial de visitas para un miembro específico por su id_miembro.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_miembro).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarVisitasPorMiembro: (req, res) => {
const { id_miembro } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar visitas por miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cv.id_visita,
cv.matricula_registrada,
cv.fecha_hora_visita,
cv.nombre_area_acceso,
cv.estado_acceso,
cv.motivo_denegacion,
cv.registrado_por,
cv.observaciones
FROM
clientes_miembros_visitas cv
WHERE cv.id_miembro = ?
ORDER BY cv.fecha_hora_visita DESC
`;
connection.query(query, [id_miembro], (err, rows) => {
if (err) {
console.error('Error al listar visitas por miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar visitas por miembro', error: err.message });
}
if (rows.length === 0) {
return res.status(404).json({ mensaje: 'No se encontraron visitas para el miembro con el ID proporcionado.' });
}
res.json(rows);
});
});
},
/**
* @function listarVisitasPorEstadoAcceso
* @description Lista las visitas filtradas por un estado de acceso específico (CONCEDIDO/DENEGADO).
* @param {Object} req - Objeto de solicitud de Express (req.params.estado_acceso).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarVisitasPorEstadoAcceso: (req, res) => {
const { estado_acceso } = req.params;
// Validar que el estado sea uno de los permitidos por el ENUM
const estadosPermitidos = ['CONCEDIDO', 'DENEGADO'];
if (!estadosPermitidos.includes(estado_acceso.toUpperCase())) {
return res.status(400).json({ mensaje: `El estado de acceso proporcionado '${estado_acceso}' no es válido. Los estados permitidos son: ${estadosPermitidos.join(', ')}.` });
}
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar visitas por estado de acceso:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cv.id_visita,
cv.id_miembro,
cm.matricula AS matricula_miembro,
cli.client_nombre AS nombre_cliente,
cv.matricula_registrada,
cv.fecha_hora_visita,
cv.nombre_area_acceso,
cv.estado_acceso,
cv.motivo_denegacion
FROM
clientes_miembros_visitas cv
JOIN
clientes_miembros cm ON cv.id_miembro = cm.id_miembro
JOIN
clientes cli ON cm.client_id = cli.client_id
WHERE cv.estado_acceso = ?
ORDER BY cv.fecha_hora_visita DESC
`;
connection.query(query, [estado_acceso.toUpperCase()], (err, rows) => {
if (err) {
console.error('Error al listar visitas por estado de acceso:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar visitas por estado de acceso', error: err.message });
}
res.json(rows);
});
});
},
/**
* @function listarVisitasPorArea
* @description Lista las visitas filtradas por el nombre del área de acceso.
* @param {Object} req - Objeto de solicitud de Express (req.params.nombre_area).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarVisitasPorArea: (req, res) => {
const { nombre_area } = req.params;
if (!nombre_area) {
return res.status(400).json({ mensaje: 'El nombre del área es obligatorio.' });
}
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar visitas por área:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cv.id_visita,
cv.id_miembro,
cm.matricula AS matricula_miembro,
cli.client_nombre AS nombre_cliente,
cv.matricula_registrada,
cv.fecha_hora_visita,
cv.nombre_area_acceso,
cv.estado_acceso,
cv.motivo_denegacion
FROM
clientes_miembros_visitas cv
JOIN
clientes_miembros cm ON cv.id_miembro = cm.id_miembro
JOIN
clientes cli ON cm.client_id = cli.client_id
WHERE cv.nombre_area_acceso LIKE ?
ORDER BY cv.fecha_hora_visita DESC
`;
connection.query(query, [`%${nombre_area}%`], (err, rows) => { // Uso de LIKE para búsqueda parcial
if (err) {
console.error('Error al listar visitas por área:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar visitas por área', error: err.message });
}
res.json(rows);
});
});
}
};
module.exports = controlador_Clientes_MiembrosVisitas;

View File

@@ -2,10 +2,10 @@ const express = require('express');
const rutas = express.Router();
const controladorClientes = require('../controladores/controlador_Clientes');
// Importa el NUEVO controlador de Membresías
const controladorMembresias = require('../controladores/controlador_Membresias');
const controladorMiembros = require('../controladores/controlador_Miembros');
const controladorMembresias = require('../controladores/controlador_Clientes_Membresias');
const controladorMiembros = require('../controladores/controlador_Clientes_Miembros');
const controladorAreas = require('../controladores/controlador_Areas'); // Controlador para áreas de configuración
const controladorVisitasMiembros = require('../controladores/controlador_Clientes_MiembrosVisitas'); // Controlador para visitas de miembros
//indice inical
rutas.get('/clientes', controladorClientes.ver);//ver lista de clientes
@@ -74,6 +74,28 @@ rutas.get('/api/miembros/estado/:estado', controladorMiembros.listarMiembrosPorE
// GET /api/tipos-membresia/:id_tipo_membresia/miembros
rutas.get('/api/tipos-membresia/:id_tipo_membresia/miembros', controladorMiembros.listarMiembrosPorTipoMembresia);
// --- Rutas RESTful para VISITAS de Miembros (tabla 'clientes_miembros_visitas') ---
// Estas rutas apuntarán al nuevo controlador_VisitasMiembros
// Registrar una nueva visita de miembro
// POST /api/visitas-miembros
// Datos esperados en el cuerpo: id_miembro, matricula_registrada, nombre_area_acceso, estado_acceso, motivo_denegacion (opcional), registrado_por (opcional), observaciones (opcional)
rutas.post('/api/visitas-miembros', controladorVisitasMiembros.registrarVisita);
// Obtener todas las visitas (puede ser útil para reportes o auditorías, pero cuidado con el volumen)
// GET /api/visitas-miembros
rutas.get('/api/visitas-miembros', controladorVisitasMiembros.listarVisitas);
// Obtener visitas por ID de miembro (para ver el historial de un miembro específico)
// GET /api/miembros/:id_miembro/visitas
rutas.get('/api/miembros/:id_miembro/visitas', controladorVisitasMiembros.listarVisitasPorMiembro);
// Obtener una visita específica por su ID
// GET /api/visitas-miembros/:id_visita
rutas.get('/api/visitas-miembros/:id_visita', controladorVisitasMiembros.obtenerVisitaPorId);
// (Opcional) Obtener visitas por estado de acceso (CONCEDIDO/DENEGADO)
// GET /api/visitas-miembros/estado/:estado_acceso
rutas.get('/api/visitas-miembros/estado/:estado_acceso', controladorVisitasMiembros.listarVisitasPorEstadoAcceso);
// (Opcional) Obtener visitas por área de acceso
// GET /api/visitas-miembros/area/:nombre_area
rutas.get('/api/visitas-miembros/area/:nombre_area', controladorVisitasMiembros.listarVisitasPorArea);
// Rutas para la administración de Áreas de Acceso
rutas.get('/api/areas', controladorAreas.listarAreas);
rutas.get('/api/areas/:id', controladorAreas.obtenerAreaPorId);