Files
FRASA-CAS/api-gateway/src/routes/index.ts
Consult AS Technology 9021733455 feat(clientes-maestro): importar y exportar clientes del archivo maestro
- Tabla ClienteMaestro (27 campos, unique numCliente)
- Importador Excel: 1535 clientes del Reporte maestro
- API: listar/filtros/exportar/detalle/importar
- Frontend: tabla paginada, filtros, exportar Excel
- Dark mode completo, 52 tests verdes
2026-09-07 09:11:09 +00:00

274 lines
12 KiB
TypeScript

import { Router } from 'express'
import { health } from '../controllers/health.controller.js'
import { listarUnidades, obtenerUnidad } from '../controllers/unidades.controller.js'
import {
alertasInventarioEndpoint,
crearCotizacion,
listarCotizaciones,
listarMisCotizaciones,
obtenerCotizacion,
obtenerCotizacionPublica,
} from '../controllers/cotizaciones.controller.js'
import {
actualizarProgreso,
completarProgreso,
crearCliente,
iniciarProgreso,
listarDocumentos,
obtenerCliente,
prefillApartadoEndpoint,
subirDocumentos,
uploadDocumentos,
} from '../controllers/clientes.controller.js'
import {
eliminarBorrador,
guardarBorrador,
listarBorradores,
obtenerBorrador,
} from '../controllers/borradores.controller.js'
import {
firmarRemoto,
generarLiga,
limitadorLiga,
obtenerClientePublico,
subirDocumentosPublico,
uploadDocumentosPublico,
} from '../controllers/liga.controller.js'
import {
agregarNota,
cancelarPlan,
cobranzaHoy,
crearPlan,
ligarMondayItem,
listarPlanes,
obtenerPlan,
registrarAbonoEndpoint,
} from '../controllers/planes.controller.js'
import {
cambiarEtapaOportunidadEndpoint,
perderOportunidadEndpoint,
} from '../controllers/oportunidades.controller.js'
import { cambiarEstadoApartadoEndpoint, listarDocumentosApartado, subirDocumentosApartado, uploadDocumentosApartado } from '../controllers/apartados.controller.js'
import { correrRecordatorios, listarRecordatorios } from '../controllers/recordatorios.controller.js'
import {
cambiarEstadoLeadEndpoint,
crearAfluenciaEndpoint,
crearLeadEndpoint,
buscarLeadsEndpoint,
convertirLeadEndpoint,
descartarLeadEndpoint,
} from '../controllers/leads.controller.js'
import {
actualizarRolEndpoint,
actualizarVinculoMondayEndpoint,
listarUsuariosMondayEndpoint,
} from '../controllers/usuarios.controller.js'
import { resumenMiDiaEndpoint } from '../controllers/mi-dia.controller.js'
import { listarContactosEndpoint, detalleContactoEndpoint } from '../controllers/contactos.controller.js'
import { webhookMonday } from '../controllers/webhooks.controller.js'
import {
correrRoundRobin,
estadoAutomatizaciones,
previewInactividad,
} from '../controllers/automatizaciones.controller.js'
import {
chatIA,
eliminarDocumento,
listarConversaciones,
listarDocumentosIA,
obtenerConversacion,
subirDocumento,
} from '../controllers/ai.controller.js'
import { loginEndpoint, meEndpoint, cambiarPasswordEndpoint } from '../controllers/auth.controller.js'
import { resumenReportes } from '../controllers/reportes.controller.js'
import { estadoSistema } from '../controllers/sistema.controller.js'
import {
requireAdmin,
obtenerConfigsEndpoint,
actualizarConfigsEndpoint,
obtenerRolesConfigEndpoint,
actualizarRolConfigEndpoint,
obtenerUsuariosEndpoint,
actualizarUsuarioEndpoint,
resetRolesEndpoint,
obtenerAccionesEndpoint,
} from '../controllers/config.controller.js'
import { crearNotaEndpoint, listarNotasEndpoint } from '../controllers/notas.controller.js'
import { listarAuditoriaEndpoint } from '../controllers/auditoria.controller.js'
import { buscarEndpoint } from '../controllers/buscar.controller.js'
import {
miTableroEndpoint,
metricasUsoEndpoint,
requireAdminOrCoordinador,
} from '../controllers/reporte-mi-tablero.controller.js'
import {
suscribirEndpoint,
desuscribirEndpoint,
vapidKeyEndpoint,
} from '../controllers/push.controller.js'
import {
listarEndpoint as listarCapturaEndpoint,
unidadesEndpoint as unidadesCapturaEndpoint,
resumenEndpoint as resumenCapturaEndpoint,
guardarEndpoint as guardarCapturaEndpoint,
bulkEndpoint as bulkCapturaEndpoint,
importarEndpoint as importarCapturaEndpoint,
requireAdminCaptura,
} from '../controllers/captura-departamento.controller.js'
import {
listarEndpoint as listarMaestroEndpoint,
exportarEndpoint as exportarMaestroEndpoint,
obtenerEndpoint as obtenerMaestroEndpoint,
importarEndpoint as importarMaestroEndpoint,
requireAdmin as requireAdminMaestro,
} from '../controllers/cliente-maestro.controller.js'
export const apiRouter = Router()
apiRouter.get('/health', health)
apiRouter.get('/buscar', buscarEndpoint)
apiRouter.post('/auth/login', loginEndpoint)
apiRouter.get('/auth/me', meEndpoint)
apiRouter.post('/auth/cambiar-password', cambiarPasswordEndpoint)
apiRouter.get('/unidades', listarUnidades)
apiRouter.get('/unidades/:codigo', obtenerUnidad)
apiRouter.post('/cotizaciones', crearCotizacion)
apiRouter.get('/cotizaciones', listarCotizaciones)
apiRouter.get('/cotizaciones/mias', listarMisCotizaciones)
apiRouter.post('/cotizaciones/alertas-inventario', alertasInventarioEndpoint)
// Público (sin auth): destino del QR del PDF; ver RUTAS_PUBLICAS/PATRONES_PUBLICOS
apiRouter.get('/cotizaciones/:id/publico', obtenerCotizacionPublica)
apiRouter.get('/cotizaciones/:id', obtenerCotizacion)
apiRouter.post('/clientes', crearCliente)
// Prefill del alta desde un apartado de Monday (botón "Firma Cliente (Venta)"
// de Mis apartados). Va ANTES de /clientes/:id para no colisionar.
apiRouter.get('/altas/prefill-apartado/:itemId', prefillApartadoEndpoint)
// Alta progresiva: guardado etapa por etapa del wizard (Contacto PROSPECTO → CLIENTE).
// Van ANTES de /clientes/:id para no colisionar con el parámetro.
apiRouter.post('/clientes/progreso/iniciar', iniciarProgreso)
apiRouter.patch('/clientes/progreso/:id', actualizarProgreso)
apiRouter.post('/clientes/progreso/:id/completar', completarProgreso)
// Liga remota: endpoints públicos con token propio (scope 'firma-remota'); el
// scope se verifica dentro de cada controlador. Van ANTES de /clientes/:id.
apiRouter.get('/clientes/publico/:token', limitadorLiga, obtenerClientePublico)
apiRouter.post('/clientes/publico/:token/firma', limitadorLiga, firmarRemoto)
apiRouter.post(
'/clientes/publico/:token/documentos',
limitadorLiga,
uploadDocumentosPublico.array('archivos', 10),
subirDocumentosPublico,
)
apiRouter.post('/clientes/:id/liga', generarLiga)
apiRouter.get('/clientes/:id', obtenerCliente)
apiRouter.post('/clientes/:id/documentos', uploadDocumentos.array('archivos', 10), subirDocumentos)
apiRouter.get('/clientes/:id/documentos', listarDocumentos)
apiRouter.get('/borradores', listarBorradores)
apiRouter.post('/borradores', guardarBorrador)
apiRouter.get('/borradores/:id', obtenerBorrador)
apiRouter.delete('/borradores/:id', eliminarBorrador)
apiRouter.post('/planes', crearPlan)
apiRouter.get('/planes', listarPlanes)
apiRouter.get('/planes/cobranza-del-dia', cobranzaHoy)
apiRouter.get('/planes/:id', obtenerPlan)
apiRouter.post('/planes/:id/abonos', registrarAbonoEndpoint)
apiRouter.post('/planes/:id/notas', agregarNota)
apiRouter.post('/planes/:id/cancelar', cancelarPlan)
apiRouter.patch('/planes/:id/monday', ligarMondayItem)
apiRouter.get('/cobranza/recordatorios', listarRecordatorios)
apiRouter.post('/cobranza/recordatorios/run', correrRecordatorios)
apiRouter.post('/oportunidades/:mondayItemId/perder', perderOportunidadEndpoint)
// Cambio de etapa desde los botones de "Mis oportunidades" (Mi día)
apiRouter.post('/oportunidades/:itemId/etapa', cambiarEtapaOportunidadEndpoint)
// Cambio de fase del pipeline Enkontrol desde "Mis apartados" (Mi día)
apiRouter.post('/apartados/:itemId/estado', cambiarEstadoApartadoEndpoint)
// Precarga de documentos del expediente desde "Mis apartados": se guardan en
// el cliente ligado al apartado (se crea la ficha mínima si aún no existe)
apiRouter.get('/apartados/:itemId/documentos', listarDocumentosApartado)
apiRouter.post('/apartados/:itemId/documentos', uploadDocumentosApartado.array('archivos', 10), subirDocumentosApartado)
// Notas del apartado
apiRouter.post('/apartados/:id/notas', crearNotaEndpoint)
apiRouter.get('/apartados/:id/notas', listarNotasEndpoint)
apiRouter.get('/mi-dia/resumen', resumenMiDiaEndpoint)
apiRouter.get('/contactos', listarContactosEndpoint)
apiRouter.get('/contactos/:id/detalle', detalleContactoEndpoint)
// GET estático: va ANTES de /leads/:itemId para no colisionar con el parámetro
apiRouter.get('/leads/buscar', buscarLeadsEndpoint)
apiRouter.post('/leads', crearLeadEndpoint)
apiRouter.post('/leads/:itemId/estado', cambiarEstadoLeadEndpoint)
apiRouter.post('/leads/:itemId/descartar', descartarLeadEndpoint)
// Botón "Agendo" de Mis leads: convierte el lead en oportunidad (Agendo Cita)
apiRouter.post('/leads/:itemId/convertir', convertirLeadEndpoint)
// Alta Afluencia (forma completa de /client): vive en el tablero Oportunidades
apiRouter.post('/afluencias', crearAfluenciaEndpoint)
apiRouter.get('/monday/usuarios', listarUsuariosMondayEndpoint)
apiRouter.patch('/usuarios/me/monday', actualizarVinculoMondayEndpoint)
apiRouter.patch('/usuarios/:id/rol', actualizarRolEndpoint)
apiRouter.get('/reportes/resumen', resumenReportes)
// Tablero personal del vendedor: métricas, conversión, ventas, origen, desarrollos
apiRouter.get('/reportes/mi-tablero', miTableroEndpoint)
// Métricas de uso (admin/coordinador): leads por usuario, tasa de descarte, actividades
apiRouter.get('/reportes/metricas-uso', requireAdminOrCoordinador, metricasUsoEndpoint)
// Estado del modo local (banner del front): salud de Monday + cola de sync
apiRouter.get('/sistema/estado', estadoSistema)
apiRouter.post('/webhooks/monday', webhookMonday)
apiRouter.get('/automatizaciones/estado', estadoAutomatizaciones)
apiRouter.post('/automatizaciones/round-robin/run', correrRoundRobin)
apiRouter.get('/automatizaciones/inactividad/preview', previewInactividad)
apiRouter.post('/ai/chat', chatIA)
apiRouter.get('/ai/conversations', listarConversaciones)
apiRouter.get('/ai/conversations/:id', obtenerConversacion)
apiRouter.post('/ai/documents', subirDocumento)
apiRouter.get('/ai/documents', listarDocumentosIA)
apiRouter.delete('/ai/documents/:id', eliminarDocumento)
// ── Auditoría (admin) ────────────────────────────────────────────────
apiRouter.get('/auditoria', requireAdmin, listarAuditoriaEndpoint)
// ── Configuración (admin) ──────────────────────────────────────────────
apiRouter.get('/config/sistema', requireAdmin, obtenerConfigsEndpoint)
apiRouter.patch('/config/sistema', requireAdmin, actualizarConfigsEndpoint)
apiRouter.get('/config/roles', requireAdmin, obtenerRolesConfigEndpoint)
apiRouter.patch('/config/roles/:rol', requireAdmin, actualizarRolConfigEndpoint)
apiRouter.get('/config/usuarios', requireAdmin, obtenerUsuariosEndpoint)
apiRouter.patch('/config/usuarios/:id', requireAdmin, actualizarUsuarioEndpoint)
apiRouter.post('/config/reset-roles', requireAdmin, resetRolesEndpoint)
apiRouter.get('/config/acciones', obtenerAccionesEndpoint)
// ── Captura por departamentos ────────────────────────────────────────
apiRouter.get('/captura', listarCapturaEndpoint)
apiRouter.get('/captura/unidades', unidadesCapturaEndpoint)
apiRouter.get('/captura/resumen', resumenCapturaEndpoint)
apiRouter.post('/captura', guardarCapturaEndpoint)
apiRouter.post('/captura/bulk', bulkCapturaEndpoint)
apiRouter.post('/captura/importar', requireAdminCaptura, importarCapturaEndpoint)
// ── Push notifications ──────────────────────────────────────────────
apiRouter.get('/push/vapid-key', vapidKeyEndpoint)
apiRouter.post('/push/suscribir', suscribirEndpoint)
apiRouter.post('/push/desuscribir', desuscribirEndpoint)
// ── Clientes Maestro ──────────────────────────────────────────────
apiRouter.get('/clientes-maestro', listarMaestroEndpoint)
// Exportar va ANTES de /:numCliente para no colisionar con el parámetro
apiRouter.get('/clientes-maestro/exportar', exportarMaestroEndpoint)
apiRouter.get('/clientes-maestro/:numCliente', obtenerMaestroEndpoint)
apiRouter.post('/clientes-maestro/importar', requireAdminMaestro, importarMaestroEndpoint)