Рефакторинг системы вариативных товаров и справочник атрибутов
Основные изменения: - Переименование ConfigurableKitProduct → ConfigurableProduct - Добавлена поддержка Product как варианта (не только ProductKit) - Создан справочник атрибутов (ProductAttribute, ProductAttributeValue) - CRUD для управления атрибутами с inline редактированием значений - Пересозданы миграции с нуля для всех приложений - Добавлена ссылка на атрибуты в навигацию 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# Generated by Django 5.0.10 on 2025-12-23 20:38
|
||||
# Generated by Django 5.0.10 on 2025-12-29 22:19
|
||||
|
||||
import django.db.models.deletion
|
||||
import phonenumber_field.modelfields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@@ -9,6 +11,7 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@@ -16,7 +19,7 @@ class Migration(migrations.Migration):
|
||||
name='DocumentCounter',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('counter_type', models.CharField(choices=[('transfer', 'Перемещение товара'), ('writeoff', 'Списание товара'), ('incoming', 'Поступление товара'), ('inventory', 'Инвентаризация')], max_length=20, unique=True, verbose_name='Тип счетчика')),
|
||||
('counter_type', models.CharField(choices=[('transfer', 'Перемещение товара'), ('writeoff', 'Списание товара'), ('incoming', 'Поступление товара'), ('inventory', 'Инвентаризация'), ('transformation', 'Трансформация товара')], max_length=20, unique=True, verbose_name='Тип счетчика')),
|
||||
('current_value', models.IntegerField(default=0, verbose_name='Текущее значение')),
|
||||
],
|
||||
options={
|
||||
@@ -24,74 +27,6 @@ class Migration(migrations.Migration):
|
||||
'verbose_name_plural': 'Счетчики документов',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Incoming',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
('cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Закупочная цена')),
|
||||
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Товар в поступлении',
|
||||
'verbose_name_plural': 'Товары в поступлениях',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IncomingBatch',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')),
|
||||
('receipt_type', models.CharField(choices=[('supplier', 'Поступление от поставщика'), ('inventory', 'Оприходование при инвентаризации'), ('adjustment', 'Оприходование без инвентаризации')], db_index=True, default='supplier', max_length=20, verbose_name='Тип поступления')),
|
||||
('supplier_name', models.CharField(blank=True, max_length=200, null=True, verbose_name='Наименование поставщика')),
|
||||
('notes', models.TextField(blank=True, null=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': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IncomingDocument',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')),
|
||||
('status', models.CharField(choices=[('draft', 'Черновик'), ('confirmed', 'Проведён'), ('cancelled', 'Отменён')], db_index=True, default='draft', max_length=20, verbose_name='Статус')),
|
||||
('date', models.DateField(help_text='Дата, к которой относится поступление', verbose_name='Дата документа')),
|
||||
('receipt_type', models.CharField(choices=[('supplier', 'Поступление от поставщика'), ('inventory', 'Оприходование при инвентаризации'), ('adjustment', 'Оприходование без инвентаризации')], db_index=True, default='supplier', max_length=20, verbose_name='Тип поступления')),
|
||||
('supplier_name', models.CharField(blank=True, help_text="Заполняется для типа 'Поступление от поставщика'", max_length=200, null=True, verbose_name='Наименование поставщика')),
|
||||
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
||||
('confirmed_at', models.DateTimeField(blank=True, null=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': ['-date', '-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IncomingDocumentItem',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
('cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Закупочная цена')),
|
||||
('notes', models.TextField(blank=True, null=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': ['id'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Inventory',
|
||||
fields=[
|
||||
@@ -130,7 +65,7 @@ class Migration(migrations.Migration):
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
('status', models.CharField(choices=[('reserved', 'Зарезервирован'), ('released', 'Освобожден'), ('converted_to_sale', 'Преобразован в продажу'), ('converted_to_writeoff', 'Преобразован в списание')], default='reserved', max_length=25, verbose_name='Статус')),
|
||||
('status', models.CharField(choices=[('reserved', 'Зарезервирован'), ('released', 'Освобожден'), ('converted_to_sale', 'Преобразован в продажу'), ('converted_to_writeoff', 'Преобразован в списание'), ('converted_to_transformation', 'Преобразован в трансформацию')], default='reserved', max_length=30, verbose_name='Статус')),
|
||||
('reserved_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата резервирования')),
|
||||
('released_at', models.DateTimeField(blank=True, null=True, verbose_name='Дата освобождения')),
|
||||
('converted_at', models.DateTimeField(blank=True, help_text='Дата преобразования в продажу или списание', null=True, verbose_name='Дата преобразования')),
|
||||
@@ -234,34 +169,7 @@ class Migration(migrations.Migration):
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StockMovement',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('change', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Изменение')),
|
||||
('reason', models.CharField(choices=[('purchase', 'Закупка'), ('sale', 'Продажа'), ('write_off', 'Списание'), ('adjustment', 'Корректировка')], max_length=20, verbose_name='Причина')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Движение товара',
|
||||
'verbose_name_plural': 'Движения товаров',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Transfer',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')),
|
||||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Перемещение',
|
||||
'verbose_name_plural': 'Перемещения',
|
||||
'ordering': ['-date'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TransferBatch',
|
||||
name='TransferDocument',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')),
|
||||
@@ -276,7 +184,7 @@ class Migration(migrations.Migration):
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TransferItem',
|
||||
name='TransferDocumentItem',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
@@ -287,6 +195,45 @@ class Migration(migrations.Migration):
|
||||
'ordering': ['id'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Transformation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')),
|
||||
('status', models.CharField(choices=[('draft', 'Черновик'), ('completed', 'Проведён'), ('cancelled', 'Отменён')], db_index=True, default='draft', max_length=20, verbose_name='Статус')),
|
||||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
('comment', 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': ['-date'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TransformationInput',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Входной товар трансформации',
|
||||
'verbose_name_plural': 'Входные товары трансформации',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TransformationOutput',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Выходной товар трансформации',
|
||||
'verbose_name_plural': 'Выходные товары трансформации',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Warehouse',
|
||||
fields=[
|
||||
@@ -359,4 +306,43 @@ class Migration(migrations.Migration):
|
||||
'ordering': ['id'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IncomingDocument',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')),
|
||||
('status', models.CharField(choices=[('draft', 'Черновик'), ('confirmed', 'Проведён'), ('cancelled', 'Отменён')], db_index=True, default='draft', max_length=20, verbose_name='Статус')),
|
||||
('date', models.DateField(help_text='Дата, к которой относится поступление', verbose_name='Дата документа')),
|
||||
('receipt_type', models.CharField(choices=[('supplier', 'Поступление от поставщика'), ('inventory', 'Оприходование при инвентаризации'), ('adjustment', 'Оприходование без инвентаризации')], db_index=True, default='supplier', max_length=20, verbose_name='Тип поступления')),
|
||||
('supplier_name', models.CharField(blank=True, help_text="Заполняется для типа 'Поступление от поставщика'", max_length=200, null=True, verbose_name='Наименование поставщика')),
|
||||
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
||||
('confirmed_at', models.DateTimeField(blank=True, null=True, verbose_name='Дата проведения')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Создан')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Обновлён')),
|
||||
('confirmed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='confirmed_incoming_documents', to=settings.AUTH_USER_MODEL, verbose_name='Провёл')),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_incoming_documents', to=settings.AUTH_USER_MODEL, verbose_name='Создал')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Документ поступления',
|
||||
'verbose_name_plural': 'Документы поступления',
|
||||
'ordering': ['-date', '-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='IncomingDocumentItem',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
('cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Закупочная цена')),
|
||||
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Создан')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Обновлён')),
|
||||
('document', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.incomingdocument', verbose_name='Документ')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Позиция документа поступления',
|
||||
'verbose_name_plural': 'Позиции документа поступления',
|
||||
'ordering': ['id'],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.10 on 2025-12-23 20:38
|
||||
# Generated by Django 5.0.10 on 2025-12-29 22:19
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
@@ -18,31 +18,6 @@ class Migration(migrations.Migration):
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='incoming',
|
||||
name='product',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incomings', to='products.product', verbose_name='Товар'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='incoming',
|
||||
name='batch',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.incomingbatch', verbose_name='Партия'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='incomingdocument',
|
||||
name='confirmed_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='confirmed_incoming_documents', to=settings.AUTH_USER_MODEL, verbose_name='Провёл'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='incomingdocument',
|
||||
name='created_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_incoming_documents', to=settings.AUTH_USER_MODEL, verbose_name='Создал'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='incomingdocumentitem',
|
||||
name='document',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.incomingdocument', verbose_name='Документ'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='incomingdocumentitem',
|
||||
name='product',
|
||||
@@ -149,49 +124,59 @@ class Migration(migrations.Migration):
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_allocations', to='inventory.stockbatch', verbose_name='Партия'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='incoming',
|
||||
model_name='transferdocumentitem',
|
||||
name='batch',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_document_items', to='inventory.stockbatch', verbose_name='Исходная партия (FIFO)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferdocumentitem',
|
||||
name='new_batch',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transfer_document_items_created', to='inventory.stockbatch', verbose_name='Созданная партия на целевом складе'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferdocumentitem',
|
||||
name='product',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_document_items', to='products.product', verbose_name='Товар'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferdocumentitem',
|
||||
name='transfer_document',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.transferdocument', verbose_name='Документ перемещения'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transformation',
|
||||
name='employee',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transformations', to=settings.AUTH_USER_MODEL, verbose_name='Сотрудник'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transformationinput',
|
||||
name='product',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transformation_inputs', to='products.product', verbose_name='Товар'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transformationinput',
|
||||
name='transformation',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inputs', to='inventory.transformation', verbose_name='Трансформация'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='reservation',
|
||||
name='transformation_input',
|
||||
field=models.ForeignKey(blank=True, help_text='Резерв для входного товара трансформации (черновик)', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.transformationinput', verbose_name='Входной товар трансформации'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transformationoutput',
|
||||
name='product',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transformation_outputs', to='products.product', verbose_name='Товар'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transformationoutput',
|
||||
name='stock_batch',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='incomings', to='inventory.stockbatch', verbose_name='Складская партия'),
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transformation_outputs', to='inventory.stockbatch', verbose_name='Созданная партия'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stockmovement',
|
||||
name='order',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stock_movements', to='orders.order', verbose_name='Заказ'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stockmovement',
|
||||
name='product',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movements', to='products.product', verbose_name='Товар'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transfer',
|
||||
name='batch',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers', to='inventory.stockbatch', verbose_name='Партия'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transfer',
|
||||
name='new_batch',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transfer_sources', to='inventory.stockbatch', verbose_name='Новая партия'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferitem',
|
||||
name='batch',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_items', to='inventory.stockbatch', verbose_name='Исходная партия (FIFO)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferitem',
|
||||
name='new_batch',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transfer_items_created', to='inventory.stockbatch', verbose_name='Созданная партия на целевом складе'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferitem',
|
||||
name='product',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_items', to='products.product', verbose_name='Товар'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferitem',
|
||||
name='transfer_batch',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.transferbatch', verbose_name='Документ перемещения'),
|
||||
model_name='transformationoutput',
|
||||
name='transformation',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='outputs', to='inventory.transformation', verbose_name='Трансформация'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='warehouse',
|
||||
@@ -206,24 +191,19 @@ class Migration(migrations.Migration):
|
||||
index=models.Index(fields=['is_pickup_point'], name='inventory_w_is_pick_e86268_idx'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferbatch',
|
||||
model_name='transformation',
|
||||
name='warehouse',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transformations', to='inventory.warehouse', verbose_name='Склад'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferdocument',
|
||||
name='from_warehouse',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_batches_from', to='inventory.warehouse', verbose_name='Склад-отгрузки'),
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_documents_from', to='inventory.warehouse', verbose_name='Склад-отгрузки'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transferbatch',
|
||||
model_name='transferdocument',
|
||||
name='to_warehouse',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_batches_to', to='inventory.warehouse', verbose_name='Склад-приемки'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transfer',
|
||||
name='from_warehouse',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_from', to='inventory.warehouse', verbose_name='Из склада'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transfer',
|
||||
name='to_warehouse',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_to', to='inventory.warehouse', verbose_name='На склад'),
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_documents_to', to='inventory.warehouse', verbose_name='Склад-приемки'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stockbatch',
|
||||
@@ -260,11 +240,6 @@ class Migration(migrations.Migration):
|
||||
name='warehouse',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='incoming_documents', to='inventory.warehouse', verbose_name='Склад'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='incomingbatch',
|
||||
name='warehouse',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incoming_batches', to='inventory.warehouse', verbose_name='Склад'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='writeoff',
|
||||
name='batch',
|
||||
@@ -335,60 +310,40 @@ class Migration(migrations.Migration):
|
||||
index=models.Index(fields=['locked_by_user', 'status'], name='inventory_s_locked__88eac9_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='incoming',
|
||||
index=models.Index(fields=['batch'], name='inventory_i_batch_i_c50b63_idx'),
|
||||
model_name='transferdocumentitem',
|
||||
index=models.Index(fields=['transfer_document'], name='inventory_t_transfe_02e7fe_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='incoming',
|
||||
index=models.Index(fields=['product'], name='inventory_i_product_39b00d_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='incoming',
|
||||
index=models.Index(fields=['-created_at'], name='inventory_i_created_563ec0_idx'),
|
||||
model_name='transferdocumentitem',
|
||||
index=models.Index(fields=['product'], name='inventory_t_product_a5ed4b_idx'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='incoming',
|
||||
unique_together={('batch', 'product')},
|
||||
name='transferdocumentitem',
|
||||
unique_together={('transfer_document', 'batch')},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='stockmovement',
|
||||
index=models.Index(fields=['product'], name='inventory_s_product_cbdc37_idx'),
|
||||
model_name='transformation',
|
||||
index=models.Index(fields=['document_number'], name='inventory_t_documen_559778_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='stockmovement',
|
||||
index=models.Index(fields=['created_at'], name='inventory_s_created_05ebf5_idx'),
|
||||
model_name='transformation',
|
||||
index=models.Index(fields=['warehouse', 'status'], name='inventory_t_warehou_934275_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transferitem',
|
||||
index=models.Index(fields=['transfer_batch'], name='inventory_t_transfe_f7479b_idx'),
|
||||
model_name='transformation',
|
||||
index=models.Index(fields=['-date'], name='inventory_t_date_65cfab_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transferitem',
|
||||
index=models.Index(fields=['product'], name='inventory_t_product_0e0ec9_idx'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='transferitem',
|
||||
unique_together={('transfer_batch', 'batch')},
|
||||
model_name='transferdocument',
|
||||
index=models.Index(fields=['document_number'], name='inventory_t_documen_d9087d_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transferbatch',
|
||||
index=models.Index(fields=['document_number'], name='inventory_t_documen_143275_idx'),
|
||||
model_name='transferdocument',
|
||||
index=models.Index(fields=['from_warehouse', 'to_warehouse'], name='inventory_t_from_wa_118a47_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transferbatch',
|
||||
index=models.Index(fields=['from_warehouse', 'to_warehouse'], name='inventory_t_from_wa_2a41f1_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transferbatch',
|
||||
index=models.Index(fields=['-created_at'], name='inventory_t_created_b6fd05_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transfer',
|
||||
index=models.Index(fields=['from_warehouse', 'to_warehouse'], name='inventory_t_from_wa_578feb_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transfer',
|
||||
index=models.Index(fields=['date'], name='inventory_t_date_e1402d_idx'),
|
||||
model_name='transferdocument',
|
||||
index=models.Index(fields=['-created_at'], name='inventory_t_created_5ad653_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='stockbatch',
|
||||
@@ -458,22 +413,6 @@ class Migration(migrations.Migration):
|
||||
model_name='incomingdocument',
|
||||
index=models.Index(fields=['-created_at'], name='inventory_i_created_174930_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='incomingbatch',
|
||||
index=models.Index(fields=['document_number'], name='inventory_i_documen_679096_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='incomingbatch',
|
||||
index=models.Index(fields=['warehouse'], name='inventory_i_warehou_cc3a73_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='incomingbatch',
|
||||
index=models.Index(fields=['receipt_type'], name='inventory_i_receipt_ce70c1_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='incomingbatch',
|
||||
index=models.Index(fields=['-created_at'], name='inventory_i_created_59ee8b_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='writeoff',
|
||||
index=models.Index(fields=['batch'], name='inventory_w_batch_i_b098ce_idx'),
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
# Generated by Django 5.0.10 on 2025-12-25 14:36
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0002_initial'),
|
||||
('products', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='documentcounter',
|
||||
name='counter_type',
|
||||
field=models.CharField(choices=[('transfer', 'Перемещение товара'), ('writeoff', 'Списание товара'), ('incoming', 'Поступление товара'), ('inventory', 'Инвентаризация'), ('transformation', 'Трансформация товара')], max_length=20, unique=True, verbose_name='Тип счетчика'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='reservation',
|
||||
name='status',
|
||||
field=models.CharField(choices=[('reserved', 'Зарезервирован'), ('released', 'Освобожден'), ('converted_to_sale', 'Преобразован в продажу'), ('converted_to_writeoff', 'Преобразован в списание'), ('converted_to_transformation', 'Преобразован в трансформацию')], default='reserved', max_length=30, verbose_name='Статус'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Transformation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')),
|
||||
('status', models.CharField(choices=[('draft', 'Черновик'), ('completed', 'Проведён'), ('cancelled', 'Отменён')], db_index=True, default='draft', max_length=20, verbose_name='Статус')),
|
||||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
('comment', 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='Обновлён')),
|
||||
('employee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transformations', to=settings.AUTH_USER_MODEL, verbose_name='Сотрудник')),
|
||||
('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transformations', to='inventory.warehouse', verbose_name='Склад')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Трансформация товара',
|
||||
'verbose_name_plural': 'Трансформации товаров',
|
||||
'ordering': ['-date'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TransformationInput',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transformation_inputs', to='products.product', verbose_name='Товар')),
|
||||
('transformation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inputs', to='inventory.transformation', verbose_name='Трансформация')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Входной товар трансформации',
|
||||
'verbose_name_plural': 'Входные товары трансформации',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='reservation',
|
||||
name='transformation_input',
|
||||
field=models.ForeignKey(blank=True, help_text='Резерв для входного товара трансформации (черновик)', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.transformationinput', verbose_name='Входной товар трансформации'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TransformationOutput',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transformation_outputs', to='products.product', verbose_name='Товар')),
|
||||
('stock_batch', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transformation_outputs', to='inventory.stockbatch', verbose_name='Созданная партия')),
|
||||
('transformation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='outputs', to='inventory.transformation', verbose_name='Трансформация')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Выходной товар трансформации',
|
||||
'verbose_name_plural': 'Выходные товары трансформации',
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transformation',
|
||||
index=models.Index(fields=['document_number'], name='inventory_t_documen_559778_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transformation',
|
||||
index=models.Index(fields=['warehouse', 'status'], name='inventory_t_warehou_934275_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='transformation',
|
||||
index=models.Index(fields=['-date'], name='inventory_t_date_65cfab_idx'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 5.0.10 on 2025-12-26 14:54
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0003_alter_documentcounter_counter_type_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='incomingbatch',
|
||||
name='warehouse',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Incoming',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='IncomingBatch',
|
||||
),
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
# Generated migration for Transfer models refactoring
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inventory', '0004_remove_incoming_batch_and_incoming'),
|
||||
('products', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# 1. Удаление устаревших моделей ПЕРЕД переименованием
|
||||
migrations.DeleteModel(
|
||||
name='Transfer',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='StockMovement',
|
||||
),
|
||||
|
||||
# 2. Переименование моделей
|
||||
migrations.RenameModel(
|
||||
old_name='TransferBatch',
|
||||
new_name='TransferDocument',
|
||||
),
|
||||
migrations.RenameModel(
|
||||
old_name='TransferItem',
|
||||
new_name='TransferDocumentItem',
|
||||
),
|
||||
|
||||
# 3. Переименование поля transfer_batch → transfer_document в TransferDocumentItem
|
||||
migrations.RenameField(
|
||||
model_name='transferdocumentitem',
|
||||
old_name='transfer_batch',
|
||||
new_name='transfer_document',
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user