Добавлена система трансформации товаров
Реализована полная система трансформации товаров (превращение одного товара в другой). Пример: белая гипсофила → крашеная гипсофила. Особенности реализации: - Резервирование входных товаров в статусе draft - FIFO списание входных товаров при проведении - Автоматический расчёт себестоимости выходных товаров - Возможность отмены как черновиков, так и проведённых трансформаций Модели (inventory/models.py): - Transformation: документ трансформации (draft/completed/cancelled) - TransformationInput: входные товары (списание) - TransformationOutput: выходные товары (оприходование) - Добавлен статус 'converted_to_transformation' в Reservation - Добавлен тип 'transformation' в DocumentCounter Бизнес-логика (inventory/services/transformation_service.py): - TransformationService с методами CRUD - Валидация наличия товаров - Автоматическая генерация номеров документов Сигналы (inventory/signals.py): - Автоматическое резервирование входных товаров - FIFO списание при проведении - Создание партий выходных товаров - Откат операций при отмене Интерфейс без Django Admin: - Список трансформаций (list.html) - Форма создания (form.html) - Детальный просмотр с добавлением товаров (detail.html) - Интеграция с компонентом поиска товаров - 8 views для полного CRUD + проведение/отмена Миграция: - 0003_alter_documentcounter_counter_type_and_more.py 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# 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'),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user