Files

119 lines
5.8 KiB
Python
Raw Permalink 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.
import logging
from celery import shared_task
from django.db import transaction
from django_tenants.utils import schema_context
from integrations.models import RecommerceIntegration
from integrations.recommerce.services import RecommerceService
from products.models import Product
from integrations.recommerce.exceptions import RecommerceError, RecommerceAPIError
logger = logging.getLogger(__name__)
@shared_task(bind=True)
def sync_products_batch_task(self, product_ids, options=None, schema_name=None):
"""
Celery задача для массовой синхронизации товаров с Recommerce.
Args:
product_ids (list): Список ID товаров (PK) для синхронизации
options (dict): Настройки синхронизации
- fields (list): Список полей для обновления ['price', 'count', 'content', 'images']
- create_if_missing (bool): Создавать товар, если он не найден (404)
schema_name (str): Имя схемы тенанта для выполнения запросов
"""
if options is None:
options = {}
fields = options.get('fields', [])
create_if_missing = options.get('create_if_missing', False)
# Используем schema_context для выполнения запросов в правильной tenant схеме
if schema_name:
with schema_context(schema_name):
return _do_sync(product_ids, fields, create_if_missing)
else:
return _do_sync(product_ids, fields, create_if_missing)
def _do_sync(product_ids, fields, create_if_missing):
"""
Внутренняя функция для выполнения синхронизации в контексте схемы.
Args:
product_ids (list): Список ID товаров (PK) для синхронизации
fields (list): Список полей для обновления ['price', 'count', 'content', 'images']
create_if_missing (bool): Создавать товар, если он не найден (404)
"""
# 1. Получаем интеграцию
integration = RecommerceIntegration.objects.filter(is_active=True).first()
if not integration or not integration.is_configured:
msg = "Recommerce integration is not active or configured."
logger.error(msg)
return {"success": False, "error": msg}
service = RecommerceService(integration)
# 2. Получаем товары
products = Product.objects.filter(pk__in=product_ids)
results = {
"total": len(product_ids),
"success": 0,
"failed": 0,
"created": 0,
"updated": 0,
"errors": []
}
logger.info(f"Starting Recommerce sync for {len(product_ids)} products. Fields: {fields}, create_if_missing: {create_if_missing}")
for product in products:
try:
# Если fields пустой или содержит 'all' - обновляем всё (передаем None в сервис)
# Иначе передаем список полей.
# В сервисе update_product(fields=None) обновляет всё.
# Маппинг опций фронтенда на логику сервиса
# Фронт: ['price', 'count', 'content', 'images']
# Сервис: ожидает список полей или None (всё).
# Если выбраны не все галочки, передаем конкретные поля.
# Но 'content' и 'images' в сервисе могут не поддерживаться напрямую как ключи,
# нужно смотреть реализацию to_api_product.
# Пока передаем как есть, предполагая, что сервис или маппер разберется,
# либо если выбрано "все", передаем None.
# Упрощение: если выбраны все основные группы, считаем это полным обновлением
is_full_update = False
if 'content' in fields and 'images' in fields and 'price' in fields and 'count' in fields:
is_full_update = True
service_fields = None if is_full_update else fields
# Если список полей пуст (ничего не выбрано), но задача запущена - странно, но пропустим
if not is_full_update and not service_fields:
logger.warning(f"Product {product.id}: No fields selected for update.")
continue
try:
service.update_product(product, fields=service_fields)
results["updated"] += 1
results["success"] += 1
except RecommerceAPIError as e:
# Если товар не найден (404) и разрешено создание
if e.status_code == 404 and create_if_missing:
logger.info(f"Product {product.sku} not found. Creating...")
service.create_product(product)
results["created"] += 1
results["success"] += 1
else:
raise e
except Exception as e:
results["failed"] += 1
error_msg = f"Product {product.sku} ({product.id}): {str(e)}"
logger.error(error_msg)
results["errors"].append(error_msg)
logger.info(f"Recommerce sync completed. Results: {results}")
return results