Упрощена система номеров заказов: переход на числовые номера
- Изменено поле order_number с CharField на PositiveIntegerField - Удален метод generate_order_number() - Упрощен метод save() - автоинкремент на основе максимального значения - Номера заказов теперь хранятся как числа (1, 2, 3, ...) без форматирования - Удалены все миграции для чистого старта 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
import django.contrib.auth.validators
|
import django.contrib.auth.validators
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import phonenumber_field.modelfields
|
import phonenumber_field.modelfields
|
||||||
@@ -38,11 +38,13 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('recipient_name', models.CharField(help_text='Имя человека, которому будет доставлен заказ', max_length=200, verbose_name='Имя получателя')),
|
('recipient_name', models.CharField(help_text='Имя человека, которому будет доставлен заказ', max_length=200, verbose_name='Имя получателя')),
|
||||||
|
('recipient_phone', phonenumber_field.modelfields.PhoneNumberField(blank=True, help_text='Контактный телефон получателя для уточнения адреса', max_length=128, null=True, region=None, verbose_name='Телефон получателя')),
|
||||||
('street', models.CharField(max_length=255, verbose_name='Улица')),
|
('street', models.CharField(max_length=255, verbose_name='Улица')),
|
||||||
('building_number', models.CharField(max_length=20, verbose_name='Номер здания')),
|
('building_number', models.CharField(max_length=20, verbose_name='Номер здания')),
|
||||||
('apartment_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='Номер квартиры/офиса')),
|
('apartment_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='Номер квартиры/офиса')),
|
||||||
('district', models.CharField(blank=True, help_text='Район в Минске для удобства доставки', max_length=100, null=True, verbose_name='Район')),
|
('district', models.CharField(blank=True, help_text='Район в Минске для удобства доставки', max_length=100, null=True, verbose_name='Район')),
|
||||||
('delivery_instructions', models.TextField(blank=True, help_text='Дополнительные инструкции для курьера (домофон, подъезд и т.д.)', null=True, verbose_name='Инструкции для доставки')),
|
('delivery_instructions', models.TextField(blank=True, help_text='Дополнительные инструкции для курьера (домофон, подъезд и т.д.)', null=True, verbose_name='Инструкции для доставки')),
|
||||||
|
('confirm_address_with_recipient', models.BooleanField(default=False, help_text='Курьер должен уточнить адрес у получателя перед доставкой', verbose_name='Уточнить адрес у получателя')),
|
||||||
('is_default', models.BooleanField(default=False, help_text='Использовать этот адрес для доставки по умолчанию', verbose_name='Адрес по умолчанию')),
|
('is_default', models.BooleanField(default=False, help_text='Использовать этот адрес для доставки по умолчанию', verbose_name='Адрес по умолчанию')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-06 20:54
|
|
||||||
|
|
||||||
import phonenumber_field.modelfields
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('customers', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='address',
|
|
||||||
name='confirm_address_with_recipient',
|
|
||||||
field=models.BooleanField(default=False, help_text='Курьер должен уточнить адрес у получателя перед доставкой', verbose_name='Уточнить адрес у получателя'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='address',
|
|
||||||
name='recipient_phone',
|
|
||||||
field=phonenumber_field.modelfields.PhoneNumberField(blank=True, help_text='Контактный телефон получателя для уточнения адреса', max_length=128, null=True, region=None, verbose_name='Телефон получателя'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@@ -9,11 +8,52 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('orders', '0001_initial'),
|
|
||||||
('products', '0001_initial'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
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(
|
migrations.CreateModel(
|
||||||
name='Inventory',
|
name='Inventory',
|
||||||
fields=[
|
fields=[
|
||||||
@@ -37,14 +77,28 @@ class Migration(migrations.Migration):
|
|||||||
('quantity_fact', 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='Разница (факт - система)')),
|
('difference', models.DecimalField(decimal_places=3, default=0, editable=False, max_digits=10, verbose_name='Разница (факт - система)')),
|
||||||
('processed', models.BooleanField(default=False, verbose_name='Обработана (создана операция)')),
|
('processed', models.BooleanField(default=False, verbose_name='Обработана (создана операция)')),
|
||||||
('inventory', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lines', to='inventory.inventory', verbose_name='Инвентаризация')),
|
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.product', verbose_name='Товар')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Строка инвентаризации',
|
'verbose_name': 'Строка инвентаризации',
|
||||||
'verbose_name_plural': 'Строки инвентаризации',
|
'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(
|
migrations.CreateModel(
|
||||||
name='Sale',
|
name='Sale',
|
||||||
fields=[
|
fields=[
|
||||||
@@ -54,8 +108,6 @@ class Migration(migrations.Migration):
|
|||||||
('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')),
|
('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')),
|
||||||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')),
|
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')),
|
||||||
('processed', models.BooleanField(default=False, verbose_name='Обработана (FIFO применена)')),
|
('processed', models.BooleanField(default=False, verbose_name='Обработана (FIFO применена)')),
|
||||||
('order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sales', to='orders.order', verbose_name='Заказ')),
|
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='products.product', verbose_name='Товар')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Продажа',
|
'verbose_name': 'Продажа',
|
||||||
@@ -63,6 +115,31 @@ class Migration(migrations.Migration):
|
|||||||
'ordering': ['-date'],
|
'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(
|
migrations.CreateModel(
|
||||||
name='StockBatch',
|
name='StockBatch',
|
||||||
fields=[
|
fields=[
|
||||||
@@ -72,7 +149,6 @@ class Migration(migrations.Migration):
|
|||||||
('is_active', models.BooleanField(default=True, verbose_name='Активна')),
|
('is_active', models.BooleanField(default=True, verbose_name='Активна')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stock_batches', to='products.product', verbose_name='Товар')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Партия товара',
|
'verbose_name': 'Партия товара',
|
||||||
@@ -81,17 +157,57 @@ class Migration(migrations.Migration):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='SaleBatchAllocation',
|
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=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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='Количество')),
|
('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')),
|
||||||
('cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Закупочная цена')),
|
('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')),
|
||||||
('sale', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='batch_allocations', to='inventory.sale', verbose_name='Продажа')),
|
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')),
|
||||||
('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_allocations', to='inventory.stockbatch', verbose_name='Партия')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Распределение продажи по партиям',
|
'verbose_name': 'Перемещение',
|
||||||
'verbose_name_plural': 'Распределения продаж по партиям',
|
'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(
|
migrations.CreateModel(
|
||||||
@@ -108,73 +224,6 @@ class Migration(migrations.Migration):
|
|||||||
options={
|
options={
|
||||||
'verbose_name': 'Склад',
|
'verbose_name': 'Склад',
|
||||||
'verbose_name_plural': 'Склады',
|
'verbose_name_plural': 'Склады',
|
||||||
'indexes': [models.Index(fields=['is_active'], name='inventory_w_is_acti_3ddeac_idx'), models.Index(fields=['is_default'], name='inventory_w_is_defa_4b7615_idx')],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='stockbatch',
|
|
||||||
name='warehouse',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stock_batches', to='inventory.warehouse', verbose_name='Склад'),
|
|
||||||
),
|
|
||||||
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='Дата обновления')),
|
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stocks', to='products.product', verbose_name='Товар')),
|
|
||||||
('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stocks', to='inventory.warehouse', verbose_name='Склад')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Остаток на складе',
|
|
||||||
'verbose_name_plural': 'Остатки на складе',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sale',
|
|
||||||
name='warehouse',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.warehouse', verbose_name='Склад'),
|
|
||||||
),
|
|
||||||
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='Дата преобразования в продажу')),
|
|
||||||
('order_item', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='orders.orderitem', verbose_name='Позиция заказа')),
|
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='products.product', verbose_name='Товар')),
|
|
||||||
('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.warehouse', verbose_name='Склад')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Резервирование',
|
|
||||||
'verbose_name_plural': 'Резервирования',
|
|
||||||
'ordering': ['-reserved_at'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='inventory',
|
|
||||||
name='warehouse',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inventories', to='inventory.warehouse', verbose_name='Склад'),
|
|
||||||
),
|
|
||||||
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='Дата обновления')),
|
|
||||||
('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incoming_batches', to='inventory.warehouse', verbose_name='Склад')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Партия поступления',
|
|
||||||
'verbose_name_plural': 'Партии поступлений',
|
|
||||||
'ordering': ['-created_at'],
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@@ -187,7 +236,6 @@ class Migration(migrations.Migration):
|
|||||||
('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')),
|
('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')),
|
||||||
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')),
|
||||||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')),
|
('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')),
|
||||||
('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='writeoffs', to='inventory.stockbatch', verbose_name='Партия')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Списание',
|
'verbose_name': 'Списание',
|
||||||
@@ -195,123 +243,4 @@ class Migration(migrations.Migration):
|
|||||||
'ordering': ['-date'],
|
'ordering': ['-date'],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
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='Дата создания')),
|
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incomings', to='products.product', verbose_name='Товар')),
|
|
||||||
('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.incomingbatch', verbose_name='Партия')),
|
|
||||||
('stock_batch', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='incomings', to='inventory.stockbatch', verbose_name='Складская партия')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Товар в поступлении',
|
|
||||||
'verbose_name_plural': 'Товары в поступлениях',
|
|
||||||
'ordering': ['-created_at'],
|
|
||||||
'indexes': [models.Index(fields=['batch'], name='inventory_i_batch_i_c50b63_idx'), models.Index(fields=['product'], name='inventory_i_product_39b00d_idx'), models.Index(fields=['-created_at'], name='inventory_i_created_563ec0_idx')],
|
|
||||||
'unique_together': {('batch', 'product')},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
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='Дата создания')),
|
|
||||||
('order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stock_movements', to='orders.order', verbose_name='Заказ')),
|
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='movements', to='products.product', verbose_name='Товар')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Движение товара',
|
|
||||||
'verbose_name_plural': 'Движения товаров',
|
|
||||||
'indexes': [models.Index(fields=['product'], name='inventory_s_product_cbdc37_idx'), models.Index(fields=['created_at'], name='inventory_s_created_05ebf5_idx')],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
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='Дата операции')),
|
|
||||||
('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers', to='inventory.stockbatch', verbose_name='Партия')),
|
|
||||||
('new_batch', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transfer_sources', to='inventory.stockbatch', verbose_name='Новая партия')),
|
|
||||||
('from_warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_from', to='inventory.warehouse', verbose_name='Из склада')),
|
|
||||||
('to_warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfers_to', to='inventory.warehouse', verbose_name='На склад')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Перемещение',
|
|
||||||
'verbose_name_plural': 'Перемещения',
|
|
||||||
'ordering': ['-date'],
|
|
||||||
'indexes': [models.Index(fields=['from_warehouse', 'to_warehouse'], name='inventory_t_from_wa_578feb_idx'), models.Index(fields=['date'], name='inventory_t_date_e1402d_idx')],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='stockbatch',
|
|
||||||
index=models.Index(fields=['product', 'warehouse'], name='inventory_s_product_022460_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='stockbatch',
|
|
||||||
index=models.Index(fields=['created_at'], name='inventory_s_created_10279b_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='stockbatch',
|
|
||||||
index=models.Index(fields=['is_active'], name='inventory_s_is_acti_0dd559_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='stock',
|
|
||||||
index=models.Index(fields=['product', 'warehouse'], name='inventory_s_product_112b63_idx'),
|
|
||||||
),
|
|
||||||
migrations.AlterUniqueTogether(
|
|
||||||
name='stock',
|
|
||||||
unique_together={('product', 'warehouse')},
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='sale',
|
|
||||||
index=models.Index(fields=['product', 'warehouse'], name='inventory_s_product_084314_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='sale',
|
|
||||||
index=models.Index(fields=['date'], name='inventory_s_date_8972d4_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='sale',
|
|
||||||
index=models.Index(fields=['order'], name='inventory_s_order_i_7d13ea_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='reservation',
|
|
||||||
index=models.Index(fields=['product', 'warehouse'], name='inventory_r_product_fa0d33_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='reservation',
|
|
||||||
index=models.Index(fields=['status'], name='inventory_r_status_806333_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='reservation',
|
|
||||||
index=models.Index(fields=['order_item'], name='inventory_r_order_i_ae991f_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=['-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'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='writeoff',
|
|
||||||
index=models.Index(fields=['date'], name='inventory_w_date_70c7e3_idx'),
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-02 20:37
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0001_initial'),
|
|
||||||
('products', '0005_remove_kititem_notes'),
|
|
||||||
]
|
|
||||||
|
|
||||||
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='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='Дата обновления')),
|
|
||||||
('from_warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_batches_from', to='inventory.warehouse', verbose_name='Склад-отгрузки')),
|
|
||||||
('to_warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_batches_to', to='inventory.warehouse', 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='Количество')),
|
|
||||||
('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_items', to='inventory.stockbatch', verbose_name='Исходная партия (FIFO)')),
|
|
||||||
('new_batch', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transfer_items_created', to='inventory.stockbatch', verbose_name='Созданная партия на целевом складе')),
|
|
||||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_items', to='products.product', verbose_name='Товар')),
|
|
||||||
('transfer_batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='inventory.transferbatch', verbose_name='Документ перемещения')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Строка перемещения',
|
|
||||||
'verbose_name_plural': 'Строки перемещения',
|
|
||||||
'ordering': ['id'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='transferbatch',
|
|
||||||
index=models.Index(fields=['document_number'], name='inventory_t_documen_143275_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='transferitem',
|
|
||||||
index=models.Index(fields=['transfer_batch'], name='inventory_t_transfe_f7479b_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')},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
306
myproject/inventory/migrations/0002_initial.py
Normal file
306
myproject/inventory/migrations/0002_initial.py
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0001_initial'),
|
||||||
|
('orders', '0001_initial'),
|
||||||
|
('products', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
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='inventoryline',
|
||||||
|
name='inventory',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lines', to='inventory.inventory', verbose_name='Инвентаризация'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventoryline',
|
||||||
|
name='product',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='products.product', verbose_name='Товар'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='reservation',
|
||||||
|
name='order_item',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='orders.orderitem', verbose_name='Позиция заказа'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='reservation',
|
||||||
|
name='product',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='products.product', verbose_name='Товар'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='sale',
|
||||||
|
name='order',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sales', to='orders.order', verbose_name='Заказ'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='sale',
|
||||||
|
name='product',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='products.product', verbose_name='Товар'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salebatchallocation',
|
||||||
|
name='sale',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='batch_allocations', to='inventory.sale', verbose_name='Продажа'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stock',
|
||||||
|
name='product',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stocks', to='products.product', verbose_name='Товар'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stockbatch',
|
||||||
|
name='product',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stock_batches', to='products.product', verbose_name='Товар'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='salebatchallocation',
|
||||||
|
name='batch',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_allocations', to='inventory.stockbatch', verbose_name='Партия'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='incoming',
|
||||||
|
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='Складская партия'),
|
||||||
|
),
|
||||||
|
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='Документ перемещения'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='warehouse',
|
||||||
|
index=models.Index(fields=['is_active'], name='inventory_w_is_acti_3ddeac_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='warehouse',
|
||||||
|
index=models.Index(fields=['is_default'], name='inventory_w_is_defa_4b7615_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='transferbatch',
|
||||||
|
name='from_warehouse',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transfer_batches_from', to='inventory.warehouse', verbose_name='Склад-отгрузки'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='transferbatch',
|
||||||
|
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='На склад'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stockbatch',
|
||||||
|
name='warehouse',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stock_batches', to='inventory.warehouse', verbose_name='Склад'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='stock',
|
||||||
|
name='warehouse',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stocks', to='inventory.warehouse', verbose_name='Склад'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='sale',
|
||||||
|
name='warehouse',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sales', to='inventory.warehouse', verbose_name='Склад'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='reservation',
|
||||||
|
name='warehouse',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='inventory.warehouse', verbose_name='Склад'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventory',
|
||||||
|
name='warehouse',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inventories', 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',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='writeoffs', to='inventory.stockbatch', verbose_name='Партия'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='incoming',
|
||||||
|
index=models.Index(fields=['batch'], name='inventory_i_batch_i_c50b63_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'),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='incoming',
|
||||||
|
unique_together={('batch', 'product')},
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='stockmovement',
|
||||||
|
index=models.Index(fields=['product'], name='inventory_s_product_cbdc37_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='stockmovement',
|
||||||
|
index=models.Index(fields=['created_at'], name='inventory_s_created_05ebf5_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='transferitem',
|
||||||
|
index=models.Index(fields=['transfer_batch'], name='inventory_t_transfe_f7479b_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')},
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='transferbatch',
|
||||||
|
index=models.Index(fields=['document_number'], name='inventory_t_documen_143275_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'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='stockbatch',
|
||||||
|
index=models.Index(fields=['product', 'warehouse'], name='inventory_s_product_022460_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='stockbatch',
|
||||||
|
index=models.Index(fields=['created_at'], name='inventory_s_created_10279b_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='stockbatch',
|
||||||
|
index=models.Index(fields=['is_active'], name='inventory_s_is_acti_0dd559_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='stock',
|
||||||
|
index=models.Index(fields=['product', 'warehouse'], name='inventory_s_product_112b63_idx'),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='stock',
|
||||||
|
unique_together={('product', 'warehouse')},
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='sale',
|
||||||
|
index=models.Index(fields=['product', 'warehouse'], name='inventory_s_product_084314_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='sale',
|
||||||
|
index=models.Index(fields=['date'], name='inventory_s_date_8972d4_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='sale',
|
||||||
|
index=models.Index(fields=['order'], name='inventory_s_order_i_7d13ea_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='reservation',
|
||||||
|
index=models.Index(fields=['product', 'warehouse'], name='inventory_r_product_fa0d33_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='reservation',
|
||||||
|
index=models.Index(fields=['status'], name='inventory_r_status_806333_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='reservation',
|
||||||
|
index=models.Index(fields=['order_item'], name='inventory_r_order_i_ae991f_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=['-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'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='writeoff',
|
||||||
|
index=models.Index(fields=['date'], name='inventory_w_date_70c7e3_idx'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
import simple_history.models
|
||||||
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@@ -10,31 +12,97 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('customers', '0001_initial'),
|
('customers', '0001_initial'),
|
||||||
('products', '0001_initial'),
|
|
||||||
('shops', '0001_initial'),
|
('shops', '0001_initial'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Order',
|
name='Payment',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('order_number', models.CharField(editable=False, help_text='Уникальный номер заказа для отображения клиенту', max_length=50, unique=True, verbose_name='Номер заказа')),
|
('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Сумма платежа')),
|
||||||
('delivery_type', models.CharField(choices=[('courier', 'Курьерская доставка'), ('pickup', 'Самовывоз')], default='courier', max_length=20, verbose_name='Тип доставки')),
|
('payment_method', models.CharField(choices=[('cash_to_courier', 'Наличные курьеру'), ('card_to_courier', 'Карта курьеру'), ('online', 'Онлайн оплата'), ('bank_transfer', 'Банковский перевод')], max_length=20, verbose_name='Способ оплаты')),
|
||||||
('delivery_date', models.DateField(verbose_name='Дата доставки/самовывоза')),
|
('payment_date', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время платежа')),
|
||||||
('delivery_time_start', models.TimeField(help_text='Начало временного интервала', verbose_name='Время от')),
|
('notes', models.TextField(blank=True, help_text='Дополнительная информация о платеже', null=True, verbose_name='Примечания')),
|
||||||
('delivery_time_end', models.TimeField(help_text='Конец временного интервала', verbose_name='Время до')),
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Платеж',
|
||||||
|
'verbose_name_plural': 'Платежи',
|
||||||
|
'ordering': ['-payment_date'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='HistoricalOrder',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||||
|
('order_number', models.PositiveIntegerField(db_index=True, editable=False, help_text='Уникальный номер заказа', verbose_name='Номер заказа')),
|
||||||
|
('is_delivery', models.BooleanField(default=True, help_text='True - доставка курьером, False - самовывоз', verbose_name='С доставкой')),
|
||||||
|
('delivery_date', models.DateField(blank=True, help_text='Может быть заполнено позже', null=True, verbose_name='Дата доставки/самовывоза')),
|
||||||
|
('delivery_time_start', models.TimeField(blank=True, help_text='Начало временного интервала', null=True, verbose_name='Время от')),
|
||||||
|
('delivery_time_end', models.TimeField(blank=True, help_text='Конец временного интервала', null=True, verbose_name='Время до')),
|
||||||
('delivery_cost', models.DecimalField(decimal_places=2, default=0, help_text='0 для самовывоза', max_digits=10, verbose_name='Стоимость доставки')),
|
('delivery_cost', models.DecimalField(decimal_places=2, default=0, help_text='0 для самовывоза', max_digits=10, verbose_name='Стоимость доставки')),
|
||||||
('status', models.CharField(choices=[('new', 'Новый'), ('confirmed', 'Подтвержден'), ('in_assembly', 'В сборке'), ('in_delivery', 'В доставке'), ('delivered', 'Доставлен'), ('cancelled', 'Отменен')], default='new', max_length=20, verbose_name='Статус заказа')),
|
('status', models.CharField(choices=[('draft', 'Черновик'), ('new', 'Новый'), ('confirmed', 'Подтвержден'), ('in_assembly', 'В сборке'), ('in_delivery', 'В доставке'), ('delivered', 'Доставлен'), ('cancelled', 'Отменен')], default='new', max_length=20, verbose_name='Статус заказа')),
|
||||||
|
('last_autosave_at', models.DateTimeField(blank=True, help_text='Время последнего автоматического сохранения черновика', null=True, verbose_name='Последнее автосохранение')),
|
||||||
('payment_method', models.CharField(choices=[('cash_to_courier', 'Наличные курьеру'), ('card_to_courier', 'Карта курьеру'), ('online', 'Онлайн оплата'), ('bank_transfer', 'Банковский перевод')], default='cash_to_courier', max_length=20, verbose_name='Способ оплаты')),
|
('payment_method', models.CharField(choices=[('cash_to_courier', 'Наличные курьеру'), ('card_to_courier', 'Карта курьеру'), ('online', 'Онлайн оплата'), ('bank_transfer', 'Банковский перевод')], default='cash_to_courier', max_length=20, verbose_name='Способ оплаты')),
|
||||||
('is_paid', models.BooleanField(default=False, verbose_name='Оплачен')),
|
('is_paid', models.BooleanField(default=False, verbose_name='Оплачен')),
|
||||||
('total_amount', models.DecimalField(decimal_places=2, default=0, help_text='Общая сумма заказа включая доставку', max_digits=10, verbose_name='Итоговая сумма заказа')),
|
('total_amount', models.DecimalField(decimal_places=2, default=0, help_text='Общая сумма заказа включая доставку', max_digits=10, verbose_name='Итоговая сумма заказа')),
|
||||||
|
('discount_amount', models.DecimalField(decimal_places=2, default=0, help_text='Применяется вручную или через систему скидок', max_digits=10, verbose_name='Сумма скидки')),
|
||||||
|
('amount_paid', models.DecimalField(decimal_places=2, default=0, help_text='Сумма, внесенная клиентом', max_digits=10, verbose_name='Оплачено')),
|
||||||
|
('payment_status', models.CharField(choices=[('unpaid', 'Не оплачен'), ('partial', 'Частично оплачен'), ('paid', 'Оплачен полностью')], default='unpaid', help_text='Обновляется автоматически при добавлении платежей', max_length=20, verbose_name='Статус оплаты')),
|
||||||
|
('customer_is_recipient', models.BooleanField(default=True, help_text='Если отмечено, данные получателя не требуются отдельно', verbose_name='Покупатель является получателем')),
|
||||||
|
('recipient_name', models.CharField(blank=True, help_text='Заполняется, если покупатель не является получателем', max_length=200, null=True, verbose_name='Имя получателя')),
|
||||||
|
('recipient_phone', models.CharField(blank=True, help_text='Контактный телефон получателя', max_length=20, null=True, verbose_name='Телефон получателя')),
|
||||||
|
('is_anonymous', models.BooleanField(default=False, help_text='Не сообщать получателю имя отправителя', verbose_name='Анонимная доставка')),
|
||||||
|
('special_instructions', models.TextField(blank=True, help_text='Комментарии и пожелания к заказу', null=True, verbose_name='Особые пожелания')),
|
||||||
|
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата создания')),
|
||||||
|
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата обновления')),
|
||||||
|
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('history_date', models.DateTimeField(db_index=True)),
|
||||||
|
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||||
|
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||||
|
('customer', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='customers.customer', verbose_name='Клиент')),
|
||||||
|
('delivery_address', models.ForeignKey(blank=True, db_constraint=False, help_text='Обязательно для курьерской доставки', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='customers.address', verbose_name='Адрес доставки')),
|
||||||
|
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('modified_by', models.ForeignKey(blank=True, db_constraint=False, help_text='Последний пользователь, изменивший заказ', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Изменен пользователем')),
|
||||||
|
('pickup_shop', models.ForeignKey(blank=True, db_constraint=False, help_text='Обязательно для самовывоза', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='shops.shop', verbose_name='Точка самовывоза')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'historical Заказ',
|
||||||
|
'verbose_name_plural': 'historical Заказы',
|
||||||
|
'ordering': ('-history_date', '-history_id'),
|
||||||
|
'get_latest_by': ('history_date', 'history_id'),
|
||||||
|
},
|
||||||
|
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Order',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('order_number', models.PositiveIntegerField(editable=False, help_text='Уникальный номер заказа', unique=True, verbose_name='Номер заказа')),
|
||||||
|
('is_delivery', models.BooleanField(default=True, help_text='True - доставка курьером, False - самовывоз', verbose_name='С доставкой')),
|
||||||
|
('delivery_date', models.DateField(blank=True, help_text='Может быть заполнено позже', null=True, verbose_name='Дата доставки/самовывоза')),
|
||||||
|
('delivery_time_start', models.TimeField(blank=True, help_text='Начало временного интервала', null=True, verbose_name='Время от')),
|
||||||
|
('delivery_time_end', models.TimeField(blank=True, help_text='Конец временного интервала', null=True, verbose_name='Время до')),
|
||||||
|
('delivery_cost', models.DecimalField(decimal_places=2, default=0, help_text='0 для самовывоза', max_digits=10, verbose_name='Стоимость доставки')),
|
||||||
|
('status', models.CharField(choices=[('draft', 'Черновик'), ('new', 'Новый'), ('confirmed', 'Подтвержден'), ('in_assembly', 'В сборке'), ('in_delivery', 'В доставке'), ('delivered', 'Доставлен'), ('cancelled', 'Отменен')], default='new', max_length=20, verbose_name='Статус заказа')),
|
||||||
|
('last_autosave_at', models.DateTimeField(blank=True, help_text='Время последнего автоматического сохранения черновика', null=True, verbose_name='Последнее автосохранение')),
|
||||||
|
('payment_method', models.CharField(choices=[('cash_to_courier', 'Наличные курьеру'), ('card_to_courier', 'Карта курьеру'), ('online', 'Онлайн оплата'), ('bank_transfer', 'Банковский перевод')], default='cash_to_courier', max_length=20, verbose_name='Способ оплаты')),
|
||||||
|
('is_paid', models.BooleanField(default=False, verbose_name='Оплачен')),
|
||||||
|
('total_amount', models.DecimalField(decimal_places=2, default=0, help_text='Общая сумма заказа включая доставку', max_digits=10, verbose_name='Итоговая сумма заказа')),
|
||||||
|
('discount_amount', models.DecimalField(decimal_places=2, default=0, help_text='Применяется вручную или через систему скидок', max_digits=10, verbose_name='Сумма скидки')),
|
||||||
|
('amount_paid', models.DecimalField(decimal_places=2, default=0, help_text='Сумма, внесенная клиентом', max_digits=10, verbose_name='Оплачено')),
|
||||||
|
('payment_status', models.CharField(choices=[('unpaid', 'Не оплачен'), ('partial', 'Частично оплачен'), ('paid', 'Оплачен полностью')], default='unpaid', help_text='Обновляется автоматически при добавлении платежей', max_length=20, verbose_name='Статус оплаты')),
|
||||||
|
('customer_is_recipient', models.BooleanField(default=True, help_text='Если отмечено, данные получателя не требуются отдельно', verbose_name='Покупатель является получателем')),
|
||||||
|
('recipient_name', models.CharField(blank=True, help_text='Заполняется, если покупатель не является получателем', max_length=200, null=True, verbose_name='Имя получателя')),
|
||||||
|
('recipient_phone', models.CharField(blank=True, help_text='Контактный телефон получателя', max_length=20, null=True, verbose_name='Телефон получателя')),
|
||||||
('is_anonymous', models.BooleanField(default=False, help_text='Не сообщать получателю имя отправителя', verbose_name='Анонимная доставка')),
|
('is_anonymous', models.BooleanField(default=False, help_text='Не сообщать получателю имя отправителя', verbose_name='Анонимная доставка')),
|
||||||
('special_instructions', models.TextField(blank=True, help_text='Комментарии и пожелания к заказу', null=True, verbose_name='Особые пожелания')),
|
('special_instructions', models.TextField(blank=True, help_text='Комментарии и пожелания к заказу', null=True, verbose_name='Особые пожелания')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||||
('customer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='orders', to='customers.customer', verbose_name='Клиент')),
|
('customer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='orders', to='customers.customer', verbose_name='Клиент')),
|
||||||
('delivery_address', models.ForeignKey(blank=True, help_text='Обязательно для курьерской доставки', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='orders', to='customers.address', verbose_name='Адрес доставки')),
|
('delivery_address', models.ForeignKey(blank=True, help_text='Обязательно для курьерской доставки', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='orders', to='customers.address', verbose_name='Адрес доставки')),
|
||||||
|
('modified_by', models.ForeignKey(blank=True, help_text='Последний пользователь, изменивший заказ', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='modified_orders', to=settings.AUTH_USER_MODEL, verbose_name='Изменен пользователем')),
|
||||||
('pickup_shop', models.ForeignKey(blank=True, help_text='Обязательно для самовывоза', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pickup_orders', to='shops.shop', verbose_name='Точка самовывоза')),
|
('pickup_shop', models.ForeignKey(blank=True, help_text='Обязательно для самовывоза', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pickup_orders', to='shops.shop', verbose_name='Точка самовывоза')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@@ -49,50 +117,13 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('quantity', models.PositiveIntegerField(default=1, verbose_name='Количество')),
|
('quantity', models.PositiveIntegerField(default=1, verbose_name='Количество')),
|
||||||
('price', models.DecimalField(decimal_places=2, help_text='Цена на момент создания заказа (фиксируется)', max_digits=10, verbose_name='Цена за единицу')),
|
('price', models.DecimalField(decimal_places=2, help_text='Цена на момент создания заказа (фиксируется)', max_digits=10, verbose_name='Цена за единицу')),
|
||||||
|
('is_custom_price', models.BooleanField(default=False, help_text='True если цена была изменена вручную при создании заказа', verbose_name='Цена изменена вручную')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата добавления')),
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата добавления')),
|
||||||
('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='orders.order', verbose_name='Заказ')),
|
('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='orders.order', verbose_name='Заказ')),
|
||||||
('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='order_items', to='products.product', verbose_name='Товар')),
|
|
||||||
('product_kit', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='order_items', to='products.productkit', verbose_name='Комплект товаров')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Позиция заказа',
|
'verbose_name': 'Позиция заказа',
|
||||||
'verbose_name_plural': 'Позиции заказа',
|
'verbose_name_plural': 'Позиции заказа',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['customer'], name='orders_orde_custome_59b6fb_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['status'], name='orders_orde_status_c6dd84_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['delivery_date'], name='orders_orde_deliver_e4274f_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['delivery_type'], name='orders_orde_deliver_f68568_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['created_at'], name='orders_orde_created_0e92de_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['order_number'], name='orders_orde_order_n_f3ada5_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='orderitem',
|
|
||||||
index=models.Index(fields=['order'], name='orders_orde_order_i_5d347b_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='orderitem',
|
|
||||||
index=models.Index(fields=['product'], name='orders_orde_product_32ff41_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='orderitem',
|
|
||||||
index=models.Index(fields=['product_kit'], name='orders_orde_product_925b51_idx'),
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-06 20:54
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
import simple_history.models
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('customers', '0002_address_confirm_address_with_recipient_and_more'),
|
|
||||||
('orders', '0001_initial'),
|
|
||||||
('shops', '0001_initial'),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='HistoricalOrder',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
|
||||||
('order_number', models.CharField(db_index=True, editable=False, help_text='Уникальный номер заказа для отображения клиенту', max_length=50, verbose_name='Номер заказа')),
|
|
||||||
('is_delivery', models.BooleanField(default=True, help_text='True - доставка курьером, False - самовывоз', verbose_name='С доставкой')),
|
|
||||||
('delivery_date', models.DateField(blank=True, help_text='Может быть заполнено позже', null=True, verbose_name='Дата доставки/самовывоза')),
|
|
||||||
('delivery_time_start', models.TimeField(blank=True, help_text='Начало временного интервала', null=True, verbose_name='Время от')),
|
|
||||||
('delivery_time_end', models.TimeField(blank=True, help_text='Конец временного интервала', null=True, verbose_name='Время до')),
|
|
||||||
('delivery_cost', models.DecimalField(decimal_places=2, default=0, help_text='0 для самовывоза', max_digits=10, verbose_name='Стоимость доставки')),
|
|
||||||
('status', models.CharField(choices=[('new', 'Новый'), ('confirmed', 'Подтвержден'), ('in_assembly', 'В сборке'), ('in_delivery', 'В доставке'), ('delivered', 'Доставлен'), ('cancelled', 'Отменен')], default='new', max_length=20, verbose_name='Статус заказа')),
|
|
||||||
('payment_method', models.CharField(choices=[('cash_to_courier', 'Наличные курьеру'), ('card_to_courier', 'Карта курьеру'), ('online', 'Онлайн оплата'), ('bank_transfer', 'Банковский перевод')], default='cash_to_courier', max_length=20, verbose_name='Способ оплаты')),
|
|
||||||
('is_paid', models.BooleanField(default=False, verbose_name='Оплачен')),
|
|
||||||
('total_amount', models.DecimalField(decimal_places=2, default=0, help_text='Общая сумма заказа включая доставку', max_digits=10, verbose_name='Итоговая сумма заказа')),
|
|
||||||
('discount_amount', models.DecimalField(decimal_places=2, default=0, help_text='Применяется вручную или через систему скидок', max_digits=10, verbose_name='Сумма скидки')),
|
|
||||||
('amount_paid', models.DecimalField(decimal_places=2, default=0, help_text='Сумма, внесенная клиентом', max_digits=10, verbose_name='Оплачено')),
|
|
||||||
('payment_status', models.CharField(choices=[('unpaid', 'Не оплачен'), ('partial', 'Частично оплачен'), ('paid', 'Оплачен полностью')], default='unpaid', help_text='Обновляется автоматически при добавлении платежей', max_length=20, verbose_name='Статус оплаты')),
|
|
||||||
('customer_is_recipient', models.BooleanField(default=True, help_text='Если отмечено, данные получателя не требуются отдельно', verbose_name='Покупатель является получателем')),
|
|
||||||
('is_anonymous', models.BooleanField(default=False, help_text='Не сообщать получателю имя отправителя', verbose_name='Анонимная доставка')),
|
|
||||||
('special_instructions', models.TextField(blank=True, help_text='Комментарии и пожелания к заказу', null=True, verbose_name='Особые пожелания')),
|
|
||||||
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата создания')),
|
|
||||||
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата обновления')),
|
|
||||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
|
||||||
('history_date', models.DateTimeField(db_index=True)),
|
|
||||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
|
||||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'historical Заказ',
|
|
||||||
'verbose_name_plural': 'historical Заказы',
|
|
||||||
'ordering': ('-history_date', '-history_id'),
|
|
||||||
'get_latest_by': ('history_date', 'history_id'),
|
|
||||||
},
|
|
||||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Payment',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('amount', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Сумма платежа')),
|
|
||||||
('payment_method', models.CharField(choices=[('cash_to_courier', 'Наличные курьеру'), ('card_to_courier', 'Карта курьеру'), ('online', 'Онлайн оплата'), ('bank_transfer', 'Банковский перевод')], max_length=20, verbose_name='Способ оплаты')),
|
|
||||||
('payment_date', models.DateTimeField(auto_now_add=True, verbose_name='Дата и время платежа')),
|
|
||||||
('notes', models.TextField(blank=True, help_text='Дополнительная информация о платеже', null=True, verbose_name='Примечания')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Платеж',
|
|
||||||
'verbose_name_plural': 'Платежи',
|
|
||||||
'ordering': ['-payment_date'],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.RemoveIndex(
|
|
||||||
model_name='order',
|
|
||||||
name='orders_orde_deliver_f68568_idx',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='order',
|
|
||||||
name='delivery_type',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='amount_paid',
|
|
||||||
field=models.DecimalField(decimal_places=2, default=0, help_text='Сумма, внесенная клиентом', max_digits=10, verbose_name='Оплачено'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='customer_is_recipient',
|
|
||||||
field=models.BooleanField(default=True, help_text='Если отмечено, данные получателя не требуются отдельно', verbose_name='Покупатель является получателем'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='discount_amount',
|
|
||||||
field=models.DecimalField(decimal_places=2, default=0, help_text='Применяется вручную или через систему скидок', max_digits=10, verbose_name='Сумма скидки'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='is_delivery',
|
|
||||||
field=models.BooleanField(default=True, help_text='True - доставка курьером, False - самовывоз', verbose_name='С доставкой'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='modified_by',
|
|
||||||
field=models.ForeignKey(blank=True, help_text='Последний пользователь, изменивший заказ', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='modified_orders', to=settings.AUTH_USER_MODEL, verbose_name='Изменен пользователем'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='payment_status',
|
|
||||||
field=models.CharField(choices=[('unpaid', 'Не оплачен'), ('partial', 'Частично оплачен'), ('paid', 'Оплачен полностью')], default='unpaid', help_text='Обновляется автоматически при добавлении платежей', max_length=20, verbose_name='Статус оплаты'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='order',
|
|
||||||
name='delivery_date',
|
|
||||||
field=models.DateField(blank=True, help_text='Может быть заполнено позже', null=True, verbose_name='Дата доставки/самовывоза'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='order',
|
|
||||||
name='delivery_time_end',
|
|
||||||
field=models.TimeField(blank=True, help_text='Конец временного интервала', null=True, verbose_name='Время до'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='order',
|
|
||||||
name='delivery_time_start',
|
|
||||||
field=models.TimeField(blank=True, help_text='Начало временного интервала', null=True, verbose_name='Время от'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['is_delivery'], name='orders_orde_is_deli_07c9c0_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='order',
|
|
||||||
index=models.Index(fields=['payment_status'], name='orders_orde_payment_bc131d_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='customer',
|
|
||||||
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='customers.customer', verbose_name='Клиент'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='delivery_address',
|
|
||||||
field=models.ForeignKey(blank=True, db_constraint=False, help_text='Обязательно для курьерской доставки', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='customers.address', verbose_name='Адрес доставки'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='history_user',
|
|
||||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='modified_by',
|
|
||||||
field=models.ForeignKey(blank=True, db_constraint=False, help_text='Последний пользователь, изменивший заказ', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Изменен пользователем'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='pickup_shop',
|
|
||||||
field=models.ForeignKey(blank=True, db_constraint=False, help_text='Обязательно для самовывоза', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='shops.shop', verbose_name='Точка самовывоза'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='payment',
|
|
||||||
name='created_by',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='payments_created', to=settings.AUTH_USER_MODEL, verbose_name='Принял платеж'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='payment',
|
|
||||||
name='order',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='orders.order', verbose_name='Заказ'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='payment',
|
|
||||||
index=models.Index(fields=['order'], name='orders_paym_order_i_8c8d98_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='payment',
|
|
||||||
index=models.Index(fields=['payment_date'], name='orders_paym_payment_9e5ac0_idx'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
87
myproject/orders/migrations/0002_initial.py
Normal file
87
myproject/orders/migrations/0002_initial.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('orders', '0001_initial'),
|
||||||
|
('products', '0001_initial'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='orderitem',
|
||||||
|
name='product',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='order_items', to='products.product', verbose_name='Товар'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='orderitem',
|
||||||
|
name='product_kit',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='order_items', to='products.productkit', verbose_name='Комплект товаров'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='payment',
|
||||||
|
name='created_by',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='payments_created', to=settings.AUTH_USER_MODEL, verbose_name='Принял платеж'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='payment',
|
||||||
|
name='order',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='orders.order', verbose_name='Заказ'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='order',
|
||||||
|
index=models.Index(fields=['customer'], name='orders_orde_custome_59b6fb_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='order',
|
||||||
|
index=models.Index(fields=['status'], name='orders_orde_status_c6dd84_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='order',
|
||||||
|
index=models.Index(fields=['delivery_date'], name='orders_orde_deliver_e4274f_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='order',
|
||||||
|
index=models.Index(fields=['is_delivery'], name='orders_orde_is_deli_07c9c0_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='order',
|
||||||
|
index=models.Index(fields=['payment_status'], name='orders_orde_payment_bc131d_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='order',
|
||||||
|
index=models.Index(fields=['created_at'], name='orders_orde_created_0e92de_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='order',
|
||||||
|
index=models.Index(fields=['order_number'], name='orders_orde_order_n_f3ada5_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='orderitem',
|
||||||
|
index=models.Index(fields=['order'], name='orders_orde_order_i_5d347b_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='orderitem',
|
||||||
|
index=models.Index(fields=['product'], name='orders_orde_product_32ff41_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='orderitem',
|
||||||
|
index=models.Index(fields=['product_kit'], name='orders_orde_product_925b51_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='payment',
|
||||||
|
index=models.Index(fields=['order'], name='orders_paym_order_i_8c8d98_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='payment',
|
||||||
|
index=models.Index(fields=['payment_date'], name='orders_paym_payment_9e5ac0_idx'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-06 21:54
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('orders', '0002_historicalorder_payment_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='recipient_name',
|
|
||||||
field=models.CharField(blank=True, help_text='Заполняется, если покупатель не является получателем', max_length=200, null=True, verbose_name='Имя получателя'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='recipient_phone',
|
|
||||||
field=models.CharField(blank=True, help_text='Контактный телефон получателя', max_length=20, null=True, verbose_name='Телефон получателя'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='recipient_name',
|
|
||||||
field=models.CharField(blank=True, help_text='Заполняется, если покупатель не является получателем', max_length=200, null=True, verbose_name='Имя получателя'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='recipient_phone',
|
|
||||||
field=models.CharField(blank=True, help_text='Контактный телефон получателя', max_length=20, null=True, verbose_name='Телефон получателя'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-07 06:34
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('orders', '0003_historicalorder_recipient_name_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='orderitem',
|
|
||||||
name='is_custom_price',
|
|
||||||
field=models.BooleanField(default=False, help_text='True если цена была изменена вручную при создании заказа', verbose_name='Цена изменена вручную'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-08 15:14
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('orders', '0004_orderitem_is_custom_price'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='last_autosave_at',
|
|
||||||
field=models.DateTimeField(blank=True, help_text='Время последнего автоматического сохранения черновика', null=True, verbose_name='Последнее автосохранение'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='order',
|
|
||||||
name='last_autosave_at',
|
|
||||||
field=models.DateTimeField(blank=True, help_text='Время последнего автоматического сохранения черновика', null=True, verbose_name='Последнее автосохранение'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='historicalorder',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(choices=[('draft', 'Черновик'), ('new', 'Новый'), ('confirmed', 'Подтвержден'), ('in_assembly', 'В сборке'), ('in_delivery', 'В доставке'), ('delivered', 'Доставлен'), ('cancelled', 'Отменен')], default='new', max_length=20, verbose_name='Статус заказа'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='order',
|
|
||||||
name='status',
|
|
||||||
field=models.CharField(choices=[('draft', 'Черновик'), ('new', 'Новый'), ('confirmed', 'Подтвержден'), ('in_assembly', 'В сборке'), ('in_delivery', 'В доставке'), ('delivered', 'Доставлен'), ('cancelled', 'Отменен')], default='new', max_length=20, verbose_name='Статус заказа'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -5,7 +5,6 @@ from customers.models import Customer, Address
|
|||||||
from products.models import Product, ProductKit
|
from products.models import Product, ProductKit
|
||||||
from shops.models import Shop
|
from shops.models import Shop
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
import uuid
|
|
||||||
|
|
||||||
|
|
||||||
class Order(models.Model):
|
class Order(models.Model):
|
||||||
@@ -20,12 +19,11 @@ class Order(models.Model):
|
|||||||
verbose_name="Клиент"
|
verbose_name="Клиент"
|
||||||
)
|
)
|
||||||
|
|
||||||
order_number = models.CharField(
|
order_number = models.PositiveIntegerField(
|
||||||
max_length=50,
|
|
||||||
unique=True,
|
unique=True,
|
||||||
editable=False,
|
editable=False,
|
||||||
verbose_name="Номер заказа",
|
verbose_name="Номер заказа",
|
||||||
help_text="Уникальный номер заказа для отображения клиенту"
|
help_text="Уникальный номер заказа"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Тип доставки
|
# Тип доставки
|
||||||
@@ -254,17 +252,10 @@ class Order(models.Model):
|
|||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# Генерируем уникальный номер заказа при создании
|
# Генерируем уникальный номер заказа при создании
|
||||||
if not self.order_number:
|
if not self.order_number:
|
||||||
self.order_number = self.generate_order_number()
|
last_order = Order.objects.order_by('-order_number').first()
|
||||||
|
self.order_number = (last_order.order_number if last_order else 0) + 1
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def generate_order_number(self):
|
|
||||||
"""Генерирует уникальный номер заказа"""
|
|
||||||
# Формат: ORD-YYYYMMDD-XXXX (например: ORD-20250126-A3F2)
|
|
||||||
from datetime import datetime
|
|
||||||
date_str = datetime.now().strftime('%Y%m%d')
|
|
||||||
unique_id = uuid.uuid4().hex[:4].upper()
|
|
||||||
return f"ORD-{date_str}-{unique_id}"
|
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
"""Валидация модели"""
|
"""Валидация модели"""
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -10,6 +10,7 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
('orders', '0001_initial'),
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ class Migration(migrations.Migration):
|
|||||||
('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='Время удаления')),
|
('deleted_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='Суффикс варианта')),
|
('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='Единица измерения')),
|
('unit', models.CharField(choices=[('шт', 'Штука'), ('м', 'Метр'), ('г', 'Грамм'), ('л', 'Литр'), ('кг', 'Килограмм')], default='шт', max_length=10, verbose_name='Единица измерения')),
|
||||||
('cost_price', models.DecimalField(decimal_places=2, help_text='В будущем будет вычисляться автоматически из партий (FIFO)', max_digits=10, verbose_name='Себестоимость')),
|
('cost_price', models.DecimalField(decimal_places=2, help_text='Автоматически вычисляется из партий (средневзвешенная стоимость по FIFO)', max_digits=10, verbose_name='Себестоимость')),
|
||||||
('price', models.DecimalField(decimal_places=2, help_text='Цена продажи товара (бывшее поле sale_price)', max_digits=10, 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='Цена со скидкой')),
|
('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='В наличии')),
|
('in_stock', models.BooleanField(db_index=True, default=False, help_text='Автоматически обновляется при изменении остатков на складе', verbose_name='В наличии')),
|
||||||
@@ -94,9 +95,11 @@ class Migration(migrations.Migration):
|
|||||||
name='ProductCategoryPhoto',
|
name='ProductCategoryPhoto',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('image', models.ImageField(upload_to='categories/temp/', verbose_name='Оригинальное фото')),
|
|
||||||
('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')),
|
('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
|
('image', models.ImageField(upload_to='categories/temp/', 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='Категория')),
|
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='products.productcategory', verbose_name='Категория')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@@ -119,14 +122,15 @@ class Migration(migrations.Migration):
|
|||||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||||
('is_deleted', models.BooleanField(db_index=True, default=False, verbose_name='Удален')),
|
('is_deleted', models.BooleanField(db_index=True, default=False, verbose_name='Удален')),
|
||||||
('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='Время удаления')),
|
('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='Время удаления')),
|
||||||
('pricing_method', models.CharField(choices=[('manual', 'Ручная цена'), ('from_sale_prices', 'По ценам продажи компонентов'), ('from_cost_plus_percent', 'Себестоимость + процент наценки'), ('from_cost_plus_amount', 'Себестоимость + фикс. наценка')], default='from_sale_prices', max_length=30, verbose_name='Метод ценообразования')),
|
('base_price', models.DecimalField(decimal_places=2, default=0, help_text='Сумма actual_price всех компонентов. Пересчитывается автоматически.', max_digits=10, verbose_name='Базовая цена')),
|
||||||
('cost_price', models.DecimalField(blank=True, decimal_places=2, help_text='Можно задать вручную или вычислить из компонентов', max_digits=10, null=True, verbose_name='Себестоимость')),
|
('price', models.DecimalField(decimal_places=2, default=0, help_text='Базовая цена с учетом корректировок. Вычисляется автоматически.', max_digits=10, verbose_name='Итоговая цена')),
|
||||||
('price', models.DecimalField(blank=True, decimal_places=2, help_text="Цена при методе 'Ручная цена' (бывшее поле fixed_price)", max_digits=10, null=True, verbose_name='Ручная цена')),
|
|
||||||
('sale_price', models.DecimalField(blank=True, decimal_places=2, help_text='Если задана, комплект продается по этой цене', max_digits=10, null=True, verbose_name='Цена со скидкой')),
|
('sale_price', models.DecimalField(blank=True, decimal_places=2, help_text='Если задана, комплект продается по этой цене', max_digits=10, null=True, verbose_name='Цена со скидкой')),
|
||||||
('markup_percent', models.DecimalField(blank=True, decimal_places=2, help_text="Для метода 'Себестоимость + процент наценки'", max_digits=5, 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='Тип корректировки цены')),
|
||||||
('markup_amount', models.DecimalField(blank=True, decimal_places=2, help_text="Для метода 'Себестоимость + фиксированная наценка'", max_digits=10, null=True, 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='Временный комплект')),
|
||||||
('categories', models.ManyToManyField(blank=True, related_name='kits', to='products.productcategory', verbose_name='Категории')),
|
('categories', models.ManyToManyField(blank=True, related_name='kits', to='products.productcategory', verbose_name='Категории')),
|
||||||
('deleted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='deleted_%(class)s_set', to=settings.AUTH_USER_MODEL, verbose_name='Удален пользователем')),
|
('deleted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='deleted_%(class)s_set', to=settings.AUTH_USER_MODEL, 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='Заказ')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Комплект',
|
'verbose_name': 'Комплект',
|
||||||
@@ -137,9 +141,11 @@ class Migration(migrations.Migration):
|
|||||||
name='ProductKitPhoto',
|
name='ProductKitPhoto',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('image', models.ImageField(upload_to='kits/temp/', verbose_name='Оригинальное фото')),
|
|
||||||
('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')),
|
('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
|
('image', models.ImageField(upload_to='kits/temp/', 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='Комплект')),
|
('kit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='products.productkit', verbose_name='Комплект')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@@ -152,9 +158,11 @@ class Migration(migrations.Migration):
|
|||||||
name='ProductPhoto',
|
name='ProductPhoto',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('image', models.ImageField(upload_to='products/temp/', verbose_name='Оригинальное фото')),
|
|
||||||
('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')),
|
('order', models.PositiveIntegerField(default=0, verbose_name='Порядок')),
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||||
|
('image', models.ImageField(upload_to='products/temp/', 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='Товар')),
|
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='products.product', verbose_name='Товар')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@@ -200,7 +208,6 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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='Количество')),
|
('quantity', models.DecimalField(blank=True, decimal_places=3, max_digits=10, null=True, verbose_name='Количество')),
|
||||||
('notes', models.CharField(blank=True, max_length=200, verbose_name='Примечание')),
|
|
||||||
('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='kit_items_direct', to='products.product', verbose_name='Конкретный товар')),
|
('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='kit_items_direct', to='products.product', verbose_name='Конкретный товар')),
|
||||||
('kit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='kit_items', to='products.productkit', verbose_name='Комплект')),
|
('kit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='kit_items', to='products.productkit', verbose_name='Комплект')),
|
||||||
('variant_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='kit_items', to='products.productvariantgroup', verbose_name='Группа вариантов')),
|
('variant_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='kit_items', to='products.productvariantgroup', verbose_name='Группа вариантов')),
|
||||||
@@ -251,6 +258,42 @@ class Migration(migrations.Migration):
|
|||||||
model_name='productcategory',
|
model_name='productcategory',
|
||||||
index=models.Index(fields=['is_deleted', 'created_at'], name='products_pr_is_dele_b8cdf3_idx'),
|
index=models.Index(fields=['is_deleted', 'created_at'], name='products_pr_is_dele_b8cdf3_idx'),
|
||||||
),
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productcategoryphoto',
|
||||||
|
index=models.Index(fields=['quality_level'], name='products_pr_quality_ab44c2_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productcategoryphoto',
|
||||||
|
index=models.Index(fields=['quality_warning'], name='products_pr_quality_d7c69b_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productcategoryphoto',
|
||||||
|
index=models.Index(fields=['quality_warning', 'category'], name='products_pr_quality_fc505a_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productkitphoto',
|
||||||
|
index=models.Index(fields=['quality_level'], name='products_pr_quality_b03c5c_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productkitphoto',
|
||||||
|
index=models.Index(fields=['quality_warning'], name='products_pr_quality_2aa941_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productkitphoto',
|
||||||
|
index=models.Index(fields=['quality_warning', 'kit'], name='products_pr_quality_867664_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productphoto',
|
||||||
|
index=models.Index(fields=['quality_level'], name='products_pr_quality_d8f85c_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productphoto',
|
||||||
|
index=models.Index(fields=['quality_warning'], name='products_pr_quality_defb5a_idx'),
|
||||||
|
),
|
||||||
|
migrations.AddIndex(
|
||||||
|
model_name='productphoto',
|
||||||
|
index=models.Index(fields=['quality_warning', 'product'], name='products_pr_quality_6e8b51_idx'),
|
||||||
|
),
|
||||||
migrations.AddIndex(
|
migrations.AddIndex(
|
||||||
model_name='producttag',
|
model_name='producttag',
|
||||||
index=models.Index(fields=['is_deleted'], name='products_pr_is_dele_ea9be0_idx'),
|
index=models.Index(fields=['is_deleted'], name='products_pr_is_dele_ea9be0_idx'),
|
||||||
@@ -261,7 +304,11 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
migrations.AddIndex(
|
migrations.AddIndex(
|
||||||
model_name='productkit',
|
model_name='productkit',
|
||||||
index=models.Index(fields=['pricing_method'], name='products_pr_pricing_8bb5a7_idx'),
|
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(
|
migrations.AddIndex(
|
||||||
model_name='product',
|
model_name='product',
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-01 17:59
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('products', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='product',
|
|
||||||
name='cost_price',
|
|
||||||
field=models.DecimalField(decimal_places=2, help_text='Автоматически вычисляется из партий (средневзвешенная стоимость по FIFO)', max_digits=10, verbose_name='Себестоимость'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-02 11:38
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('products', '0002_alter_product_cost_price'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productcategoryphoto',
|
|
||||||
name='quality_level',
|
|
||||||
field=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='Уровень качества'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productcategoryphoto',
|
|
||||||
name='quality_warning',
|
|
||||||
field=models.BooleanField(db_index=True, default=False, help_text='True если нужно обновить фото перед выгрузкой на сайт', verbose_name='Требует обновления'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productkitphoto',
|
|
||||||
name='quality_level',
|
|
||||||
field=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='Уровень качества'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productkitphoto',
|
|
||||||
name='quality_warning',
|
|
||||||
field=models.BooleanField(db_index=True, default=False, help_text='True если нужно обновить фото перед выгрузкой на сайт', verbose_name='Требует обновления'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productphoto',
|
|
||||||
name='quality_level',
|
|
||||||
field=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='Уровень качества'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productphoto',
|
|
||||||
name='quality_warning',
|
|
||||||
field=models.BooleanField(db_index=True, default=False, help_text='True если нужно обновить фото перед выгрузкой на сайт (poor или very_poor)', verbose_name='Требует обновления'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productcategoryphoto',
|
|
||||||
index=models.Index(fields=['quality_level'], name='products_pr_quality_ab44c2_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productcategoryphoto',
|
|
||||||
index=models.Index(fields=['quality_warning'], name='products_pr_quality_d7c69b_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productcategoryphoto',
|
|
||||||
index=models.Index(fields=['quality_warning', 'category'], name='products_pr_quality_fc505a_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productkitphoto',
|
|
||||||
index=models.Index(fields=['quality_level'], name='products_pr_quality_b03c5c_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productkitphoto',
|
|
||||||
index=models.Index(fields=['quality_warning'], name='products_pr_quality_2aa941_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productkitphoto',
|
|
||||||
index=models.Index(fields=['quality_warning', 'kit'], name='products_pr_quality_867664_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productphoto',
|
|
||||||
index=models.Index(fields=['quality_level'], name='products_pr_quality_d8f85c_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productphoto',
|
|
||||||
index=models.Index(fields=['quality_warning'], name='products_pr_quality_defb5a_idx'),
|
|
||||||
),
|
|
||||||
migrations.AddIndex(
|
|
||||||
model_name='productphoto',
|
|
||||||
index=models.Index(fields=['quality_warning', 'product'], name='products_pr_quality_6e8b51_idx'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-02 15:06
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('products', '0003_productcategoryphoto_quality_level_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveIndex(
|
|
||||||
model_name='productkit',
|
|
||||||
name='products_pr_pricing_8bb5a7_idx',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='cost_price',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='markup_amount',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='markup_percent',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='pricing_method',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='base_price',
|
|
||||||
field=models.DecimalField(decimal_places=2, default=0, help_text='Сумма actual_price всех компонентов. Пересчитывается автоматически.', max_digits=10, verbose_name='Базовая цена'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='price_adjustment_type',
|
|
||||||
field=models.CharField(choices=[('none', 'Без изменения'), ('increase_percent', 'Увеличить на %'), ('increase_amount', 'Увеличить на сумму'), ('decrease_percent', 'Уменьшить на %'), ('decrease_amount', 'Уменьшить на сумму')], default='none', max_length=20, verbose_name='Тип корректировки цены'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='price_adjustment_value',
|
|
||||||
field=models.DecimalField(decimal_places=2, default=0, help_text='Процент (%) или сумма (руб) в зависимости от типа корректировки', max_digits=10, verbose_name='Значение корректировки'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='price',
|
|
||||||
field=models.DecimalField(decimal_places=2, default=0, help_text='Базовая цена с учетом корректировок. Вычисляется автоматически.', max_digits=10, verbose_name='Итоговая цена'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-02 18:06
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('products', '0004_add_kit_price_adjustment_fields'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='kititem',
|
|
||||||
name='notes',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-11-08 11:52
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('orders', '0004_orderitem_is_custom_price'),
|
|
||||||
('products', '0005_remove_kititem_notes'),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='is_temporary',
|
|
||||||
field=models.BooleanField(default=False, help_text='Временные комплекты не показываются в каталоге и создаются для конкретного заказа', verbose_name='Временный комплект'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='productkit',
|
|
||||||
name='order',
|
|
||||||
field=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='Заказ'),
|
|
||||||
),
|
|
||||||
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'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
import phonenumber_field.modelfields
|
import phonenumber_field.modelfields
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||||
|
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|||||||
Reference in New Issue
Block a user