Упрощена логика системы путём замены отдельной сущности "Магазин" на универсальную сущность "Склад", которая может использоваться как точка самовывоза. Изменения: - Расширена модель Warehouse: добавлены адрес, контакты, флаг is_pickup_point - Модель Order: поле pickup_shop заменено на pickup_warehouse - Обновлены все формы, сервисы, views, admin для работы со складами - Обновлены шаблоны HTML и JavaScript код - Удалено приложение shops полностью - Пересозданы миграции БД - Обновлён навбар (удалена ссылка на магазины) Преимущества: - Упрощена архитектура системы - Единая точка управления складами и точками самовывоза - Интеграция с системой инвентаризации 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
253 lines
16 KiB
Python
253 lines
16 KiB
Python
# Generated by Django 5.0.10 on 2025-11-14 20:45
|
||
|
||
import phonenumber_field.modelfields
|
||
from django.db import migrations, models
|
||
|
||
|
||
class Migration(migrations.Migration):
|
||
|
||
initial = True
|
||
|
||
dependencies = [
|
||
]
|
||
|
||
operations = [
|
||
migrations.CreateModel(
|
||
name='DocumentCounter',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('counter_type', models.CharField(choices=[('transfer', 'Перемещение товара')], max_length=20, unique=True, verbose_name='Тип счетчика')),
|
||
('current_value', models.IntegerField(default=0, verbose_name='Текущее значение')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Счетчик документов',
|
||
'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='Номер документа')),
|
||
('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='Inventory',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата инвентаризации')),
|
||
('status', models.CharField(choices=[('draft', 'Черновик'), ('processing', 'В обработке'), ('completed', 'Завершена')], default='draft', max_length=20, verbose_name='Статус')),
|
||
('conducted_by', models.CharField(blank=True, max_length=200, null=True, verbose_name='Провел инвентаризацию')),
|
||
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Инвентаризация',
|
||
'verbose_name_plural': 'Инвентаризации',
|
||
'ordering': ['-date'],
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='InventoryLine',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('quantity_system', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество в системе')),
|
||
('quantity_fact', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Фактическое количество')),
|
||
('difference', models.DecimalField(decimal_places=3, default=0, editable=False, max_digits=10, verbose_name='Разница (факт - система)')),
|
||
('processed', models.BooleanField(default=False, verbose_name='Обработана (создана операция)')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Строка инвентаризации',
|
||
'verbose_name_plural': 'Строки инвентаризации',
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='Reservation',
|
||
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', 'Преобразован в продажу')], default='reserved', max_length=20, 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, null=True, verbose_name='Дата преобразования в продажу')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Резервирование',
|
||
'verbose_name_plural': 'Резервирования',
|
||
'ordering': ['-reserved_at'],
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='Sale',
|
||
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='Количество')),
|
||
('sale_price', models.DecimalField(decimal_places=2, 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='Дата операции')),
|
||
('processed', models.BooleanField(default=False, verbose_name='Обработана (FIFO применена)')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Продажа',
|
||
'verbose_name_plural': 'Продажи',
|
||
'ordering': ['-date'],
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='SaleBatchAllocation',
|
||
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='Закупочная цена')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Распределение продажи по партиям',
|
||
'verbose_name_plural': 'Распределения продаж по партиям',
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='Stock',
|
||
fields=[
|
||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||
('quantity_available', models.DecimalField(decimal_places=3, default=0, editable=False, max_digits=10, verbose_name='Доступное количество')),
|
||
('quantity_reserved', models.DecimalField(decimal_places=3, default=0, editable=False, max_digits=10, verbose_name='Зарезервированное количество')),
|
||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Остаток на складе',
|
||
'verbose_name_plural': 'Остатки на складе',
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='StockBatch',
|
||
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='Закупочная цена')),
|
||
('is_active', models.BooleanField(default=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='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',
|
||
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='Номер документа')),
|
||
('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='TransferItem',
|
||
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': 'Строки перемещения',
|
||
'ordering': ['id'],
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='Warehouse',
|
||
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, null=True, verbose_name='Описание')),
|
||
('street', models.CharField(blank=True, max_length=255, null=True, verbose_name='Улица')),
|
||
('building_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='Номер здания')),
|
||
('phone', phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, null=True, region='BY', verbose_name='Телефон')),
|
||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='Email')),
|
||
('is_active', models.BooleanField(default=True, verbose_name='Активен')),
|
||
('is_default', models.BooleanField(default=False, help_text='Автоматически выбирается при создании новых документов', verbose_name='Склад по умолчанию')),
|
||
('is_pickup_point', models.BooleanField(default=True, 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': 'Склады',
|
||
},
|
||
),
|
||
migrations.CreateModel(
|
||
name='WriteOff',
|
||
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='Количество')),
|
||
('reason', models.CharField(choices=[('damage', 'Повреждение'), ('spoilage', 'Порча'), ('shortage', 'Недостача'), ('inventory', 'Инвентаризационная недостача'), ('other', 'Другое')], default='other', max_length=20, verbose_name='Причина')),
|
||
('cost_price', models.DecimalField(decimal_places=2, editable=False, max_digits=10, verbose_name='Закупочная цена')),
|
||
('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')),
|
||
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')),
|
||
],
|
||
options={
|
||
'verbose_name': 'Списание',
|
||
'verbose_name_plural': 'Списания',
|
||
'ordering': ['-date'],
|
||
},
|
||
),
|
||
]
|