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:
@@ -557,6 +557,97 @@ describe('MondayService', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('asignarVendedorALead (columna people Vendedor del tablero Leads)', () => {
|
||||
it('escribe personsAndTeams con el user id en el board Leads (444 en tests)', async () => {
|
||||
const llamadas = mockearFetch((body) => {
|
||||
if (body.query.includes('columns')) {
|
||||
return respuestaOk({ boards: [{ columns: [{ id: 'people_v', title: 'Vendedor', type: 'people' }] }] })
|
||||
}
|
||||
return respuestaOk({ change_column_value: { id: 'lead-1' } })
|
||||
})
|
||||
|
||||
await crearServicio().asignarVendedorALead('lead-1', 12345)
|
||||
|
||||
const mutacion = llamadas.find((l) => l.body.query.includes('change_column_value'))
|
||||
expect(mutacion?.body.variables['boardId']).toBe('444')
|
||||
expect(mutacion?.body.variables['columnId']).toBe('people_v')
|
||||
expect(JSON.parse(String(mutacion?.body.variables['value']))).toEqual({
|
||||
personsAndTeams: [{ id: 12345, kind: 'person' }],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('crearLead (captura ligera en el tablero Leads)', () => {
|
||||
const COLUMNAS_LEADS_LIGERO = [
|
||||
{ id: 'color_estado', title: 'Estado', type: 'status' },
|
||||
{ id: 'date_fecha', title: 'Fecha', type: 'date' },
|
||||
{ id: 'phone_tel', title: 'Teléfono', type: 'phone' },
|
||||
{ id: 'email_em', title: 'Email', type: 'email' },
|
||||
{ id: 'color_or', title: 'Origen', type: 'status' },
|
||||
{ id: 'color_des', title: 'Desarrollo', type: 'status' },
|
||||
{ id: 'text_notas', title: 'Notas', type: 'text' },
|
||||
]
|
||||
|
||||
it('crea el item ligero con Estado NUEVO y Fecha de hoy (sin perfil ni oportunidad)', async () => {
|
||||
const llamadas = mockearFetch((body) => {
|
||||
if (body.query.includes('settings_str')) {
|
||||
return respuestaOk({
|
||||
boards: [
|
||||
{
|
||||
columns: COLUMNAS_LEADS_LIGERO.filter((c) => c.type === 'status').map((c) => ({
|
||||
id: c.id,
|
||||
title: c.title,
|
||||
settings_str: '{"labels":{"1":"Nuevo"}}',
|
||||
})),
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
if (body.query.includes('columns')) return respuestaOk({ boards: [{ columns: COLUMNAS_LEADS_LIGERO }] })
|
||||
return respuestaOk({ create_item: { id: 'lead-nuevo-1' } })
|
||||
})
|
||||
|
||||
const id = await crearServicio().crearLead({
|
||||
nombre: 'Lead Prueba',
|
||||
telefono: '4771234567',
|
||||
email: 'lead@correo.com',
|
||||
origenLabel: 'Facebook',
|
||||
desarrolloLabel: 'SENDA',
|
||||
notas: 'Vio el volante',
|
||||
})
|
||||
expect(id).toBe('lead-nuevo-1')
|
||||
|
||||
const mutacion = llamadas.find((l) => l.body.query.includes('create_item'))
|
||||
expect(mutacion?.body.variables['boardId']).toBe('444') // tablero Leads
|
||||
const parsed = JSON.parse(String(mutacion?.body.variables['columnValues'])) as Record<string, unknown>
|
||||
expect(parsed['color_estado']).toEqual({ label: 'Nuevo' }) // 'NUEVO' resuelto al label real
|
||||
expect(parsed['date_fecha']).toMatchObject({ date: expect.stringMatching(/^\d{4}-\d{2}-\d{2}$/) })
|
||||
expect(parsed['phone_tel']).toEqual({ phone: '4771234567', countryShortName: 'MX' })
|
||||
expect(parsed['email_em']).toEqual({ email: 'lead@correo.com', text: 'lead@correo.com' })
|
||||
expect(parsed['color_or']).toEqual({ label: 'Facebook' })
|
||||
expect(parsed['color_des']).toEqual({ label: 'SENDA' })
|
||||
expect(parsed['text_notas']).toBe('Vio el volante')
|
||||
})
|
||||
|
||||
it('solo envía las columnas capturadas (las vacías se omiten)', async () => {
|
||||
const llamadas = mockearFetch((body) => {
|
||||
if (body.query.includes('settings_str')) {
|
||||
return respuestaOk({
|
||||
boards: [{ columns: [{ id: 'color_estado', title: 'Estado', settings_str: '{"labels":{"1":"Nuevo"}}' }] }],
|
||||
})
|
||||
}
|
||||
if (body.query.includes('columns')) return respuestaOk({ boards: [{ columns: COLUMNAS_LEADS_LIGERO }] })
|
||||
return respuestaOk({ create_item: { id: 'lead-nuevo-2' } })
|
||||
})
|
||||
|
||||
await crearServicio().crearLead({ nombre: 'Solo Nombre' })
|
||||
|
||||
const mutacion = llamadas.find((l) => l.body.query.includes('create_item'))
|
||||
const parsed = JSON.parse(String(mutacion?.body.variables['columnValues'])) as Record<string, unknown>
|
||||
expect(Object.keys(parsed).sort()).toEqual(['color_estado', 'date_fecha'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('asignarAsesorAOportunidad (columna people Asesor)', () => {
|
||||
it('escribe personsAndTeams con el user id en el board Oportunidades (555 en tests)', async () => {
|
||||
const llamadas = mockearFetch((body) => {
|
||||
|
||||
Reference in New Issue
Block a user