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
This commit is contained in:
2026-09-04 22:32:40 +00:00
parent 1963c06d93
commit cbd50e2066
19 changed files with 700 additions and 44 deletions

View File

@@ -108,3 +108,28 @@ export async function getMisCotizaciones(): Promise<CotizacionGuardada[]> {
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
return (await resp.json()) as CotizacionGuardada[]
}
// ---------- Búsqueda de clientes en Monday (prellenado del cotizador) ----------
export interface LeadResumen {
id: string
nombre: string
telefono: string
email: string
estado: string
origen: string
/** 'lead' = tablero Leads; 'oportunidad' = tablero Oportunidades (se vincula al guardar) */
fuente: 'lead' | 'oportunidad'
/** Desarrollo de interés ('' si no tiene) */
desarrollo?: string
/** Modelo de interés ('' si no tiene) */
modeloInteres?: string
}
/** GET /leads/buscar?q= — busca en AMBOS tableros (Leads + Oportunidades) */
export async function buscarLeads(q: string): Promise<LeadResumen[]> {
const res = await fetch(`${API_URL}/leads/buscar?q=${encodeURIComponent(q)}`, conAuth())
manejar401(res)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
return (await res.json()) as LeadResumen[]
}