From 57257326caf7e6ba531593551868e2141afdab1e Mon Sep 17 00:00:00 2001 From: Alex55 Date: Fri, 7 Aug 2026 17:53:48 +0300 Subject: [PATCH] rev --- files2.py | 165 ++++++++++++++++++++---------------------- last_order_state.json | 2 +- 2 files changed, 78 insertions(+), 89 deletions(-) diff --git a/files2.py b/files2.py index 204c8f2..764512a 100644 --- a/files2.py +++ b/files2.py @@ -2,6 +2,7 @@ from fast_bitrix24 import Bitrix from woocommerce import API from tg import send_telegram from dotenv import load_dotenv +import html import os load_dotenv() @@ -20,10 +21,34 @@ wcapi = API( ) # замените на ваш вебхук для доступа к Bitrix24 -webhook = os.getenv('WEBHOOKS') -bx = Bitrix(webhook) +webhook = os.getenv('WEBHOOKS') +bx = Bitrix(webhook, verbose=False) +def clean(value): + """Woo отдаёт поля с HTML-сущностями: " & и т.п.""" + return html.unescape(str(value or '')).strip() + + +def find_contact_by_email(email): + """Ищет контакт по email штатным методом Битрикса. + + ⚠️ crm.contact.list НЕ умеет фильтровать по мультиполю EMAIL: + фильтр молча игнорируется и возвращается вся база контактов. + После такой выкачки fast_bitrix24 упирается в лимит времени + отработки метода (480 сек / 10 мин) и засыпает на ~10 минут — + именно из-за этого скрипт «висел» после создания сделки. + """ + response = bx.call('crm.duplicate.findbycomm', { + 'entity_type': 'CONTACT', + 'type': 'EMAIL', + 'values': [email], + }, raw=True) + + result = (response or {}).get('result') or {} + ids = result.get('CONTACT') if isinstance(result, dict) else None + + return str(ids[0]) if ids else None @@ -32,7 +57,13 @@ bx = Bitrix(webhook) def woo(order_id): # order_id = 112882 - order = wcapi.get(f"orders/{order_id}").json() + response = wcapi.get(f"orders/{order_id}") + + if response.status_code != 200: + print(f"❌ WooCommerce вернул {response.status_code} по заказу {order_id}: {response.text[:200]}") + return None + + order = response.json() prud = order['line_items'] rows = [] @@ -56,10 +87,10 @@ def woo(order_id): name = f"{name} {display_key}: {display_value}" rows.append({ - "PRODUCT_NAME": name, + "PRODUCT_NAME": clean(name), "PRICE": subtotal, "QUANTITY": quantity, - "CURRENCY_ID": "UAH", + "CURRENCY_ID": order.get('currency') or "UAH", }) print(rows) @@ -76,82 +107,33 @@ def woo(order_id): 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 - + email = order['billing'].get('email') + + # 🔹 1. Нормализация email 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. Если не найден — создаем новый + + # 🔹 2. Поиск через crm.duplicate.findbycomm — единственный метод, + # который реально умеет искать по мультиполю EMAIL + contact_id = find_contact_by_email(search_email) + + if contact_id: + print(f"✅ Контакт найден: #{contact_id}") + + # 🔹 3. Если не найден — создаем новый 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'}] + 'NAME': clean(order['billing'].get('first_name')), + 'LAST_NAME': clean(order['billing'].get('last_name')), + 'PHONE': [{'VALUE': clean(order['billing'].get('phone')), 'TYPE_ID': 'WORK'}] } }) @@ -171,21 +153,21 @@ def woo(order_id): stage_id = 'PREPARATION' else: stage_id = 'NEW' # Или любой другой статус по умолчанию - # 🔹 5. Создаем сделку + # 🔹 4. Создаем сделку if contact_id: deal_result = bx.call('crm.deal.add', { "fields": { "TITLE": f"Order {order['id']}", 'STAGE_ID': stage_id, 'CONTACT_IDS': [contact_id], - 'COMMENTS': f"{order['customer_note']}", - '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', '')}", + 'COMMENTS': clean(order.get('customer_note')), + 'UF_CRM_1684256942409': clean(order['billing'].get('first_name')), + 'UF_CRM_1684256770733': clean(order['billing'].get('last_name')), + 'UF_CRM_1684256782976': clean(order['billing'].get('email')), + 'UF_CRM_5ECB65AB5E752': clean(order['shipping'].get('city')), + 'UF_CRM_5ECB65AB672CE': clean(order['shipping'].get('state')), + 'UF_CRM_5ECB65AB708F4': clean(order['shipping'].get('address_1')), + 'UF_CRM_5ECB65AB7AD15': clean(order['billing'].get('phone')), }, }) @@ -196,19 +178,22 @@ def woo(order_id): if deal_id: print(f"✅ Сделка создана: #{deal_id}") - + if rows: - bx.call("crm.deal.productrows.set", { + bx.call("crm.deal.productrows.set", { "ID": deal_id, 'rows': rows }) print(f"📦 Товары добавлены") + + return deal_id else: print(f"❌ Ошибка сделки: {deal_result}") - - -# woo(112928) #920 ЗАГРУЗИЛ + return None + + +# woo(118961) #920 ЗАГРУЗИЛ def update_deal_stage(order_id): """Находит сделку и меняет её стадию""" @@ -229,7 +214,7 @@ def lists_deal(orders): 'crm.deal.list', params={ 'select': ['ID', 'STAGE_ID'], - 'filter': {"TITLE": f"Order {orders}",} + 'filter': {"=TITLE": f"Order {orders}",} }) if deals and len(deals) > 0: deal = deals[0] # Берём первую найденную сделку @@ -260,8 +245,12 @@ def toom(): if idsss is None: print(f"✅ #{order_id} | Добавить") - woo(order_id) - send_telegram(f" ✅ Добавил в Б24 {order_id}") + deal_id = woo(order_id) + + if deal_id: + send_telegram(f" ✅ Добавил в Б24 {order_id}") + else: + send_telegram(f" ❌ Не удалось добавить в Б24 {order_id}") elif status == 'processing' and stage_id == "NEW": print(f"✅ #{order_id} | Изменить статус") update_deal_stage(idsss) diff --git a/last_order_state.json b/last_order_state.json index 8bf8547..47aa433 100644 --- a/last_order_state.json +++ b/last_order_state.json @@ -1 +1 @@ -{"id": 113590, "hash": "4598a9c5561c50655b36b21c6ffed12a", "status": "pending", "total": "1615", "modified": "2026-04-06T09:51:21"} \ No newline at end of file +{"id": 118969, "hash": "5d5d8a2f0f8ceb2170bc3863cb4b470d", "status": "processing", "total": "2435", "modified": "2026-08-07T11:10:34"} \ No newline at end of file