# Generated by Django 5.0.10 on 2025-12-23 20:38 import django.db.models.deletion import products.models.photos from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ('inventory', '0001_initial'), ('orders', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='KitItem', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quantity', models.DecimalField(blank=True, decimal_places=3, max_digits=10, null=True, verbose_name='Количество')), ], options={ 'verbose_name': 'Компонент комплекта', 'verbose_name_plural': 'Компоненты комплектов', }, ), migrations.CreateModel( name='ProductVariantGroup', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=200, verbose_name='Название')), ('description', models.TextField(blank=True, verbose_name='Описание')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ], options={ 'verbose_name': 'Группа вариантов', 'verbose_name_plural': 'Группы вариантов', 'ordering': ['name'], }, ), migrations.CreateModel( name='ProductVariantGroupItem', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('priority', models.PositiveIntegerField(default=0, help_text='Меньше = выше приоритет (1 - наивысший приоритет в этой группе)')), ], options={ 'verbose_name': 'Товар в группе вариантов', 'verbose_name_plural': 'Товары в группах вариантов', 'ordering': ['priority', 'id'], }, ), migrations.CreateModel( name='SKUCounter', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('counter_type', models.CharField(choices=[('product', 'Product Counter'), ('kit', 'Kit Counter'), ('category', 'Category Counter')], max_length=20, unique=True, verbose_name='Тип счетчика')), ('current_value', models.IntegerField(default=0, verbose_name='Текущее значение')), ], options={ 'verbose_name': 'Счетчик артикулов', 'verbose_name_plural': 'Счетчики артикулов', }, ), migrations.CreateModel( name='ConfigurableKitProduct', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=200, verbose_name='Название')), ('sku', models.CharField(blank=True, db_index=True, max_length=100, null=True, verbose_name='Артикул')), ('slug', models.SlugField(blank=True, max_length=200, unique=True, verbose_name='URL-идентификатор')), ('description', models.TextField(blank=True, null=True, verbose_name='Описание')), ('short_description', models.TextField(blank=True, help_text='Используется для карточек товаров, превью и площадок', null=True, verbose_name='Краткое описание')), ('status', models.CharField(choices=[('active', 'Активный'), ('archived', 'Архивный'), ('discontinued', 'Снят')], db_index=True, default='active', max_length=20, verbose_name='Статус')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('archived_at', models.DateTimeField(blank=True, null=True, verbose_name='Время архивирования')), ('archived_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='archived_%(class)s_set', to=settings.AUTH_USER_MODEL, verbose_name='Архивировано пользователем')), ], options={ 'verbose_name': 'Вариативный товар (из комплектов)', 'verbose_name_plural': 'Вариативные товары (из комплектов)', }, ), migrations.CreateModel( name='ConfigurableKitOption', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('attributes', models.JSONField(blank=True, default=dict, help_text='Структурированные атрибуты. Пример: {"length": "60", "color": "red"}', verbose_name='Атрибуты варианта')), ('is_default', models.BooleanField(default=False, verbose_name='Вариант по умолчанию')), ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='products.configurablekitproduct', verbose_name='Родитель (вариативный товар)')), ], options={ 'verbose_name': 'Вариант комплекта', 'verbose_name_plural': 'Варианты комплектов', }, ), migrations.CreateModel( name='ConfigurableKitProductAttribute', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(help_text='Например: Цвет, Размер, Длина', max_length=150, verbose_name='Название атрибута')), ('option', models.CharField(help_text='Например: Красный, M, 60см', max_length=150, verbose_name='Значение опции')), ('position', models.PositiveIntegerField(default=0, help_text='Меньше = выше в списке', verbose_name='Порядок отображения')), ('visible', models.BooleanField(default=True, help_text='Показывать ли атрибут на странице товара', verbose_name='Видимый на витрине')), ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parent_attributes', to='products.configurablekitproduct', verbose_name='Родительский товар')), ], options={ 'verbose_name': 'Атрибут вариативного товара', 'verbose_name_plural': 'Атрибуты вариативных товаров', 'ordering': ['parent', 'position', 'name', 'option'], }, ), migrations.CreateModel( name='ConfigurableKitOptionAttribute', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('option', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attributes_set', to='products.configurablekitoption', verbose_name='Вариант')), ('attribute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.configurablekitproductattribute', verbose_name='Значение атрибута')), ], options={ 'verbose_name': 'Атрибут варианта', 'verbose_name_plural': 'Атрибуты варианта', }, ), migrations.CreateModel( name='PhotoProcessingStatus', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('photo_id', models.IntegerField(help_text='ID объекта ProductPhoto/ProductKitPhoto/ProductCategoryPhoto', verbose_name='ID фото')), ('photo_model', models.CharField(help_text='Полный путь модели (e.g., products.ProductPhoto)', max_length=100, verbose_name='Модель фото')), ('status', models.CharField(choices=[('pending', 'В очереди'), ('processing', 'Обрабатывается'), ('completed', 'Завершено'), ('failed', 'Ошибка')], db_index=True, default='pending', max_length=20, verbose_name='Статус обработки')), ('task_id', models.CharField(blank=True, db_index=True, help_text='Уникальный ID задачи для отслеживания', max_length=255, verbose_name='ID задачи Celery')), ('error_message', models.TextField(blank=True, help_text='Детальное описание ошибки при обработке', verbose_name='Сообщение об ошибке')), ('result_data', models.JSONField(blank=True, default=dict, help_text='JSON с информацией о качестве, путях и метаданных', verbose_name='Результаты обработки')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('started_at', models.DateTimeField(blank=True, null=True, verbose_name='Время начала обработки')), ('completed_at', models.DateTimeField(blank=True, null=True, verbose_name='Время завершения обработки')), ], options={ 'verbose_name': 'Статус обработки фото', 'verbose_name_plural': 'Статусы обработки фото', 'ordering': ['-created_at'], 'indexes': [models.Index(fields=['photo_id', 'photo_model'], name='products_ph_photo_i_e42a67_idx'), models.Index(fields=['task_id'], name='products_ph_task_id_748118_idx'), models.Index(fields=['status'], name='products_ph_status_1182b4_idx'), models.Index(fields=['status', 'created_at'], name='products_ph_status_41d415_idx')], }, ), migrations.CreateModel( name='Product', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=200, verbose_name='Название')), ('sku', models.CharField(blank=True, db_index=True, max_length=100, null=True, verbose_name='Артикул')), ('slug', models.SlugField(blank=True, max_length=200, unique=True, verbose_name='URL-идентификатор')), ('description', models.TextField(blank=True, null=True, verbose_name='Описание')), ('short_description', models.TextField(blank=True, help_text='Используется для карточек товаров, превью и площадок', null=True, verbose_name='Краткое описание')), ('status', models.CharField(choices=[('active', 'Активный'), ('archived', 'Архивный'), ('discontinued', 'Снят')], db_index=True, default='active', max_length=20, verbose_name='Статус')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('archived_at', models.DateTimeField(blank=True, null=True, verbose_name='Время архивирования')), ('variant_suffix', models.CharField(blank=True, help_text='Суффикс для артикула (например: 50, 60, S, M). Автоматически извлекается из названия.', max_length=20, null=True, verbose_name='Суффикс варианта')), ('unit', models.CharField(choices=[('шт', 'Штука'), ('м', 'Метр'), ('г', 'Грамм'), ('л', 'Литр'), ('кг', 'Килограмм')], default='шт', max_length=10, verbose_name='Единица измерения')), ('cost_price', models.DecimalField(blank=True, decimal_places=2, default=0, help_text='Автоматически вычисляется из партий (средневзвешенная стоимость по FIFO)', max_digits=10, null=True, verbose_name='Себестоимость')), ('price', models.DecimalField(decimal_places=2, help_text='Цена продажи товара (бывшее поле sale_price)', max_digits=10, verbose_name='Основная цена')), ('sale_price', models.DecimalField(blank=True, decimal_places=2, help_text='Если задана, товар продается по этой цене (дешевле основной)', max_digits=10, null=True, verbose_name='Цена со скидкой')), ('in_stock', models.BooleanField(db_index=True, default=False, help_text='Автоматически обновляется при изменении остатков на складе', verbose_name='В наличии')), ('search_keywords', models.TextField(blank=True, help_text='Автоматически генерируется из названия, артикула, описания и категории. Можно дополнить вручную.', verbose_name='Ключевые слова для поиска')), ('archived_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='archived_%(class)s_set', to=settings.AUTH_USER_MODEL, verbose_name='Архивировано пользователем')), ], options={ 'verbose_name': 'Товар', 'verbose_name_plural': 'Товары', }, ), migrations.CreateModel( name='KitItemPriority', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('priority', models.PositiveIntegerField(default=0, help_text='Меньше = выше приоритет (0 - наивысший)')), ('kit_item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='priorities', to='products.kititem', verbose_name='Позиция в букете')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.product', verbose_name='Товар')), ], options={ 'verbose_name': 'Приоритет варианта', 'verbose_name_plural': 'Приоритеты вариантов', 'ordering': ['priority', 'id'], }, ), migrations.AddField( model_name='kititem', name='product', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='kit_items_direct', to='products.product', verbose_name='Конкретный товар'), ), migrations.CreateModel( name='CostPriceHistory', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('old_cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Старая себестоимость')), ('new_cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Новая себестоимость')), ('reason', models.CharField(choices=[('incoming', 'Поступление товара'), ('batch_edit', 'Редактирование партии'), ('batch_delete', 'Удаление партии'), ('recalculation', 'Пересчет себестоимости'), ('system', 'Системная корректировка')], max_length=20, verbose_name='Причина изменения')), ('related_object_id', models.IntegerField(blank=True, help_text='Например, ID партии (StockBatch) для поступлений', null=True, verbose_name='ID связанного объекта')), ('related_object_type', models.CharField(blank=True, help_text="Например, 'StockBatch' для партий", max_length=50, verbose_name='Тип связанного объекта')), ('notes', models.TextField(blank=True, help_text='Дополнительная информация об изменении', verbose_name='Примечания')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время изменения')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cost_price_history', to='products.product', verbose_name='Товар')), ], options={ 'verbose_name': 'История себестоимости', 'verbose_name_plural': 'Истории себестоимости', 'ordering': ['-created_at'], }, ), migrations.CreateModel( name='ProductCategory', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=200, verbose_name='Название')), ('sku', models.CharField(blank=True, db_index=True, max_length=100, null=True, unique=True, verbose_name='Артикул')), ('slug', models.SlugField(blank=True, max_length=200, unique=True, verbose_name='URL-идентификатор')), ('is_active', models.BooleanField(default=True, verbose_name='Активна')), ('created_at', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, null=True, verbose_name='Дата обновления')), ('is_deleted', models.BooleanField(db_index=True, default=False, verbose_name='Удалена')), ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='Время удаления')), ('deleted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='deleted_categories', to=settings.AUTH_USER_MODEL, verbose_name='Удалена пользователем')), ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='products.productcategory', verbose_name='Родительская категория')), ], options={ 'verbose_name': 'Категория товара', 'verbose_name_plural': 'Категории товаров', }, ), migrations.AddField( model_name='product', name='categories', field=models.ManyToManyField(blank=True, related_name='products', to='products.productcategory', verbose_name='Категории'), ), migrations.CreateModel( name='ProductCategoryPhoto', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('image', models.ImageField(upload_to=products.models.photos.get_category_photo_upload_path, verbose_name='Оригинальное фото')), ('quality_level', models.CharField(choices=[('excellent', 'Отлично (>= 2052px)'), ('good', 'Хорошо (1512-2051px)'), ('acceptable', 'Приемлемо (864-1511px)'), ('poor', 'Плохо (432-863px)'), ('very_poor', 'Очень плохо (< 432px)')], db_index=True, default='acceptable', help_text='Определяется автоматически на основе размера изображения', max_length=15, verbose_name='Уровень качества')), ('quality_warning', models.BooleanField(db_index=True, default=False, help_text='True если нужно обновить фото перед выгрузкой на сайт', verbose_name='Требует обновления')), ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='products.productcategory', verbose_name='Категория')), ], options={ 'verbose_name': 'Фото категории', 'verbose_name_plural': 'Фото категорий', 'ordering': ['order', '-created_at'], }, ), migrations.CreateModel( name='ProductKit', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=200, verbose_name='Название')), ('sku', models.CharField(blank=True, db_index=True, max_length=100, null=True, verbose_name='Артикул')), ('slug', models.SlugField(blank=True, max_length=200, unique=True, verbose_name='URL-идентификатор')), ('description', models.TextField(blank=True, null=True, verbose_name='Описание')), ('short_description', models.TextField(blank=True, help_text='Используется для карточек товаров, превью и площадок', null=True, verbose_name='Краткое описание')), ('status', models.CharField(choices=[('active', 'Активный'), ('archived', 'Архивный'), ('discontinued', 'Снят')], db_index=True, default='active', max_length=20, verbose_name='Статус')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('archived_at', models.DateTimeField(blank=True, null=True, verbose_name='Время архивирования')), ('base_price', models.DecimalField(decimal_places=2, default=0, help_text='Сумма actual_price всех компонентов. Пересчитывается автоматически.', max_digits=10, verbose_name='Базовая цена')), ('price', models.DecimalField(decimal_places=2, default=0, help_text='Базовая цена с учетом корректировок. Вычисляется автоматически.', max_digits=10, verbose_name='Итоговая цена')), ('sale_price', models.DecimalField(blank=True, decimal_places=2, help_text='Если задана, комплект продается по этой цене', max_digits=10, null=True, verbose_name='Цена со скидкой')), ('price_adjustment_type', models.CharField(choices=[('none', 'Без изменения'), ('increase_percent', 'Увеличить на %'), ('increase_amount', 'Увеличить на сумму'), ('decrease_percent', 'Уменьшить на %'), ('decrease_amount', 'Уменьшить на сумму')], default='none', max_length=20, verbose_name='Тип корректировки цены')), ('price_adjustment_value', models.DecimalField(decimal_places=2, default=0, help_text='Процент (%) или сумма (руб) в зависимости от типа корректировки', max_digits=10, verbose_name='Значение корректировки')), ('is_temporary', models.BooleanField(default=False, help_text='Временные комплекты не показываются в каталоге и создаются для конкретного заказа', verbose_name='Временный комплект')), ('archived_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='archived_%(class)s_set', to=settings.AUTH_USER_MODEL, verbose_name='Архивировано пользователем')), ('categories', models.ManyToManyField(blank=True, related_name='kits', to='products.productcategory', verbose_name='Категории')), ('order', models.ForeignKey(blank=True, help_text='Заказ, для которого создан временный комплект', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='temporary_kits', to='orders.order', verbose_name='Заказ')), ('showcase', models.ForeignKey(blank=True, help_text='Витрина, на которой выложен временный комплект', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='temporary_kits', to='inventory.showcase', verbose_name='Витрина')), ], options={ 'verbose_name': 'Комплект', 'verbose_name_plural': 'Комплекты', }, ), migrations.AddField( model_name='kititem', name='kit', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='kit_items', to='products.productkit', verbose_name='Комплект'), ), migrations.AddField( model_name='configurablekitproductattribute', name='kit', field=models.ForeignKey(blank=True, help_text='Какой ProductKit связан с этим значением атрибута', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='as_attribute_value_in', to='products.productkit', verbose_name='Комплект для этого значения'), ), migrations.AddField( model_name='configurablekitoption', name='kit', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='as_configurable_option_in', to='products.productkit', verbose_name='Комплект (вариант)'), ), migrations.CreateModel( name='ProductKitPhoto', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('image', models.ImageField(upload_to=products.models.photos.get_kit_photo_upload_path, verbose_name='Оригинальное фото')), ('quality_level', models.CharField(choices=[('excellent', 'Отлично (>= 2052px)'), ('good', 'Хорошо (1512-2051px)'), ('acceptable', 'Приемлемо (864-1511px)'), ('poor', 'Плохо (432-863px)'), ('very_poor', 'Очень плохо (< 432px)')], db_index=True, default='acceptable', help_text='Определяется автоматически на основе размера изображения', max_length=15, verbose_name='Уровень качества')), ('quality_warning', models.BooleanField(db_index=True, default=False, help_text='True если нужно обновить фото перед выгрузкой на сайт', verbose_name='Требует обновления')), ('kit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='products.productkit', verbose_name='Комплект')), ], options={ 'verbose_name': 'Фото комплекта', 'verbose_name_plural': 'Фото комплектов', 'ordering': ['order', '-created_at'], }, ), migrations.CreateModel( name='ProductPhoto', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('image', models.ImageField(upload_to=products.models.photos.get_product_photo_upload_path, verbose_name='Оригинальное фото')), ('quality_level', models.CharField(choices=[('excellent', 'Отлично (>= 2052px)'), ('good', 'Хорошо (1512-2051px)'), ('acceptable', 'Приемлемо (864-1511px)'), ('poor', 'Плохо (432-863px)'), ('very_poor', 'Очень плохо (< 432px)')], db_index=True, default='acceptable', help_text='Определяется автоматически на основе размера изображения', max_length=15, verbose_name='Уровень качества')), ('quality_warning', models.BooleanField(db_index=True, default=False, help_text='True если нужно обновить фото перед выгрузкой на сайт (poor или very_poor)', verbose_name='Требует обновления')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='products.product', verbose_name='Товар')), ], options={ 'verbose_name': 'Фото товара', 'verbose_name_plural': 'Фото товаров', 'ordering': ['order', '-created_at'], }, ), migrations.CreateModel( name='ProductTag', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=100, verbose_name='Название')), ('slug', models.SlugField(max_length=100, unique=True, verbose_name='URL-идентификатор')), ('is_active', models.BooleanField(db_index=True, default=True, verbose_name='Активен')), ('created_at', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, null=True, verbose_name='Дата обновления')), ], options={ 'verbose_name': 'Тег товара', 'verbose_name_plural': 'Теги товаров', 'indexes': [models.Index(fields=['is_active'], name='products_pr_is_acti_7f288f_idx')], }, ), migrations.AddConstraint( model_name='producttag', constraint=models.UniqueConstraint(condition=models.Q(('is_active', True)), fields=('name',), name='unique_active_tag_name'), ), migrations.AddField( model_name='productkit', name='tags', field=models.ManyToManyField(blank=True, related_name='kits', to='products.producttag', verbose_name='Теги'), ), migrations.AddField( model_name='product', name='tags', field=models.ManyToManyField(blank=True, related_name='products', to='products.producttag', verbose_name='Теги'), ), migrations.AddField( model_name='product', name='variant_groups', field=models.ManyToManyField(blank=True, related_name='products', to='products.productvariantgroup', verbose_name='Группы вариантов'), ), migrations.AddField( model_name='kititem', name='variant_group', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='kit_items', to='products.productvariantgroup', verbose_name='Группа вариантов'), ), migrations.AddField( model_name='productvariantgroupitem', name='product', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='variant_group_items', to='products.product', verbose_name='Товар'), ), migrations.AddField( model_name='productvariantgroupitem', name='variant_group', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='products.productvariantgroup', verbose_name='Группа вариантов'), ), migrations.AddIndex( model_name='configurablekitoptionattribute', index=models.Index(fields=['option'], name='products_co_option__93b9f7_idx'), ), migrations.AddIndex( model_name='configurablekitoptionattribute', index=models.Index(fields=['attribute'], name='products_co_attribu_ccc6d9_idx'), ), migrations.AlterUniqueTogether( name='configurablekitoptionattribute', unique_together={('option', 'attribute')}, ), migrations.AlterUniqueTogether( name='kititempriority', unique_together={('kit_item', 'product')}, ), migrations.AddIndex( model_name='costpricehistory', index=models.Index(fields=['product', '-created_at'], name='products_co_product_3320c9_idx'), ), migrations.AddIndex( model_name='costpricehistory', index=models.Index(fields=['reason'], name='products_co_reason_959ee1_idx'), ), migrations.AddIndex( model_name='productcategory', index=models.Index(fields=['is_active'], name='products_pr_is_acti_226e74_idx'), ), migrations.AddIndex( model_name='productcategory', index=models.Index(fields=['is_deleted'], name='products_pr_is_dele_2a96d1_idx'), ), migrations.AddIndex( model_name='productcategory', index=models.Index(fields=['is_deleted', 'created_at'], name='products_pr_is_dele_b8cdf3_idx'), ), migrations.AddConstraint( model_name='productcategory', constraint=models.UniqueConstraint(condition=models.Q(('is_deleted', False)), fields=('name',), name='unique_active_category_name'), ), migrations.AddIndex( model_name='productcategoryphoto', index=models.Index(fields=['quality_level'], name='products_pr_quality_ab44c2_idx'), ), migrations.AddIndex( model_name='productcategoryphoto', index=models.Index(fields=['quality_warning'], name='products_pr_quality_d7c69b_idx'), ), migrations.AddIndex( model_name='productcategoryphoto', index=models.Index(fields=['quality_warning', 'category'], name='products_pr_quality_fc505a_idx'), ), migrations.AddIndex( model_name='configurablekitproductattribute', index=models.Index(fields=['parent', 'name'], name='products_co_parent__4a7869_idx'), ), migrations.AddIndex( model_name='configurablekitproductattribute', index=models.Index(fields=['parent', 'position'], name='products_co_parent__0904e2_idx'), ), migrations.AddIndex( model_name='configurablekitproductattribute', index=models.Index(fields=['kit'], name='products_co_kit_id_c5d506_idx'), ), migrations.AlterUniqueTogether( name='configurablekitproductattribute', unique_together={('parent', 'name', 'option', 'kit')}, ), migrations.AddIndex( model_name='configurablekitoption', index=models.Index(fields=['parent'], name='products_co_parent__56ecfa_idx'), ), migrations.AddIndex( model_name='configurablekitoption', index=models.Index(fields=['kit'], name='products_co_kit_id_3fa7fe_idx'), ), migrations.AddIndex( model_name='configurablekitoption', index=models.Index(fields=['parent', 'is_default'], name='products_co_parent__ffa4ca_idx'), ), migrations.AlterUniqueTogether( name='configurablekitoption', unique_together={('parent', 'kit')}, ), migrations.AddIndex( model_name='productkitphoto', index=models.Index(fields=['quality_level'], name='products_pr_quality_b03c5c_idx'), ), migrations.AddIndex( model_name='productkitphoto', index=models.Index(fields=['quality_warning'], name='products_pr_quality_2aa941_idx'), ), migrations.AddIndex( model_name='productkitphoto', index=models.Index(fields=['quality_warning', 'kit'], name='products_pr_quality_867664_idx'), ), migrations.AddIndex( model_name='productphoto', index=models.Index(fields=['quality_level'], name='products_pr_quality_d8f85c_idx'), ), migrations.AddIndex( model_name='productphoto', index=models.Index(fields=['quality_warning'], name='products_pr_quality_defb5a_idx'), ), migrations.AddIndex( model_name='productphoto', index=models.Index(fields=['quality_warning', 'product'], name='products_pr_quality_6e8b51_idx'), ), migrations.AddIndex( model_name='productkit', index=models.Index(fields=['is_temporary'], name='products_pr_is_temp_e407a2_idx'), ), migrations.AddIndex( model_name='productkit', index=models.Index(fields=['order'], name='products_pr_order_i_2b5675_idx'), ), migrations.AddIndex( model_name='productkit', index=models.Index(fields=['showcase'], name='products_pr_showcas_08c1ca_idx'), ), migrations.AddConstraint( model_name='productkit', constraint=models.UniqueConstraint(condition=models.Q(('is_temporary', False), ('status', 'active')), fields=('name',), name='unique_active_kit_name'), ), migrations.AddIndex( model_name='product', index=models.Index(fields=['in_stock'], name='products_pr_in_stoc_4fee1a_idx'), ), migrations.AddIndex( model_name='product', index=models.Index(fields=['sku'], name='products_pr_sku_ca0cdc_idx'), ), migrations.AddIndex( model_name='kititem', index=models.Index(fields=['kit'], name='products_ki_kit_id_d28dc9_idx'), ), migrations.AddIndex( model_name='kititem', index=models.Index(fields=['product'], name='products_ki_product_d2ad00_idx'), ), migrations.AddIndex( model_name='kititem', index=models.Index(fields=['variant_group'], name='products_ki_variant_e42628_idx'), ), migrations.AddIndex( model_name='kititem', index=models.Index(fields=['kit', 'product'], name='products_ki_kit_id_14738f_idx'), ), migrations.AddIndex( model_name='kititem', index=models.Index(fields=['kit', 'variant_group'], name='products_ki_kit_id_8199a8_idx'), ), migrations.AddIndex( model_name='productvariantgroupitem', index=models.Index(fields=['variant_group', 'priority'], name='products_pr_variant_b36b47_idx'), ), migrations.AddIndex( model_name='productvariantgroupitem', index=models.Index(fields=['product'], name='products_pr_product_50be04_idx'), ), migrations.AlterUniqueTogether( name='productvariantgroupitem', unique_together={('variant_group', 'product')}, ), ]