import { beforeEach, describe, expect, it, vi } from 'vitest' const prismaMock = vi.hoisted(() => ({ cliente: { findFirst: vi.fn() }, leadCaptura: { findUnique: vi.fn() }, planPago: { findMany: vi.fn() }, cotizacion: { findMany: vi.fn() }, documento: { findMany: vi.fn() }, actividadLocal: { findFirst: vi.fn() }, })) vi.mock('../services/prisma.js', () => ({ prisma: prismaMock })) // Mock lead-scoring to avoid circular dependency vi.mock('../services/lead-scoring.service.js', () => ({ calcularScore: vi.fn(() => 75), })) import { perfilCompleto } from './contactos-detalle.service.js' beforeEach(() => { vi.clearAllMocks() prismaMock.cliente.findFirst.mockResolvedValue(null) prismaMock.leadCaptura.findUnique.mockResolvedValue(null) prismaMock.planPago.findMany.mockResolvedValue([]) prismaMock.cotizacion.findMany.mockResolvedValue([]) prismaMock.documento.findMany.mockResolvedValue([]) prismaMock.actividadLocal.findFirst.mockResolvedValue(null) }) describe('perfilCompleto', () => { it('devuelve null si el contacto no existe', async () => { const result = await perfilCompleto('no-existe') expect(result).toBeNull() }) it('arma perfil completo desde Cliente', async () => { prismaMock.cliente.findFirst.mockResolvedValue({ id: 'c1', nombreCompleto: 'Juan Pérez', curp: 'CURP123', rfc: 'RFC123', email: 'juan@test.com', celular: '4771234567', proyecto: 'SENDA', unidadCodigo: 'SENDA-101', mondayContactoId: null, createdAt: new Date('2026-09-01'), }) prismaMock.planPago.findMany.mockResolvedValue([ { id: 'plan1', clienteNombre: 'Juan Pérez', unidadCodigo: 'SENDA-101', proyecto: 'SENDA', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-10-01'), monto: 5000, montoPagado: 0 }, ], }, ]) prismaMock.documento.findMany.mockResolvedValue([ { id: 'd1', tipo: 'INE', nombreArchivo: 'ine.pdf', createdAt: new Date('2026-09-02') }, ]) const result = await perfilCompleto('c1') expect(result).not.toBeNull() expect(result?.contacto['nombre']).toBe('Juan Pérez') expect(result?.contacto['CURP']).toBe('CURP123') expect(result?.historialPagos).toHaveLength(1) expect(result?.historialPagos[0]?.estado).toBe('pendiente') expect(result?.documentos).toHaveLength(1) expect(result?.documentos[0]?.tipo).toBe('INE') }) it('arma perfil desde LeadCaptura cuando no hay Cliente', async () => { prismaMock.leadCaptura.findUnique.mockResolvedValue({ leadId: 'loc_1', nombreLead: 'Ana López', telefono: '6649998877', email: 'ana@test.com', origen: 'Facebook', etapa: 'INTERESADO', createdAt: new Date('2026-09-05'), updatedAt: new Date('2026-09-07'), }) prismaMock.actividadLocal.findFirst.mockResolvedValue({ titulo: 'Llamar a Ana', tipo: 'SEGUIMIENTO', createdAt: new Date('2026-09-07'), }) const result = await perfilCompleto('loc_1') expect(result).not.toBeNull() expect(result?.contacto['nombre']).toBe('Ana López') expect(result?.contacto['Etapa']).toBe('INTERESADO') expect(result?.leadScore).toBe(75) expect(result?.ultimaActividad?.titulo).toBe('Llamar a Ana') }) it('cotizaciones se incluyen cuando hay teléfono', async () => { prismaMock.cliente.findFirst.mockResolvedValue({ id: 'c1', nombreCompleto: 'Test', curp: '', rfc: '', email: null, celular: '4771234567', proyecto: 'A', unidadCodigo: null, mondayContactoId: null, createdAt: new Date(), }) prismaMock.cotizacion.findMany.mockResolvedValue([ { id: 'cot1', unidadCodigo: 'U-101', tipoPropuesta: 'BANCARIO', precioFinal: 3000000, createdAt: new Date('2026-09-01'), }, ]) const result = await perfilCompleto('c1') expect(result?.cotizaciones).toHaveLength(1) expect(result?.cotizaciones[0]?.tipoPropuesta).toBe('BANCARIO') }) })