import uuid from django.db import models class SourceSystem(models.Model): """External system that supplies observations and business events.""" code = models.SlugField("Код", max_length=64, unique=True) name = models.CharField("Название", max_length=128) is_active = models.BooleanField("Активен", default=True) metadata = models.JSONField("Настройки без секретов", default=dict, blank=True) created_at = models.DateTimeField("Создано", auto_now_add=True) updated_at = models.DateTimeField("Обновлено", auto_now=True) class Meta: verbose_name = "Источник данных" verbose_name_plural = "Источники данных" ordering = ["name"] def __str__(self): return self.name class SourceRecord(models.Model): """Latest source payload retained with provenance for repeatable imports.""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) source = models.ForeignKey( SourceSystem, on_delete=models.PROTECT, related_name="records", verbose_name="Источник", ) entity_type = models.CharField("Тип объекта", max_length=64) external_id = models.CharField("Внешний ID", max_length=255) payload = models.JSONField("Исходные данные", default=dict) payload_hash = models.CharField("Хеш данных", max_length=64, editable=False) source_updated_at = models.DateTimeField( "Изменено в источнике", null=True, blank=True ) received_at = models.DateTimeField("Получено", auto_now=True) created_at = models.DateTimeField("Создано", auto_now_add=True) class Meta: verbose_name = "Исходная запись" verbose_name_plural = "Исходные записи" constraints = [ models.UniqueConstraint( fields=["source", "entity_type", "external_id"], name="commerce_source_record_identity", ) ] indexes = [ models.Index( fields=["source", "entity_type", "source_updated_at"], name="commerce_source_record_sync", ) ] def __str__(self): return f"{self.source.code}:{self.entity_type}:{self.external_id}" class ProductBinding(models.Model): """Maps an external product/offer identifier to the canonical product.""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) product = models.ForeignKey( "commerce.Product", on_delete=models.CASCADE, related_name="bindings", verbose_name="Товар", ) source = models.ForeignKey( SourceSystem, on_delete=models.PROTECT, related_name="product_bindings", verbose_name="Источник", ) external_id = models.CharField("Внешний ID", max_length=255) external_sku = models.CharField( "Артикул в источнике", max_length=128, blank=True, db_index=True ) is_primary = models.BooleanField("Основная привязка", default=False) created_at = models.DateTimeField("Создано", auto_now_add=True) updated_at = models.DateTimeField("Обновлено", auto_now=True) class Meta: verbose_name = "Привязка товара" verbose_name_plural = "Привязки товаров" constraints = [ models.UniqueConstraint( fields=["source", "external_id"], name="commerce_binding_source_external", ) ] indexes = [ models.Index( fields=["source", "external_sku"], name="commerce_binding_source_sku", ) ] def __str__(self): return f"{self.product.sku} ← {self.source.code}:{self.external_id}"