from typing import List, Dict, Any, Optional from django.conf import settings from .client import RecommerceClient from .mappers import to_api_product, from_api_order, RECOMMERCE_INFINITY_COUNT from .exceptions import RecommerceError # Imports for typing only to avoid circular dependency issues at module level if possible # but for simplicity in this structure we'll import inside methods if needed or use 'Any' class RecommerceService: """ Высокоуровневый сервис для интеграции с Recommerce. Предоставляет методы для синхронизации товаров и заказов. """ def __init__(self, integration_instance): """ Args: integration_instance: Экземпляр модели RecommerceIntegration """ self.integration = integration_instance self.client = RecommerceClient( store_url=integration_instance.store_url, api_token=integration_instance.api_token ) def update_product(self, product: Any, fields: Optional[List[str]] = None) -> bool: """ Обновить товар в Recommerce. Args: product: Экземпляр Product fields: Список полей для обновления (например ['price', 'count']). Если None - обновляются все поля. Returns: bool: Успех операции """ # Получаем остаток, если нужно stock_count = None if fields is None or 'count' in fields: # Используем in_stock для определения наличия в формате Recommerce: # - in_stock=False → count=0 (нет в наличии) # - in_stock=True → count=999999 (есть в наличии, "бесконечность") stock_count = RECOMMERCE_INFINITY_COUNT if product.in_stock else 0 data = to_api_product(product, stock_count=stock_count, fields=fields) try: # Сначала пробуем обновить # SKU берем из data или продукта sku = data.get('sku', getattr(product, 'sku', str(product.id))) # Recommerce API: POST /catalog/products/{sku} для обновления self.client.update_product(sku, data) return True except RecommerceError as e: # Если 404 - товар не найден, можно попробовать создать? # В рамках "простой" интеграции - пока просто логируем или рейзим # Если нужно автоматическое создание: # if isinstance(e, RecommerceAPIError) and e.status_code == 404: # return self.create_product(product) raise e def create_product(self, product: Any) -> bool: """ Создать товар в Recommerce. Raises: RecommerceError: Если отсутствует обязательное поле parent_category_sku """ # Для создания нужны все поля # Используем in_stock для определения наличия в формате Recommerce stock_count = RECOMMERCE_INFINITY_COUNT if product.in_stock else 0 data = to_api_product(product, stock_count=stock_count, fields=None, for_create=True) # Проверяем обязательное поле для создания if 'parent_category_sku' not in data: raise RecommerceError( f"Невозможно создать товар '{product.sku}' в Recommerce: " f"не указана категория (parent_category_sku). " f"Добавьте поле recommerce_category_sku к товару или категории." ) self.client.create_product(data) return True def get_new_orders(self, updated_after: str) -> List[Dict[str, Any]]: """ Получить список новых заказов из Recommerce. Args: updated_after: Дата в формате 'Y-m-d-H-i-s' Returns: List[Dict]: Список DTO заказов (готовых для сохранения) """ raw_orders = self.client.get_orders(updated_after=updated_after) orders_dto = [] for raw_order in raw_orders: dto = from_api_order(raw_order) orders_dto.append(dto) return orders_dto def check_connection(self) -> bool: """Проверить соединение""" try: # Пробуем получить список заказов (легкий запрос) self.client.get_orders() return True except RecommerceError: return False