Tomati/files2.py

276 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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) # или ваш обработчик