Files
FRASA-CAS/api-gateway/src/services/grupos-estado.service.test.ts
Consult AS Technology 89fcd1c579 feat(monday): mover items al grupo correcto al cambiar de estado
Webhook change_column_value en los 5 tableros (Leads, Oportunidades,
Unidades, Apartado, Contactos) + mapeo central estado->grupo: el API
re-consulta el item y lo mueve con move_item_to_group (idempotente).
El funnel mueve la oportunidad de Afluencia al crearla (Monday la crea
en el grupo top del board). Incluye script de backfill one-off
(249 items reubicados) y tests del mapeo y del webhook.
2026-09-03 00:14:18 +00:00

115 lines
3.9 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
vi.mock('../config/index.js', () => ({
config: {
monday: {
boards: {
leads: '111',
oportunidades: '222',
contactos: '333',
unidades: '444',
apartado: '555',
},
},
},
}))
import { GRUPOS_POR_ESTADO, grupoDestino, moverAGrupoSegunEstado } from './grupos-estado.service.js'
interface ItemFake {
id: string
name: string
groupId: string
column_values: { id: string; text: string | null; value: string | null }[]
}
/** Monday mockeado: registra los movimientos de grupo solicitados */
function mondayMock(opts: { item?: ItemFake | null; columnaId?: string | null } = {}) {
return {
movimientos: [] as { itemId: string; groupId: string }[],
async columnaIdPorTitulo(_boardId: string, _titulo: string) {
return opts.columnaId !== undefined ? opts.columnaId : 'status_col'
},
async getItemConGrupo(_itemId: string) {
return opts.item ?? null
},
async moverItemAGrupo(itemId: string, groupId: string) {
this.movimientos.push({ itemId, groupId })
},
}
}
const itemCon = (groupId: string, estado: string): ItemFake => ({
id: '999',
name: 'Item Prueba',
groupId,
column_values: [{ id: 'status_col', text: estado, value: null }],
})
describe('grupoDestino', () => {
it('mapea labels conocidos de cada tablero', () => {
expect(grupoDestino('111', 'NUEVO')).toBe('topics')
expect(grupoDestino('111', 'CONTACTADO')).toBe('group_mm6s1jct')
expect(grupoDestino('111', 'DESCARTADO')).toBe('group_mm6s96mc')
expect(grupoDestino('222', 'Ganado')).toBe('group_mm6scqz3')
expect(grupoDestino('222', 'Afluencia')).toBe('topics')
expect(grupoDestino('333', 'INACTIVO')).toBe('group_mm6sqqq2')
expect(grupoDestino('444', 'Notaría')).toBe('group_mm6syf9c')
expect(grupoDestino('555', 'LIBERADO')).toBe('group_mm6s2yyx')
})
it('label desconocido → null', () => {
expect(grupoDestino('111', 'INVENTADO')).toBeNull()
})
it('board sin mapeo → null', () => {
expect(grupoDestino('999', 'NUEVO')).toBeNull()
})
it('etapa vacía en Unidades → null (no se mueve)', () => {
expect(grupoDestino('444', '')).toBeNull()
expect(grupoDestino('444', ' ')).toBeNull()
})
it('los 5 tableros del CRM tienen mapeo', () => {
expect(Object.keys(GRUPOS_POR_ESTADO).sort()).toEqual(['111', '222', '333', '444', '555'])
})
})
describe('moverAGrupoSegunEstado', () => {
it('mueve el item cuando el grupo actual difiere del destino', async () => {
const monday = mondayMock({ item: itemCon('topics', 'DESCARTADO') })
const r = await moverAGrupoSegunEstado(monday, '111', '999')
expect(r).toEqual({ movido: true, grupo: 'group_mm6s96mc' })
expect(monday.movimientos).toEqual([{ itemId: '999', groupId: 'group_mm6s96mc' }])
})
it('no mueve cuando el item ya está en el grupo destino', async () => {
const monday = mondayMock({ item: itemCon('group_mm6s96mc', 'DESCARTADO') })
const r = await moverAGrupoSegunEstado(monday, '111', '999')
expect(r).toEqual({ movido: false })
expect(monday.movimientos).toEqual([])
})
it('item inexistente (borrado tras el webhook) no truena ni mueve', async () => {
const monday = mondayMock({ item: null })
const r = await moverAGrupoSegunEstado(monday, '111', '999')
expect(r).toEqual({ movido: false })
expect(monday.movimientos).toEqual([])
})
it('board sin mapeo no consulta ni mueve nada', async () => {
const monday = mondayMock({ item: itemCon('topics', 'NUEVO') })
const r = await moverAGrupoSegunEstado(monday, '999', '999')
expect(r).toEqual({ movido: false })
expect(monday.movimientos).toEqual([])
})
it('label no mapeado no mueve', async () => {
const monday = mondayMock({ item: itemCon('topics', 'INVENTADO') })
const r = await moverAGrupoSegunEstado(monday, '111', '999')
expect(r).toEqual({ movido: false })
expect(monday.movimientos).toEqual([])
})
})