feat: roles con modulos por rol + mejoras Mi dia y descarte
- Matriz de roles (vendedor, administracion_venta, director_ventas, escrituracion, direccion_general, admin) con modulos visibles por rol; auth/me y login incluyen 'modulos'; PATCH /usuarios/:id/rol (admin). - Landing: Cobranza -> Clientes, Chat IA -> Chat Hermes, nuevo modulo Contactos (vista interna leyendo el tablero Contactos), grid filtrado por rol, rol visible en Configuracion de cuenta. - Dashboards: tab 'Tablero comercial' y tabs filtrados por rol. - Boton '<- Menu' en el header de todas las apps. - Mi dia: cada lead muestra el ultimo cambio (que, quien, cuando) desde el activity log de Monday (normalizacion de created_at 100ns/us/ms). - Descarte: el motivo se crea en el grupo de su categoria en el tablero Motivos No Compra.
This commit is contained in:
@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { Request, Response } from 'express'
|
||||
import type { Usuario } from '@prisma/client'
|
||||
import {
|
||||
actualizarRolEndpoint,
|
||||
actualizarVinculoMondayEndpoint,
|
||||
listarUsuariosMondayEndpoint,
|
||||
} from './usuarios.controller.js'
|
||||
@@ -91,6 +92,7 @@ describe('actualizarVinculoMondayEndpoint (PATCH /api/usuarios/me/monday)', () =
|
||||
rol: 'vendedor',
|
||||
asignacion: 'MONTEBELLO',
|
||||
mondayUserId: 13676,
|
||||
modulos: ['mi-dia', 'alta-cliente', 'alta-afluencia', 'cotizador', 'mi-tablero', 'contactos', 'chat'],
|
||||
})
|
||||
})
|
||||
|
||||
@@ -137,3 +139,57 @@ describe('actualizarVinculoMondayEndpoint (PATCH /api/usuarios/me/monday)', () =
|
||||
expect(prismaMock.usuario.update).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('actualizarRolEndpoint (PATCH /api/usuarios/:id/rol)', () => {
|
||||
function reqAdmin(overrides: Partial<Request> = {}): Request {
|
||||
return {
|
||||
body: { rol: 'escrituracion' },
|
||||
params: { id: 'u-9' },
|
||||
usuarioToken: { sub: 'u-1', username: 'admin', rol: 'admin' },
|
||||
...overrides,
|
||||
} as Request
|
||||
}
|
||||
|
||||
it('admin con rol válido: actualiza y devuelve el perfil con sus módulos', async () => {
|
||||
prismaMock.usuario.update.mockResolvedValue(usuarioFake({ id: 'u-9', rol: 'escrituracion' }))
|
||||
const { res, json } = resFake()
|
||||
|
||||
await actualizarRolEndpoint(reqAdmin(), res)
|
||||
|
||||
expect(prismaMock.usuario.update).toHaveBeenCalledWith({
|
||||
where: { id: 'u-9' },
|
||||
data: { rol: 'escrituracion' },
|
||||
})
|
||||
expect(json).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ rol: 'escrituracion', modulos: expect.arrayContaining(['cobranza']) }),
|
||||
)
|
||||
})
|
||||
|
||||
it('sin rol admin: 403 y no toca la BD', async () => {
|
||||
const { res } = resFake()
|
||||
const error = await actualizarRolEndpoint(
|
||||
reqAdmin({ usuarioToken: { sub: 'u-2', username: 'x', rol: 'vendedor' } }),
|
||||
res,
|
||||
).catch((e: unknown) => e)
|
||||
expect(error).toMatchObject({ status: 403 })
|
||||
expect(prismaMock.usuario.update).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('rol inválido: 400 y no toca la BD', async () => {
|
||||
const { res } = resFake()
|
||||
const error = await actualizarRolEndpoint(reqAdmin({ body: { rol: 'coordinador' } }), res).catch(
|
||||
(e: unknown) => e,
|
||||
)
|
||||
expect(error).toMatchObject({ status: 400 })
|
||||
expect(prismaMock.usuario.update).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('sin token verificado: 400', async () => {
|
||||
const { res } = resFake()
|
||||
await expect(actualizarRolEndpoint(reqAdmin({ usuarioToken: undefined }), res)).rejects.toThrow(
|
||||
'Falta el token verificado',
|
||||
)
|
||||
expect(prismaMock.usuario.update).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user