Обновление админки и представлений для интеграций
This commit is contained in:
@@ -4,7 +4,7 @@ from django.http import JsonResponse
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from user_roles.mixins import OwnerRequiredMixin
|
||||
from .models import RecommerceIntegration, WooCommerceIntegration
|
||||
from .models import RecommerceIntegration, WooCommerceIntegration, GLMIntegration, OpenRouterIntegration
|
||||
from integrations.recommerce.tasks import sync_products_batch_task
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ from integrations.recommerce.tasks import sync_products_batch_task
|
||||
INTEGRATION_REGISTRY = {
|
||||
'recommerce': (RecommerceIntegration, 'Recommerce', 'Маркетплейс'),
|
||||
'woocommerce': (WooCommerceIntegration, 'WooCommerce', 'Маркетплейс'),
|
||||
'glm': (GLMIntegration, 'GLM от Z.AI', 'Сервис ИИ'),
|
||||
'openrouter': (OpenRouterIntegration, 'OpenRouter.ai', 'Сервис ИИ'),
|
||||
# Добавлять новые интеграции здесь:
|
||||
# 'shopify': (ShopifyIntegration, 'Shopify', 'Маркетплейс'),
|
||||
}
|
||||
@@ -110,27 +112,51 @@ def test_integration_connection(request, integration_id: str):
|
||||
Тестировать соединение с интеграцией.
|
||||
POST /integrations/test/<integration_id>/
|
||||
"""
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
logger.info(f"=== Начало тестирования интеграции: {integration_id} ===")
|
||||
|
||||
if not hasattr(request, 'user') or not request.user.is_authenticated:
|
||||
logger.error("Пользователь не авторизован")
|
||||
return JsonResponse({'error': 'Unauthorized'}, status=401)
|
||||
|
||||
model = get_integration_model(integration_id)
|
||||
if not model:
|
||||
logger.error(f"Неизвестная интеграция: {integration_id}")
|
||||
return JsonResponse({'error': f'Unknown integration: {integration_id}'}, status=404)
|
||||
|
||||
instance = model.objects.first()
|
||||
if not instance:
|
||||
logger.error(f"Интеграция {integration_id} не настроена (нет записи в БД)")
|
||||
return JsonResponse({'error': 'Интеграция не настроена'}, status=400)
|
||||
|
||||
logger.info(f"Найдена интеграция: {instance.name}, is_active={instance.is_active}, is_configured={instance.is_configured}")
|
||||
|
||||
if not instance.is_configured:
|
||||
logger.error(f"Интеграция {integration_id} не сконфигурирована")
|
||||
return JsonResponse({'error': 'Заполните настройки интеграции'}, status=400)
|
||||
|
||||
# Получить сервис для интеграции
|
||||
service = get_integration_service(integration_id, instance)
|
||||
if not service:
|
||||
return JsonResponse({'error': 'Сервис не реализован'}, status=501)
|
||||
try:
|
||||
logger.info(f"Попытка получить сервис для {integration_id}...")
|
||||
service = get_integration_service(integration_id, instance)
|
||||
if not service:
|
||||
logger.error(f"Сервис для {integration_id} не реализован")
|
||||
return JsonResponse({'error': 'Сервис не реализован'}, status=501)
|
||||
logger.info(f"Сервис успешно создан: {service.__class__.__name__}")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при создании сервиса для {integration_id}: {str(e)}", exc_info=True)
|
||||
return JsonResponse({'error': f'Ошибка при создании сервиса: {str(e)}'}, status=500)
|
||||
|
||||
# Выполнить тест
|
||||
success, message = service.test_connection()
|
||||
try:
|
||||
logger.info(f"Выполнение теста соединения...")
|
||||
success, message = service.test_connection()
|
||||
logger.info(f"Результат теста: success={success}, message={message}")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при выполнении теста соединения: {str(e)}", exc_info=True)
|
||||
return JsonResponse({'error': f'Ошибка при тестировании: {str(e)}'}, status=500)
|
||||
|
||||
return JsonResponse({
|
||||
'success': success,
|
||||
@@ -146,6 +172,12 @@ def get_integration_service(integration_id: str, instance):
|
||||
elif integration_id == 'woocommerce':
|
||||
# TODO: WooCommerceService
|
||||
return None
|
||||
elif integration_id == 'glm':
|
||||
from .services.ai_services.glm_service import GLMIntegrationService
|
||||
return GLMIntegrationService(instance)
|
||||
elif integration_id == 'openrouter':
|
||||
from .services.ai_services.openrouter_service import OpenRouterIntegrationService
|
||||
return OpenRouterIntegrationService(instance)
|
||||
return None
|
||||
|
||||
|
||||
@@ -168,16 +200,16 @@ class RecommerceBatchSyncView(TemplateView):
|
||||
data = json.loads(request.body)
|
||||
product_ids = data.get('product_ids', [])
|
||||
options = data.get('options', {})
|
||||
|
||||
|
||||
if not product_ids:
|
||||
return JsonResponse({'error': 'No products selected'}, status=400)
|
||||
|
||||
|
||||
# Запуск Celery задачи с передачей schema_name
|
||||
from django_tenants.utils import get_tenant_model
|
||||
Tenant = get_tenant_model()
|
||||
schema_name = request.tenant.schema_name
|
||||
task = sync_products_batch_task.delay(product_ids, options, schema_name)
|
||||
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'task_id': task.id,
|
||||
@@ -285,18 +317,89 @@ def get_integration_form_data(request, integration_id: str):
|
||||
def get_form_fields_meta(model):
|
||||
"""Получить метаданные полей для построения формы на фронте"""
|
||||
fields = []
|
||||
for field_name in get_editable_fields(model):
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'text', # default
|
||||
}
|
||||
editable_fields = get_editable_fields(model)
|
||||
|
||||
# Определить тип поля
|
||||
if isinstance(field, model._meta.get_field(field_name).__class__):
|
||||
# Для GLM отображаем только имя и API ключ
|
||||
if model.__name__ == 'GLMIntegration':
|
||||
for field_name in editable_fields:
|
||||
if field_name in ['name', 'api_key']:
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'text', # default
|
||||
}
|
||||
|
||||
# Определить тип поля
|
||||
if 'BooleanField' in field.__class__.__name__:
|
||||
field_info['type'] = 'checkbox'
|
||||
elif 'URLField' in field.__class__.__name__:
|
||||
field_info['type'] = 'url'
|
||||
elif 'secret' in field_name.lower() or 'token' in field_name.lower() or 'key' in field_name.lower():
|
||||
field_info['type'] = 'password'
|
||||
|
||||
fields.append(field_info)
|
||||
elif field_name == 'model_name':
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'select', # dropdown
|
||||
'choices': getattr(field, 'choices', [])
|
||||
}
|
||||
|
||||
fields.append(field_info)
|
||||
# Для OpenRouter отображаем только имя, API ключ, модель и температуру
|
||||
elif model.__name__ == 'OpenRouterIntegration':
|
||||
for field_name in editable_fields:
|
||||
if field_name in ['name', 'api_key']:
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'text', # default
|
||||
}
|
||||
|
||||
# Определить тип поля
|
||||
if 'BooleanField' in field.__class__.__name__:
|
||||
field_info['type'] = 'checkbox'
|
||||
elif 'URLField' in field.__class__.__name__:
|
||||
field_info['type'] = 'url'
|
||||
elif 'secret' in field_name.lower() or 'token' in field_name.lower() or 'key' in field_name.lower():
|
||||
field_info['type'] = 'password'
|
||||
|
||||
fields.append(field_info)
|
||||
elif field_name in ['model_name', 'temperature']:
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'select', # dropdown
|
||||
'choices': getattr(field, 'choices', [])
|
||||
}
|
||||
|
||||
fields.append(field_info)
|
||||
else:
|
||||
# Для других интеграций - все редактируемые поля
|
||||
for field_name in editable_fields:
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'text', # default
|
||||
}
|
||||
|
||||
# Определить тип поля
|
||||
if 'BooleanField' in field.__class__.__name__:
|
||||
field_info['type'] = 'checkbox'
|
||||
elif 'URLField' in field.__class__.__name__:
|
||||
@@ -304,5 +407,6 @@ def get_form_fields_meta(model):
|
||||
elif 'secret' in field_name.lower() or 'token' in field_name.lower() or 'key' in field_name.lower():
|
||||
field_info['type'] = 'password'
|
||||
|
||||
fields.append(field_info)
|
||||
fields.append(field_info)
|
||||
|
||||
return fields
|
||||
|
||||
Reference in New Issue
Block a user