Files
Autoparts-DB/pos/blueprints/whatsapp_bp.py
consultoria-as e43894b7a4 feat: WhatsApp bridge con Baileys directo — QR funcional
Reemplaza Evolution API con bridge Node.js propio usando Baileys.
QR se genera en ~10 segundos. Auto-reply con chatbot IA.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 04:02:16 +00:00

156 lines
4.7 KiB
Python

# /home/Autopartes/pos/blueprints/whatsapp_bp.py
"""WhatsApp via Baileys Bridge.
Endpoints:
GET /pos/api/whatsapp/status -- Connection status
GET /pos/api/whatsapp/qr -- Get QR code
POST /pos/api/whatsapp/connect -- Start connection
POST /pos/api/whatsapp/logout -- Disconnect
POST /pos/api/whatsapp/webhook -- Receive messages (public)
POST /pos/api/whatsapp/send -- Send message
GET /pos/api/whatsapp/conversations -- List conversations
"""
from flask import Blueprint, request, jsonify, g
from middleware import require_auth
from tenant_db import get_tenant_conn
from services import whatsapp_service
whatsapp_bp = Blueprint('whatsapp', __name__, url_prefix='/pos/api/whatsapp')
@whatsapp_bp.route('/status', methods=['GET'])
@require_auth()
def status():
return jsonify(whatsapp_service.get_status())
@whatsapp_bp.route('/qr', methods=['GET'])
@require_auth()
def qr():
return jsonify(whatsapp_service.get_qr())
@whatsapp_bp.route('/connect', methods=['POST'])
@require_auth()
def connect():
return jsonify(whatsapp_service.connect())
@whatsapp_bp.route('/logout', methods=['POST'])
@require_auth()
def logout():
return jsonify(whatsapp_service.logout())
@whatsapp_bp.route('/webhook', methods=['POST'])
def webhook():
"""Receive messages from Baileys bridge (public, no auth)."""
data = request.get_json(force=True, silent=True) or {}
if data.get('event') != 'messages.upsert':
return jsonify({'ok': True})
msg = whatsapp_service.process_incoming(data)
if not msg.get('phone') or msg.get('from_me'):
return jsonify({'ok': True})
# Save to DB if tenant connection available
try:
# Try to get a tenant connection (use default tenant for webhook)
conn = get_tenant_conn(11) # TODO: resolve tenant from phone number
cur = conn.cursor()
cur.execute("""
INSERT INTO whatsapp_messages (phone, direction, message_text, wa_message_id)
VALUES (%s, 'incoming', %s, %s)
ON CONFLICT DO NOTHING
""", (msg['phone'], msg['text'], msg['message_id']))
conn.commit()
cur.close()
conn.close()
except Exception:
pass
# Auto-reply with AI chatbot
if msg.get('text'):
try:
from services.ai_chat import chat
ai_resp = chat(msg['text'])
reply = ai_resp.get('message', '')
if reply:
whatsapp_service.send_message(msg['phone'], reply)
except Exception:
pass
return jsonify({'ok': True})
@whatsapp_bp.route('/send', methods=['POST'])
@require_auth()
def send():
data = request.get_json() or {}
phone = data.get('phone', '')
message = data.get('message', '')
if not phone or not message:
return jsonify({'error': 'phone and message required'}), 400
result = whatsapp_service.send_message(phone, message)
# Save outgoing message
try:
conn = get_tenant_conn(g.tenant_id)
cur = conn.cursor()
cur.execute("""
INSERT INTO whatsapp_messages (phone, direction, message_text)
VALUES (%s, 'outgoing', %s)
""", (phone, message))
conn.commit()
cur.close()
conn.close()
except Exception:
pass
return jsonify(result)
@whatsapp_bp.route('/conversations', methods=['GET'])
@require_auth()
def conversations():
try:
conn = get_tenant_conn(g.tenant_id)
cur = conn.cursor()
cur.execute("""
SELECT phone, MAX(message_text) as last_message, MAX(created_at) as last_at, COUNT(*) as msg_count
FROM whatsapp_messages
GROUP BY phone
ORDER BY MAX(created_at) DESC
LIMIT 50
""")
convos = [{'phone': r[0], 'last_message': r[1], 'last_at': str(r[2]), 'count': r[3]} for r in cur.fetchall()]
cur.close()
conn.close()
return jsonify({'conversations': convos})
except Exception as e:
return jsonify({'conversations': [], 'error': str(e)})
@whatsapp_bp.route('/conversations/<phone>', methods=['GET'])
@require_auth()
def conversation_messages(phone):
try:
conn = get_tenant_conn(g.tenant_id)
cur = conn.cursor()
cur.execute("""
SELECT id, direction, message_text, created_at
FROM whatsapp_messages
WHERE phone = %s
ORDER BY created_at
LIMIT 100
""", (phone,))
msgs = [{'id': r[0], 'direction': r[1], 'text': r[2], 'date': str(r[3])} for r in cur.fetchall()]
cur.close()
conn.close()
return jsonify({'messages': msgs})
except Exception as e:
return jsonify({'messages': [], 'error': str(e)})