# Generated by Django 5.0.10 on 2026-01-14 07:04

import django.core.validators
import django.db.models.deletion
import products.models.photos
from decimal import Decimal
from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('accounts', '0001_initial'),
        ('inventory', '0001_initial'),
        ('orders', '0001_initial'),
    ]

    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='ProductAttribute',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(help_text='Например: Длина стебля, Цвет, Размер', max_length=100, unique=True, verbose_name='Название')),
                ('slug', models.SlugField(blank=True, help_text='Автоматически генерируется из названия', max_length=100, unique=True, verbose_name='Slug')),
                ('description', models.TextField(blank=True, help_text='Опциональное описание атрибута', verbose_name='Описание')),
                ('position', models.PositiveIntegerField(default=0, help_text='Порядок отображения в списке', 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': ['position', 'name'],
            },
        ),
        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'), ('configurable', 'Configurable Product 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='UnitOfMeasure',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('code', models.CharField(help_text='Короткий код: шт, кг, банч, ветка', max_length=20, unique=True, verbose_name='Код')),
                ('name', models.CharField(help_text='Полное название: Штука, Килограмм, Банч', max_length=100, verbose_name='Название')),
                ('short_name', models.CharField(help_text='Для UI: шт., кг., бч.', max_length=10, verbose_name='Сокращение')),
                ('is_active', models.BooleanField(default=True, verbose_name='Активна')),
                ('position', models.PositiveIntegerField(default=0, verbose_name='Порядок сортировки')),
            ],
            options={
                'verbose_name': 'Единица измерения',
                'verbose_name_plural': 'Единицы измерения',
                'ordering': ['position', 'name'],
            },
        ),
        migrations.CreateModel(
            name='ConfigurableProduct',
            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='Статус')),
                ('is_new', models.BooleanField(default=False, help_text='Отображать как новый товар', verbose_name='Новинка')),
                ('is_popular', models.BooleanField(default=False, help_text='Отображать как популярный товар', verbose_name='Популярный')),
                ('is_special', models.BooleanField(default=False, help_text='Отображать как спецпредложение (акция)', 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='accounts.customuser', verbose_name='Архивировано пользователем')),
            ],
            options={
                'verbose_name': 'Вариативный товар',
                'verbose_name_plural': 'Вариативные товары',
            },
        ),
        migrations.CreateModel(
            name='ConfigurableProductAttribute',
            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.configurableproduct', verbose_name='Родительский товар')),
            ],
            options={
                'verbose_name': 'Атрибут вариативного товара',
                'verbose_name_plural': 'Атрибуты вариативных товаров',
                'ordering': ['parent', 'position', 'name', 'option'],
            },
        ),
        migrations.CreateModel(
            name='ConfigurableProductOption',
            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='Вариант по умолчанию')),
                ('variant_sku', models.CharField(blank=True, help_text='Дополнительный артикул для внешних площадок. Генерируется автоматически.', max_length=50, verbose_name='Артикул варианта')),
                ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='products.configurableproduct', verbose_name='Родитель (вариативный товар)')),
            ],
            options={
                'verbose_name': 'Вариант товара',
                'verbose_name_plural': 'Варианты товаров',
            },
        ),
        migrations.CreateModel(
            name='ConfigurableProductOptionAttribute',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('attribute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.configurableproductattribute', verbose_name='Значение атрибута')),
                ('option', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attributes_set', to='products.configurableproductoption', 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='Статус')),
                ('is_new', models.BooleanField(default=False, help_text='Отображать как новый товар', verbose_name='Новинка')),
                ('is_popular', models.BooleanField(default=False, help_text='Отображать как популярный товар', verbose_name='Популярный')),
                ('is_special', models.BooleanField(default=False, help_text='Отображать как спецпредложение (акция)', 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='Единица измерения (deprecated)')),
                ('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='accounts.customuser', 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.AddField(
            model_name='configurableproductoption',
            name='product',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='as_configurable_option_in', to='products.product', verbose_name='Товар (вариант)'),
        ),
        migrations.AddField(
            model_name='configurableproductattribute',
            name='product',
            field=models.ForeignKey(blank=True, help_text='Какой Product связан с этим значением атрибута', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='as_attribute_value_in', to='products.product', verbose_name='Товар для этого значения'),
        ),
        migrations.CreateModel(
            name='ProductAttributeValue',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('value', models.CharField(help_text='Например: 50, 60, 70 (для длины) или Красный, Белый (для цвета)', max_length=100, verbose_name='Значение')),
                ('slug', models.SlugField(blank=True, max_length=100, verbose_name='Slug')),
                ('position', models.PositiveIntegerField(default=0, help_text='Порядок отображения в списке значений', verbose_name='Позиция')),
                ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
                ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
                ('attribute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='values', to='products.productattribute', verbose_name='Атрибут')),
            ],
            options={
                'verbose_name': 'Значение атрибута',
                'verbose_name_plural': 'Значения атрибутов',
                'ordering': ['position', 'value'],
            },
        ),
        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='accounts.customuser', 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.AddField(
            model_name='product',
            name='external_category',
            field=models.ForeignKey(blank=True, help_text='Категория для интеграций с внешними площадками (Recommerce, WooCommerce и др.)', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='external_%(class)ss', to='products.productcategory', verbose_name='Внешняя категория'),
        ),
        migrations.AddField(
            model_name='configurableproduct',
            name='external_category',
            field=models.ForeignKey(blank=True, help_text='Категория для интеграций с внешними площадками (Recommerce, WooCommerce и др.)', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='external_%(class)ss', to='products.productcategory', verbose_name='Внешняя категория'),
        ),
        migrations.CreateModel(
            name='ProductCategoryPhoto',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('is_main', models.BooleanField(db_index=True, default=False, help_text='Главное фото отображается в карточках, каталоге и превью. Может быть только одно.', verbose_name='Главное фото')),
                ('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': ['-is_main', 'order', '-created_at'],
            },
        ),
        migrations.CreateModel(
            name='ProductImportJob',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('task_id', models.CharField(max_length=255, unique=True, verbose_name='ID задачи Celery')),
                ('file_name', models.CharField(max_length=255, verbose_name='Имя файла')),
                ('file_path', models.CharField(help_text='Временный путь для обработки', max_length=500, verbose_name='Путь к файлу')),
                ('update_existing', models.BooleanField(default=False, verbose_name='Обновлять существующие')),
                ('status', models.CharField(choices=[('pending', 'Ожидает'), ('processing', 'Обрабатывается'), ('completed', 'Завершён'), ('failed', 'Ошибка')], db_index=True, default='pending', max_length=20, verbose_name='Статус')),
                ('total_rows', models.IntegerField(default=0, verbose_name='Всего строк')),
                ('processed_rows', models.IntegerField(default=0, verbose_name='Обработано строк')),
                ('created_count', models.IntegerField(default=0, verbose_name='Создано товаров')),
                ('updated_count', models.IntegerField(default=0, verbose_name='Обновлено товаров')),
                ('skipped_count', models.IntegerField(default=0, verbose_name='Пропущено')),
                ('errors_count', models.IntegerField(default=0, verbose_name='Ошибок')),
                ('errors_json', models.JSONField(blank=True, default=list, verbose_name='Детали ошибок')),
                ('error_message', 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='Обновлено')),
                ('completed_at', models.DateTimeField(blank=True, null=True, verbose_name='Завершено')),
                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='product_import_jobs', to='accounts.customuser', verbose_name='Пользователь')),
            ],
            options={
                'verbose_name': 'Задача импорта товаров',
                'verbose_name_plural': 'Задачи импорта товаров',
                'ordering': ['-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='Статус')),
                ('is_new', models.BooleanField(default=False, help_text='Отображать как новый товар', verbose_name='Новинка')),
                ('is_popular', models.BooleanField(default=False, help_text='Отображать как популярный товар', verbose_name='Популярный')),
                ('is_special', models.BooleanField(default=False, help_text='Отображать как спецпредложение (акция)', 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='accounts.customuser', verbose_name='Архивировано пользователем')),
                ('categories', models.ManyToManyField(blank=True, related_name='kits', to='products.productcategory', verbose_name='Категории')),
                ('external_category', models.ForeignKey(blank=True, help_text='Категория для интеграций с внешними площадками (Recommerce, WooCommerce и др.)', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='external_%(class)ss', 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='configurableproductoption',
            name='kit',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='as_configurable_option_in', to='products.productkit', verbose_name='Комплект (вариант)'),
        ),
        migrations.AddField(
            model_name='configurableproductattribute',
            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.CreateModel(
            name='ProductKitPhoto',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('is_main', models.BooleanField(db_index=True, default=False, help_text='Главное фото отображается в карточках, каталоге и превью. Может быть только одно.', verbose_name='Главное фото')),
                ('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': ['-is_main', 'order', '-created_at'],
            },
        ),
        migrations.CreateModel(
            name='ProductPhoto',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('is_main', models.BooleanField(db_index=True, default=False, help_text='Главное фото отображается в карточках, каталоге и превью. Может быть только одно.', verbose_name='Главное фото')),
                ('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': ['-is_main', 'order', '-created_at'],
            },
        ),
        migrations.CreateModel(
            name='ProductSalesUnit',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(help_text="Например: 'Ветка большая', 'Ветка средняя'", max_length=100, verbose_name='Название')),
                ('conversion_factor', models.DecimalField(decimal_places=6, help_text='Сколько единиц продажи в 1 базовой единице товара. Например: 15 (из 1 банча получается 15 больших веток)', max_digits=15, validators=[django.core.validators.MinValueValidator(Decimal('0.000001'))], verbose_name='Коэффициент конверсии')),
                ('price', models.DecimalField(decimal_places=2, max_digits=10, validators=[django.core.validators.MinValueValidator(Decimal('0'))], verbose_name='Цена продажи')),
                ('sale_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, validators=[django.core.validators.MinValueValidator(Decimal('0'))], verbose_name='Цена со скидкой')),
                ('min_quantity', models.DecimalField(decimal_places=3, default=Decimal('1'), help_text='Минимальное количество для продажи', max_digits=10, validators=[django.core.validators.MinValueValidator(Decimal('0.001'))], verbose_name='Мин. количество')),
                ('quantity_step', models.DecimalField(decimal_places=3, default=Decimal('1'), help_text='С каким шагом можно заказывать (0.1, 0.5, 1)', max_digits=10, validators=[django.core.validators.MinValueValidator(Decimal('0.001'))], verbose_name='Шаг количества')),
                ('is_default', models.BooleanField(default=False, help_text='Единица, выбираемая по умолчанию при добавлении в заказ', verbose_name='Единица по умолчанию')),
                ('is_active', models.BooleanField(default=True, verbose_name='Активна')),
                ('position', models.PositiveIntegerField(default=0, verbose_name='Порядок сортировки')),
                ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sales_units', to='products.product', verbose_name='Товар')),
            ],
            options={
                'verbose_name': 'Единица продажи товара',
                'verbose_name_plural': 'Единицы продажи товаров',
                'ordering': ['position', 'id'],
            },
        ),
        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.AddField(
            model_name='productsalesunit',
            name='unit',
            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='products.unitofmeasure', verbose_name='Единица измерения'),
        ),
        migrations.AddField(
            model_name='product',
            name='base_unit',
            field=models.ForeignKey(blank=True, help_text="Единица хранения и закупки (банч, кг, шт). Если указана, используется вместо поля 'unit'.", null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='products.unitofmeasure', verbose_name='Базовая единица'),
        ),
        migrations.AddIndex(
            model_name='configurableproductoptionattribute',
            index=models.Index(fields=['option'], name='products_co_option__bd950a_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductoptionattribute',
            index=models.Index(fields=['attribute'], name='products_co_attribu_705d5a_idx'),
        ),
        migrations.AlterUniqueTogether(
            name='configurableproductoptionattribute',
            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='productattributevalue',
            index=models.Index(fields=['attribute', 'position'], name='products_pr_attribu_460f9e_idx'),
        ),
        migrations.AlterUniqueTogether(
            name='productattributevalue',
            unique_together={('attribute', 'value')},
        ),
        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.AddConstraint(
            model_name='productcategoryphoto',
            constraint=models.UniqueConstraint(condition=models.Q(('is_main', True)), fields=('category',), name='unique_main_photo_per_category'),
        ),
        migrations.AddIndex(
            model_name='productimportjob',
            index=models.Index(fields=['task_id'], name='products_pr_task_id_d8dc9f_idx'),
        ),
        migrations.AddIndex(
            model_name='productimportjob',
            index=models.Index(fields=['status', '-created_at'], name='products_pr_status_326f2c_idx'),
        ),
        migrations.AddIndex(
            model_name='productimportjob',
            index=models.Index(fields=['user', '-created_at'], name='products_pr_user_id_e32ca9_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductoption',
            index=models.Index(fields=['parent'], name='products_co_parent__36761a_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductoption',
            index=models.Index(fields=['kit'], name='products_co_kit_id_9e9a00_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductoption',
            index=models.Index(fields=['product'], name='products_co_product_4d77ae_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductoption',
            index=models.Index(fields=['parent', 'is_default'], name='products_co_parent__be8830_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductoption',
            index=models.Index(fields=['variant_sku'], name='products_co_variant_2da938_idx'),
        ),
        migrations.AddConstraint(
            model_name='configurableproductoption',
            constraint=models.CheckConstraint(check=models.Q(models.Q(('kit__isnull', False), ('product__isnull', True)), models.Q(('kit__isnull', True), ('product__isnull', False)), _connector='OR'), name='configurable_option_kit_xor_product'),
        ),
        migrations.AddIndex(
            model_name='configurableproductattribute',
            index=models.Index(fields=['parent', 'name'], name='products_co_parent__78337c_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductattribute',
            index=models.Index(fields=['parent', 'position'], name='products_co_parent__90f012_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductattribute',
            index=models.Index(fields=['kit'], name='products_co_kit_id_db7ebb_idx'),
        ),
        migrations.AddIndex(
            model_name='configurableproductattribute',
            index=models.Index(fields=['product'], name='products_co_product_68c16a_idx'),
        ),
        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.AddConstraint(
            model_name='productkitphoto',
            constraint=models.UniqueConstraint(condition=models.Q(('is_main', True)), fields=('kit',), name='unique_main_photo_per_kit'),
        ),
        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.AddConstraint(
            model_name='productphoto',
            constraint=models.UniqueConstraint(condition=models.Q(('is_main', True)), fields=('product',), name='unique_main_photo_per_product'),
        ),
        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='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')},
        ),
        migrations.AlterUniqueTogether(
            name='productsalesunit',
            unique_together={('product', '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'),
        ),
    ]
