from fast_bitrix24 import Bitrix from woocommerce import API from tg import send_telegram from dotenv import load_dotenv import os load_dotenv() CONSUMER_KEY = os.getenv('CONSUMER_KEY') # токен бота CONSUMER_SECRET = os.getenv('CONSUMER_SECRET') # id чата URLS = os.getenv('URLS') # Настройки подключения wcapi = API( url=URLS, consumer_key = CONSUMER_KEY, # ключ пользователя с правами admin/shop_manager consumer_secret = CONSUMER_SECRET, version="wc/v3", timeout=30 ) # замените на ваш вебхук для доступа к Bitrix24 webhook = os.getenv('WEBHOOKS') bx = Bitrix(webhook) def woo(order_id): # order_id = 112882 order = wcapi.get(f"orders/{order_id}").json() prud = order['line_items'] rows = [] for p in prud: name = p['name'] quantity = p['quantity'] subtotal = p['price'] # 🔹 meta_data — это список, ищем нужный элемент display_value = None display_key = None for meta in p.get('meta_data', []): # Ищем метаданные с ключом 'pa_kh' (вес/объём) if meta.get('key') == 'pa_kh': display_value = meta.get('display_value') display_key = meta.get('display_key') break # формируем название с характеристикой if display_value: name = f"{name} {display_key}: {display_value}" rows.append({ "PRODUCT_NAME": name, "PRICE": subtotal, "QUANTITY": quantity, "CURRENCY_ID": "UAH", }) print(rows) # print(order) print(f"Заказ #{order['id']}") print(f"Статус: {order['status']}") print(f"Клиент: {order['billing']['first_name']} {order['billing']['last_name']}") print(f"Сумма: {order['total']} {order['currency']}") print(f"email: {order['billing']['email']}") print(f"phone: {order['billing']['phone']}") print(f"City : {order['shipping']['city']}") print(f"state : {order['shipping']['state']}") print(f"address_1 : {order['shipping']['address_1']}") email = {order['billing']['email']} """ Поиск контакта по email ⚠️ email должен быть строкой, а не set/list! """ # 🔹 Защита: если вдруг передали set/list — берём первый элемент # 🔹 1. Защита и нормализация email # 🔹 1. Нормализация email if isinstance(email, (set, list)): email = list(email)[0] if email else None if not email or not isinstance(email, str): print(f"❌ Неверный тип email: {type(email)}") return None search_email = email.lower().strip() print(f"🔍 Ищем контакт с email: {search_email}") contact_id = None # 🔹 2. Поиск через ПРАВИЛЬНЫЙ фильтр для мультиполя # Оператор '=EMAIL' ищет точное совпадение значения в мультиполе found_contacts = bx.call('crm.contact.list', { 'filter': {'=EMAIL': search_email}, 'select': ['ID', 'NAME', 'LAST_NAME', 'EMAIL'], 'limit': 5 # Берем с запасом для отладки }) # Получаем список результатов contacts_list = [] if isinstance(found_contacts, dict): contacts_list = found_contacts.get('result', []) elif isinstance(found_contacts, list): contacts_list = found_contacts print(f"📋 Найдено контактов через фильтр: {len(contacts_list)}") # 🔹 3. Если фильтр не сработал — ищем вручную (Fallback) # Это нужно, если в Битриксе много мусора или нестандартные данные if not contacts_list: print("⚠️ Фильтр не дал результатов. Пробуем ручной перебор...") all_contacts = bx.get_all('crm.contact.list', { 'select': ['ID', 'NAME', 'LAST_NAME', 'EMAIL'], 'filter': {'!@EMAIL': ''} # Только где есть email }) for contact in all_contacts: for email_item in contact.get('EMAIL', []): stored_email = email_item.get('VALUE', '').lower().strip() if stored_email == search_email: contact_id = contact['ID'] print(f"✅ Контакт найден вручную: #{contact_id}") break if contact_id: break if not contact_id: print(f"❌ Контакт действительно не найден в базе") else: # Берем первый из найденных фильтром contact_id = contacts_list[0]['ID'] print(f"✅ Контакт найден через фильтр: #{contact_id}") # 🔹 4. Если не найден — создаем новый if not contact_id: print(f"⚡ Создаем новый контакт...") add_result = bx.call('crm.contact.add', { 'fields': { 'EMAIL': [{'VALUE': search_email, 'TYPE_ID': 'WORK'}], 'NAME': order['billing'].get('first_name', ''), 'LAST_NAME': order['billing'].get('last_name', ''), 'PHONE': [{'VALUE': order['billing'].get('phone', ''), 'TYPE_ID': 'WORK'}] } }) if isinstance(add_result, dict): contact_id = add_result.get('result') else: contact_id = add_result if contact_id: print(f"✅ Контакт создан: #{contact_id}") else: print(f"❌ Ошибка создания: {add_result}") return None order_status = order['status'] if order_status == 'processing': stage_id = 'PREPARATION' else: stage_id = 'NEW' # Или любой другой статус по умолчанию # 🔹 5. Создаем сделку if contact_id: deal_result = bx.call('crm.deal.add', { "fields": { "TITLE": f"Order {order['id']}", 'STAGE_ID': stage_id, 'CONTACT_IDS': [contact_id], 'UF_CRM_1684256942409': f"{order['billing'].get('first_name', '')}", 'UF_CRM_1684256770733': f"{order['billing'].get('last_name', '')}", 'UF_CRM_1684256782976': f"{order['billing'].get('email', '')}", 'UF_CRM_5ECB65AB5E752': f"{order['shipping'].get('city', '')}", 'UF_CRM_5ECB65AB672CE': f"{order['shipping'].get('state', '')}", 'UF_CRM_5ECB65AB708F4': f"{order['shipping'].get('address_1', '')}", 'UF_CRM_5ECB65AB7AD15': f"{order['billing'].get('phone', '')}", }, }) if isinstance(deal_result, dict): deal_id = deal_result.get('result') else: deal_id = deal_result if deal_id: print(f"✅ Сделка создана: #{deal_id}") if rows: bx.call("crm.deal.productrows.set", { "ID": deal_id, 'rows': rows }) print(f"📦 Товары добавлены") else: print(f"❌ Ошибка сделки: {deal_result}") # woo(112928) #920 ЗАГРУЗИЛ def update_deal_stage(order_id): """Находит сделку и меняет её стадию""" result = bx.call('crm.deal.update', { 'id': order_id, 'fields': {'STAGE_ID': 'PREPARATION'} }) if result: print(f"✅ Стадия успешно обновлена") return True else: print(f"❌ Ошибка обновления: {result}") return False def lists_deal(orders): deals = bx.get_all( 'crm.deal.list', params={ 'select': ['ID', 'STAGE_ID'], 'filter': {"TITLE": f"Order {orders}",} }) if deals and len(deals) > 0: deal = deals[0] # Берём первую найденную сделку return deal['ID'], deal['STAGE_ID'] else: return None, None # Если не найдено def toom(): # Получаем только заказы со статусом "processing" orders = wcapi.get("orders", params={ # "status": "processing", # Фильтр по статусу "per_page": 10, # Количество за раз "orderby": "date", # Сортировка по дате "order": "desc" # Сначала новые }).json() print(f"📋 Найдено заказов в обработке: {len(orders)}") for order in orders: order_id = order['id'] customer_email = order.get('billing', {}).get('email', 'нет') status = order.get('status') idsss, stage_id = lists_deal(order_id) if idsss is None: print(f"✅ #{order_id} | Добавить") woo(order_id) send_telegram(f" ✅ Добавил в Б24 {order_id}") elif status == 'processing' and stage_id == "NEW": print(f"✅ #{order_id} | Изменить статус") update_deal_stage(idsss) # изменить статус else: print(f"✅ #{order_id} | 👤 {customer_email} {status}") print(f"{idsss} {stage_id}") print(f"✓ Сделка #{idsss} в стадии {stage_id} — обновление не требуется") # 🔹 Здесь можно запускать вашу логику с Битриксом: # woo(order_id) # или ваш обработчик