feat(api): Agrega endpoint para búsqueda de clientes y estado de membresía
Se ha creado una nueva ruta en la API v2 (`GET /api/v2/search-client-member-status`) para dar soporte al frontend en la búsqueda dinámica de clientes para el registro de pagos. Cambios principales: - Se crea el archivo `api_v2_controlador.js` en la carpeta `controladores` para alojar la nueva lógica. - La nueva API busca clientes por nombre o RUC/cédula. - Para cada cliente encontrado, se realiza una consulta a la tabla `clientes_miembros` para determinar si es un miembro activo y si tiene valores vencidos. - Se registra la nueva ruta en `rt_api_v2.js`, asociándola con su controlador. - Se actualiza la colección de Postman (`APP_SIGMA_NODE.postman_collection.json`) para incluir y documentar el nuevo endpoint. Esta funcionalidad es clave para mejorar la experiencia de usuario en el formulario de registro de pagos, permitiendo una selección de cliente más ágil e informativa.
This commit is contained in:
61
src/controladores/controlador_api_v2.js
Normal file
61
src/controladores/controlador_api_v2.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
const controlador = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Busca clientes y verifica su estado de membresía.
|
||||||
|
* Busca por nombre o RUC/cédula.
|
||||||
|
* Si el cliente es miembro, añade información sobre su estado y si tiene valores vencidos.
|
||||||
|
* Ruta: GET /api/v2/search-client-member-status
|
||||||
|
*/
|
||||||
|
controlador.searchClientMemberStatus = (req, res) => {
|
||||||
|
const { query } = req.query;
|
||||||
|
|
||||||
|
if (!query || query.length < 2) {
|
||||||
|
return res.status(400).json({ error: 'Se requiere un término de búsqueda de al menos 2 caracteres.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
req.getConnection((err, conn) => {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error de conexión a la BD:", err);
|
||||||
|
return res.status(500).json({ error: 'Error interno del servidor.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paso 1: Buscar clientes que coincidan con el término de búsqueda.
|
||||||
|
const clientSql = `
|
||||||
|
SELECT
|
||||||
|
c.client_id,
|
||||||
|
c.client_nombre,
|
||||||
|
c.client_rucCed
|
||||||
|
FROM clientes c
|
||||||
|
WHERE c.client_nombre LIKE ? OR c.client_rucCed LIKE ?
|
||||||
|
LIMIT 10
|
||||||
|
`;
|
||||||
|
const searchTerm = `%${query}%`;
|
||||||
|
|
||||||
|
conn.query(clientSql, [searchTerm, searchTerm], (err, clients) => {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error en la búsqueda de clientes:", err);
|
||||||
|
return res.status(500).json({ error: 'Error al buscar clientes.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paso 2: Para cada cliente, verificar si es miembro y su estado.
|
||||||
|
const promises = clients.map(client => new Promise((resolve, reject) => {
|
||||||
|
const memberSql = `SELECT estado, fecha_fin FROM clientes_miembros WHERE client_id = ? ORDER BY fecha_fin DESC LIMIT 1`;
|
||||||
|
conn.query(memberSql, [client.client_id], (err, memberStatus) => {
|
||||||
|
if (err) return reject(err);
|
||||||
|
const isMember = memberStatus.length > 0;
|
||||||
|
const hasOverdue = isMember && (memberStatus[0].estado === 'VENCIDO' || new Date(memberStatus[0].fecha_fin) < new Date());
|
||||||
|
resolve({ ...client, isMember, hasOverdue, memberStatus: isMember ? memberStatus[0].estado : null });
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
Promise.all(promises)
|
||||||
|
.then(results => res.status(200).json(results))
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Error verificando estado de miembros:", error);
|
||||||
|
res.status(500).json({ error: 'Error al verificar estado de miembros.' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = controlador;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"info": {
|
"info": {
|
||||||
"_postman_id": "1710a3ae-fba9-4526-8084-a066897ddadd",
|
"_postman_id": "1710a3ae-fba9-4526-8084-a066897ddadd",
|
||||||
"name": "APP_SIGMA_NODE",
|
"name": "APP-SIGMA-WEB",
|
||||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||||
"_exporter_id": "11858928"
|
"_exporter_id": "11858928"
|
||||||
},
|
},
|
||||||
@@ -244,6 +244,41 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Endpoints para la gestión de documentos electrónicos sincronizados desde n8n."
|
"description": "Endpoints para la gestión de documentos electrónicos sincronizados desde n8n."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "API V2",
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Buscar Cliente y Estado de Membresía",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "http://localhost:3001/api/v2/search-client-member-status?query=pablo",
|
||||||
|
"protocol": "http",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "3001",
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"v2",
|
||||||
|
"search-client-member-status"
|
||||||
|
],
|
||||||
|
"query": [
|
||||||
|
{
|
||||||
|
"key": "query",
|
||||||
|
"value": "pablo",
|
||||||
|
"description": "Término de búsqueda para nombre o RUC/cédula del cliente."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "Busca clientes por nombre o RUC/cédula y devuelve su estado de membresía (si aplica)."
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Nuevos endpoints para la versión 2 de la API."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,90 +1,32 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const rutas = express.Router();
|
const rutas = express.Router();
|
||||||
|
|
||||||
const controladorPedidosApi = require('../controladores/controlador_pedidos_api');
|
const apiV2Controller = require('../controladores/controlador_api_v2');
|
||||||
const controladorItemsApi = require('../controladores/controlador_items_api');
|
|
||||||
const controladorClientesApi = require('../controladores/controlador_clientes_api'); // Importar el nuevo controlador de clientes
|
|
||||||
|
|
||||||
// --- Rutas para la nueva API de Pedidos V2 ---
|
// Aquí puedes añadir tus nuevas rutas de la API v2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /api/v2/items:
|
* /api/v2/search-client-member-status:
|
||||||
* get:
|
* get:
|
||||||
* summary: Obtiene la lista de productos para la app de pedidos v2.
|
* summary: Busca clientes y verifica el estado de su membresía.
|
||||||
* tags: [Pedidos V2]
|
* tags: [API V2]
|
||||||
* parameters:
|
* parameters:
|
||||||
* - in: query
|
* - in: query
|
||||||
* name: consulta
|
* name: query
|
||||||
* schema:
|
* schema:
|
||||||
* type: string
|
* type: string
|
||||||
* description: Término de búsqueda para filtrar productos.
|
* required: true
|
||||||
* - in: query
|
* description: Término de búsqueda para nombre o RUC/cédula del cliente (mínimo 2 caracteres).
|
||||||
* name: gp_precio
|
|
||||||
* schema:
|
|
||||||
* type: string
|
|
||||||
* description: Grupo de precios a aplicar (ej. PUBLICO).
|
|
||||||
* responses:
|
* responses:
|
||||||
* 200:
|
* 200:
|
||||||
* description: Una lista de productos.
|
* description: Una lista de clientes con su estado de membresía.
|
||||||
|
* 400:
|
||||||
|
* description: El término de búsqueda es muy corto.
|
||||||
* 500:
|
* 500:
|
||||||
* description: Error del servidor.
|
* description: Error interno del servidor.
|
||||||
*/
|
*/
|
||||||
rutas.get('/api/v2/items', controladorItemsApi.getItemsForV2);
|
rutas.get('/api/v2/search-client-member-status', apiV2Controller.searchClientMemberStatus);
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /api/v2/clientes:
|
|
||||||
* get:
|
|
||||||
* summary: Obtiene la lista de clientes para la app de pedidos v2.
|
|
||||||
* tags: [Pedidos V2]
|
|
||||||
* parameters:
|
|
||||||
* - in: query
|
|
||||||
* name: consulta
|
|
||||||
* schema:
|
|
||||||
* type: string
|
|
||||||
* description: Término de búsqueda para filtrar clientes por nombre o RUC/CI.
|
|
||||||
* responses:
|
|
||||||
* 200:
|
|
||||||
* description: Una lista de clientes.
|
|
||||||
* 500:
|
|
||||||
* description: Error del servidor.
|
|
||||||
*/
|
|
||||||
rutas.get('/api/v2/clientes', controladorClientesApi.getClientesForV2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @swagger
|
|
||||||
* /api/v2/pedidos:
|
|
||||||
* post:
|
|
||||||
* summary: Crea un nuevo pedido de forma transaccional.
|
|
||||||
* tags: [Pedidos V2]
|
|
||||||
* requestBody:
|
|
||||||
* required: true
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* type: object
|
|
||||||
* properties:
|
|
||||||
* clienteId: { type: integer, example: 1 }
|
|
||||||
* user: { type: string, example: 'WebAppUser' }
|
|
||||||
* estado: { type: string, example: 'ACTIVO' }
|
|
||||||
* valor: { type: number, example: 112.00 }
|
|
||||||
* iva: { type: number, example: 12.00 }
|
|
||||||
* plataforma: { type: string, example: 'APP-SIGMA-WEB-V2' }
|
|
||||||
* origen: { type: string, example: 'WebApp' }
|
|
||||||
* items:
|
|
||||||
* type: array
|
|
||||||
* items:
|
|
||||||
* type: object
|
|
||||||
* properties:
|
|
||||||
* cod: { type: string, example: 'PROD-001' }
|
|
||||||
* cant: { type: integer, example: 2 }
|
|
||||||
* precio: { type: number, example: 50.00 }
|
|
||||||
* responses:
|
|
||||||
* 201: { description: Pedido creado exitosamente. }
|
|
||||||
* 400: { description: Datos inválidos. }
|
|
||||||
* 500: { description: Error del servidor. }
|
|
||||||
*/
|
|
||||||
rutas.post('/api/v2/pedidos', controladorPedidosApi.crearPedido);
|
|
||||||
|
|
||||||
module.exports = rutas;
|
module.exports = rutas;
|
||||||
Reference in New Issue
Block a user