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:
@@ -8,13 +8,14 @@ import {
|
||||
claveVentaCreada,
|
||||
esEstadoTerminal,
|
||||
esEtapa,
|
||||
ESTADOS_TERMINALES_LEAD,
|
||||
oportunidadesInactivas,
|
||||
oportunidadesSinContactar,
|
||||
parseRrUserIds,
|
||||
vendedorEnTurno,
|
||||
type StateStore,
|
||||
} from './automatizaciones.service.js'
|
||||
import type { OportunidadMonday, UsuarioMonday } from './monday.service.js'
|
||||
import type { LeadMonday, OportunidadMonday, UsuarioMonday } from './monday.service.js'
|
||||
|
||||
// ---------- Fixtures ----------
|
||||
|
||||
@@ -24,6 +25,21 @@ const VENDEDORES: UsuarioMonday[] = [
|
||||
{ id: 103, nombre: 'Carla', email: 'carla@x.com' },
|
||||
]
|
||||
|
||||
function lead(id: string, overrides: Partial<LeadMonday> = {}): LeadMonday {
|
||||
return {
|
||||
id,
|
||||
nombre: `Lead ${id}`,
|
||||
createdAt: '2026-08-01T09:00:00Z',
|
||||
updatedAt: '2026-08-01T10:00:00Z',
|
||||
estado: 'Nuevo',
|
||||
origen: '',
|
||||
vendedorIds: [],
|
||||
telefono: '',
|
||||
email: '',
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
function oportunidad(id: string, overrides: Partial<OportunidadMonday> = {}): OportunidadMonday {
|
||||
return {
|
||||
id,
|
||||
@@ -55,10 +71,10 @@ function stateEnMemoria(): StateStore & { mapa: Map<string, string> } {
|
||||
}
|
||||
}
|
||||
|
||||
/** Monday mockeado: oportunidades fijas, registra asignaciones, updates y actividades */
|
||||
function mondayMock(oportunidades: OportunidadMonday[] = []) {
|
||||
/** Monday mockeado: leads y oportunidades fijos, registra asignaciones, updates y actividades */
|
||||
function mondayMock(leads: LeadMonday[] = [], oportunidades: OportunidadMonday[] = []) {
|
||||
return {
|
||||
asignaciones: [] as { itemId: string; userId: number }[],
|
||||
asignaciones: [] as { itemId: string; userId: number; tablero: string }[],
|
||||
updates: [] as { itemId: string; body: string }[],
|
||||
actividades: [] as {
|
||||
nombre: string
|
||||
@@ -70,11 +86,17 @@ function mondayMock(oportunidades: OportunidadMonday[] = []) {
|
||||
}[],
|
||||
apartados: [] as Record<string, unknown>[],
|
||||
ventas: [] as Record<string, unknown>[],
|
||||
async getLeads() {
|
||||
return leads
|
||||
},
|
||||
async getOportunidades() {
|
||||
return oportunidades
|
||||
},
|
||||
async asignarVendedorALead(itemId: string, userId: number) {
|
||||
this.asignaciones.push({ itemId, userId, tablero: 'leads' })
|
||||
},
|
||||
async asignarAsesorAOportunidad(itemId: string, userId: number) {
|
||||
this.asignaciones.push({ itemId, userId })
|
||||
this.asignaciones.push({ itemId, userId, tablero: 'oportunidades' })
|
||||
},
|
||||
async crearUpdateEnItem(itemId: string, body: string) {
|
||||
this.updates.push({ itemId, body })
|
||||
@@ -125,8 +147,8 @@ describe('parseRrUserIds', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('esEstadoTerminal (etapas terminales de Oportunidades)', () => {
|
||||
it('Ganado / Perdido / Abandono son terminales, sin importar mayúsculas ni espacios', () => {
|
||||
describe('esEstadoTerminal (terminales por tablero)', () => {
|
||||
it('Ganado / Perdido / Abandono son terminales en Oportunidades (default)', () => {
|
||||
expect(esEstadoTerminal('GANADO')).toBe(true)
|
||||
expect(esEstadoTerminal(' perdido ')).toBe(true)
|
||||
expect(esEstadoTerminal('Abandono')).toBe(true)
|
||||
@@ -135,6 +157,14 @@ describe('esEstadoTerminal (etapas terminales de Oportunidades)', () => {
|
||||
expect(esEstadoTerminal('Intento de contacto')).toBe(false)
|
||||
expect(esEstadoTerminal('')).toBe(false)
|
||||
})
|
||||
|
||||
it('Descartado / Calificado / Abandono son terminales en Leads (title case, case-insensitive)', () => {
|
||||
expect(esEstadoTerminal('Descartado', ESTADOS_TERMINALES_LEAD)).toBe(true)
|
||||
expect(esEstadoTerminal('calificado', ESTADOS_TERMINALES_LEAD)).toBe(true)
|
||||
expect(esEstadoTerminal('ABANDONO', ESTADOS_TERMINALES_LEAD)).toBe(true)
|
||||
expect(esEstadoTerminal('Nuevo', ESTADOS_TERMINALES_LEAD)).toBe(false)
|
||||
expect(esEstadoTerminal('Contactado', ESTADOS_TERMINALES_LEAD)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('vendedorEnTurno (rotación round-robin)', () => {
|
||||
@@ -188,18 +218,24 @@ describe('claveRecordatorio (dedup por día)', () => {
|
||||
// ---------- Servicio (monday mockeado, sin red) ----------
|
||||
|
||||
describe('AutomatizacionesService.runRoundRobin', () => {
|
||||
it('asigna asesores en rotación a afluencias sin persona y persiste el índice', async () => {
|
||||
const monday = mondayMock([oportunidad('1'), oportunidad('2'), oportunidad('3'), oportunidad('4')])
|
||||
it('asigna en rotación sobre AMBOS tableros y persiste el índice (Leads → Vendedor, Oportunidades → Asesor)', async () => {
|
||||
const monday = mondayMock([lead('l1'), lead('l2')], [oportunidad('o1'), oportunidad('o2')])
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
|
||||
const r1 = await svc.runRoundRobin()
|
||||
expect(r1.asignados).toBe(4)
|
||||
expect(monday.asignaciones.map((a) => a.userId)).toEqual([101, 102, 103, 101])
|
||||
expect(monday.asignaciones).toEqual([
|
||||
{ itemId: 'l1', userId: 101, tablero: 'leads' },
|
||||
{ itemId: 'l2', userId: 102, tablero: 'leads' },
|
||||
{ itemId: 'o1', userId: 103, tablero: 'oportunidades' },
|
||||
{ itemId: 'o2', userId: 101, tablero: 'oportunidades' },
|
||||
])
|
||||
expect(r1.detalle.map((d) => d.tablero)).toEqual(['leads', 'leads', 'oportunidades', 'oportunidades'])
|
||||
expect(state.mapa.get('rr:indice')).toBe('1') // 4 asignaciones % 3 vendedores
|
||||
|
||||
// Segunda pasada con una afluencia nueva: continúa donde quedó (no reinicia en 0)
|
||||
const monday2 = mondayMock([oportunidad('5')])
|
||||
const monday2 = mondayMock([], [oportunidad('o5')])
|
||||
const svc2 = new AutomatizacionesService(monday2, state)
|
||||
const r2 = await svc2.runRoundRobin()
|
||||
expect(r2.asignados).toBe(1)
|
||||
@@ -207,8 +243,25 @@ describe('AutomatizacionesService.runRoundRobin', () => {
|
||||
expect(state.mapa.get('rr:indice')).toBe('2')
|
||||
})
|
||||
|
||||
it('solo reparte etapa Afluencia: Cotizador/Contactado NO entran al reparto', async () => {
|
||||
it('Leads: reparte los sin Vendedor y no terminales (labels title case, case-insensitive)', async () => {
|
||||
const monday = mondayMock([
|
||||
lead('1'),
|
||||
lead('2', { vendedorIds: [101] }), // ya asignado
|
||||
lead('3', { estado: 'Descartado' }), // terminal
|
||||
lead('4', { estado: 'Calificado' }), // terminal
|
||||
lead('5', { estado: 'Contactado' }), // en seguimiento: sí entra
|
||||
])
|
||||
const svc = crearServicio(monday, stateEnMemoria())
|
||||
const r = await svc.runRoundRobin(undefined, 'leads')
|
||||
expect(r.asignados).toBe(2)
|
||||
expect(monday.asignaciones).toEqual([
|
||||
{ itemId: '1', userId: 101, tablero: 'leads' },
|
||||
{ itemId: '5', userId: 102, tablero: 'leads' },
|
||||
])
|
||||
})
|
||||
|
||||
it('Oportunidades: solo reparte etapa Afluencia (Cotizador/Contactado NO entran)', async () => {
|
||||
const monday = mondayMock([], [
|
||||
oportunidad('1'),
|
||||
oportunidad('2', { asesorIds: [101] }), // ya asignada
|
||||
oportunidad('3', { etapa: 'Cotizador' }), // creada por el cotizador: no entra
|
||||
@@ -217,35 +270,43 @@ describe('AutomatizacionesService.runRoundRobin', () => {
|
||||
oportunidad('6', { etapa: 'afluencia' }), // case-insensitive: sí entra
|
||||
])
|
||||
const svc = crearServicio(monday, stateEnMemoria())
|
||||
const r = await svc.runRoundRobin()
|
||||
const r = await svc.runRoundRobin(undefined, 'oportunidades')
|
||||
expect(r.asignados).toBe(2)
|
||||
expect(monday.asignaciones).toEqual([
|
||||
{ itemId: '1', userId: 101 },
|
||||
{ itemId: '6', userId: 102 },
|
||||
{ itemId: '1', userId: 101, tablero: 'oportunidades' },
|
||||
{ itemId: '6', userId: 102, tablero: 'oportunidades' },
|
||||
])
|
||||
})
|
||||
|
||||
it('omite afluencias con bandera rr:skip=capturista (las asigna su capturista)', async () => {
|
||||
const monday = mondayMock([oportunidad('1'), oportunidad('2')])
|
||||
it('omite items con bandera rr:skip=capturista (los asigna su capturista)', async () => {
|
||||
const monday = mondayMock([lead('1')], [oportunidad('2')])
|
||||
const state = stateEnMemoria()
|
||||
state.mapa.set('rr:skip:1', 'capturista') // el capturista la asigna
|
||||
state.mapa.set('rr:skip:1', 'capturista') // el capturista lo asigna
|
||||
state.mapa.set('rr:skip:2', 'round-robin') // bandera liberada: sí entra al reparto
|
||||
const svc = crearServicio(monday, state)
|
||||
const r = await svc.runRoundRobin()
|
||||
expect(r.asignados).toBe(1)
|
||||
expect(monday.asignaciones).toEqual([{ itemId: '2', userId: 101 }])
|
||||
expect(monday.asignaciones).toEqual([{ itemId: '2', userId: 101, tablero: 'oportunidades' }])
|
||||
})
|
||||
|
||||
it('con soloItemId solo evalúa ese item (ruta del webhook create_item)', async () => {
|
||||
const monday = mondayMock([oportunidad('1'), oportunidad('2')])
|
||||
it('con soloItemId + board solo evalúa ese item (ruta de los webhooks create_item)', async () => {
|
||||
const monday = mondayMock([lead('1'), lead('2')], [oportunidad('9')])
|
||||
const svc = crearServicio(monday, stateEnMemoria())
|
||||
const r = await svc.runRoundRobin('2')
|
||||
const r = await svc.runRoundRobin('2', 'leads')
|
||||
expect(r.asignados).toBe(1)
|
||||
expect(monday.asignaciones).toEqual([{ itemId: '2', userId: 101 }])
|
||||
expect(monday.asignaciones).toEqual([{ itemId: '2', userId: 101, tablero: 'leads' }])
|
||||
})
|
||||
|
||||
it('con soloItemId de otro tablero no asigna nada', async () => {
|
||||
const monday = mondayMock([lead('1')], [oportunidad('9')])
|
||||
const svc = crearServicio(monday, stateEnMemoria())
|
||||
const r = await svc.runRoundRobin('9', 'leads') // '9' no está en Leads
|
||||
expect(r.asignados).toBe(0)
|
||||
expect(monday.asignaciones).toEqual([])
|
||||
})
|
||||
|
||||
it('cachea los vendedores del equipo en el estado (una sola llamada dentro del TTL)', async () => {
|
||||
const monday = mondayMock([])
|
||||
const monday = mondayMock()
|
||||
const spy = vi.spyOn(monday, 'getUsuariosEquipo')
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
@@ -258,7 +319,7 @@ describe('AutomatizacionesService.runRoundRobin', () => {
|
||||
})
|
||||
|
||||
it('cache con formato viejo (arreglo sin ts) se descarta y re-consulta', async () => {
|
||||
const monday = mondayMock([])
|
||||
const monday = mondayMock()
|
||||
const spy = vi.spyOn(monday, 'getUsuariosEquipo')
|
||||
const state = stateEnMemoria()
|
||||
state.mapa.set('rr:vendedores', JSON.stringify([{ id: 999, nombre: 'Viejo', email: '' }]))
|
||||
@@ -277,7 +338,7 @@ describe('AutomatizacionesService.escaneoInactividad', () => {
|
||||
]
|
||||
|
||||
it('preview: lista candidatos sin escribir en Monday ni en el estado', async () => {
|
||||
const monday = mondayMock(oportunidadesViejas())
|
||||
const monday = mondayMock([], oportunidadesViejas())
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
|
||||
@@ -291,7 +352,7 @@ describe('AutomatizacionesService.escaneoInactividad', () => {
|
||||
})
|
||||
|
||||
it('ejecución real: crea update, marca dedup y no repite el mismo día', async () => {
|
||||
const monday = mondayMock(oportunidadesViejas())
|
||||
const monday = mondayMock([], oportunidadesViejas())
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
|
||||
@@ -320,7 +381,7 @@ describe('Actividades automáticas (ACTIVIDADES_ENABLED)', () => {
|
||||
const ahora = new Date('2026-08-22T09:00:00Z')
|
||||
|
||||
it('el round-robin crea "Contactar a {nombre}" tipo Llamada, Abierto, ligada a la oportunidad', async () => {
|
||||
const monday = mondayMock([oportunidad('1'), oportunidad('2')])
|
||||
const monday = mondayMock([], [oportunidad('1'), oportunidad('2')])
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: true })
|
||||
|
||||
const r = await svc.runRoundRobin()
|
||||
@@ -343,7 +404,7 @@ describe('Actividades automáticas (ACTIVIDADES_ENABLED)', () => {
|
||||
})
|
||||
|
||||
it('con actividadesEnabled=false el round-robin no crea actividades', async () => {
|
||||
const monday = mondayMock([oportunidad('1')])
|
||||
const monday = mondayMock([], [oportunidad('1')])
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: false })
|
||||
await svc.runRoundRobin()
|
||||
expect(monday.actividades).toEqual([])
|
||||
@@ -355,7 +416,7 @@ describe('Actividades automáticas (ACTIVIDADES_ENABLED)', () => {
|
||||
|
||||
await svc.asignarACapturista('op-77', 'Lead Propio', 555)
|
||||
|
||||
expect(monday.asignaciones).toEqual([{ itemId: 'op-77', userId: 555 }])
|
||||
expect(monday.asignaciones).toEqual([{ itemId: 'op-77', userId: 555, tablero: 'oportunidades' }])
|
||||
expect(monday.actividades[0]).toMatchObject({
|
||||
nombre: 'Contactar a Lead Propio',
|
||||
responsableId: 555,
|
||||
@@ -364,18 +425,28 @@ describe('Actividades automáticas (ACTIVIDADES_ENABLED)', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('asignarACapturista con board "leads" escribe la columna Vendedor del tablero Leads', async () => {
|
||||
const monday = mondayMock([])
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: true })
|
||||
|
||||
await svc.asignarACapturista('lead-77', 'Lead Propio', 555, 'leads')
|
||||
|
||||
expect(monday.asignaciones).toEqual([{ itemId: 'lead-77', userId: 555, tablero: 'leads' }])
|
||||
expect(monday.actividades[0]).toMatchObject({ nombre: 'Contactar a Lead Propio', leadItemId: 'lead-77' })
|
||||
})
|
||||
|
||||
it('asignarACapturista con actividadesEnabled=false solo asigna', async () => {
|
||||
const monday = mondayMock([])
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: false })
|
||||
|
||||
await svc.asignarACapturista('op-78', 'Lead Propio', 555)
|
||||
|
||||
expect(monday.asignaciones).toEqual([{ itemId: 'op-78', userId: 555 }])
|
||||
expect(monday.asignaciones).toEqual([{ itemId: 'op-78', userId: 555, tablero: 'oportunidades' }])
|
||||
expect(monday.actividades).toEqual([])
|
||||
})
|
||||
|
||||
it('inactividad: crea "Retomar contacto" al asesor asignado; las candidatas siempre tienen asesor', async () => {
|
||||
const monday = mondayMock([oportunidad('1', { updatedAt: '2026-08-01T00:00:00Z', asesorIds: [103] })])
|
||||
const monday = mondayMock([], [oportunidad('1', { updatedAt: '2026-08-01T00:00:00Z', asesorIds: [103] })])
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: true })
|
||||
|
||||
const r = await svc.escaneoInactividad({ preview: false, ahora })
|
||||
@@ -391,21 +462,21 @@ describe('Actividades automáticas (ACTIVIDADES_ENABLED)', () => {
|
||||
})
|
||||
|
||||
it('preview de inactividad no crea actividades', async () => {
|
||||
const monday = mondayMock([oportunidad('1', { updatedAt: '2026-08-01T00:00:00Z', asesorIds: [101] })])
|
||||
const monday = mondayMock([], [oportunidad('1', { updatedAt: '2026-08-01T00:00:00Z', asesorIds: [101] })])
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: true })
|
||||
await svc.escaneoInactividad({ preview: true, ahora })
|
||||
expect(monday.actividades).toEqual([])
|
||||
})
|
||||
|
||||
it('un fallo al crear la actividad no rompe la asignación', async () => {
|
||||
const monday = mondayMock([oportunidad('1')])
|
||||
const monday = mondayMock([], [oportunidad('1')])
|
||||
vi.spyOn(monday, 'crearActividad').mockRejectedValueOnce(new Error('Monday caído'))
|
||||
const spyError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: true })
|
||||
|
||||
const r = await svc.runRoundRobin()
|
||||
expect(r.asignados).toBe(1) // la asignación se hizo igual
|
||||
expect(monday.asignaciones).toEqual([{ itemId: '1', userId: 101 }])
|
||||
expect(monday.asignaciones).toEqual([{ itemId: '1', userId: 101, tablero: 'oportunidades' }])
|
||||
spyError.mockRestore()
|
||||
})
|
||||
})
|
||||
@@ -462,7 +533,7 @@ describe('AutomatizacionesService.escaneoEscalado', () => {
|
||||
const anterior = configAuto['coordinadorUserId']
|
||||
configAuto['coordinadorUserId'] = 0
|
||||
try {
|
||||
const monday = mondayMock([oportunidad('1', { asesorIds: [102], updatedAt: '2026-08-19T12:00:00Z' })])
|
||||
const monday = mondayMock([], [oportunidad('1', { asesorIds: [102], updatedAt: '2026-08-19T12:00:00Z' })])
|
||||
const state = stateEnMemoria()
|
||||
const svc = new AutomatizacionesService(monday, state, { actividadesEnabled: true })
|
||||
|
||||
@@ -487,7 +558,7 @@ describe('AutomatizacionesService.escaneoEscalado', () => {
|
||||
const anterior = configAuto['coordinadorUserId']
|
||||
configAuto['coordinadorUserId'] = 999
|
||||
try {
|
||||
const monday = mondayMock([oportunidad('1', { asesorIds: [102], updatedAt: '2026-08-19T12:00:00Z' })])
|
||||
const monday = mondayMock([], [oportunidad('1', { asesorIds: [102], updatedAt: '2026-08-19T12:00:00Z' })])
|
||||
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: true })
|
||||
const r = await svc.escaneoEscalado({ ahora })
|
||||
expect(r.escalados).toBe(1)
|
||||
@@ -502,7 +573,7 @@ describe('AutomatizacionesService.escaneoEscalado', () => {
|
||||
const anterior = configAuto['coordinadorUserId']
|
||||
configAuto['coordinadorUserId'] = 0
|
||||
try {
|
||||
const monday = mondayMock([oportunidad('1', { asesorIds: [101], updatedAt: '2026-08-19T12:00:00Z' })])
|
||||
const monday = mondayMock([], [oportunidad('1', { asesorIds: [101], updatedAt: '2026-08-19T12:00:00Z' })])
|
||||
const state = stateEnMemoria()
|
||||
const svc = new AutomatizacionesService(monday, state, { actividadesEnabled: true })
|
||||
|
||||
@@ -523,7 +594,7 @@ describe('AutomatizacionesService.escaneoEscalado', () => {
|
||||
configAuto['coordinadorUserId'] = 0
|
||||
const spyError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
try {
|
||||
const monday = mondayMock([
|
||||
const monday = mondayMock([], [
|
||||
oportunidad('1', { asesorIds: [101], updatedAt: '2026-08-19T12:00:00Z' }),
|
||||
oportunidad('2', { asesorIds: [102], updatedAt: '2026-08-19T12:00:00Z' }),
|
||||
])
|
||||
@@ -546,7 +617,7 @@ describe('AutomatizacionesService.escaneoEscalado', () => {
|
||||
|
||||
describe('AutomatizacionesService.escaneoOportunidades', () => {
|
||||
it('una oportunidad en Aparto crea su item en Apartado (estado Pago Apartado)', async () => {
|
||||
const monday = mondayMock([oportunidad('10', { etapa: 'Aparto' })])
|
||||
const monday = mondayMock([], [oportunidad('10', { etapa: 'Aparto' })])
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
|
||||
@@ -562,7 +633,7 @@ describe('AutomatizacionesService.escaneoOportunidades', () => {
|
||||
})
|
||||
|
||||
it('una oportunidad en Ganado crea su item en Ventas con unidad y valor', async () => {
|
||||
const monday = mondayMock([oportunidad('11', { etapa: 'GANADO' })])
|
||||
const monday = mondayMock([], [oportunidad('11', { etapa: 'GANADO' })])
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
|
||||
@@ -573,7 +644,7 @@ describe('AutomatizacionesService.escaneoOportunidades', () => {
|
||||
})
|
||||
|
||||
it('dedup: la segunda pasada no duplica apartados ni ventas', async () => {
|
||||
const monday = mondayMock([oportunidad('10', { etapa: 'Aparto' }), oportunidad('11', { etapa: 'Ganado' })])
|
||||
const monday = mondayMock([], [oportunidad('10', { etapa: 'Aparto' }), oportunidad('11', { etapa: 'Ganado' })])
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
|
||||
@@ -588,7 +659,7 @@ describe('AutomatizacionesService.escaneoOportunidades', () => {
|
||||
})
|
||||
|
||||
it('ignora oportunidades en otras etapas', async () => {
|
||||
const monday = mondayMock([
|
||||
const monday = mondayMock([], [
|
||||
oportunidad('10', { etapa: 'Cotizador' }),
|
||||
oportunidad('11', { etapa: 'Perdido' }),
|
||||
oportunidad('12', { etapa: 'Afluencia' }),
|
||||
@@ -602,7 +673,7 @@ describe('AutomatizacionesService.escaneoOportunidades', () => {
|
||||
})
|
||||
|
||||
it('un fallo de Monday en una oportunidad no detiene a las demás', async () => {
|
||||
const monday = mondayMock([oportunidad('10', { etapa: 'Aparto' }), oportunidad('11', { etapa: 'Ganado' })])
|
||||
const monday = mondayMock([], [oportunidad('10', { etapa: 'Aparto' }), oportunidad('11', { etapa: 'Ganado' })])
|
||||
vi.spyOn(monday, 'crearApartado').mockRejectedValueOnce(new Error('Monday caído'))
|
||||
const state = stateEnMemoria()
|
||||
const svc = crearServicio(monday, state)
|
||||
|
||||
Reference in New Issue
Block a user