refactor: las afluencias viven en Oportunidades (no en Leads)

- POST /api/leads crea UN solo item en Oportunidades (Estado Afluencia)
  con todo el perfil (desarrollo, modelo, estado civil, credito, etc.)
  en las columnas del board; dedup por telefono contra Oportunidades;
  asignacion al capturista via columna Asesor o round-robin del equipo.
- Round-robin, escalado e inactividad operan sobre Oportunidades (solo
  etapa Afluencia sin asesor entra al reparto).
- Acciones del vendedor (contactado/cita/descartar) escriben directo en
  la oportunidad; descarte = Perdido + Motivo No Compra.
- Mi dia y reportes leen Oportunidades; el funnel de /dash arranca en
  Afluencia; misOportunidades.porEtapa ya es real (columna Asesor).
- El picker del alta busca en Leads (historico) Y Oportunidades, con
  insignia de origen; moverAAparto tolera ambos ids.
- Lectura de status con value null = vacio (quirk del default Monday).
- Script de migracion del historial de agosto Leads -> Oportunidades.
This commit is contained in:
2026-09-04 04:46:34 +00:00
parent d4fc9ee892
commit 845f314560
26 changed files with 1496 additions and 985 deletions

View File

@@ -104,8 +104,10 @@ export function unidadesEnEtapa(resumen: ResumenReportes, etapa: string): number
}
/**
* Datos del funnel comercial: Leads → Oportunidades → Aparto o más → Ganado.
* "Aparto o más" es acumulado (Aparto + Ganado) para que el funnel no suba.
* Datos del funnel comercial, todo desde el tablero Oportunidades (la
* afluencia ES la oportunidad en etapa 'Afluencia'): Afluencia → Agendo Cita
* → Cotizador → Aparto o más → Ganado. "Aparto o más" es acumulado
* (Aparto + Ganado) porque Aparto es subconjunto del camino a Ganado.
*/
export function datosFunnel(resumen: ResumenReportes): EtapaFunnel[] {
const porEtapa = resumen.oportunidades.porEtapa
@@ -115,8 +117,9 @@ export function datosFunnel(resumen: ResumenReportes): EtapaFunnel[] {
.reduce((acc, [, v]) => acc + v, 0)
const apartoOMas = conteo('APARTO') + conteo('GANADO')
return [
{ etapa: 'Leads', valor: resumen.leads.total },
{ etapa: 'Oportunidades', valor: resumen.oportunidades.total },
{ etapa: 'Afluencia', valor: conteo('AFLUENCIA') },
{ etapa: 'Agendo Cita', valor: conteo('AGENDO CITA') },
{ etapa: 'Cotizador', valor: conteo('COTIZADOR') },
{ etapa: 'Aparto o más', valor: apartoOMas },
{ etapa: 'Ganado', valor: conteo('GANADO') },
]