feat(config): modulo Configuraciones admin + permisos por rol
- Tablas ConfiguracionSistema (7 configs) + RolConfiguracion (6 roles) - Endpoints: config/sistema GET/PATCH, config/roles GET/PATCH, config/usuarios GET/PATCH, config/reset-roles POST, config/acciones GET - modulosDeRol() async con fallback a MATRIZ estatica - auth/me devuelve acciones[] segun rol del usuario - saludMonday.estaDisponible() lee modo_local_forzado de DB (cache 30s) - Landing: vista Configuraciones con 4 tabs (Modo, Roles, Usuarios, Sistema) - Mi-dia: boton Descartar se deshabilita si !descartar_lead - 630 API tests + 24 landing tests + 20 mi-dia tests verdes Seed: npm run seed:config
This commit is contained in:
79
api-gateway/src/config/acciones.ts
Normal file
79
api-gateway/src/config/acciones.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
// Catálogo de acciones granulares disponibles por rol.
|
||||
// Cada acción controla un permiso específico en la UI y el backend.
|
||||
|
||||
export const ACCIONES_DISPONIBLES = [
|
||||
{ clave: 'descartar_lead', nombre: 'Descartar leads', descripcion: 'Puede descartar leads con motivo' },
|
||||
{ clave: 'editar_cotizacion', nombre: 'Editar cotizaciones', descripcion: 'Puede editar cotizaciones existentes' },
|
||||
{ clave: 'asignar_vendedor', nombre: 'Reasignar leads', descripcion: 'Puede reasignar leads a otros vendedores' },
|
||||
{ clave: 'ver_reportes', nombre: 'Ver reportes', descripcion: 'Puede ver dashboards y reportes' },
|
||||
{ clave: 'exportar_pdf', nombre: 'Exportar PDFs', descripcion: 'Puede generar y descargar PDFs' },
|
||||
{ clave: 'ver_precios', nombre: 'Ver precios completos', descripcion: 'Puede ver precios y descuentos en cotizador' },
|
||||
{ clave: 'gestionar_clientes', nombre: 'Gestionar clientes', descripcion: 'Puede gestionar fichas de clientes' },
|
||||
] as const
|
||||
|
||||
export type AccionClave = (typeof ACCIONES_DISPONIBLES)[number]['clave']
|
||||
|
||||
// Acciones por defecto por rol: true = habilitado, false = deshabilitado.
|
||||
// 'admin' tiene todo habilitado por convención.
|
||||
export const ACCIONES_POR_ROL_DEFAULT: Record<string, Record<AccionClave, boolean>> = {
|
||||
vendedor: {
|
||||
descartar_lead: true,
|
||||
editar_cotizacion: false,
|
||||
asignar_vendedor: false,
|
||||
ver_reportes: false,
|
||||
exportar_pdf: true,
|
||||
ver_precios: true,
|
||||
gestionar_clientes: false,
|
||||
},
|
||||
administracion_venta: {
|
||||
descartar_lead: true,
|
||||
editar_cotizacion: true,
|
||||
asignar_vendedor: false,
|
||||
ver_reportes: true,
|
||||
exportar_pdf: true,
|
||||
ver_precios: true,
|
||||
gestionar_clientes: true,
|
||||
},
|
||||
director_ventas: {
|
||||
descartar_lead: true,
|
||||
editar_cotizacion: true,
|
||||
asignar_vendedor: true,
|
||||
ver_reportes: true,
|
||||
exportar_pdf: true,
|
||||
ver_precios: true,
|
||||
gestionar_clientes: true,
|
||||
},
|
||||
escrituracion: {
|
||||
descartar_lead: false,
|
||||
editar_cotizacion: false,
|
||||
asignar_vendedor: false,
|
||||
ver_reportes: false,
|
||||
exportar_pdf: true,
|
||||
ver_precios: true,
|
||||
gestionar_clientes: true,
|
||||
},
|
||||
direccion_general: {
|
||||
descartar_lead: false,
|
||||
editar_cotizacion: false,
|
||||
asignar_vendedor: false,
|
||||
ver_reportes: true,
|
||||
exportar_pdf: true,
|
||||
ver_precios: true,
|
||||
gestionar_clientes: false,
|
||||
},
|
||||
admin: {
|
||||
descartar_lead: true,
|
||||
editar_cotizacion: true,
|
||||
asignar_vendedor: true,
|
||||
ver_reportes: true,
|
||||
exportar_pdf: true,
|
||||
ver_precios: true,
|
||||
gestionar_clientes: true,
|
||||
},
|
||||
}
|
||||
|
||||
/** Devuelve las acciones de un rol (o vacío si el rol no existe) */
|
||||
export function accionesPorRol(rol: string): Record<AccionClave, boolean> {
|
||||
const clave = rol.trim().toLowerCase()
|
||||
return (ACCIONES_POR_ROL_DEFAULT[clave] ?? ACCIONES_POR_ROL_DEFAULT.vendedor)!
|
||||
}
|
||||
Reference in New Issue
Block a user