Files

91 lines
3.0 KiB
Python

from django.db import models
from django.core.exceptions import ValidationError
class IntegrationType(models.TextChoices):
MARKETPLACE = 'marketplace', 'Маркетплейс'
PAYMENT = 'payment', 'Платёжная система'
SHIPPING = 'shipping', 'Служба доставки'
AI_SERVICE = 'ai_service', 'Сервис ИИ'
class BaseIntegration(models.Model):
"""
Абстрактный базовый класс для всех интеграций.
Singleton-паттерн: каждая конкретная интеграция имеет только одну запись в БД.
Поле is_active служит глобальным тумблером включения/выключения.
"""
integration_type = models.CharField(
max_length=20,
choices=IntegrationType.choices,
editable=False,
verbose_name="Тип интеграции"
)
is_active = models.BooleanField(
default=False,
verbose_name="Активна",
db_index=True,
help_text="Глобальный тумблер включения интеграции"
)
name = models.CharField(
max_length=100,
blank=True,
default='',
verbose_name="Название",
help_text="Произвольное название для удобства (опционально)"
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="Дата создания"
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="Дата обновления"
)
# Дополнительные настройки в JSON для гибкости
extra_config = models.JSONField(
default=dict,
blank=True,
verbose_name="Доп. настройки"
)
class Meta:
abstract = True
ordering = ['-is_active', 'name']
indexes = [
models.Index(fields=['is_active', 'integration_type']),
]
# Singleton: только одна запись на тип интеграции
constraints = [
models.UniqueConstraint(
fields=['integration_type'],
name='%(class)s_singleton'
)
]
def __str__(self):
status = "вкл" if self.is_active else "выкл"
return f"{self.get_integration_type_display()}: {self.name or self._meta.verbose_name} ({status})"
@property
def is_configured(self) -> bool:
"""
Проверить, есть ли необходимые credentials.
Переопределить в наследниках.
"""
return False
def clean(self):
"""Валидация: нельзя включить ненастроенную интеграцию"""
if self.is_active and not self.is_configured:
raise ValidationError(
'Невозможно включить интеграцию без настроенных credentials'
)