diff --git a/api-gateway/src/controllers/mi-dia.controller.test.ts b/api-gateway/src/controllers/mi-dia.controller.test.ts index 549705a..84ccade 100644 --- a/api-gateway/src/controllers/mi-dia.controller.test.ts +++ b/api-gateway/src/controllers/mi-dia.controller.test.ts @@ -105,7 +105,7 @@ describe('resumenMiDiaEndpoint (modo local y unión)', () => { expect(mondayMock.getLeads).not.toHaveBeenCalled() expect(mondayMock.getOportunidades).not.toHaveBeenCalled() const resumen = json.mock.calls[0]?.[0] as Record - expect((resumen['misLeads'] as unknown[]).length).toBe(2) + expect((resumen["misLeads"] as unknown[]).length).toBe(1) // solo leads, no oportunidades expect((resumen['misOportunidades'] as { items: unknown[] }).items).toHaveLength(1) expect(resumen['misActividadesHoy']).toEqual([]) expect(resumen['conteos']).toMatchObject({ actividadesAbiertas: 0 }) diff --git a/api-gateway/src/services/mi-dia-local.test.ts b/api-gateway/src/services/mi-dia-local.test.ts index 6737441..5498848 100644 --- a/api-gateway/src/services/mi-dia-local.test.ts +++ b/api-gateway/src/services/mi-dia-local.test.ts @@ -62,9 +62,8 @@ describe('resumenMiDiaLocal (Monday caído)', () => { const r = resumenMiDiaLocal(vendedor, capturas, [], AHORA) expect(r.sinMapeoMonday).toBe(false) - expect(r.misLeads.map((l) => l.id).sort()).toEqual(['loc_l1', 'loc_o1']) + expect(r.misLeads.map((l) => l.id).sort()).toEqual(['loc_l1']) // solo leads, no oportunidades expect(r.misLeads.find((l) => l.id === 'loc_l1')?.fuente).toBe('lead') - expect(r.misLeads.find((l) => l.id === 'loc_o1')?.fuente).toBe('oportunidad') // porEtapa cuenta TODAS las oportunidades (incluye terminales, como Monday) expect(r.misOportunidades.porEtapa).toEqual({ Afluencia: 1, Perdido: 1 }) expect(r.misOportunidades.items.map((o) => o.id)).toEqual(['loc_o1']) diff --git a/api-gateway/src/services/mi-dia.service.test.ts b/api-gateway/src/services/mi-dia.service.test.ts index e403ff7..85d4775 100644 --- a/api-gateway/src/services/mi-dia.service.test.ts +++ b/api-gateway/src/services/mi-dia.service.test.ts @@ -126,8 +126,8 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => { }) const r = await resumenMiDia(monday, vendedor, new Map(), [], [], AHORA) expect(r.sinMapeoMonday).toBe(false) - expect(r.misLeads.map((l) => l.id)).toEqual(['l2', 'o1', 'o2', 'l1']) // updatedAt desc mezclando tableros - expect(r.misLeads.map((l) => l.fuente)).toEqual(['lead', 'oportunidad', 'oportunidad', 'lead']) + expect(r.misLeads.map((l) => l.id)).toEqual(['l2', 'l1']) // solo leads, no oportunidades // updatedAt desc mezclando tableros + expect(r.misLeads.map((l) => l.fuente)).toEqual(['lead', 'lead']) // solo leads expect(r.misLeads[0]?.telefono).toBe('4771234567') }) @@ -147,12 +147,7 @@ describe('resumenMiDia (GET /api/mi-dia/resumen)', () => { usuario: 'Martin Zavala', detalle: 'Actualización', }) - // usuarioId sin nombre en el mapa → fallback null - expect(r.misLeads.find((l) => l.id === 'o1')?.ultimoCambio).toEqual({ - fechaISO: '2026-08-28T09:00:00.000Z', - usuario: null, - detalle: 'Alta', - }) + // 'o1' ya no esta en misLeads (es oportunidad) }) it('ultimoCambio: null cuando el item no tiene eventos en el activity log', async () => { @@ -562,7 +557,7 @@ describe('resumenMiDia — cuenta compartida / uso solo-app (sin Monday)', () => { leadId: 'o1', nombreLead: 'Lead o1', telefono: null, createdAt: new Date('2026-08-27') }, ] const r = await resumenMiDia(monday, sinMapeo, new Map(), capturas, [], AHORA) - expect(r.misLeads.map((l) => l.id)).toEqual(['o1', 'l1']) + expect(r.misLeads.map((l) => l.id)).toEqual(['l1']) // solo leads expect(r.misOportunidades.items.map((o) => o.id)).toEqual(['o1']) }) diff --git a/api-gateway/src/services/mi-dia.service.ts b/api-gateway/src/services/mi-dia.service.ts index 95a54ed..564c0b0 100644 --- a/api-gateway/src/services/mi-dia.service.ts +++ b/api-gateway/src/services/mi-dia.service.ts @@ -282,11 +282,9 @@ export async function resumenMiDia( fuente: 'oportunidad', ultimoCambio: null, })) - // Excluir de "Mis leads" los que ya aparecen en "Mis oportunidades" - // para no mostrar el mismo item en dos pestañas - const idsEnOportunidades = new Set(misLeadsOportunidades.map((o) => o.id)) - const misLeadsLeadsSinDuplicados = misLeadsLeads.filter((l) => !idsEnOportunidades.has(l.id)) - const misLeads: LeadMiDia[] = [...misLeadsLeadsSinDuplicados, ...misLeadsOportunidades].sort((a, b) => + // "Mis leads" solo muestra items del tablero Leads (captura ligera). + // Las oportunidades van exclusivamente en "Mis oportunidades". + const misLeads: LeadMiDia[] = misLeadsLeads.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt), ) @@ -589,37 +587,23 @@ export function resumenMiDiaLocal( const oportunidadesLocales = capturas.filter((c) => c.board === 'OPORTUNIDADES') const apartadosLocales = capturas.filter((c) => c.board === 'APARTADO') - // "Mis leads" mezcla Leads + Oportunidades, igual que el camino Monday - const misLeads: LeadMiDia[] = [ - ...leadsLocales - .filter((c) => !esEstadoTerminalLead(c.etapa)) - .map((c) => ({ - id: c.leadId, - nombre: c.nombreLead, - telefono: c.telefono ?? '', - email: c.email ?? '', - estado: c.etapa, - origen: c.origen ?? '', - updatedAt: c.updatedAt.toISOString(), - fuente: 'lead' as const, - ultimoCambio: ultimoCambioLocal(c, usuario.nombre), - pendienteSync: c.pendienteSync, - })), - ...oportunidadesLocales - .filter((c) => !esEtapaTerminal(c.etapa)) - .map((c) => ({ - id: c.leadId, - nombre: c.nombreLead, - telefono: c.telefono ?? '', - email: c.email ?? '', - estado: c.etapa, - origen: c.origen ?? '', - updatedAt: c.updatedAt.toISOString(), - fuente: 'oportunidad' as const, - ultimoCambio: ultimoCambioLocal(c, usuario.nombre), - pendienteSync: c.pendienteSync, - })), - ].sort(porUpdatedAtDesc) + // "Mis leads" solo muestra leads (board LEADS), no oportunidades + const misLeads: LeadMiDia[] = leadsLocales + .filter((c) => !esEstadoTerminalLead(c.etapa)) + .map((c) => ({ + id: c.leadId, + nombre: c.nombreLead, + telefono: c.telefono ?? '', + email: c.email ?? '', + estado: c.etapa, + origen: c.origen ?? '', + updatedAt: c.updatedAt.toISOString(), + fuente: 'lead' as const, + ultimoCambio: ultimoCambioLocal(c, usuario.nombre), + pendienteSync: c.pendienteSync, + })) + .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)) + // (oportunidades se muestran exclusivamente en misOportunidades) // Conteo por etapa de TODAS las oportunidades (incluye terminales, como Monday) const porEtapa: Record = {}