From e8db3e926cb0a5008be400b798eddf9c794a6962 Mon Sep 17 00:00:00 2001 From: consultoria-as Date: Mon, 18 May 2026 04:54:56 +0000 Subject: [PATCH] feat(manager): auto-provision WhatsApp Bridge on demo create/destroy - Add POS_INTERNAL_URL config for cross-VM API calls - create_demo now calls POS /internal/whatsapp-bridge after tenant creation - delete_tenant now destroys bridge container before dropping DB - Graceful fallback if bridge provisioning fails --- manager/config.py | 3 ++ manager/services/tenant_service.py | 45 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/manager/config.py b/manager/config.py index d5684a1..b6e996c 100644 --- a/manager/config.py +++ b/manager/config.py @@ -29,6 +29,9 @@ MANAGER_JWT_EXPIRES = int(os.environ.get("MANAGER_JWT_EXPIRES", "28800")) # 8 h # Internal API key for manager-to-POS operations INTERNAL_API_KEY = os.environ.get("INTERNAL_API_KEY", "") +# ─── POS Server (for internal API calls from manager VM) ─────────────────── +POS_INTERNAL_URL = os.environ.get("POS_INTERNAL_URL", "http://192.168.10.91:5001") + # ─── Demo Settings ───────────────────────────────────────────────────────── DEMO_DEFAULT_DAYS = int(os.environ.get("DEMO_DEFAULT_DAYS", "14")) DEMO_DEFAULT_PIN = os.environ.get("DEMO_DEFAULT_PIN", "0000") diff --git a/manager/services/tenant_service.py b/manager/services/tenant_service.py index c06c69e..0df77ac 100644 --- a/manager/services/tenant_service.py +++ b/manager/services/tenant_service.py @@ -153,6 +153,31 @@ def create_demo(name, email, demo_days=None, subdomain=None, pin="0000"): cur.close() conn.close() + # Auto-provision WhatsApp Bridge + try: + import urllib.request + import json as _json + from config import POS_INTERNAL_URL, INTERNAL_API_KEY + bridge_payload = _json.dumps({ + "tenant_id": tenant_id, + "subdomain": subdomain, + "db_name": result["db_name"] + }).encode() + req = urllib.request.Request( + f"{POS_INTERNAL_URL}/pos/api/internal/whatsapp-bridge", + data=bridge_payload, + headers={ + "Content-Type": "application/json", + "X-Internal-Key": INTERNAL_API_KEY + }, + method="POST" + ) + with urllib.request.urlopen(req, timeout=30) as resp: + bridge_data = _json.loads(resp.read().decode()) + result["whatsapp_bridge"] = bridge_data + except Exception as e: + result["whatsapp_bridge_error"] = str(e) + result["demo_days"] = days result["expires_at"] = str(datetime.now() + timedelta(days=days)) result["access_url"] = f"https://{subdomain}.nexusautoparts.com.mx/pos/login" @@ -221,6 +246,26 @@ def delete_tenant(tenant_id): if not tenant: raise ValueError("Tenant not found") db_name = tenant["db_name"] + subdomain = tenant.get("subdomain") or f"tenant-{tenant_id}" + + # Destroy WhatsApp Bridge container + try: + import urllib.request + import json as _json + from config import POS_INTERNAL_URL, INTERNAL_API_KEY + bridge_payload = _json.dumps({"subdomain": subdomain}).encode() + req = urllib.request.Request( + f"{POS_INTERNAL_URL}/pos/api/internal/whatsapp-bridge", + data=bridge_payload, + headers={ + "Content-Type": "application/json", + "X-Internal-Key": INTERNAL_API_KEY + }, + method="DELETE" + ) + urllib.request.urlopen(req, timeout=15) + except Exception: + pass # Bridge may not exist conn = get_master_conn() cur = conn.cursor()