feat: conversión lead→oportunidad (Agendo) y alta ligada a apartado

- Mis leads: botón 'Agendo →' convierte el lead en oportunidad (etapa
  Agendo Cita, con sus datos, asesor = vendedor del lead o quien
  convierte), marca el lead Calificado y guarda el mapping
  LeadOportunidad; 409 si ya fue convertido
- Mis oportunidades: se quitan No Asistio y Abandono (redundantes con
  Descartar); quedan Cotizar, Afluencia, Agendo Cita y Aparto
- Mis apartados: 'Firma cliente (venta) →' abre el alta de cliente con
  TODO lo recolectado prellenado (ficha del apartado + contacto +
  oportunidad + cotización vinculada vía GET /altas/prefill-apartado/:id)
- El alta con apartadoMondayId se LIGA al apartado existente y lo
  enriquece (curp, teléfono, email, precio final, enganche, forma de
  pago, unidad) en vez de crear un duplicado
- monday.service: actualizarApartado + ApartadoMonday con curp, forma de
  pago, enganche y monto apartado
- Tests: 470 API + 120 alta-clientes + 16 mi-dia, verde
This commit is contained in:
2026-09-05 00:33:53 +00:00
parent a4575bb948
commit 5b348d21e5
14 changed files with 654 additions and 17 deletions

View File

@@ -16,6 +16,7 @@ import {
iniciarProgreso,
listarDocumentos,
obtenerCliente,
prefillApartadoEndpoint,
subirDocumentos,
uploadDocumentos,
} from '../controllers/clientes.controller.js'
@@ -54,6 +55,7 @@ import {
crearAfluenciaEndpoint,
crearLeadEndpoint,
buscarLeadsEndpoint,
convertirLeadEndpoint,
descartarLeadEndpoint,
} from '../controllers/leads.controller.js'
import {
@@ -100,6 +102,9 @@ 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)
@@ -157,6 +162,8 @@ 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)