""" WhatsApp Customer Service — identificación y vinculación de clientes. Funciones para buscar, crear y vincular clientes desde el flujo de WhatsApp. """ import re def find_customer_by_phone(phone, tenant_conn): """Buscar cliente por número de teléfono exacto o parcial.""" if not tenant_conn or not phone: return [] cur = tenant_conn.cursor() # Limpiar phone de prefijos internacionales para búsqueda flexible clean = phone.replace('+52', '').replace('52', '').lstrip('1') cur.execute(""" SELECT id, name, phone, address, rfc FROM customers WHERE phone = %s OR phone LIKE %s OR phone LIKE %s LIMIT 5 """, (phone, f'%{clean}', f'%{clean[-10:]}' if len(clean) >= 10 else f'%{clean}')) rows = cur.fetchall() cur.close() return [{'id': r[0], 'name': r[1], 'phone': r[2], 'address': r[3], 'rfc': r[4]} for r in rows] def find_customer_by_name(name, tenant_conn): """Buscar cliente por nombre (ILIKE).""" if not tenant_conn or not name: return [] cur = tenant_conn.cursor() # Buscar por nombre completo o primer palabra first_word = name.split()[0] if name else name cur.execute(""" SELECT id, name, phone, address, rfc FROM customers WHERE name ILIKE %s OR name ILIKE %s LIMIT 5 """, (f'%{name}%', f'%{first_word}%')) rows = cur.fetchall() cur.close() return [{'id': r[0], 'name': r[1], 'phone': r[2], 'address': r[3], 'rfc': r[4]} for r in rows] def search_customers(query, tenant_conn): """Buscar por teléfono o nombre.""" if not tenant_conn or not query: return [] # Detectar si es número de teléfono digits = re.sub(r'\D', '', query) if len(digits) >= 7: by_phone = find_customer_by_phone(digits, tenant_conn) if by_phone: return by_phone return find_customer_by_name(query, tenant_conn) def get_customer_by_id(tenant_conn, customer_id): """Obtener cliente por ID.""" if not tenant_conn or not customer_id: return None cur = tenant_conn.cursor() cur.execute(""" SELECT id, name, phone, address, rfc, vehicle_info FROM customers WHERE id = %s """, (customer_id,)) row = cur.fetchone() cur.close() if row: return { 'id': row[0], 'name': row[1], 'phone': row[2], 'address': row[3], 'rfc': row[4], 'vehicle_info': row[5] } return None def create_customer(tenant_conn, phone, name, email=None, address=None, rfc=None): """Crear cliente nuevo desde WhatsApp.""" if not tenant_conn: return None cur = tenant_conn.cursor() cur.execute(""" INSERT INTO customers (name, phone, email, address, rfc, is_active, created_at) VALUES (%s, %s, %s, %s, %s, TRUE, NOW()) RETURNING id """, (name, phone, email, address, rfc)) cid = cur.fetchone()[0] tenant_conn.commit() cur.close() return cid def link_wa_customer(phone, customer_id, tenant_conn): """Vincular número WA a cliente permanentemente.""" if not tenant_conn or not phone or not customer_id: return cur = tenant_conn.cursor() cur.execute(""" INSERT INTO wa_customer_links (phone, customer_id, updated_at) VALUES (%s, %s, NOW()) ON CONFLICT (phone) DO UPDATE SET customer_id = EXCLUDED.customer_id, updated_at = NOW() """, (phone, customer_id)) tenant_conn.commit() cur.close() def get_linked_customer(phone, tenant_conn): """Obtener customer_id vinculado a un número WA.""" if not tenant_conn or not phone: return None cur = tenant_conn.cursor() cur.execute("SELECT customer_id FROM wa_customer_links WHERE phone = %s", (phone,)) row = cur.fetchone() cur.close() return row[0] if row else None def get_customer_address(tenant_conn, customer_id): """Obtener dirección del cliente.""" if not tenant_conn or not customer_id: return None cur = tenant_conn.cursor() cur.execute("SELECT address FROM customers WHERE id = %s", (customer_id,)) row = cur.fetchone() cur.close() return row[0] if row and row[0] else None def update_customer_address(tenant_conn, customer_id, address): """Actualizar dirección del cliente.""" if not tenant_conn or not customer_id or not address: return cur = tenant_conn.cursor() cur.execute( "UPDATE customers SET address = %s WHERE id = %s", (address, customer_id) ) tenant_conn.commit() cur.close()