Commit Graph

16 Commits

Author SHA1 Message Date
d546460ba4 feat(8-mejoras): cancelar+motivo, brocker, etapas, calendario, modal cliente
1. Cancelar con motivo: Mis apartados y Escrituración piden motivo (modal reutilizado)
2. Origen BROCKER agregado en alta afluencia y captura rápida
3. Etapas oportunidades reordenadas: Agendo Cita → Afluencia → Cotizador
4. Cotizador: mensualidades diferibles (6, 12, 14, 18, 24 meses)
5. Calendario semanal por vendedor en Mi día
6. Hora en citas (datetime-local en vez de solo fecha)
7. Click en nombre → modal DetalleLeadModal (info + notas + historial)
2026-09-09 10:26:36 +00:00
2fc817887d fix(cache): deshabilitar caché del navegador en llamadas API
Añadido cache: 'no-store' a conAuth() en todas las apps. El navegador
cacheaba respuestas GET de la API, causando que los cambios (crear lead,
cambiar estado, etc.) no se reflejaran hasta borrar cookies.

6 apps reconstruidas.
2026-09-08 02:11:41 +00:00
c77b4c0628 feat(mejoras): 14 mejoras al CRM Frasa
Fase 1 - UI: dark mode, skeletons, toasts
Fase 2 - Filtros: avanzados Mi día, búsqueda global Ctrl+K
Fase 3 - Datos: export Excel, notas apartados, auditoría
Fase 4 - Dashboard: gráficas vendedor + métricas uso
Fase 5 - Responsive: tablets optimizadas
Fase 6 - PWA: IndexedDB offline, push notifications

Backend: 3 tablas nuevas, 6 services, 6 endpoints nuevos
721 API tests + fronts verdes.
2026-09-07 06:04:49 +00:00
97c4e5cdf3 fix(fronts): reemplazar IP hardcodeada 192.168.10.123 por /api relativo en TODOS los archivos
Causa raiz: import.meta.env.VITE_API_URL ?? '/api' no activa el fallback
cuando VITE_API_URL es string vacio (?? solo cubre null/undefined).
Cambiado a || en auth.ts y sistema.ts de todas las apps.

Tambien reemplazada la IP hardcodeada en api.ts, mi-dia.ts, reportes.ts
y agente-ia.api.ts de todas las apps. Ahora funciona desde IP y dominio
sin depender de la red local.
2026-09-06 18:50:33 +00:00
1597c6be34 fix(fronts): API_URL usa '/api' relativo en vez de IP hardcodeada
Las apps (cotizador, mi-dia, alta-clientes, cobranza, dashboards) tenían
VITE_API_URL default a http://192.168.10.123:3000/api que no funciona
desde dominio externo (Cloudflare). Cambiado a '/api' relativo como
ya lo usaba landing. Ahora funciona desde IP y desde dominio.
2026-09-06 18:09:35 +00:00
b2634f97ab 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
2026-09-06 09:46:19 +00:00
60649890eb feat(modo-local): fallback completo sin Monday + cola de sincronización
- Circuit breaker saludMonday (3 fallos → modo local; ping cada 60s)
- Endpoint GET /api/sistema/estado {mondayOk, pendientesSync}
- LeadCaptura extendida (board, etapa, origen, motivo, pendienteSync)
- Tablas Unidad (espejo inventario, 288 seed) + SyncPendiente
- crmLocal: crearLead, afluencia, cambio etapa, descarte, conversión, apartar
- Ruteo en controllers: fallback local ante 502 o Monday caído
- Mi día local: resumen completo desde SQLite + unión con Monday
- Fallbacks: unidades, contactos, reportes, prefill, buscador
- Sync worker cada 2min + handlers 15 tipos (con DependenciaPendienteError)
- Gate automatizaciones: skip si !mondayOk
- Banner 'Modo local' en 5 apps + badge pendiente en mi-dia
- 597 API tests + 263 front tests verdes

Env MODO_LOCAL_FORZADO=true para testing sin Monday.
2026-09-06 08:08:56 +00:00
5b348d21e5 feat: conversión lead→oportunidad (Agendo) y alta ligada a apartado
- Mis leads: botón 'Agendo →' convierte el lead en oportunidad (etapa
  Agendo Cita, con sus datos, asesor = vendedor del lead o quien
  convierte), marca el lead Calificado y guarda el mapping
  LeadOportunidad; 409 si ya fue convertido
- Mis oportunidades: se quitan No Asistio y Abandono (redundantes con
  Descartar); quedan Cotizar, Afluencia, Agendo Cita y Aparto
- Mis apartados: 'Firma cliente (venta) →' abre el alta de cliente con
  TODO lo recolectado prellenado (ficha del apartado + contacto +
  oportunidad + cotización vinculada vía GET /altas/prefill-apartado/:id)
- El alta con apartadoMondayId se LIGA al apartado existente y lo
  enriquece (curp, teléfono, email, precio final, enganche, forma de
  pago, unidad) en vez de crear un duplicado
- monday.service: actualizarApartado + ApartadoMonday con curp, forma de
  pago, enganche y monto apartado
- Tests: 470 API + 120 alta-clientes + 16 mi-dia, verde
2026-09-05 00:33:53 +00:00
27ba9ea8fa feat: Interesado en leads, lada MX/USA, orígenes FRASA y subcategoría de descarte
- Mis leads: botón Interesado (label sembrado en Monday, mueve a Leads
  Progreso); el botón Agenda cita ahora solo vive en Mis oportunidades
- Descarte: además de la categoría, subcategoría del catálogo de Monday
  (workspace de referencia CRM FRASA); se guarda en la columna
  Subcategoria del tablero Motivos No Compra y el item queda en el grupo
  de su categoría
- Teléfonos con selector de lada 🇲🇽 +52 / 🇺🇸 +1 en captura rápida (Mi
  día), Alta Afluencia y Alta de Cliente (tel. casa y celular); Monday
  escribe countryShortName MX/US y el número compacto (rechaza espacios);
  el dedup sigue comparando por los últimos 10 dígitos
- Origen nuevo en captura rápida y afluencia: PASE, PROSPECCION ASESOR,
  ACTIVACION, FACEBOOK FRASA, REFERIDO, OTRO (sembrados en Leads.Origen y
  Oportunidades.Origen del Lead)
- Tests: 461 API + 16 mi-dia + 116 alta-clientes, verde
2026-09-04 23:28:56 +00:00
cbd50e2066 feat: docs en apartados, enganche seleccionable y prefill de clientes
- Mis apartados (Mi día): botón Documentos con precarga del expediente —
  captura del cotizador y captura de pago apartado (obligatorios) más
  documentos generales; los archivos se guardan en el cliente ligado al
  apartado (se crea la ficha mínima si no existe). Endpoints
  GET/POST /apartados/:id/documentos (multipart, 10 MB, pdf/jpg/png)
- Cotizador: se oculta el editor de descuento (usan los % del Excel);
  enganche seleccionable con mínimo 2.5% del valor de la propiedad, solo
  en esquemas con crédito (bancario/Infonavit); mensualidades se
  recalculan con el enganche elegido y nunca quedan en negativo
- Cotizador: buscador de cliente en Monday (lead u oportunidad) que
  prellena nombre/contacto/desarrollo y vincula la cotización a la
  oportunidad al guardar
- Alta Afluencia: buscador que jala nombre, contacto, origen, desarrollo
  y modelo desde leads y oportunidades existentes
- buscarLeads devuelve desarrollo y modelo de interés
- Landing: el módulo Clientes vuelve a llamarse Cobranza
- Tests: 456 API + 94 cotizador + 14 mi-dia + 116 alta-clientes, verde
2026-09-04 22:32:40 +00:00
1963c06d93 feat(mi-dia): tabs Mis oportunidades/Mis apartados con fases y cotizador vinculado
- Resumen Mi día: misOportunidades.items (lista de trabajo con perfil y
  último cambio) y misApartados (Vendedor = yo, estados no finales)
- Nuevos endpoints: POST /oportunidades/:id/etapa (Agendo Cita, Afluencia,
  Cotizador, Aparto, No Asistio, Abandono; con fecha de cita) y
  POST /apartados/:id/estado (pipeline Enkontrol: Pago Apartado →
  Firma Cliente (Venta) / Cancelacion Apartado); ambos mueven el item al
  grupo Monday correspondiente
- Mi día: tabs Mis leads / Mis oportunidades / Mis apartados; botón
  Cotizar abre /quote con el cliente prellenado y la oportunidad ligada
- Cotizador: prefill desde query params (cliente, teléfono, email,
  desarrollo, unidad) y envío de oportunidadId; al guardar, el API
  actualiza ESE item (Precio final, Tipo propuesta, etapa Cotizador)
  en vez de buscar por teléfono o crear duplicado
- grupos-estado: 'Cancelacion Apartado' → Historico
- Estados finales de apartado: agrega Firma Cliente (Venta) y
  Cancelacion Apartado
- Tests: 455 API + 14 mi-dia + 88 cotizador, todo en verde
2026-09-04 21:54:44 +00:00
135e3e6de5 feat(leads): doble via de captura — lead rapido a Leads, afluencia a Oportunidades
- POST /api/leads: captura ligera al tablero Leads (sin oportunidad),
  self-assign a Vendedor o round-robin; tambien cubre la captura manual
  desde la UI de Monday (webhook create_item re-registrado).
- POST /api/afluencias (nuevo): la forma completa sigue cayendo en
  Oportunidades con todo el perfil (etapa Afluencia, columna Asesor).
- Round-robin dual (ambos tableros), Mi dia mezcla leads+oportunidades
  con insignia de origen, acciones con parametro fuente, reportes:
  leads desde Leads, perfilamiento desde Oportunidades, funnel
  Leads->Afluencia->...->Ganado.
2026-09-04 06:09:38 +00:00
f382987fbf feat(leads): la captura desde una app se asigna al capturista
POST /api/leads con sesion y Monday vinculado asigna el lead a quien lo
registro (mas su actividad de contacto) en vez del round-robin; sin
vinculo o sin token sigue el reparto. Bandera rr:skip para que el
webhook create_item no pise la asignacion durante la propagacion de
Monday (la carrera se observo en el smoke). Mensajes de exito en
/hoy y /client reflejan a quien quedo asignado.
2026-09-03 21:26:20 +00:00
ead7a71025 feat(leads): captura rápida pide email y desarrollo de interés
- Columna 'Desarrollo' (status, 5 labels) creada en el board Leads de
  Monday (color_mm6sw4c2)
- API: crearLead acepta email y desarrollo; el desarrollo se valida
  contra los labels reales de la columna (mismo patrón que Origen)
- Mi día: formulario de captura con campos Email y Desarrollo de interés
  (select con los 5 desarrollos, opcional)
- Tests: api 296, mi-dia 12
2026-09-01 07:43:42 +00:00
cb86a5190a feat: PWA instalable, cambio de contraseña y dashboards por rol
- POST /api/auth/cambiar-password (bcrypt 12, política ≥8+1 número) +
  modal en las 6 apps con auth
- PWA: manifest + íconos de marca en las 7 apps (sin service worker a
  propósito, documentado); instalable en celular
- Dashboards: 'Mi tablero' para vendedor (sus KPIs y funnel) y sección
  Equipo para coordinador/corporativo/admin
- mi-dia: equipo.porVendedor gana leadsNuevosSemana
- Tests: api 271, cotizador 88, alta 88, cobranza 81, agente-ia 19,
  dashboards 15, mi-dia 11, landing 4
2026-08-28 08:37:41 +00:00
bc0f9da8fe feat(mi-dia): app /hoy + CRM ligero para vendedores
- App Mi día: KPIs, mis actividades, mis leads con acciones rápidas
  (contactado/intento/agenda cita/descartar con motivo), captura rápida
  de lead (409 en duplicado por teléfono), vista equipo para coordinadores
- API: GET /api/mi-dia/resumen, POST /api/leads, /leads/:id/estado,
  /leads/:id/descartar; mapeo Usuario.mondayUserId (seed listo para
  cuando inviten a los vendedores a Monday)
- Landing: tarjeta Mi día; tests api 188, mi-dia 8, landing 4
2026-08-28 06:23:15 +00:00