Creacion de aoi miembros en ruta clientes.

This commit is contained in:
Pablinux
2025-06-05 00:33:52 -05:00
parent 84e1c2af3c
commit 053c55ca96
2 changed files with 554 additions and 1 deletions

View File

@@ -0,0 +1,519 @@
// src/controladores/controlador_Miembros.js
const controladorMiembros = {
/**
* @function listarMiembros
* @description Lista todos los registros de miembros, incluyendo información de su cliente y tipo de membresía.
* @param {Object} req - Objeto de solicitud de Express.
* @param {Object} res - Objeto de respuesta de Express.
*/
listarMiembros: (req, res) => {
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar miembros:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cm.id_miembro,
cm.matricula,
cm.client_id,
cli.client_nombre,
cli.client_rucCed,
cm.id_tipo_membresia,
ctm.nombre_tipo AS nombre_tipo_membresia,
ctm.categoria_membresia,
cm.estado,
cm.fecha_registro,
cm.fecha_inicio,
cm.fecha_fin,
cm.fecha_ultimo_acceso,
cm.visitas_realizadas_hoy,
cm.observaciones,
cm.creado_por,
cm.fecha_creacion,
cm.fecha_actualizacion
FROM
clientes_miembros cm
JOIN
clientes cli ON cm.client_id = cli.client_id
JOIN
clientes_membresias ctm ON cm.id_tipo_membresia = ctm.id_tipo_membresia
ORDER BY cm.fecha_registro DESC
`;
connection.query(query, (err, rows) => {
if (err) {
console.error('Error al listar miembros:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar miembros', error: err.message });
}
res.json(rows);
});
});
},
/**
* @function obtenerMiembroPorId
* @description Obtiene un miembro específico por su ID.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_miembro).
* @param {Object} res - Objeto de respuesta de Express.
*/
obtenerMiembroPorId: (req, res) => {
const { id_miembro } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para miembro por ID:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cm.id_miembro,
cm.matricula,
cm.client_id,
cli.client_nombre,
cli.client_rucCed,
cm.id_tipo_membresia,
ctm.nombre_tipo AS nombre_tipo_membresia,
ctm.categoria_membresia,
cm.estado,
cm.fecha_registro,
cm.fecha_inicio,
cm.fecha_fin,
cm.fecha_ultimo_acceso,
cm.visitas_realizadas_hoy,
cm.observaciones,
cm.creado_por,
cm.fecha_creacion,
cm.fecha_actualizacion
FROM
clientes_miembros cm
JOIN
clientes cli ON cm.client_id = cli.client_id
JOIN
clientes_membresias ctm ON cm.id_tipo_membresia = ctm.id_tipo_membresia
WHERE cm.id_miembro = ?
`;
connection.query(query, [id_miembro], (err, rows) => {
if (err) {
console.error('Error al obtener miembro por ID:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener miembro', error: err.message });
}
if (rows.length === 0) {
return res.status(404).json({ mensaje: 'Miembro no encontrado' });
}
res.json(rows[0]);
});
});
},
/**
* @function crearMiembro
* @description Crea un nuevo registro de miembro.
* @param {Object} req - Objeto de solicitud de Express (req.body contiene los datos del miembro).
* @param {Object} res - Objeto de respuesta de Express.
*/
crearMiembro: (req, res) => {
const {
matricula, client_id, id_tipo_membresia, fecha_inicio, fecha_fin,
observaciones, creado_por // Añadir creado_por si lo envías desde el frontend
} = req.body;
// Validar campos obligatorios
if (!matricula || !client_id || !id_tipo_membresia || !fecha_inicio || !fecha_fin) {
return res.status(400).json({ mensaje: 'Faltan campos obligatorios para crear el miembro (matricula, client_id, id_tipo_membresia, fecha_inicio, fecha_fin).' });
}
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para crear miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
INSERT INTO clientes_miembros (
matricula, client_id, id_tipo_membresia, estado, fecha_registro,
fecha_inicio, fecha_fin, observaciones, creado_por
) VALUES (?, ?, ?, ?, NOW(), ?, ?, ?, ?)
`;
// 'ACTIVO' como estado por defecto en el INSERT
const values = [
matricula, client_id, id_tipo_membresia, 'ACTIVO',
fecha_inicio, fecha_fin, observaciones, creado_por
];
connection.query(query, values, (err, result) => {
if (err) {
console.error('Error al crear miembro:', err);
if (err.code === 'ER_DUP_ENTRY') {
return res.status(409).json({ mensaje: 'Ya existe un miembro con esa matrícula.', error: err.message });
}
// Posibles errores de clave foránea (client_id o id_tipo_membresia no existen)
if (err.code === 'ER_NO_REFERENCED_ROW_2' || err.code === 'ER_NO_REFERENCED_ROW') {
return res.status(400).json({ mensaje: 'El cliente o el tipo de membresía especificado no existe.', error: err.message });
}
return res.status(500).json({ mensaje: 'Error interno del servidor al crear miembro', error: err.message });
}
res.status(201).json({ mensaje: 'Miembro creado exitosamente', id_miembro: result.insertId });
});
});
},
/**
* @function actualizarMiembro
* @description Actualiza un registro de miembro existente por su ID.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_miembro, req.body).
* @param {Object} res - Objeto de respuesta de Express.
*/
actualizarMiembro: (req, res) => {
const { id_miembro } = req.params;
const {
matricula, client_id, id_tipo_membresia, estado, fecha_inicio, fecha_fin,
fecha_ultimo_acceso, visitas_realizadas_hoy, observaciones // No incluir 'creado_por' aquí, ya que es en la creación
} = req.body;
// Validar campos obligatorios para la actualización (aquí podrías hacer que algunos sean opcionales)
if (!matricula || !client_id || !id_tipo_membresia || !estado || !fecha_inicio || !fecha_fin) {
return res.status(400).json({ mensaje: 'Faltan campos obligatorios para actualizar el miembro (matricula, client_id, id_tipo_membresia, estado, fecha_inicio, fecha_fin).' });
}
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para actualizar miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
UPDATE clientes_miembros SET
matricula = ?, client_id = ?, id_tipo_membresia = ?, estado = ?,
fecha_inicio = ?, fecha_fin = ?, fecha_ultimo_acceso = ?,
visitas_realizadas_hoy = ?, observaciones = ?, fecha_actualizacion = NOW()
WHERE id_miembro = ?
`;
const values = [
matricula, client_id, id_tipo_membresia, estado,
fecha_inicio, fecha_fin, fecha_ultimo_acceso,
visitas_realizadas_hoy, observaciones, id_miembro
];
connection.query(query, values, (err, result) => {
if (err) {
console.error('Error al actualizar miembro:', err);
if (err.code === 'ER_DUP_ENTRY') {
return res.status(409).json({ mensaje: 'Ya existe otro miembro con esa matrícula.', error: err.message });
}
if (err.code === 'ER_NO_REFERENCED_ROW_2' || err.code === 'ER_NO_REFERENCED_ROW') {
return res.status(400).json({ mensaje: 'El cliente o el tipo de membresía especificado no existe.', error: err.message });
}
return res.status(500).json({ mensaje: 'Error interno del servidor al actualizar miembro', error: err.message });
}
if (result.affectedRows === 0) {
return res.status(404).json({ mensaje: 'Miembro no encontrado para actualizar' });
}
res.json({ mensaje: 'Miembro actualizado exitosamente' });
});
});
},
/**
* @function actualizarEstadoMiembro
* @description Actualiza el estado de un miembro por su ID (ej. a 'SUSPENDIDO' o 'CANCELADO').
* Esta función es para cambios de estado específicos sin actualizar todos los campos.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_miembro, req.body.estado).
* @param {Object} res - Objeto de respuesta de Express.
*/
actualizarEstadoMiembro: (req, res) => {
const { id_miembro } = req.params;
const { estado, observaciones } = req.body; // Puedes añadir motivo, usuario, etc.
if (!estado) {
return res.status(400).json({ mensaje: 'El campo estado es obligatorio para actualizar el estado del miembro.' });
}
// Validar que el estado sea uno de los permitidos por el ENUM
const estadosPermitidos = ['ACTIVO', 'VENCIDO', 'SUSPENDIDO', 'CANCELADO'];
if (!estadosPermitidos.includes(estado)) {
return res.status(400).json({ mensaje: `El estado proporcionado '${estado}' no es válido. Los estados permitidos son: ${estadosPermitidos.join(', ')}.` });
}
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para actualizar estado de miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
// Opcional: Obtener el estado anterior para el historial antes de actualizar
connection.query('SELECT estado, fecha_inicio, fecha_fin, id_tipo_membresia FROM clientes_miembros WHERE id_miembro = ?', [id_miembro], (err, currentMemberRows) => {
if (err) {
console.error('Error al obtener estado actual del miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener estado actual', error: err.message });
}
if (currentMemberRows.length === 0) {
return res.status(404).json({ mensaje: 'Miembro no encontrado para actualizar estado' });
}
const estadoAnterior = currentMemberRows[0].estado;
const fechaInicioAnterior = currentMemberRows[0].fecha_inicio;
const fechaFinAnterior = currentMemberRows[0].fecha_fin;
const idTipoMembresiaAnterior = currentMemberRows[0].id_tipo_membresia;
connection.query(
`UPDATE clientes_miembros SET estado = ?, observaciones = ?, fecha_actualizacion = NOW() WHERE id_miembro = ?`,
[estado, observaciones, id_miembro],
(err, result) => {
if (err) {
console.error('Error al actualizar estado del miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al actualizar estado del miembro', error: err.message });
}
if (result.affectedRows === 0) {
return res.status(404).json({ mensaje: 'Miembro no encontrado para actualizar estado' });
}
// Registrar el cambio en historial_estados_miembro
connection.query(
`INSERT INTO historial_estados_miembro (
id_miembro, estado_anterior, estado_nuevo, fecha_cambio, motivo_cambio,
fecha_inicio_anterior, fecha_fin_anterior, fecha_inicio_nueva, fecha_fin_nueva,
id_tipo_membresia_anterior, id_tipo_membresia_nueva, usuario_responsable, observaciones
) VALUES (?, ?, ?, NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
id_miembro,
estadoAnterior,
estado, // Nuevo estado
`Cambio de estado a ${estado}`, // Motivo por defecto, puedes personalizarlo
fechaInicioAnterior, fechaFinAnterior, // Fechas anteriores
currentMemberRows[0].fecha_inicio, currentMemberRows[0].fecha_fin, // Fechas actuales (no cambiadas por esta función, pero para el registro)
idTipoMembresiaAnterior, idTipoMembresiaAnterior, // Tipos de membresía (no cambiados por esta función)
req.body.usuario_responsable || 'Sistema/API', // O del token/sesión
observaciones
],
(historialErr) => {
if (historialErr) {
console.error('Error al registrar historial de estado:', historialErr);
// No se devuelve un 500 aquí para no afectar la respuesta principal,
// pero es importante loguear este error.
}
res.json({ mensaje: 'Estado del miembro actualizado exitosamente', nuevo_estado: estado });
}
);
}
);
});
});
},
/**
* @function eliminarMiembro
* @description Elimina lógicamente un miembro por su ID (cambia su estado a 'CANCELADO').
* Se recomienda esta operación en lugar de la eliminación física para mantener el historial.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_miembro para el ID).
* @param {Object} res - Objeto de respuesta de Express.
*/
eliminarMiembro: (req, res) => {
const { id_miembro } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para eliminar miembro:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
// Obtener estado actual antes de actualizar para el historial
connection.query('SELECT estado, fecha_inicio, fecha_fin, id_tipo_membresia FROM clientes_miembros WHERE id_miembro = ?', [id_miembro], (err, currentMemberRows) => {
if (err) {
console.error('Error al obtener estado actual del miembro para eliminación:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener estado para eliminación', error: err.message });
}
if (currentMemberRows.length === 0) {
return res.status(404).json({ mensaje: 'Miembro no encontrado para eliminar' });
}
const estadoAnterior = currentMemberRows[0].estado;
const fechaInicioAnterior = currentMemberRows[0].fecha_inicio;
const fechaFinAnterior = currentMemberRows[0].fecha_fin;
const idTipoMembresiaAnterior = currentMemberRows[0].id_tipo_membresia;
connection.query('UPDATE clientes_miembros SET estado = "CANCELADO", fecha_actualizacion = NOW() WHERE id_miembro = ?', [id_miembro], (err, result) => {
if (err) {
console.error('Error al eliminar miembro (lógicamente):', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al eliminar miembro', error: err.message });
}
if (result.affectedRows === 0) {
return res.status(404).json({ mensaje: 'Miembro no encontrado para eliminar' });
}
// Registrar el cambio en historial_estados_miembro
connection.query(
`INSERT INTO historial_estados_miembro (
id_miembro, estado_anterior, estado_nuevo, fecha_cambio, motivo_cambio,
fecha_inicio_anterior, fecha_fin_anterior, fecha_inicio_nueva, fecha_fin_nueva,
id_tipo_membresia_anterior, id_tipo_membresia_nueva, usuario_responsable, observaciones
) VALUES (?, ?, ?, NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
id_miembro,
estadoAnterior,
'CANCELADO', // Nuevo estado
'Eliminación lógica del miembro (estado CANCELADO)',
fechaInicioAnterior, fechaFinAnterior, // Fechas anteriores
currentMemberRows[0].fecha_inicio, currentMemberRows[0].fecha_fin, // Fechas actuales
idTipoMembresiaAnterior, idTipoMembresiaAnterior, // Tipos de membresía
req.body.usuario_responsable || 'Sistema/API', // O del token/sesión
`Miembro con matrícula ${currentMemberRows[0].matricula} ha sido cancelado.` // Observaciones
],
(historialErr) => {
if (historialErr) {
console.error('Error al registrar historial de eliminación (lógica):', historialErr);
// No se devuelve un 500 aquí.
}
res.json({ mensaje: 'Miembro eliminado (lógicamente) exitosamente' });
}
);
});
});
});
},
/**
* @function listarMiembrosPorCliente
* @description Lista todos los miembros asociados a un cliente específico por su client_id.
* @param {Object} req - Objeto de solicitud de Express (req.params.client_id).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarMiembrosPorCliente: (req, res) => {
const { client_id } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar miembros por cliente:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cm.id_miembro,
cm.matricula,
cm.client_id,
cli.client_nombre,
cli.client_rucCed,
cm.id_tipo_membresia,
ctm.nombre_tipo AS nombre_tipo_membresia,
ctm.categoria_membresia,
cm.estado,
cm.fecha_inicio,
cm.fecha_fin
FROM
clientes_miembros cm
JOIN
clientes cli ON cm.client_id = cli.client_id
JOIN
clientes_membresias ctm ON cm.id_tipo_membresia = ctm.id_tipo_membresia
WHERE cm.client_id = ?
ORDER BY cm.fecha_registro DESC
`;
connection.query(query, [client_id], (err, rows) => {
if (err) {
console.error('Error al listar miembros por cliente:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar miembros por cliente', error: err.message });
}
res.json(rows);
});
});
},
/**
* @function listarMiembrosPorEstado
* @description Lista todos los miembros con un estado específico.
* @param {Object} req - Objeto de solicitud de Express (req.params.estado).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarMiembrosPorEstado: (req, res) => {
const { estado } = req.params;
// Validar que el estado sea uno de los permitidos por el ENUM
const estadosPermitidos = ['ACTIVO', 'VENCIDO', 'SUSPENDIDO', 'CANCELADO'];
if (!estadosPermitidos.includes(estado)) {
return res.status(400).json({ mensaje: `El estado proporcionado '${estado}' 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 miembros por estado:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cm.id_miembro,
cm.matricula,
cli.client_nombre,
ctm.nombre_tipo AS nombre_tipo_membresia,
cm.estado,
cm.fecha_inicio,
cm.fecha_fin
FROM
clientes_miembros cm
JOIN
clientes cli ON cm.client_id = cli.client_id
JOIN
clientes_membresias ctm ON cm.id_tipo_membresia = ctm.id_tipo_membresia
WHERE cm.estado = ?
ORDER BY cm.fecha_registro DESC
`;
connection.query(query, [estado], (err, rows) => {
if (err) {
console.error('Error al listar miembros por estado:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar miembros por estado', error: err.message });
}
res.json(rows);
});
});
},
/**
* @function listarMiembrosPorTipoMembresia
* @description Lista todos los miembros asociados a un tipo de membresía específico por su id_tipo_membresia.
* @param {Object} req - Objeto de solicitud de Express (req.params.id_tipo_membresia).
* @param {Object} res - Objeto de respuesta de Express.
*/
listarMiembrosPorTipoMembresia: (req, res) => {
const { id_tipo_membresia } = req.params;
req.getConnection((err, connection) => {
if (err) {
console.error('Error al obtener conexión para listar miembros por tipo de membresía:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al obtener conexión', error: err.message });
}
const query = `
SELECT
cm.id_miembro,
cm.matricula,
cli.client_nombre,
cm.estado,
cm.fecha_inicio,
cm.fecha_fin
FROM
clientes_miembros cm
JOIN
clientes cli ON cm.client_id = cli.client_id
WHERE cm.id_tipo_membresia = ?
ORDER BY cm.fecha_registro DESC
`;
connection.query(query, [id_tipo_membresia], (err, rows) => {
if (err) {
console.error('Error al listar miembros por tipo de membresía:', err);
return res.status(500).json({ mensaje: 'Error interno del servidor al listar miembros por tipo de membresía', error: err.message });
}
res.json(rows);
});
});
}
};
module.exports = controladorMiembros;

View File

@@ -4,6 +4,7 @@ const rutas = express.Router();
const controladorClientes = require('../controladores/controlador_Clientes'); const controladorClientes = require('../controladores/controlador_Clientes');
// Importa el NUEVO controlador de Membresías // Importa el NUEVO controlador de Membresías
const controladorMembresias = require('../controladores/controlador_Membresias'); const controladorMembresias = require('../controladores/controlador_Membresias');
const controladorMiembros = require('../controladores/controlador_Miembros');
//indice inical //indice inical
rutas.get('/clientes', controladorClientes.ver);//ver lista de clientes rutas.get('/clientes', controladorClientes.ver);//ver lista de clientes
@@ -31,9 +32,42 @@ rutas.post('/api/tipos-membresia', controladorMembresias.crearTipoMembresia);
rutas.put('/api/tipos-membresia/:id', controladorMembresias.actualizarTipoMembresia); rutas.put('/api/tipos-membresia/:id', controladorMembresias.actualizarTipoMembresia);
rutas.delete('/api/tipos-membresia/:id', controladorMembresias.eliminarTipoMembresia); rutas.delete('/api/tipos-membresia/:id', controladorMembresias.eliminarTipoMembresia);
// --- Rutas RESTful para MIEMBROS (tabla 'clientes_miembros') ---
// Estas rutas apuntarán al nuevo controlador_Miembros
// Obtener todos los miembros
// GET /api/miembros
rutas.get('/api/miembros', controladorMiembros.listarMiembros);
// Obtener un miembro por su ID
// GET /api/miembros/:id_miembro
rutas.get('/api/miembros/:id_miembro', controladorMiembros.obtenerMiembroPorId);
// Crear un nuevo miembro
// POST /api/miembros
// Datos esperados en el cuerpo de la solicitud: matricula, client_id, id_tipo_membresia, fecha_inicio, fecha_fin, etc.
rutas.post('/api/miembros', controladorMiembros.crearMiembro);
// Actualizar un miembro existente por su ID
// PUT /api/miembros/:id_miembro
// Datos esperados en el cuerpo de la solicitud para actualizar: estado, fechas, etc.
rutas.put('/api/miembros/:id_miembro', controladorMiembros.actualizarMiembro);
// Eliminar (lógicamente/cambiar estado a CANCELADO/SUSPENDIDO) un miembro por su ID
// DELETE /api/miembros/:id_miembro
// NOTA: Dada la importancia del historial, es más común cambiar el estado a 'CANCELADO' o 'SUSPENDIDO'
// en lugar de una eliminación física. El controlador debería manejar esto.
rutas.delete('/api/miembros/:id_miembro', controladorMiembros.eliminarMiembro);
// --- Rutas Adicionales Comunes para Miembros (Opcional) ---
// Obtener miembros por client_id (útil para ver todas las membresías de un cliente)
// GET /api/clientes/:client_id/miembros
rutas.get('/api/clientes/:client_id/miembros', controladorMiembros.listarMiembrosPorCliente);
// Obtener miembros por estado (ej. 'ACTIVO', 'VENCIDO')
// GET /api/miembros/estado/:estado
rutas.get('/api/miembros/estado/:estado', controladorMiembros.listarMiembrosPorEstado);
// Obtener miembros por tipo de membresía
// GET /api/tipos-membresia/:id_tipo_membresia/miembros
rutas.get('/api/tipos-membresia/:id_tipo_membresia/miembros', controladorMiembros.listarMiembrosPorTipoMembresia);
// Ruta para obtener ciudades // Ruta para obtener ciudades
rutas.get('/api/ciudades', controladorClientes.obtenerCiudades); rutas.get('/api/ciudades', controladorClientes.obtenerCiudades);
//APP_SIGMA consultas //APP_SIGMA consultas
rutas.get('/consultaClientesJson', controladorClientes.app_pedidos_clientes);//consulta clientes: /consultaClientesJson?consulta=dato rutas.get('/consultaClientesJson', controladorClientes.app_pedidos_clientes);//consulta clientes: /consultaClientesJson?consulta=dato
rutas.get('/busquedaSRI/', controladorClientes.buscarCli_sri);//API consulta clientes rutas.get('/busquedaSRI/', controladorClientes.buscarCli_sri);//API consulta clientes