feat(leads): la captura desde una app se asigna al capturista

POST /api/leads con sesion y Monday vinculado asigna el lead a quien lo
registro (mas su actividad de contacto) en vez del round-robin; sin
vinculo o sin token sigue el reparto. Bandera rr:skip para que el
webhook create_item no pise la asignacion durante la propagacion de
Monday (la carrera se observo en el smoke). Mensajes de exito en
/hoy y /client reflejan a quien quedo asignado.
This commit is contained in:
2026-09-03 21:26:20 +00:00
parent d59c8c0d7e
commit f382987fbf
9 changed files with 166 additions and 6 deletions

View File

@@ -225,6 +225,17 @@ describe('AutomatizacionesService.runRoundRobin', () => {
expect(monday.asignaciones).toEqual([{ itemId: '1', userId: 101 }])
})
it('omite leads con bandera rr:skip=capturista (los asigna su capturista)', async () => {
const monday = mondayMock([lead('1'), lead('2')])
const state = stateEnMemoria()
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 }])
})
it('con soloItemId solo evalúa ese item (ruta del webhook create_item)', async () => {
const monday = mondayMock([lead('1'), lead('2')])
const svc = crearServicio(monday, stateEnMemoria())
@@ -326,6 +337,31 @@ describe('Actividades automáticas (ACTIVIDADES_ENABLED)', () => {
expect(monday.actividades).toEqual([])
})
it('asignarACapturista: asigna al capturista y le crea su actividad de contacto', async () => {
const monday = mondayMock([])
const svc = new AutomatizacionesService(monday, stateEnMemoria(), { actividadesEnabled: true })
await svc.asignarACapturista('lead-77', 'Lead Propio', 555)
expect(monday.asignaciones).toEqual([{ itemId: 'lead-77', userId: 555 }])
expect(monday.actividades[0]).toMatchObject({
nombre: 'Contactar a Lead Propio',
responsableId: 555,
estadoLabel: 'Abierto',
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('lead-78', 'Lead Propio', 555)
expect(monday.asignaciones).toEqual([{ itemId: 'lead-78', userId: 555 }])
expect(monday.actividades).toEqual([])
})
it('inactividad: crea "Retomar contacto" al vendedor asignado; sin vendedor no crea nada', async () => {
const monday = mondayMock([
lead('1', { updatedAt: '2026-08-01T00:00:00Z', vendedorIds: [103] }), // inactivo con vendedor