Ir al contenido
Nu Promo | NEXUS Bot Strategy v1.0
v1.0 — Marzo 2026
🏗️ Arquitectura General — NuPromoBot NEXUS

🎯 Objetivo del Sistema

Bot de WhatsApp para Nu Promo que gestiona el ciclo completo: desde primer contacto hasta levantamiento de pedidos, integrado bidirecionalmente con Google Sheets vía GAS como backend intermedio. Preparado para futura migración a Odoo CRM.

Stack: Botpress (Nodos Autónomos + Router) → GAS Webhooks → Google Sheets (12 Hojas) → WhatsApp Cloud API

📐 Capas del Sistema

CAPA 1 — Conversación
Botpress: 11 nodos (N0-N10), FAQ autónomo, calificación 6-3-1, captura de pedidos, escalamiento a humano
CAPA 2 — Backend
Google Apps Script: 18 endpoints, lógica de rotación PCT, validaciones, notificaciones, cron jobs
CAPA 3 — Datos
Google Sheets: 12 hojas (Leads, Cotizaciones, Pedidos, Productos, Asesores, Config, Logs, FAQ, Muestras, Pipeline, Métricas, Plantillas)
CAPA 4 — Comunicación
WhatsApp: Templates F#, mensajes interactivos, notificaciones push a asesores, confirmaciones automáticas

🔄 Flujo Macro del Sistema

👋 WhatsApp Entrante
N0: Extractor
N1: Router
N2-N8: Flujos
GAS Webhook
📋 Google Sheets
📋 Sheets
GAS Respuesta
Botpress Continúa
N9: Notifica Asesor
N10: Cierre/HITL

📊 Resumen de Componentes

11
Nodos Botpress
18
Endpoints GAS
12
Hojas Sheets
45+
Variables Bot
15
FAQs Mapeadas
6
Etapas Pipeline
⚠️ SEGURIDAD NEXUS: Todas las URLs de webhooks y secretos van en Configuration Variables de Botpress (env.GAS_WEBHOOK_URL, env.GAS_SECRET). NUNCA hardcodear en nodos.
🤖 Arquitectura de Nodos Botpress
Convenciones: Standard = Nodo estándar sin IA Autonomous = Nodo con IA + Write Access Router = Nodo decisor de ruta Expression = Card de condición lógica Execute = Card de código JS/webhook Hook = Before/After Incoming
N0

EXTRACTOR — Entry Point

Standard Execute Code

Propósito: Captura datos WhatsApp del usuario al primer mensaje.

Variables que escribe:

user_phone ← event.tags.conversation['whatsapp:userPhone']

user_name ← event.tags.conversation['whatsapp:userName'] || 'Visitante'

conversation_id ← event.conversationId

entry_timestamp ← new Date().toISOString()

source_channel ← 'whatsapp'

Execute Card → GAS:

POST env.GAS_WEBHOOK_URL → action: check_returning_user
Si usuario existe → carga historial, asesor previo, etapa pipeline

✅ Transición: Siempre → N1_ROUTER
N1

ROUTER — Clasificador Principal

Router Autonomous

Propósito: Analiza intención del mensaje y enruta al nodo correcto.

Intenciones detectadas:

🔹 FAQ → N2_FAQ (precios, mínimos, envíos, ubicación, etc.)

🔹 COTIZACION → N3_QUALIFIER (quiere cotizar producto)

🔹 PEDIDO_SEGUIMIENTO → N4_ORDER_TRACKER

🔹 MUESTRA_FISICA → N5_SAMPLES

🔹 HABLAR_ASESOR → N9_HITL_BRIDGE

🔹 CATALOGO → N6_CATALOG

🔹 RECLAMO → N7_COMPLAINTS

🔹 INFO_EMPRESA → N2_FAQ (sub-ruta /info)

Contexto del Router:

"Eres el clasificador de Nu Promo, una agencia de artículos promocionales. Analiza el mensaje y determina la intención. Si el usuario menciona producto específico, precio o cantidad → COTIZACION. Si pregunta info general → FAQ."

N2

FAQ — Respuestas Rápidas

Autonomous Execute Code

Propósito: Responde las 15 FAQ pre-programadas con IA contextual.

Lógica:

1. IA clasifica sub-intención → mapea a FAQ_ID (1-15)

2. Execute Card → GAS get_faq_response trae template

3. IA personaliza respuesta con nombre del usuario

4. Si detecta interés comercial → transiciona a N3

Knowledge Base:

Archivo KB con las 15 respuestas + políticas + filosofía servicio al cliente Mini Guía

✅ Transiciones: FAQ pura → Loop N2 | Interés comercial → N3 | Asesor → N9
N3

QUALIFIER — Método 6-3-1

Autonomous Execute Code

Propósito: Califica lead usando Método 6-3-1 completo de Nu Promo.

Fase 1 — Datos del Cliente (pre-6):

client_name, client_company, client_email, client_phone

Fase 2 — Las 6 Preguntas Clave:

Q1: ¿Qué producto necesitas?

Q2: ¿Cuándo lo necesitas?

Q3: ¿Dónde lo necesitas? (local/foráneo)

Q4: ¿Cuántos necesitas?

Q5: ¿Cuánto quieres invertir? (presupuesto)

Q6: ¿Tienes logotipo o identidad corporativa?

Fase 3 — 3 Preguntas de Valor:

Q7: Cuéntame del evento, ¿de qué se trata?

Q8: ¿A quién va dirigido?

Q9: ¿Qué quieres que sientan al recibirlo?

Fase 4 — 1 Pregunta Estratégica:

Q10: Pregunta contextual de relación (varía por proyecto)

⚡ Al completar → POST GAS create_lead + assign_advisor → N8_QUOTE
N4

ORDER TRACKER — Seguimiento

Standard Execute Code

Propósito: Consulta estado de pedido por número o teléfono.

Lógica:

1. Pide #pedido o usa user_phone como lookup

2. Execute → GAS get_order_status

3. Retorna: etapa, fecha estimada, asesor asignado

4. Si hay problema → escala a N9_HITL

Estados: Cotizado → Anticipo Recibido → En Producción → Muestra Virtual → En Decorado → Listo → Enviado/Entregado
N5

SAMPLES — Muestras Físicas

Autonomous Expression

Propósito: Evalúa elegibilidad de muestra según política.

Reglas de Negocio:

✅ Proyecto ≥ $20,000 MXN

✅ Muestras ≤ 3% del valor cotizado

✅ Lead en etapa ≥ 5 (cotización filtrada)

✅ Muestra con logo → tiene costo (abonable)

Expression Cards:

IF lead_stage >= 5 AND quote_total >= 20000 → Aprueba

IF sample_value > quote_total * 0.03 → Rechaza auto

ELSE → Escala a asesor vía N9

N6

CATALOG — Explorador de Productos

Autonomous Execute Code

Propósito: Ayuda al usuario a explorar catálogo y encontrar productos.

Capacidades:

🔍 Búsqueda por categoría, color, rango de precio

📸 Envía links de producto con imagen desde web

💰 Consulta existencias en tiempo real (si integrado)

📙 Comparte links: nupromo.mx + FlippingBook

GAS Endpoint:

search_products → busca en hoja Productos por keyword/categoría

✅ Si elige producto → auto-transición a N3 con producto pre-cargado
N7

COMPLAINTS — Quejas y Reclamos

Autonomous Execute Code

Propósito: Captura reclamo con contexto emocional + escala inmediato.

Flujo:

1. IA con tono empático (Mini Guía: "Vamos a resolverlo juntos")

2. Captura: tipo de problema, #pedido, descripción

3. POST GAS create_complaint con prioridad ALTA

4. Notifica asesor + supervisor inmediatamente

5. Auto-transición a N9_HITL con contexto

⚠️ Filosofía: "El cliente NO siempre tiene la razón, pero siempre debe sentirse escuchado"
N8

QUOTE BUILDER — Cotizador

Standard Execute Code

Propósito: Genera cotización preliminar y la registra.

Flujo:

1. Recibe datos de N3 (producto, cantidad, decorado)

2. Execute → GAS generate_quote

3. GAS calcula: precio unitario × cantidad + decorado

4. Retorna cotización con desglose al usuario

5. Pregunta: ¿Deseas formalizar? → Asigna asesor

Datos cotización:

quote_id, productos, cantidades, precios, subtotal, IVA, total, decorado, tiempo estimado

📝 Mínimo de compra: $5,000 + IVA (combinable). Bot valida antes de generar.
N9

HITL BRIDGE — Escalamiento Humano

Standard Execute Code

Propósito: Asigna asesor por rotación PCT y transfiere conversación.

Lógica MAGNETIK:

1. POST GAS assign_advisor con datos del lead

2. GAS ejecuta rotación PCT (déficit vs cuota)

3. Retorna: nombre_asesor, phone_asesor, email

4. Bot envía mensaje split al asesor vía WA

5. Bot informa al cliente quién le atenderá

6. Activa HITL en Botpress

Mensaje al asesor:

MSG1: "🔔 Nuevo lead asignado"
MSG2: Resumen 6-3-1 completo
MSG3: Link a Sheets del lead

N10

CLOSER — Cierre y Seguimiento

Autonomous Execute Code

Propósito: Cierra interacción con NPS + programa seguimiento.

Flujo:

1. Cuando asesor cierra HITL → bot retoma

2. "¿Hay algo más en lo que pueda ayudarte?"

3. Si no → Pregunta NPS (1-10)

4. POST GAS close_interaction

5. Programa follow-up automático (3 días)

Frases de cierre (Mini Guía):

"Queremos que te encante el resultado" 🎯

"En Nu Promo construimos relaciones, no solo vendemos productos" 🤝

📊 Mapa de Variables Botpress

👤 Variables de Usuario (Sesión)

Variable
Tipo
Descripción
user_phone
string
Teléfono WhatsApp del usuario
user_name
string
Nombre WhatsApp o capturado
conversation_id
string
ID de conversación Botpress
entry_timestamp
string
ISO timestamp de entrada
source_channel
string
Canal origen (whatsapp)
is_returning
boolean
Si es usuario recurrente
previous_advisor
string
Asesor previo si existe
lead_id
string
ID del lead en Sheets

🎯 Variables Método 6-3-1

Variable
Tipo
Descripción
client_name
string
Nombre completo del prospecto
client_company
string
Empresa del prospecto
client_email
string
Correo electrónico
client_phone
string
Teléfono de contacto
q1_producto
string
¿Qué producto necesitas?
q2_cuando
string
¿Cuándo lo necesitas?
q3_donde
enum
local | foráneo | ambos
q4_cantidad
number
¿Cuántos necesitas?
q5_presupuesto
string
¿Cuánto quieres invertir?
q6_logotipo
boolean
¿Tiene logotipo/identidad?
q7_evento
string
Cuéntame del evento
q8_audiencia
string
¿A quién va dirigido?
q9_emocion
string
¿Qué quieres que sientan?
q10_estrategica
string
Pregunta de relación profunda
qualification_phase
number
Fase actual (0-4)
qualification_score
number
Score calculado del lead

📋 Variables de Cotización y Pedido

Variable
Tipo
Descripción
quote_id
string
ID cotización (NP-YYYYMMDD-###)
quote_products
object[]
Array de productos cotizados
quote_subtotal
number
Subtotal antes de IVA
quote_iva
number
IVA calculado (16%)
quote_total
number
Total con IVA
quote_decorado
string
Técnica de decorado seleccionada
order_id
string
ID pedido confirmado
order_status
enum
Estado actual del pedido
delivery_date_est
string
Fecha estimada entrega
payment_status
enum
pendiente|anticipo|liquidado

🧑‍💼 Variables de Asesor / Sistema

Variable
Tipo
Descripción
assigned_advisor
string
Nombre asesor asignado
advisor_phone
string
WhatsApp del asesor
advisor_email
string
Email del asesor
pipeline_stage
number
Etapa pipeline (1-6)
nps_score
number
Score NPS del cliente
interaction_count
number
Número de interacciones
last_faq_id
string
Última FAQ consultada
current_intent
enum
Intención actual clasificada
sample_eligible
boolean
Si califica para muestra gratis
gas_response
object
Última respuesta de GAS
⚠️ Write Access: Los nodos Autonomous (N1, N2, N3, N5, N6, N7, N10) tienen "Allow write access" habilitado para modificar variables durante la conversación.
📋 Esquema Google Sheets — 12 Hojas
📊 Hoja 1: LEADS
Columna
Tipo
Descripción
lead_id
STRING
ID único auto-generado (NP-L-XXXX)
timestamp
DATETIME
Fecha/hora de creación
phone
STRING
WhatsApp del lead
name
STRING
Nombre completo
company
STRING
Empresa
email
STRING
Correo electrónico
source
STRING
Canal de origen
q1_producto
STRING
Respuesta Q1
q2_cuando
STRING
Respuesta Q2
q3_donde
STRING
Respuesta Q3
q4_cantidad
NUMBER
Respuesta Q4
q5_presupuesto
STRING
Respuesta Q5
q6_logotipo
BOOLEAN
Respuesta Q6
q7_evento
STRING
Respuesta Q7
q8_audiencia
STRING
Respuesta Q8
q9_emocion
STRING
Respuesta Q9
q10_estrategica
STRING
Respuesta Q10
qualification_score
NUMBER
Score calculado (0-100)
pipeline_stage
NUMBER
Etapa pipeline (1-6)
assigned_advisor
STRING
Asesor asignado
status
STRING
activo|ganado|perdido|dormido
notes
STRING
Notas adicionales
last_interaction
DATETIME
Última interacción
is_80_20
BOOLEAN
Si es cliente estratégico (Pulpo)
📝 Hoja 2: COTIZACIONES
Columna
Tipo
Descripción
quote_id
STRING
NP-Q-YYYYMMDD-###
lead_id
STRING
FK → LEADS
timestamp
DATETIME
Fecha creación
products_json
JSON
[{code, name, qty, unit_price, decoration}]
subtotal
NUMBER
Subtotal sin IVA
iva
NUMBER
IVA 16%
total
NUMBER
Total con IVA
decoration_type
STRING
Técnica de decorado
delivery_est
STRING
8-12 días hábiles est.
status
STRING
borrador|enviada|aceptada|rechazada|expirada
advisor
STRING
Asesor que gestiona
valid_until
DATE
Vigencia (15 días default)
📦 Hoja 3: PEDIDOS
Columna
Tipo
Descripción
order_id
STRING
NP-O-YYYYMMDD-###
quote_id
STRING
FK → COTIZACIONES
lead_id
STRING
FK → LEADS
order_date
DATETIME
Fecha de pedido
products_json
JSON
Productos confirmados
total
NUMBER
Monto total
advance_paid
NUMBER
Anticipo recibido (50%)
balance_due
NUMBER
Saldo pendiente
payment_status
STRING
pendiente|anticipo|liquidado
production_status
STRING
7 etapas de producción
virtual_sample_approved
BOOLEAN
Muestra virtual autorizada
delivery_type
STRING
local_zmg|foraneo
shipping_address
STRING
Dirección de envío
tracking_number
STRING
Guía de envío
estimated_delivery
DATE
Fecha estimada entrega
delivered_date
DATE
Fecha real entrega
advisor
STRING
Asesor responsable
🏷️ Hoja 4: PRODUCTOS

code, name, category, brand, unit_price_mayoreo, min_qty, colors, decoration_suggested, image_url, stock_status, nupromo_url

👥 Hoja 5: ASESORES

advisor_id, name, phone, email, is_active, daily_quota, leads_today, leads_month, pct_deficit, specialty, schedule, is_available

⚙️ Hoja 6: CONFIG

param_key, param_value, description — Incluye: min_order_amount, iva_rate, default_delivery_days, sample_max_pct, sample_min_project, quote_validity_days, working_hours

📝 Hoja 7: LOGS

log_id, timestamp, action, lead_id, advisor, source_node, payload_json, status, error_msg

💬 Hoja 8: FAQ_TEMPLATES

faq_id (1-15), command (/precios, /minimo...), category, response_template, links_json, emoji_set, active

📦 Hoja 9: MUESTRAS

sample_id, lead_id, quote_id, product_code, type (sin_logo|con_logo), value, approved, approved_by, shipped_date, status

📈 Hoja 10: PIPELINE_HISTORY

history_id, lead_id, from_stage, to_stage, timestamp, changed_by, notes

📊 Hoja 11: METRICAS

date, total_leads, total_quotes, total_orders, conversion_rate, avg_ticket, avg_nps, top_product, top_advisor, response_time_avg

📄 Hoja 12: PLANTILLAS_WA

template_id, trigger_event, message_body, variables_used, target (client|advisor|supervisor), active

⚡ Google Apps Script — 18 Endpoints

🔌 Arquitectura GAS

Todos los endpoints se ejecutan vía doPost(e) con un action param que enruta al handler correcto. Autenticación por secret header que valida contra CONFIG.gas_secret.

URL Base: https://script.google.com/macros/s/{DEPLOY_ID}/exec
Method: POST (siempre) | Content-Type: application/json
Auth: Header x-gas-secret = env.GAS_SECRET de Botpress

📡 Lista de Endpoints

Method
Action
Descripción
Hoja Target
POST
check_returning_user
Busca usuario por phone, retorna historial
LEADS
POST
create_lead
Crea lead nuevo con datos 6-3-1
LEADS, LOGS
POST
update_lead
Actualiza campos de lead existente
LEADS
POST
assign_advisor
Rotación PCT MAGNETIK → asigna asesor
ASESORES, LEADS
POST
get_faq_response
Trae template FAQ por ID
FAQ_TEMPLATES
POST
search_products
Busca productos por keyword/categoría
PRODUCTOS
POST
generate_quote
Calcula y genera cotización
COTIZACIONES
POST
update_quote_status
Cambia estado de cotización
COTIZACIONES
POST
create_order
Convierte cotización en pedido
PEDIDOS
POST
get_order_status
Consulta estado de pedido
PEDIDOS
POST
update_order_status
Actualiza estado producción
PEDIDOS, LOGS
POST
check_sample_eligibility
Valida elegibilidad muestra física
MUESTRAS, CONFIG
POST
request_sample
Registra solicitud de muestra
MUESTRAS
POST
create_complaint
Registra queja con prioridad
LOGS
POST
close_interaction
Cierra interacción + NPS
LEADS, METRICAS
POST
update_pipeline_stage
Mueve lead a nueva etapa
PIPELINE_HISTORY
POST
get_daily_metrics
Retorna métricas del día
METRICAS
POST
send_notification
Dispara notificación WA a asesor
PLANTILLAS_WA

🔄 Algoritmo de Rotación PCT (MAGNETIK)

El endpoint assign_advisor ejecuta:

// Pseudocódigo rotación MAGNETIK para Nu Promo function assignAdvisor(leadData) { const advisors = getActiveAdvisors(); // Hoja ASESORES, is_active=TRUE const config = getConfig(); // 1. Si lead recurrente → priorizar asesor previo if (leadData.previous_advisor) { const prev = advisors.find(a => a.name === leadData.previous_advisor); if (prev && prev.is_available) return prev; } // 2. Calcular PCT déficit por asesor advisors.forEach(a => { a.pct_ideal = 100 / advisors.length; // Distribución equitativa a.pct_actual = (a.leads_month / totalLeadsMonth) * 100; a.deficit = a.pct_ideal - a.pct_actual; // Mayor déficit = prioridad }); // 3. Filtrar disponibles en horario + no saturados hoy const available = advisors .filter(a => a.is_available && a.leads_today < a.daily_quota) .sort((a, b) => b.deficit - a.deficit); // Mayor déficit primero // 4. Asignar al de mayor déficit const selected = available[0]; updateAdvisorCount(selected); // +1 lead logAssignment(leadData.lead_id, selected.name); return selected; }
🔀 Flujos Conversacionales Detallados

🟢 Flujo 1: Primer Contacto → Calificación Completa

👋 "Hola"
N0: Extrae phone/name
GAS: check_returning
¿Nuevo?
SÍ nuevo
Bienvenida + ¿En qué puedo ayudarte?
N1: Router clasifica
Quiere cotizar
N3: Pide datos cliente
N3: 6 preguntas producto
N3: 3 preguntas valor
N3: 1 estratégica
GAS: create_lead
GAS: assign_advisor
N8: Genera cotización
N9: Transfiere a asesor
HITL Activo

🔵 Flujo 2: Cliente Recurrente → Seguimiento

📱 Mensaje entrante
N0: Detecta phone
GAS: check_returning ✅
"¡Hola [nombre]! Bienvenido de vuelta"
¿Tiene pedido activo?
"Tu pedido [#] está en: [estado]"
N1: ¿Qué necesita?
Seguimiento
N4: Order Tracker
||
Nuevo pedido
N3: Qualifier (con asesor previo)
||
Asesor directo
N9: HITL con mismo asesor

🟡 Flujo 3: FAQ → Detección de Oportunidad Comercial

"¿Cuál es su mínimo?"
N1: FAQ detected
N2: FAQ /minimo
Respuesta + "¿Te gustaría cotizar?"
N3: Qualifier
||
NO
"¿Algo más? Estoy para ayudarte"
N10: Cierre

🔴 Flujo 4: Queja → Resolución

"Tengo un problema con mi pedido"
N1: RECLAMO
N7: Empático + captura
GAS: create_complaint
GAS: notify supervisor
N9: HITL prioritario
Asesor toma control

🟣 Flujo 5: Muestra Física

"¿Puedo ver una muestra?"
N5: ¿Tiene cotización?
SÍ + ≥$20K
GAS: check_sample ✅
¿Sin logo o con logo?
Sin logo = GRATIS
GAS: request_sample
||
Con logo = COSTO (abonable)
Informa costo + pide OK
NO califica
"La muestra tiene costo, sujeto a aprobación"
N9: Escala a asesor
💬 Sistema FAQ — 15 Respuestas Rápidas
📌 Implementación: Las FAQ se almacenan en la hoja FAQ_TEMPLATES y se cargan vía GAS endpoint get_faq_response. El nodo N2 usa IA para personalizar la respuesta con el nombre del usuario y contexto. Las respuestas originales se usan como base/template.
/precios (FAQ #1)

Intent: precio, lista de precios, cuánto cuesta
Acción: Dirige a web + ofrece cotización personalizada
Nota clave: "Precios de mayoreo, no incluyen impresión"

/minimo (FAQ #2)

Intent: mínimo de compra, pedido mínimo
Respuesta: $5,000 + IVA (puede combinar productos)
Transición: Si interesado → N3

/catalogos (FAQ #3)

Intent: catálogo, ver productos
Links: nupromo.mx + FlippingBook
Mínimo mencionado: $2,000 + IVA

/ubicacion (FAQ #4)

Intent: dónde están, dirección
Dirección: Francisco Javier Alegre 446, GDL
Nota: "Necesario agendar cita"

/envios (FAQ #5)

Intent: envíos, cómo entregan
Local: Gratis dentro ZMG
Foráneo: Paquetería, cuenta y riesgo del cliente

/tiempos (FAQ #6)

Intent: tiempo entrega, cuánto tarda
Respuesta: 8-12 días hábiles post muestra+anticipo

/decorados (FAQ #7)

Intent: decorado, impresión, serigrafía
Link: nupromo.mx/decorados

/costoimpresiones (FAQ #8)

Intent: cuánto cuesta imprimir
Respuesta: Varía por producto/cantidad/técnica
Transición: Pide código → N8

/especial (FAQ #9)

Intent: producto especial, personalizado
Respuesta: Pide imagen + ¿revisaste catálogo?

/existencias (FAQ #10)

Intent: stock, hay existencia
Respuesta: Web muestra stock real-time
Si agotado: "Pregunta fechas de llegada"

/maquila (FAQ #11)

Intent: servicio de maquila
Respuesta: No disponible — solo producto vendido por Nu Promo

/presupuesto (FAQ #12)

Intent: cuánto debería gastar
Respuesta: Pregunta precio target → mejor propuesta

/condiciones (FAQ #13)

Intent: condiciones de pago, políticas
Clave: 50/50 anticipo, sin cambios post-autorización

/ficha (FAQ #14)

Intent: ficha técnica, especificaciones
Respuesta: Disponible en web al dar click en producto

/info (FAQ #15)

Intent: quiénes son, qué hacen
Respuesta: Presentación completa + web + catálogo + video
17,000+ artículos disponibles

⚠️ Discrepancia detectada: FAQ #2 dice mínimo $5,000 + IVA pero FAQ #3 (/catalogos) menciona $2,000 + IVA. Recomendación: Unificar en CONFIG.min_order_amount y que GAS inyecte el valor correcto en ambas respuestas.
📈 Pipeline CRM — 6 Etapas

🔄 Pipeline Visual

1️⃣ CONTACTOPrimer mensaje WA
2️⃣ CALIFICADO6-3-1 completado
3️⃣ COTIZADOCotización enviada
4️⃣ NEGOCIACIÓNAsesor en seguimiento
5️⃣ PEDIDOAnticipo recibido
6️⃣ ENTREGADOPedido completado

📊 Triggers de Cambio de Etapa

1→2: Bot completa Método 6-3-1 → GAS create_lead con score > 0

2→3: Cotización generada y enviada → GAS generate_quote

3→4: Asesor marca "cliente interesado" en Sheets o Botpress HITL command

4→5: Anticipo registrado → GAS create_order con payment_status='anticipo'

5→6: Pedido entregado/enviado → GAS update_order_status status='entregado'

Cada cambio de etapa: Se registra en PIPELINE_HISTORY + se recalculan METRICAS diarias automáticamente via trigger en GAS.

📦 Sub-Pipeline de Producción (dentro de Etapa 5)

5a
Anticipo50% recibido
5b
ProducciónEn fabricación
5c
Muestra VirtualAprobación cliente
5d
DecoradoImpresión/personalización
5e
ListoPago 50% restante
5f
EnviadoEn tránsito

🎯 Clasificación de Clientes (Estrategia Pulpo 80/20)

El campo is_80_20 en LEADS marca clientes estratégicos que reciben tratamiento especial basado en la Guía de Llamadas 80/20.

🥇 AAA
Recompra frecuente, alto ticket. 4 llamadas/día rotación mensual.
🥈 AA
Potencial alto, necesita nurturing. Seguimiento quincenal.
🥉 A
Compra ocasional. Bot maneja + escalamiento bajo demanda.
📋 Nuevo
Sin historial. Calificar vía 6-3-1 → clasificar.
🎯 Método 6-3-1 — Flujo Conversacional del Bot

📋 Implementación en Nodo N3 (QUALIFIER)

El nodo N3 es Autonomous con Write Access. La IA conduce la conversación de forma natural, no como cuestionario rígido. Captura respuestas en variables mientras mantiene fluidez conversacional.

📝 Fase 0 — Datos del Cliente (Pre-calificación)

Contexto IA: "Antes de ayudarte con tu cotización, necesito algunos datos. Prometo que será rápido 😊"

Captura: nombre, empresa, correo, teléfono (si no tenemos de WhatsApp)

Variable: qualification_phase = 0

Validación: Email con regex, teléfono con formato MX

🔷 Fase 1 — Armar el Producto (6 Preguntas)

Q1 — ¿Qué producto?
Variable: q1_producto
Si menciona código → búsqueda en PRODUCTOS
Si vago → ofrece catálogo/categorías
Q2 — ¿Cuándo lo necesitas?
Variable: q2_cuando
Valida vs tiempos de entrega (8-12 días)
Si urgente → flag para asesor
Q3 — ¿Dónde lo necesitas?
Variable: q3_donde (enum)
local → envío gratis ZMG
foráneo → cuenta del cliente
Q4 — ¿Cuántos necesitas?
Variable: q4_cantidad (number)
Valida vs mínimo de compra
Si < mínimo → informa y sugiere
Q5 — ¿Cuánto quieres invertir?
Variable: q5_presupuesto
Si no tiene → "OK, te armo opciones"
Si tiene → valida vs mínimo $5K
Q6 — ¿Tienes logotipo?
Variable: q6_logotipo (boolean)
Si SÍ → "Compártelo cuando gustes"
Si NO → "No te preocupes, te ayudamos"

Variable: qualification_phase = 1 al completar

🎯 Fase 2 — Construir Valor (3 Preguntas)

Contexto IA: "Excelente, ahora quiero entender mejor tu proyecto para darte la mejor propuesta posible 🎁"
Q7 — Cuéntame del evento
Variable: q7_evento
"¿De qué se trata el evento/campaña?"
Permite entender contexto completo
Q8 — ¿A quién va dirigido?
Variable: q8_audiencia
Empleados, clientes, ejecutivos, público general
Impacta en selección de producto
Q9 — ¿Qué quieres que sientan?
Variable: q9_emocion
"¿Qué quieres que piensen o sientan al recibirlo?"
🎁 Genera experiencia emocional memorable

Variable: qualification_phase = 2

🤝 Fase 3 — Crear Relaciones (1 Pregunta Estratégica)

Contexto IA: La IA selecciona UNA pregunta contextual basada en lo que ha aprendido del prospecto.

💡 "¿Cómo está estructurado su equipo?"

💡 "¿Cuántas personas forman parte de la organización?"

💡 "¿Cuál es tu rol dentro de la empresa?"

💡 "¿Cómo suelen organizar este tipo de eventos?"

💡 "¿Qué te gustaría lograr con este proyecto?"

Variable: qualification_phase = 3 → Score se calcula → POST GAS create_lead

📊 Cálculo de Score (qualification_score)

// Score 0-100 calculado en GAS al crear lead function calculateScore(lead) { let score = 0; // Datos completos (+20) if (lead.company) score += 5; if (lead.email) score += 5; if (lead.q7_evento) score += 5; if (lead.q9_emocion) score += 5; // Presupuesto (+30) const budget = parseBudget(lead.q5_presupuesto); if (budget >= 50000) score += 30; else if (budget >= 20000) score += 20; else if (budget >= 5000) score += 10; // Urgencia (+15) if (isUrgent(lead.q2_cuando)) score += 15; else score += 5; // Cantidad (+20) if (lead.q4_cantidad >= 500) score += 20; else if (lead.q4_cantidad >= 100) score += 10; else score += 5; // Tiene logo (+10) if (lead.q6_logotipo) score += 10; // Pregunta estratégica respondida (+5) if (lead.q10_estrategica) score += 5; return Math.min(score, 100); }
📦 Política de Muestras Físicas — Automatización

📋 Reglas de Negocio Implementadas en N5

✅ Muestra GRATIS (sin logo)
• Proyecto ≥ $20,000 MXN
• Muestras ≤ 3% del cotizado
• Lead en etapa ≥ 5 (post-cotización filtrada)
• Prospecto calificado con interés real
• Aprobación automática vía bot
💰 Muestra CON LOGO (costo)
• Siempre tiene costo para el cliente
• Costo abonable al total si se concreta
• Se informa desde el inicio (transparencia)
• Requiere OK explícito del cliente
• Registrada en hoja MUESTRAS
❌ NO califica
• Proyecto < $20,000 MXN
• Sin cotización previa
• Lead en etapa < 5
• Acción: Muestra con costo, sujeta a aprobación interna
• Escala a asesor vía N9
🔧 Producto CUSTOM
• Creado desde cero para el cliente
• Límite del 3% aplica OBLIGATORIO
• Mayor esfuerzo de desarrollo
• Siempre requiere aprobación interna
• Flag especial en MUESTRAS

⚡ Lógica de Expression Cards en N5

// Expression 1: ¿Tiene cotización activa? IF workflow.quote_id !== null && workflow.quote_id !== '' → Continúa a Expression 2 ELSE"Para solicitar muestra necesitas una cotización activa. ¿Te ayudo a cotizar?"Transición a N3_QUALIFIER // Expression 2: ¿Proyecto ≥ $20,000? IF workflow.quote_total >= 20000 → Continúa a Expression 3 ELSE"La muestra tiene costo en este caso. Te comunico con tu asesor."Transición a N9_HITL // Expression 3: ¿Muestras dentro del 3%? IF sampleValue <= workflow.quote_total * 0.03 → ¿Sin logo o con logo? ELSE"El valor de la muestra excede nuestro límite. Te comunico con tu asesor."Transición a N9_HITL // Expression 4: Tipo de muestra IF sampleType === 'sin_logo' → POST GAS request_sample (approved: true)"¡Excelente! Tu muestra sin costo ha sido aprobada 🎉" ELSEInforma costo + pide confirmación"La muestra con logo tiene un costo de $X, que será abonable a tu pedido final."
🧩 Estructura Código GAS — NuPromoBot_MASTER.gs

📄 Estructura de Archivos GAS

// Estructura del proyecto Google Apps Script 📁 NuPromoBot_MASTER ├── 00_Config.gs // Constantes, IDs de hojas, configuración ├── 01_Router.gs // doPost(e) + dispatcher de acciones ├── 02_Auth.gs // Validación de secret + rate limiting ├── 03_Leads.gs // CRUD leads + check_returning_user ├── 04_Advisor.gs // Rotación PCT MAGNETIK + asignación ├── 05_Quotes.gs // Generación y gestión de cotizaciones ├── 06_Orders.gs // Pedidos + sub-pipeline producción ├── 07_Products.gs // Búsqueda en catálogo ├── 08_FAQ.gs // Templates FAQ ├── 09_Samples.gs // Lógica muestras físicas ├── 10_Notifications.gs // Envío WA a asesores/supervisores ├── 11_Pipeline.gs // Cambios de etapa + historial ├── 12_Metrics.gs // Cálculo métricas diarias ├── 13_Complaints.gs // Registro de quejas ├── 14_Cron.gs // Triggers programados └── 15_Utils.gs // Helpers, formateo, validación

⚡ 01_Router.gs — Entry Point

/** * NuPromoBot MASTER — Router Principal * Powered by Veniu | NEXUS Architecture * 18 endpoints, 12 hojas, 15 archivos GAS */ function doPost(e) { try { const data = JSON.parse(e.postData.contents); const secret = e.parameter.secret || data.secret; // Validar autenticación if (!validateSecret(secret)) { return jsonResponse({ success: false, error: 'UNAUTHORIZED' }, 401); } // Router de acciones const action = data.action; const handlers = { 'check_returning_user': () => checkReturningUser(data), 'create_lead': () => createLead(data), 'update_lead': () => updateLead(data), 'assign_advisor': () => assignAdvisor(data), 'get_faq_response': () => getFaqResponse(data), 'search_products': () => searchProducts(data), 'generate_quote': () => generateQuote(data), 'update_quote_status': () => updateQuoteStatus(data), 'create_order': () => createOrder(data), 'get_order_status': () => getOrderStatus(data), 'update_order_status': () => updateOrderStatus(data), 'check_sample_eligibility': () => checkSampleEligibility(data), 'request_sample': () => requestSample(data), 'create_complaint': () => createComplaint(data), 'close_interaction': () => closeInteraction(data), 'update_pipeline_stage': () => updatePipelineStage(data), 'get_daily_metrics': () => getDailyMetrics(data), 'send_notification': () => sendNotification(data), }; if (!handlers[action]) { return jsonResponse({ success: false, error: `Unknown action: ${action}` }); } // Ejecutar + logging const result = handlers[action](); logAction(action, data.lead_id || 'N/A', 'SUCCESS', result); return jsonResponse({ success: true, data: result }); } catch (err) { logAction('ERROR', '', 'ERROR', err.message); return jsonResponse({ success: false, error: err.message }); } } function jsonResponse(obj, code = 200) { return ContentService .createTextOutput(JSON.stringify(obj)) .setMimeType(ContentService.MimeType.JSON); }

🔧 14_Cron.gs — Automatizaciones Programadas

/** * Cron Jobs — Triggers Programados * Configurar en Apps Script → Triggers */ // Diario 8:00 AM — Métricas del día anterior function cronDailyMetrics() { calculateAndSaveMetrics(yesterday()); resetAdvisorDailyCounts(); } // Cada 4 horas — Seguimiento leads dormidos function cronFollowUpReminders() { const staleLeads = getLeadsWithoutInteraction(3); // 3 días staleLeads.forEach(lead => { sendNotification({ target: 'advisor', advisor: lead.assigned_advisor, template: 'follow_up_reminder', lead_name: lead.name, lead_id: lead.lead_id }); }); } // Diario 9:00 PM — Cotizaciones por expirar function cronQuoteExpiry() { const expiring = getQuotesExpiringIn(2); // 2 días expiring.forEach(quote => { sendNotification({ target: 'advisor', advisor: quote.advisor, template: 'quote_expiring', quote_id: quote.quote_id, client_name: quote.client_name }); }); } // Semanal lunes 7:00 AM — Reporte semanal function cronWeeklyReport() { const report = generateWeeklyReport(); sendNotification({ target: 'supervisor', template: 'weekly_report', data: report }); }

📡 Execute Card en Botpress (Ejemplo N0)

// Execute Code Card — N0_EXTRACTOR // Extrae datos de WhatsApp y consulta si es usuario recurrente const phone = event.tags?.conversation?.['whatsapp:userPhone'] || ''; const name = event.tags?.conversation?.['whatsapp:userName'] || 'Visitante'; // Guardar en variables del workflow workflow.user_phone = phone; workflow.user_name = name; workflow.conversation_id = event.conversationId; workflow.entry_timestamp = new Date().toISOString(); // Consultar GAS si es usuario recurrente const response = await axios.post(env.GAS_WEBHOOK_URL, { action: 'check_returning_user', secret: env.GAS_SECRET, phone: phone }); if (response.data.success && response.data.data.found) { workflow.is_returning = true; workflow.lead_id = response.data.data.lead_id; workflow.previous_advisor = response.data.data.assigned_advisor; workflow.pipeline_stage = response.data.data.pipeline_stage; workflow.client_name = response.data.data.name; } else { workflow.is_returning = false; }