feat(leads): doble via de captura — lead rapido a Leads, afluencia a Oportunidades

- POST /api/leads: captura ligera al tablero Leads (sin oportunidad),
  self-assign a Vendedor o round-robin; tambien cubre la captura manual
  desde la UI de Monday (webhook create_item re-registrado).
- POST /api/afluencias (nuevo): la forma completa sigue cayendo en
  Oportunidades con todo el perfil (etapa Afluencia, columna Asesor).
- Round-robin dual (ambos tableros), Mi dia mezcla leads+oportunidades
  con insignia de origen, acciones con parametro fuente, reportes:
  leads desde Leads, perfilamiento desde Oportunidades, funnel
  Leads->Afluencia->...->Ganado.
This commit is contained in:
2026-09-04 06:09:38 +00:00
parent 772fdef09f
commit 135e3e6de5
21 changed files with 1053 additions and 326 deletions

View File

@@ -45,6 +45,7 @@ export function webhookMonday(req: Request, res: Response): void {
}
const { type, boardId, itemId, pulseId } = parsed.data.event
const esBoardLeads = String(boardId) === config.monday.boards.leads
const esBoardOportunidades = String(boardId) === config.monday.boards.oportunidades
const idEvento = itemId ?? pulseId
@@ -53,26 +54,26 @@ export function webhookMonday(req: Request, res: Response): void {
// Monday registra el webhook como 'create_item' pero el payload real llega
// como 'create_pulse'; se aceptan ambos.
// Item nuevo en Oportunidades → solo round-robin (la afluencia entra en
// etapa 'Afluencia' sin asesor; las del cotizador nacen en 'Cotizador' y el
// servicio las salta). El grupo NO se arregla aquí: recién creado el item aún
// no tiene Estado (moverAGrupoSegunEstado no haría nada) y el create con
// column_values no dispara el webhook de change — para items creados a mano
// en la UI, el grupo lo corrige la próxima vez que cambie una columna.
// (El tablero Leads quedó como archivo histórico: ya no tiene automatización
// de create; su webhook se desregistra en Monday.)
if ((type === 'create_item' || type === 'create_pulse') && esBoardOportunidades && idEvento !== undefined) {
// Item nuevo en Leads u Oportunidades → solo round-robin del tablero
// correspondiente (los leads NO crean oportunidad; el Alta Afluencia entra
// directo a Oportunidades vía POST /api/afluencias). El grupo NO se arregla
// aquí: recién creado el item aún no tiene Estado (moverAGrupoSegunEstado no
// haría nada) y el create con column_values no dispara el webhook de change —
// para items creados a mano en la UI, el grupo lo corrige la próxima vez que
// cambie una columna.
if ((type === 'create_item' || type === 'create_pulse') && (esBoardLeads || esBoardOportunidades) && idEvento !== undefined) {
const id = String(idEvento)
const board = esBoardLeads ? 'leads' : 'oportunidades'
// Fire-and-forget: la respuesta 200 no espera a que termine la asignación
void automatizacionesService
.runRoundRobin(id)
.runRoundRobin(id, board)
.then((r) => {
// eslint-disable-next-line no-console
console.log(`[webhook monday] round-robin item=${id}: ${r.asignados} asignado(s)`)
console.log(`[webhook monday] round-robin ${board} item=${id}: ${r.asignados} asignado(s)`)
})
.catch((err: unknown) => {
// eslint-disable-next-line no-console
console.error(`[webhook monday] error en round-robin item=${id}:`, err)
console.error(`[webhook monday] error en round-robin ${board} item=${id}:`, err)
})
}