feat(integrations): добавлена полная интеграция с Recommerce
Реализован клиент для работы с API Recommerce, включая: - Клиент с методами для работы с товарами и заказами - Сервисный слой для высокоуровневых операций - Мапперы данных между форматами - Обработку исключений Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
105
myproject/integrations/recommerce/services.py
Normal file
105
myproject/integrations/recommerce/services.py
Normal file
@@ -0,0 +1,105 @@
|
||||
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
|
||||
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:
|
||||
# Пытаемся получить остаток.
|
||||
# Логика получения остатка может зависеть от вашей системы inventory.
|
||||
# Здесь предполагаем, что у product есть метод или связь для получения общего остатка.
|
||||
# Для простоты используем первый попавшийся Stock или 0
|
||||
# В реальном проекте тут должна быть логика выбора склада
|
||||
stock = product.stocks.first()
|
||||
stock_count = int(stock.quantity_free) if 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"""
|
||||
# Для создания нужны все поля
|
||||
stock = product.stocks.first()
|
||||
stock_count = int(stock.quantity_free) if stock else 0
|
||||
|
||||
data = to_api_product(product, stock_count=stock_count, fields=None)
|
||||
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
|
||||
Reference in New Issue
Block a user