import { beforeEach, describe, expect, it, vi } from 'vitest' const prismaMock = vi.hoisted(() => ({ planPago: { findMany: vi.fn(), }, })) vi.mock('../services/prisma.js', () => ({ prisma: prismaMock })) import { resumenMora } from './mora.service.js' beforeEach(() => { vi.clearAllMocks() }) describe('resumenMora', () => { it('devuelve 0 cuando no hay pagos vencidos', async () => { prismaMock.planPago.findMany.mockResolvedValue([ { clienteNombre: 'Juan', unidadCodigo: 'U-101', proyecto: 'SENDA', clienteTelefono: '4771234567', id: 'p1', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-12-01'), monto: 10000, montoPagado: 0 }, ], }, ]) const result = await resumenMora() expect(result.clientesConMora).toBe(0) expect(result.montoTotalVencido).toBe(0) expect(result.clientes).toHaveLength(0) }) it('detecta pagos vencidos con monto restante', async () => { prismaMock.planPago.findMany.mockResolvedValue([ { clienteNombre: 'Juan Pérez', unidadCodigo: 'SENDA-101', proyecto: 'SENDA', clienteTelefono: '4771234567', id: 'plan1', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-08-01'), // vencido monto: 5000, montoPagado: 2000, // parcial: restante = 3000 }, { numPago: 2, fechaVencimiento: new Date('2026-09-01'), // vencido monto: 5000, montoPagado: 0, // sin pagar }, ], }, ]) const result = await resumenMora() expect(result.clientesConMora).toBe(2) expect(result.montoTotalVencido).toBe(8000) expect(result.diasPromedioAtraso).toBeGreaterThan(0) expect(result.clientes[0]?.clienteNombre).toBe('Juan Pérez') }) it('ordena por días de atraso (mayor primero)', async () => { prismaMock.planPago.findMany.mockResolvedValue([ { clienteNombre: 'Corto', unidadCodigo: 'U-1', proyecto: 'A', clienteTelefono: null, id: 'p1', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-08-25'), monto: 1000, montoPagado: 0 }, ], }, { clienteNombre: 'Largo', unidadCodigo: 'U-2', proyecto: 'B', clienteTelefono: null, id: 'p2', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-07-01'), monto: 2000, montoPagado: 0 }, ], }, ]) const result = await resumenMora() expect(result.clientes[0]?.clienteNombre).toBe('Largo') expect(result.clientes[0]?.diasAtraso).toBeGreaterThan(result.clientes[1]!.diasAtraso) }) it('ignora pagos totalmente cubiertos', async () => { prismaMock.planPago.findMany.mockResolvedValue([ { clienteNombre: 'Cliente', unidadCodigo: 'U-1', proyecto: 'A', clienteTelefono: null, id: 'p1', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-08-01'), monto: 5000, montoPagado: 5000 }, ], }, ]) const result = await resumenMora() expect(result.clientesConMora).toBe(0) }) it('ignora pagos cuyo vencimiento es futuro', async () => { prismaMock.planPago.findMany.mockResolvedValue([ { clienteNombre: 'Cliente', unidadCodigo: 'U-1', proyecto: 'A', clienteTelefono: null, id: 'p1', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-12-01'), monto: 5000, montoPagado: 0 }, ], }, ]) const result = await resumenMora() expect(result.clientesConMora).toBe(0) }) it('excluye planes cancelados', async () => { prismaMock.planPago.findMany.mockResolvedValue([ { clienteNombre: 'Cancelado', unidadCodigo: 'U-1', proyecto: 'A', clienteTelefono: null, id: 'p1', pagos: [ { numPago: 1, fechaVencimiento: new Date('2026-08-01'), monto: 5000, montoPagado: 0 }, ], status: 'CANCELADO', }, ]) // The where clause filters out CANCELADO before they reach the loop prismaMock.planPago.findMany.mockResolvedValue([]) const result = await resumenMora() expect(result.clientesConMora).toBe(0) }) })