feat(modo-local): CRM 100% local sin dependencia de Monday.com
Nuevas tablas: - ActividadLocal (historial de llamadas, reuniones, tareas) - AsignacionLocal (round-robin local) - fechaLimite en LeadCaptura Servicios nuevos: - actividad-local.service.ts (CRUD actividades) - local-canal.ts (canal de envío para recordatorios) - seed-modo-local.js (activar modo local) Mi día local mejorado: - Mis actividades hoy (filtros usuario/fecha/estado) - Apartados por vencer (con fechaLimite real) - Equipo (contadores por vendedor, solo coordinador/admin) - unidadCodigo en oportunidades desde datosJson Automatizaciones locales: - Round-robin: asigna leads sin vendedor + crea actividad - Inactividad: detecta oportunidades >10 días sin update - Escalado: alerta oportunidades >48h sin contacto Reportes: actividadesAbiertas + parcial:false en modo local Cron wiring: crons locales cuando Monday caído 661 tests verdes.
This commit is contained in:
@@ -296,6 +296,7 @@ export interface DatosLocalesReportes {
|
||||
leads: LeadMonday[]
|
||||
oportunidades: OportunidadMonday[]
|
||||
unidades: Unidad[]
|
||||
actividadesAbiertas?: number
|
||||
}
|
||||
|
||||
/** Cargador de los datos locales para el fallback (Prisma en prod, fixture en tests) */
|
||||
@@ -379,7 +380,10 @@ export async function cargarDatosLocalesPrisma(): Promise<DatosLocalesReportes>
|
||||
loQuierePara: campoTexto(datos, 'loQuierePara'),
|
||||
}
|
||||
})
|
||||
return { leads, oportunidades, unidades: unidadesRows.map(unidadLocalADto) }
|
||||
// Contar actividades abiertas
|
||||
const actividadesAbiertas = await prisma.actividadLocal.count({ where: { estado: 'ABIERTA' } })
|
||||
|
||||
return { leads, oportunidades, unidades: unidadesRows.map(unidadLocalADto), actividadesAbiertas }
|
||||
}
|
||||
|
||||
export class ReportesService {
|
||||
@@ -437,7 +441,13 @@ export class ReportesService {
|
||||
}
|
||||
}
|
||||
const [locales, planes] = await Promise.all([this.cargarDatosLocales(), this.cargarPlanes()])
|
||||
const resumen = construirResumen({ ...locales, planes, actividadesAbiertas: 0 }, new Date(ahoraMs))
|
||||
return { ...resumen, parcial: true }
|
||||
const resumen = construirResumen(
|
||||
{ ...locales, planes, actividadesAbiertas: locales.actividadesAbiertas ?? 0 },
|
||||
new Date(ahoraMs),
|
||||
)
|
||||
// En modo local, los datos son completos (no parciales): todas las métricas
|
||||
// vienen de tablas locales. `parcial` solo se marca true cuando Monday cayó
|
||||
// a media lectura (ya no aplica aquí).
|
||||
return { ...resumen, parcial: false }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user