feat(whatsapp): per-tenant WhatsApp configuration
- Refactor whatsapp_service.py to accept bridge_url parameter - whatsapp_bp.py: remove hardcoded tenant_id=11, use g.tenant_id - whatsapp_bp.py: webhook now accepts ?tenant_id param with fallback - config_bp.py: add GET/PUT /config/whatsapp endpoints - Each tenant can now have its own Baileys bridge URL and settings
This commit is contained in:
@@ -451,3 +451,129 @@ def update_vehicle_compat_source():
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({'message': 'Vehicle compatibility source updated', 'source': source})
|
||||
|
||||
|
||||
# ─── Allowed Part Brands ─────────────────────────────────────────────────────
|
||||
|
||||
# Whitelist of part manufacturers shown in the allowed-brands selector
|
||||
_ALLOWED_PART_BRANDS = [
|
||||
'Luk', 'Motocraft', 'Euzcadi', 'Gates', 'Injetech', 'Bilstein',
|
||||
'Monroe', 'Yokomitzu', 'Ecom', 'Lth', 'Dynamik', 'Wagner',
|
||||
'Bosch', 'Brembo', 'Champion', 'Dorman', 'Kyb', 'Handkook',
|
||||
'Tomco', 'Mann Filter', 'Total Parts', 'Kanadian', 'Pirelli',
|
||||
'NGK', 'Moresa', 'Fritec', 'Acdelco', 'Dash4', 'Moog', 'SYD',
|
||||
'FRAM', 'AUTOLITE'
|
||||
]
|
||||
|
||||
|
||||
@config_bp.route('/available-brands', methods=['GET'])
|
||||
@require_auth()
|
||||
def get_available_brands():
|
||||
"""Return whitelisted aftermarket manufacturer names from master DB."""
|
||||
from tenant_db import get_master_conn
|
||||
conn = get_master_conn()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT DISTINCT m.name_manufacture
|
||||
FROM manufacturers m
|
||||
JOIN aftermarket_parts ap ON ap.manufacturer_id = m.id_manufacture
|
||||
WHERE m.name_manufacture IS NOT NULL AND m.name_manufacture != ''
|
||||
AND LOWER(m.name_manufacture) = ANY(%s)
|
||||
ORDER BY m.name_manufacture ASC
|
||||
""", ([b.lower() for b in _ALLOWED_PART_BRANDS],))
|
||||
brands = [r[0] for r in cur.fetchall()]
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({'brands': brands})
|
||||
|
||||
|
||||
@config_bp.route('/allowed-brands', methods=['GET'])
|
||||
@require_auth()
|
||||
def get_allowed_brands():
|
||||
"""Return the tenant's allowed part brands from tenant_config."""
|
||||
import json
|
||||
conn = get_tenant_conn(g.tenant_id)
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT value FROM tenant_config WHERE key = 'allowed_part_brands'")
|
||||
row = cur.fetchone()
|
||||
cur.close()
|
||||
conn.close()
|
||||
if row and row[0]:
|
||||
try:
|
||||
brands = json.loads(row[0])
|
||||
if isinstance(brands, list):
|
||||
return jsonify({'brands': brands})
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
pass
|
||||
return jsonify({'brands': []})
|
||||
|
||||
|
||||
@config_bp.route('/allowed-brands', methods=['PUT'])
|
||||
@require_auth('config.edit')
|
||||
def update_allowed_brands():
|
||||
"""Save the tenant's allowed part brands to tenant_config."""
|
||||
import json
|
||||
data = request.get_json() or {}
|
||||
brands = data.get('brands', [])
|
||||
if not isinstance(brands, list):
|
||||
return jsonify({'error': 'brands must be an array'}), 400
|
||||
|
||||
conn = get_tenant_conn(g.tenant_id)
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
INSERT INTO tenant_config (key, value) VALUES ('allowed_part_brands', %s)
|
||||
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value
|
||||
""", (json.dumps(brands),))
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
return jsonify({'message': 'Allowed brands updated', 'brands': brands})
|
||||
|
||||
|
||||
# ─── WhatsApp Configuration ────────────────────────────────────────────────
|
||||
|
||||
@config_bp.route('/whatsapp', methods=['GET'])
|
||||
@require_auth('config.view')
|
||||
def get_whatsapp_config():
|
||||
"""Get WhatsApp bridge configuration for this tenant."""
|
||||
conn = get_tenant_conn(g.tenant_id)
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT key, value FROM tenant_config WHERE key LIKE 'whatsapp_%'")
|
||||
rows = {row[0]: row[1] for row in cur.fetchall()}
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'bridge_url': rows.get('whatsapp_bridge_url', ''),
|
||||
'bridge_key': rows.get('whatsapp_bridge_key', ''),
|
||||
'enabled': rows.get('whatsapp_enabled', 'false').lower() == 'true',
|
||||
'phone_number': rows.get('whatsapp_phone_number', ''),
|
||||
})
|
||||
|
||||
|
||||
@config_bp.route('/whatsapp', methods=['PUT'])
|
||||
@require_auth('config.edit')
|
||||
def update_whatsapp_config():
|
||||
"""Update WhatsApp bridge configuration for this tenant."""
|
||||
data = request.get_json() or {}
|
||||
conn = get_tenant_conn(g.tenant_id)
|
||||
cur = conn.cursor()
|
||||
|
||||
settings = {
|
||||
'whatsapp_bridge_url': data.get('bridge_url', ''),
|
||||
'whatsapp_bridge_key': data.get('bridge_key', ''),
|
||||
'whatsapp_enabled': 'true' if data.get('enabled') else 'false',
|
||||
'whatsapp_phone_number': data.get('phone_number', ''),
|
||||
}
|
||||
|
||||
for key, value in settings.items():
|
||||
cur.execute("""
|
||||
INSERT INTO tenant_config (key, value) VALUES (%s, %s)
|
||||
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value
|
||||
""", (key, value))
|
||||
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
return jsonify({'message': 'WhatsApp configuration updated'})
|
||||
|
||||
Reference in New Issue
Block a user