import { beforeEach, describe, expect, it, vi } from 'vitest' import { notificarEscrituracionSiLiquidado, resolverFiltroMios } from './planes.controller.js' // ---------- Prisma mockeado: el encolado de la réplica no toca la BD ---------- const prismaMock = vi.hoisted(() => ({ syncPendiente: { create: vi.fn(), }, })) vi.mock('../services/prisma.js', () => ({ prisma: prismaMock })) /** Monday mockeado: registra cambios de columna */ function mondayMock() { return { cambios: [] as { boardId: string; itemId: string; columna: string; valor: unknown }[], async cambiarValorColumna(boardId: string, itemId: string, columna: string, valor: string | number | boolean) { this.cambios.push({ boardId, itemId, columna, valor }) }, } } describe('notificarEscrituracionSiLiquidado (puente cobranza → postventa)', () => { beforeEach(() => { vi.clearAllMocks() prismaMock.syncPendiente.create.mockResolvedValue({}) }) it('plan LIQUIDADO con mondayItemId: mueve el apartado a "X Escriturar"', async () => { const monday = mondayMock() const ok = await notificarEscrituracionSiLiquidado({ mondayItemId: 'apt-55' }, true, monday) expect(ok).toBe(true) // board 666 = MONDAY_BOARD_APARTADO de test expect(monday.cambios).toEqual([ { boardId: '666', itemId: 'apt-55', columna: 'Estado', valor: 'X Escriturar' }, ]) }) it('no hace nada si el plan no está liquidado o no tiene item ligado', async () => { const monday = mondayMock() expect(await notificarEscrituracionSiLiquidado({ mondayItemId: 'apt-55' }, false, monday)).toBe(false) expect(await notificarEscrituracionSiLiquidado({ mondayItemId: null }, true, monday)).toBe(false) expect(await notificarEscrituracionSiLiquidado({}, true, monday)).toBe(false) expect(monday.cambios).toEqual([]) }) it('un fallo de Monday no rompe el abono: loguea, encola LIQUIDADO_ESCRITURAR y devuelve false', async () => { const monday = mondayMock() vi.spyOn(monday, 'cambiarValorColumna').mockRejectedValueOnce(new Error('Monday caído')) const spyError = vi.spyOn(console, 'error').mockImplementation(() => {}) const ok = await notificarEscrituracionSiLiquidado({ mondayItemId: 'apt-55' }, true, monday) expect(ok).toBe(false) expect(spyError).toHaveBeenCalled() // La escrituración queda encolada para que el worker la aplique al volver Monday expect(prismaMock.syncPendiente.create).toHaveBeenCalledWith({ data: expect.objectContaining({ tipo: 'LIQUIDADO_ESCRITURAR', payloadJson: JSON.stringify({ mondayItemId: 'apt-55' }), referenciaLocal: 'apt-55', }), }) spyError.mockRestore() }) }) describe('resolverFiltroMios (?mios=1)', () => { it('sin ?mios=1 no filtra nada', () => { expect(resolverFiltroMios(undefined, { sub: 'u1', rol: 'vendedor' })).toBeUndefined() expect(resolverFiltroMios('0', { sub: 'u1', rol: 'vendedor' })).toBeUndefined() }) it('vendedor con ?mios=1 → filtra por su sub', () => { expect(resolverFiltroMios('1', { sub: 'u1', rol: 'vendedor' })).toEqual({ vendedorId: 'u1' }) }) it('admin y coordinador ven todo aunque pidan ?mios=1', () => { expect(resolverFiltroMios('1', { sub: 'u1', rol: 'admin' })).toBeUndefined() expect(resolverFiltroMios('1', { sub: 'u1', rol: 'coordinador' })).toBeUndefined() }) it('sin token (AUTH_ENABLED=false) el filtro no aplica', () => { expect(resolverFiltroMios('1', undefined)).toBeUndefined() }) })