feat: rol manager, arreglos de reportes (cancelacion/afluencias), credito unico, cliente enkontrol, vendedor en bitacora y actualizar afluencia existente

This commit is contained in:
2026-09-18 15:25:34 +00:00
parent 9630893974
commit 4965a4488a
35 changed files with 303 additions and 90 deletions

View File

@@ -450,7 +450,9 @@ export interface ContextoUsuario {
/** admin / director_ventas / direccion_general ven los datos de todos */
export function esDireccion(rol: string | undefined): boolean {
return rol === undefined || rol === 'admin' || rol === 'director_ventas' || rol === 'direccion_general'
return (
rol === undefined || rol === 'admin' || rol === 'manager' || rol === 'director_ventas' || rol === 'direccion_general'
)
}
const FASES_APARTADO: readonly string[] = VOCABULARIO.FASES_APARTADO

View File

@@ -16,7 +16,7 @@ async function validarFechasBloqueadas(
registros: { unidad: string; campo: string; valor: string | null }[],
rol: string,
): Promise<void> {
if (rol === 'admin') return
if (rol === 'admin' || rol === 'manager') return
const bloqueados = CAMPOS_FECHA_BLOQUEADOS[departamento]
if (!bloqueados) return
const candidatos = registros.filter((r) => bloqueados.has(r.campo))

View File

@@ -162,8 +162,8 @@ describe('resetRoles', () => {
prismaMock.rolConfiguracion.create.mockResolvedValue({})
await resetRoles()
expect(prismaMock.rolConfiguracion.deleteMany).toHaveBeenCalled()
// MATRIZ tiene 6 roles
expect(prismaMock.rolConfiguracion.create).toHaveBeenCalledTimes(6)
// MATRIZ tiene 7 roles (incluye manager)
expect(prismaMock.rolConfiguracion.create).toHaveBeenCalledTimes(7)
})
})

View File

@@ -32,7 +32,7 @@ export const ESTADOS_FINALES_APARTADO = [
'TITULADO',
]
const ROLES_CON_EQUIPO = ['coordinador', 'corporativo', 'admin']
const ROLES_CON_EQUIPO = ['coordinador', 'corporativo', 'admin', 'manager']
const MS_DIA = 24 * 60 * 60 * 1000
@@ -70,6 +70,8 @@ export interface LeadMiDia {
estado: string
origen: string
desarrollo?: string
/** Vendedor asignado (nombre); '' si no tiene */
vendedor: string
updatedAt: string
/** Tablero del item: 'lead' (captura ligera) u 'oportunidad' (afluencia) */
fuente: 'lead' | 'oportunidad'
@@ -139,6 +141,8 @@ export interface ApartadoMiDia {
email: string
origen: string
desarrollo: string
/** Vendedor asignado (nombre); '' si no tiene */
vendedor: string
unidadCodigo: string
estado: string
fechaLimite: string // 'YYYY-MM-DD' ('' si no tiene)
@@ -290,6 +294,7 @@ export function resumenMiDiaLocal(
estado: c.etapa,
origen: c.origen ?? '',
desarrollo: c.desarrollo ?? '',
vendedor: nombrePorUsuarioId.get(c.usuarioId) ?? '',
updatedAt: c.updatedAt.toISOString(),
fuente: 'lead' as const,
ultimoCambio: ultimoCambioLocal(c, nombrePorUsuarioId.get(c.usuarioId) ?? ''),
@@ -326,6 +331,7 @@ export function resumenMiDiaLocal(
etapa: c.etapa,
desarrollo: c.desarrollo ?? '',
modeloInteres: c.modelo ?? '',
vendedor: nombrePorUsuarioId.get(c.usuarioId) ?? '',
unidadCodigo,
updatedAt: c.updatedAt.toISOString(),
ultimoCambio: ultimoCambioLocal(c, nombrePorUsuarioId.get(c.usuarioId) ?? ''),
@@ -350,6 +356,7 @@ export function resumenMiDiaLocal(
email: c.email ?? '',
origen: c.origen ?? '',
desarrollo: c.desarrollo ?? '',
vendedor: nombrePorUsuarioId.get(c.usuarioId) ?? '',
unidadCodigo: unidadPorApartadoId.get(c.leadId) ?? '',
estado: c.etapa,
fechaLimite: c.fechaLimite ? c.fechaLimite.toISOString().slice(0, 10) : '',
@@ -446,7 +453,7 @@ export function resumenMiDiaLocal(
const actividadesAbiertas = actividades.filter((a) => a.estado.toUpperCase() === 'ABIERTA').length
// --- Equipo (solo coordinador/admin/corporativo) ---
const ROLES_CON_EQUIPO = ['coordinador', 'corporativo', 'admin']
const ROLES_CON_EQUIPO = ['coordinador', 'corporativo', 'admin', 'manager']
let equipo: NonNullable<ResumenMiDia['equipo']> | undefined
if (ROLES_CON_EQUIPO.includes(usuario.rol) && usuarios.length > 0) {
@@ -507,6 +514,7 @@ export function resumenMiDiaLocal(
email: c.email ?? '',
origen: c.origen ?? '',
desarrollo: c.desarrollo ?? '',
vendedor: nombrePorUsuarioId.get(c.usuarioId) ?? '',
unidadCodigo: unidadPorApartadoId.get(c.leadId) ?? '',
estado: c.etapa,
fechaLimite: c.fechaLimite ? c.fechaLimite.toISOString().slice(0, 10) : '',