feat(mi-dia): seccion 'Mis capturas de afluencia' en el panel del vendedor
Nueva tabla LeadCaptura (quien capturo cada lead, algo que Monday no guarda porque el creador del item siempre es el token del API). El POST /api/leads la registra con el usuario del token y el resumen de Mi dia la enriquece con el estado/origen actual del lead en Monday. La captura rapida refresca el panel al registrar.
This commit is contained in:
@@ -83,7 +83,7 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => {
|
||||
lead({ id: '6', estado: 'NUEVO', vendedorIds: [OTRO_ID] }),
|
||||
],
|
||||
})
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), AHORA)
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), [], AHORA)
|
||||
expect(r.sinMapeoMonday).toBe(false)
|
||||
expect(r.misLeads.map((l) => l.id)).toEqual(['1', '2'])
|
||||
expect(r.misLeads[1]?.telefono).toBe('4771234567')
|
||||
@@ -101,7 +101,7 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => {
|
||||
actividad({ id: 'a7', fecha: '' }), // sin fecha: no
|
||||
],
|
||||
})
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), AHORA)
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), [], AHORA)
|
||||
// Ordenadas por fecha: vencida primero
|
||||
expect(r.misActividadesHoy.map((a) => a.id)).toEqual(['a3', 'a1', 'a2'])
|
||||
expect(r.conteos.actividadesAbiertas).toBe(5) // abiertas mías: a1,a2,a3,a4,a7
|
||||
@@ -118,7 +118,7 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => {
|
||||
apartado({ id: 'p6', fechaLimite: '2026-09-01', estado: 'Cancelacion' }),
|
||||
],
|
||||
})
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), AHORA)
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), [], AHORA)
|
||||
expect(r.apartadosPorVencer.map((a) => a.id)).toEqual(['p1', 'p2'])
|
||||
expect(r.apartadosPorVencer[0]?.diasRestantes).toBe(0)
|
||||
expect(r.apartadosPorVencer[1]?.diasRestantes).toBe(7)
|
||||
@@ -130,7 +130,7 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => {
|
||||
actividades: [actividad({ id: 'a1' })],
|
||||
apartados: [apartado({ id: 'p1' })],
|
||||
})
|
||||
const r = await resumenMiDia(monday, sinMapeo, new Map(), AHORA)
|
||||
const r = await resumenMiDia(monday, sinMapeo, new Map(), [], AHORA)
|
||||
expect(r.sinMapeoMonday).toBe(true)
|
||||
expect(r.misLeads).toEqual([])
|
||||
expect(r.misActividadesHoy).toEqual([])
|
||||
@@ -148,12 +148,12 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => {
|
||||
lead({ id: '4', createdAt: '2026-08-27T08:00:00', vendedorIds: [OTRO_ID] }), // de otro
|
||||
],
|
||||
})
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), AHORA)
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), [], AHORA)
|
||||
expect(r.conteos.leadsNuevosSemana).toBe(2)
|
||||
})
|
||||
|
||||
it('oportunidades se omiten con nota (el board no tiene columna de asesor)', async () => {
|
||||
const r = await resumenMiDia(mondayMock({}), vendedor, new Map(), AHORA)
|
||||
const r = await resumenMiDia(mondayMock({}), vendedor, new Map(), [], AHORA)
|
||||
expect(r.misOportunidades).toBeNull()
|
||||
expect(r.notaOportunidades).toContain('asesor')
|
||||
})
|
||||
@@ -171,10 +171,10 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => {
|
||||
})
|
||||
const nombres = new Map([[MI_ID, 'Martin Zavala']])
|
||||
|
||||
const rVendedor = await resumenMiDia(monday, vendedor, nombres, AHORA)
|
||||
const rVendedor = await resumenMiDia(monday, vendedor, nombres, [], AHORA)
|
||||
expect(rVendedor.equipo).toBeUndefined()
|
||||
|
||||
const rCoord = await resumenMiDia(monday, coordinador, nombres, AHORA)
|
||||
const rCoord = await resumenMiDia(monday, coordinador, nombres, [], AHORA)
|
||||
expect(rCoord.equipo?.leadsNuevosSinAsignar).toBe(1)
|
||||
expect(rCoord.equipo?.porVendedor).toEqual([
|
||||
{ mondayUserId: OTRO_ID, nombre: null, leadsAsignados: 2, leadsNuevosSemana: 1 },
|
||||
@@ -185,10 +185,57 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => {
|
||||
it('corporativo y admin también ven equipo', async () => {
|
||||
const monday = mondayMock({ leads: [lead({ id: '1' })] })
|
||||
for (const rol of ['corporativo', 'admin']) {
|
||||
const r = await resumenMiDia(monday, { nombre: 'X', rol, mondayUserId: null }, new Map(), AHORA)
|
||||
const r = await resumenMiDia(monday, { nombre: 'X', rol, mondayUserId: null }, new Map(), [], AHORA)
|
||||
expect(r.equipo).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it('mis capturas: enriquecidas con el estado/origen actual del lead en Monday', async () => {
|
||||
const monday = mondayMock({
|
||||
leads: [lead({ id: '100', nombre: 'Ana López', estado: 'CONTACTADO', origen: 'WhatsApp', vendedorIds: [OTRO_ID] })],
|
||||
})
|
||||
const capturas = [
|
||||
{ leadId: '100', nombreLead: 'Ana López', telefono: '6641112233', createdAt: new Date('2026-08-27T09:00:00Z') },
|
||||
]
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), capturas, AHORA)
|
||||
// Aunque el lead quedó asignado a OTRO por round-robin, la captura es mía
|
||||
expect(r.misCapturas).toEqual([
|
||||
{
|
||||
leadId: '100',
|
||||
nombre: 'Ana López',
|
||||
telefono: '6641112233',
|
||||
estado: 'CONTACTADO',
|
||||
origen: 'WhatsApp',
|
||||
capturadoEn: '2026-08-27T09:00:00.000Z',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('mis capturas: si el lead ya no existe en Monday, estado y origen van vacíos', async () => {
|
||||
const monday = mondayMock({})
|
||||
const capturas = [
|
||||
{ leadId: 'borrado-1', nombreLead: 'Lead Borrado', telefono: null, createdAt: new Date('2026-08-26T09:00:00Z') },
|
||||
]
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), capturas, AHORA)
|
||||
expect(r.misCapturas).toEqual([
|
||||
{ leadId: 'borrado-1', nombre: 'Lead Borrado', telefono: '', estado: '', origen: '', capturadoEn: '2026-08-26T09:00:00.000Z' },
|
||||
])
|
||||
})
|
||||
|
||||
it('mis capturas: ordenadas por fecha de captura descendente', async () => {
|
||||
const monday = mondayMock({})
|
||||
const capturas = [
|
||||
{ leadId: '1', nombreLead: 'Antiguo', telefono: null, createdAt: new Date('2026-08-20T09:00:00Z') },
|
||||
{ leadId: '2', nombreLead: 'Reciente', telefono: null, createdAt: new Date('2026-08-27T09:00:00Z') },
|
||||
]
|
||||
const r = await resumenMiDia(monday, vendedor, new Map(), capturas, AHORA)
|
||||
expect(r.misCapturas.map((c) => c.leadId)).toEqual(['2', '1'])
|
||||
})
|
||||
|
||||
it('sin capturas: misCapturas va vacío', async () => {
|
||||
const r = await resumenMiDia(mondayMock({}), vendedor, new Map(), [], AHORA)
|
||||
expect(r.misCapturas).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('clasificadores de estado', () => {
|
||||
|
||||
Reference in New Issue
Block a user