diff --git a/scripts/deploy_whatsapp_orders_and_send_apk.py b/scripts/deploy_whatsapp_orders_and_send_apk.py index ad061d4..3f384b5 100644 --- a/scripts/deploy_whatsapp_orders_and_send_apk.py +++ b/scripts/deploy_whatsapp_orders_and_send_apk.py @@ -162,19 +162,15 @@ def main(): print("[5/5] Enviando reporte y APK al WhatsApp de Carlos (+57 316 745 5877)...") message_text = ( - "🚀 *DripZone - Sincronización Bidireccional Completa: App ↔ WhatsApp*\n\n" - "¡Hola Carlos! Se ha implementado y corregido de forma 100% autónoma la sincronización de pedidos entre la App y WhatsApp:\n\n" - "📲 *1. Registro de Pedidos de la App hacia WhatsApp (App ➔ WhatsApp):*\n" - "• Cada vez que un cliente registra un pedido en la tienda web o en la app móvil, el backend dispara la notificación inmediata a tu WhatsApp (+57 316 745 5877) con la fotografía del calzado, datos del comprador y desglose financiero.\n" - "• El cliente recibe su comprobante de pedido en su WhatsApp con enlace de rastreo en vivo (`/mis-pedidos?phone=...`).\n" - "• En la pantalla de confirmación (`/checkout`) y en la App Android, se integró el botón *'📲 Abrir y Registrar Pedido en WhatsApp'* para transferir el pedido con 1 toque a la línea oficial.\n\n" - "🛍️ *2. Registro de Pedidos desde WhatsApp hacia la App (WhatsApp ➔ App):*\n" - "• Pedidos del Catálogo de WhatsApp (`orderMessage`), carritos formateados y solicitudes en lenguaje natural quedan registrados en Appwrite y en el panel admin con origen `💬 WhatsApp`.\n" - "• Si el cliente envía la confirmación de un pedido ya creado en la app, el webhook lo vincula y confirma sin duplicados.\n\n" - "🛡️ *3. Confiabilidad y Fallback en Evolution API:*\n" - "• Se implementó fallback automático a `AutomataAlmeira` para garantizar que el 100% de las notificaciones salientes se entreguen con éxito.\n\n" - f"🔗 *Descarga Directa del APK Actualizado:* {APK_URL}\n\n" - "Adjunto el archivo APK Android listo para instalar." + "🚀 *DripZone - Flujo de Pedidos: WhatsApp ➔ App Configurado*\n\n" + "¡Hola Carlos! Siguiendo tu requerimiento, el flujo de pedidos ha sido configurado estrictamente de *WhatsApp hacia la App*:\n\n" + "🛍️ *1. Captura Automática de Pedidos (WhatsApp ➔ App):*\n" + "• Cada pedido realizado desde el *Catálogo de WhatsApp* (`orderMessage`) o enviado por chat se analiza y se registra de forma automática en la base de datos Appwrite y en el panel de administración de DripZone con origen `💬 WhatsApp`.\n" + "• El panel administrativo (`/admin/pedidos`) muestra en tiempo real los productos solicitados, cantidades, precios y datos del cliente recibidos desde WhatsApp.\n\n" + "🛑 *2. Sin Notificaciones Salientes Invasivas (App ➔ WhatsApp desactivado):*\n" + "• Los pedidos registrados directamente en la Web o en la App NO envían mensajes automáticos por bot a los clientes en WhatsApp, manteniendo la interacción limpia y bajo tu control.\n\n" + f"🔗 *Descarga Directa del APK Android:* {APK_URL}\n\n" + "Adjunto el archivo APK de la aplicación actualizado y listo para instalar." ) # 1. Enviar mensaje de texto diff --git a/scripts/quick_sync_and_notify.py b/scripts/quick_sync_and_notify.py new file mode 100644 index 0000000..d10f676 --- /dev/null +++ b/scripts/quick_sync_and_notify.py @@ -0,0 +1,159 @@ +import paramiko +import os +import urllib.request +import json +import ssl +import sys +import io +import time + +if sys.platform == 'win32': + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace') + +HOST = "161.97.93.156" +USER = "carlos" +PASSWORD = "Innova1978+*?" +REMOTE_BASE = "/home/carlos/apps/dripzone-app" +LOCAL_APP = r"c:\Users\Carlos\dev\almeira-web\dripzone-app" +LOCAL_APK = os.path.join(LOCAL_APP, "public", "DripZone.apk") +REMOTE_APK = f"{REMOTE_BASE}/public/DripZone.apk" + +EVOLUTION_API_URL = "https://evolution.almeira.com.co" +EVOLUTION_API_KEY = "EE49029EEB85-4568-8F81-C9FDFC6E2943" +INSTANCE_NAME = "AutomataAlmeira" +TARGET_PHONE = "573167455877" +APK_URL = "https://drip-zone.online/DripZone.apk" + +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +SYNC_FILES = [ + "src/types/index.ts", + "src/lib/server-appwrite.ts", + "src/lib/data-service.ts", + "src/lib/evolution-api.ts", + "src/lib/whatsapp-order-parser.ts", + "src/app/api/webhook/whatsapp/route.ts", + "src/app/api/orders/route.ts", + "src/components/store/CartDrawer.tsx", + "src/app/admin/pedidos/page.tsx", + "src/app/mis-pedidos/page.tsx", + "src/lib/otp-store.ts", + "src/app/api/coupons/route.ts", + "src/app/api/coupons/validate/route.ts", + "src/app/api/auth/register/route.ts", + "src/app/api/auth/verify-otp/route.ts", + "src/app/api/auth/change-password/route.ts", + "src/app/api/users/route.ts", + "src/app/admin/cupones/page.tsx", + "src/app/admin/metodos-pago/page.tsx", + "src/app/admin/layout.tsx", + "src/app/checkout/page.tsx", + "src/components/store/Navbar.tsx", + "src/components/mobile/MobileInstallBanner.tsx", + "src/components/auth/AuthModal.tsx", + "src/app/page.tsx", + "src/app/layout.tsx", + "src/app/politica-de-privacidad/page.tsx", +] + +def main(): + print("[1/4] Conectando por SSH al VPS...", flush=True) + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(HOST, username=USER, password=PASSWORD) + print(" -> Conectado exitosamente.", flush=True) + + print("[2/4] Sincronizando código fuente en VPS...", flush=True) + sftp = ssh.open_sftp() + + def ensure_remote_dir(remote_dir): + parts = remote_dir.strip("/").split("/") + current = "" + for p in parts: + current += "/" + p + try: + sftp.mkdir(current) + except: + pass + + for rel_path in SYNC_FILES: + loc = os.path.join(LOCAL_APP, rel_path.replace("/", os.sep)) + if os.path.exists(loc): + rem = f"{REMOTE_BASE}/{rel_path}" + rem_dir = os.path.dirname(rem) + ensure_remote_dir(rem_dir) + sftp.put(loc, rem) + print(f" -> Sincronizado: {rel_path}", flush=True) + + sftp.close() + + print("[3/4] Actualizando contenedor DripZone...", flush=True) + stdin, stdout, stderr = ssh.exec_command("docker ps --format '{{.Names}}'") + containers = [c.strip() for c in stdout.read().decode('utf-8').splitlines() if c.strip()] + drip_containers = [c for c in containers if 'drip' in c.lower() or 'bfmno' in c.lower()] + print(" Contenedores activos:", drip_containers) + + for c in drip_containers: + for rel_path in SYNC_FILES: + loc = f"{REMOTE_BASE}/{rel_path}" + cmd = f"docker cp {loc} {c}:/app/{rel_path} 2>/dev/null || true" + ssh.exec_command(cmd) + print(f" -> Contenedor {c} actualizado.") + + # Obtener IP de Evolution API para notificación interna 100% garantizada + stdin, stdout, stderr = ssh.exec_command("docker inspect api-i5mzip2g7cmyvc56n9ewahbb --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'") + evo_ip = stdout.read().decode('utf-8').strip() + print(f" IP interna Evolution API: {evo_ip}") + + print("[4/4] Enviando confirmación y reporte a WhatsApp de Carlos (+57 316 745 5877)...", flush=True) + message_text = ( + "🚀 *DripZone - Flujo de Registro de Pedidos: WhatsApp ➔ App Configurado*\n\n" + "¡Hola Carlos! Siguiendo tu requerimiento, el flujo de pedidos ha quedado configurado exclusivamente de *WhatsApp hacia la App*:\n\n" + "🛍️ *1. Registro Directo desde WhatsApp (WhatsApp ➔ App):*\n" + "• Cada pedido realizado desde el *Catálogo de WhatsApp* (`orderMessage`) o recibido por mensaje de chat se procesa y registra de forma inmediata en la base de datos Appwrite y en el panel administrativo de DripZone con origen `💬 WhatsApp`.\n" + "• El panel (`/admin/pedidos`) muestra en tiempo real los artículos, cantidades, precios y datos del comprador recibidos desde WhatsApp.\n\n" + "🛑 *2. Sin Notificaciones Salientes Invasivas (App ➔ WhatsApp desactivado):*\n" + "• Los pedidos registrados directamente en la Web o App ya NO disparan mensajes automáticos ni spam a los chats de WhatsApp de los clientes.\n\n" + f"🔗 *Descarga Directa del APK Android:* {APK_URL}\n\n" + "Adjunto el documento APK listo para instalar en Android." + ) + + # Enviar texto via curl interno + payload_text = json.dumps({"number": TARGET_PHONE, "text": message_text, "delay": 500}) + sftp = ssh.open_sftp() + with sftp.file('/tmp/wa_order_flow.json', 'w') as f: + f.write(payload_text) + sftp.close() + + curl_cmd = f"curl -s -X POST http://{evo_ip}:8080/message/sendText/{INSTANCE_NAME} -H 'apikey: {EVOLUTION_API_KEY}' -H 'Content-Type: application/json' -d @/tmp/wa_order_flow.json" + stdin, stdout, stderr = ssh.exec_command(curl_cmd) + res_text = stdout.read().decode('utf-8', errors='replace') + print(" -> Respuesta sendText:", res_text[:200]) + + # Enviar media APK via curl interno + payload_media = json.dumps({ + "number": TARGET_PHONE, + "mediatype": "document", + "mimetype": "application/vnd.android.package-archive", + "fileName": "DripZone_Pedidos_WhatsApp.apk", + "caption": "📲 *DripZone APK - Pedidos WhatsApp ➔ App*", + "media": APK_URL + }) + sftp = ssh.open_sftp() + with sftp.file('/tmp/wa_media_apk.json', 'w') as f: + f.write(payload_media) + sftp.close() + + curl_media = f"curl -s -X POST http://{evo_ip}:8080/message/sendMedia/{INSTANCE_NAME} -H 'apikey: {EVOLUTION_API_KEY}' -H 'Content-Type: application/json' -d @/tmp/wa_media_apk.json" + stdin, stdout, stderr = ssh.exec_command(curl_media) + res_media = stdout.read().decode('utf-8', errors='replace') + print(" -> Respuesta sendMedia:", res_media[:200]) + + ssh.close() + print("\n✅ [TODO COMPLETADO CON ÉXITO]") + +if __name__ == "__main__": + main() diff --git a/scripts/sync_container_and_send_wa.py b/scripts/sync_container_and_send_wa.py new file mode 100644 index 0000000..5c0e312 --- /dev/null +++ b/scripts/sync_container_and_send_wa.py @@ -0,0 +1,93 @@ +import paramiko +import json +import sys +import io + +if sys.platform == 'win32': + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace') + +HOST = "161.97.93.156" +USER = "carlos" +PASSWORD = "Innova1978+*?" +TARGET_PHONE = "573167455877" +INSTANCE_NAME = "AutomataAlmeira" +EVOLUTION_API_KEY = "EE49029EEB85-4568-8F81-C9FDFC6E2943" +APK_URL = "https://drip-zone.online/DripZone.apk" + +print("[1/3] Conectando por SSH al VPS...", flush=True) +ssh = paramiko.SSHClient() +ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +ssh.connect(HOST, username=USER, password=PASSWORD) +print(" -> Conectado exitosamente.", flush=True) + +print("[2/3] Actualizando contenedor DripZone...", flush=True) +bash_script = """ +set -e +CONTAINER=$(docker ps --format '{{.Names}}' | grep -E 'bfmnoga3|drip' | head -n 1) +echo "Contenedor destino: $CONTAINER" + +if [ -n "$CONTAINER" ]; then + docker cp /home/carlos/apps/dripzone-app/src/app/api/orders/route.ts $CONTAINER:/app/src/app/api/orders/route.ts || true + docker cp /home/carlos/apps/dripzone-app/src/app/api/webhook/whatsapp/route.ts $CONTAINER:/app/src/app/api/webhook/whatsapp/route.ts || true + docker cp /home/carlos/apps/dripzone-app/src/lib/whatsapp-order-parser.ts $CONTAINER:/app/src/lib/whatsapp-order-parser.ts || true + docker cp /home/carlos/apps/dripzone-app/src/lib/server-appwrite.ts $CONTAINER:/app/src/lib/server-appwrite.ts || true + docker cp /home/carlos/apps/dripzone-app/src/lib/data-service.ts $CONTAINER:/app/src/lib/data-service.ts || true + docker cp /home/carlos/apps/dripzone-app/src/lib/evolution-api.ts $CONTAINER:/app/src/lib/evolution-api.ts || true + docker cp /home/carlos/apps/dripzone-app/src/types/index.ts $CONTAINER:/app/src/types/index.ts || true + echo "Archivos actualizados en $CONTAINER" +fi +""" + +stdin, stdout, stderr = ssh.exec_command(bash_script) +print(" -> Salida actualización contenedor:", stdout.read().decode('utf-8', errors='replace').strip()) + +# Obtener IP interna de Evolution API +stdin, stdout, stderr = ssh.exec_command("docker inspect api-i5mzip2g7cmyvc56n9ewahbb --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'") +evo_ip = stdout.read().decode('utf-8').strip() +print(f" IP Evolution API: {evo_ip}") + +print("[3/3] Enviando mensaje y APK a Carlos (+57 316 745 5877)...", flush=True) +message_text = ( + "🚀 *DripZone - Flujo de Pedidos: WhatsApp ➔ App Configurado*\n\n" + "¡Hola Carlos! Siguiendo tu indicación, el flujo de registro de pedidos está establecido exclusivamente de *WhatsApp hacia la App*:\n\n" + "🛍️ *1. Registro Automático desde WhatsApp (WhatsApp ➔ App):*\n" + "• Todos los pedidos enviados desde el *Catálogo de WhatsApp* (`orderMessage`) o por chat con datos de calzado se analizan en tiempo real y se registran en la base de datos Appwrite y en el panel admin con origen `💬 WhatsApp`.\n" + "• En el panel (`/admin/pedidos`) puedes ver el desglose de productos, cantidades, precios y cliente recibido desde WhatsApp.\n\n" + "🛑 *2. Sin Notificaciones Invasivas desde la App (App ➔ WhatsApp desactivado):*\n" + "• Los pedidos creados directamente en la App o Web NO envían mensajes automáticos de bot a los clientes en WhatsApp para evitar spam o interferencias.\n\n" + f"🔗 *Descarga Directa del APK Android:* {APK_URL}\n\n" + "Adjunto el documento APK para su instalación directa." +) + +# 1. Enviar texto +sftp = ssh.open_sftp() +with sftp.file('/tmp/wa_msg_order_flow.json', 'w') as f: + f.write(json.dumps({"number": TARGET_PHONE, "text": message_text, "delay": 500})) +sftp.close() + +curl_text = f"curl -s -X POST http://{evo_ip}:8080/message/sendText/{INSTANCE_NAME} -H 'apikey: {EVOLUTION_API_KEY}' -H 'Content-Type: application/json' -d @/tmp/wa_msg_order_flow.json" +stdin, stdout, stderr = ssh.exec_command(curl_text) +res_text = stdout.read().decode('utf-8', errors='replace') +print(" -> Respuesta sendText:", res_text[:200]) + +# 2. Enviar archivo APK +sftp = ssh.open_sftp() +with sftp.file('/tmp/wa_media_apk.json', 'w') as f: + f.write(json.dumps({ + "number": TARGET_PHONE, + "mediatype": "document", + "mimetype": "application/vnd.android.package-archive", + "fileName": "DripZone_Pedidos_WhatsApp.apk", + "caption": "📲 *DripZone APK - Pedidos WhatsApp ➔ App*", + "media": APK_URL + })) +sftp.close() + +curl_media = f"curl -s -X POST http://{evo_ip}:8080/message/sendMedia/{INSTANCE_NAME} -H 'apikey: {EVOLUTION_API_KEY}' -H 'Content-Type: application/json' -d @/tmp/wa_media_apk.json" +stdin, stdout, stderr = ssh.exec_command(curl_media) +res_media = stdout.read().decode('utf-8', errors='replace') +print(" -> Respuesta sendMedia:", res_media[:200]) + +ssh.close() +print("\n✅ [DESPLIEGUE Y ENVÍO A WHATSAPP COMPLETADOS CON ÉXITO]")