diff --git a/myproject/accounts/migrations/0001_initial.py b/myproject/accounts/migrations/0001_initial.py index 1c9bfa7..bc09017 100644 --- a/myproject/accounts/migrations/0001_initial.py +++ b/myproject/accounts/migrations/0001_initial.py @@ -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.utils.timezone diff --git a/myproject/customers/migrations/0001_initial.py b/myproject/customers/migrations/0001_initial.py index 5075ba4..bd41ede 100644 --- a/myproject/customers/migrations/0001_initial.py +++ b/myproject/customers/migrations/0001_initial.py @@ -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 phonenumber_field.modelfields @@ -38,11 +38,13 @@ class Migration(migrations.Migration): fields=[ ('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_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='Улица')), ('building_number', models.CharField(max_length=20, 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='Район')), ('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='Адрес по умолчанию')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), diff --git a/myproject/customers/migrations/0002_address_confirm_address_with_recipient_and_more.py b/myproject/customers/migrations/0002_address_confirm_address_with_recipient_and_more.py deleted file mode 100644 index 1dde004..0000000 --- a/myproject/customers/migrations/0002_address_confirm_address_with_recipient_and_more.py +++ /dev/null @@ -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='Телефон получателя'), - ), - ] diff --git a/myproject/inventory/migrations/0001_initial.py b/myproject/inventory/migrations/0001_initial.py index 05b8277..50406ea 100644 --- a/myproject/inventory/migrations/0001_initial.py +++ b/myproject/inventory/migrations/0001_initial.py @@ -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 @@ -9,11 +8,52 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('orders', '0001_initial'), - ('products', '0001_initial'), ] operations = [ + migrations.CreateModel( + name='DocumentCounter', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('counter_type', models.CharField(choices=[('transfer', 'Перемещение товара')], max_length=20, unique=True, verbose_name='Тип счетчика')), + ('current_value', models.IntegerField(default=0, verbose_name='Текущее значение')), + ], + options={ + 'verbose_name': 'Счетчик документов', + 'verbose_name_plural': 'Счетчики документов', + }, + ), + migrations.CreateModel( + name='Incoming', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')), + ('cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Закупочная цена')), + ('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), + ], + options={ + 'verbose_name': 'Товар в поступлении', + 'verbose_name_plural': 'Товары в поступлениях', + 'ordering': ['-created_at'], + }, + ), + migrations.CreateModel( + name='IncomingBatch', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')), + ('supplier_name', models.CharField(blank=True, max_length=200, null=True, verbose_name='Наименование поставщика')), + ('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), + ], + options={ + 'verbose_name': 'Партия поступления', + 'verbose_name_plural': 'Партии поступлений', + 'ordering': ['-created_at'], + }, + ), migrations.CreateModel( name='Inventory', fields=[ @@ -37,14 +77,28 @@ class Migration(migrations.Migration): ('quantity_fact', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Фактическое количество')), ('difference', models.DecimalField(decimal_places=3, default=0, editable=False, max_digits=10, verbose_name='Разница (факт - система)')), ('processed', models.BooleanField(default=False, verbose_name='Обработана (создана операция)')), - ('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={ 'verbose_name': 'Строка инвентаризации', 'verbose_name_plural': 'Строки инвентаризации', }, ), + migrations.CreateModel( + name='Reservation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')), + ('status', models.CharField(choices=[('reserved', 'Зарезервирован'), ('released', 'Освобожден'), ('converted_to_sale', 'Преобразован в продажу')], default='reserved', max_length=20, verbose_name='Статус')), + ('reserved_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата резервирования')), + ('released_at', models.DateTimeField(blank=True, null=True, verbose_name='Дата освобождения')), + ('converted_at', models.DateTimeField(blank=True, null=True, verbose_name='Дата преобразования в продажу')), + ], + options={ + 'verbose_name': 'Резервирование', + 'verbose_name_plural': 'Резервирования', + 'ordering': ['-reserved_at'], + }, + ), migrations.CreateModel( name='Sale', fields=[ @@ -54,8 +108,6 @@ class Migration(migrations.Migration): ('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')), ('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')), ('processed', models.BooleanField(default=False, verbose_name='Обработана (FIFO применена)')), - ('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={ 'verbose_name': 'Продажа', @@ -63,6 +115,31 @@ class Migration(migrations.Migration): 'ordering': ['-date'], }, ), + migrations.CreateModel( + name='SaleBatchAllocation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')), + ('cost_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Закупочная цена')), + ], + options={ + 'verbose_name': 'Распределение продажи по партиям', + 'verbose_name_plural': 'Распределения продаж по партиям', + }, + ), + migrations.CreateModel( + name='Stock', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity_available', models.DecimalField(decimal_places=3, default=0, editable=False, max_digits=10, verbose_name='Доступное количество')), + ('quantity_reserved', models.DecimalField(decimal_places=3, default=0, editable=False, max_digits=10, verbose_name='Зарезервированное количество')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), + ], + options={ + 'verbose_name': 'Остаток на складе', + 'verbose_name_plural': 'Остатки на складе', + }, + ), migrations.CreateModel( name='StockBatch', fields=[ @@ -72,7 +149,6 @@ class Migration(migrations.Migration): ('is_active', models.BooleanField(default=True, verbose_name='Активна')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), - ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stock_batches', to='products.product', verbose_name='Товар')), ], options={ 'verbose_name': 'Партия товара', @@ -81,17 +157,57 @@ class Migration(migrations.Migration): }, ), 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=[ ('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='Закупочная цена')), - ('sale', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='batch_allocations', to='inventory.sale', verbose_name='Продажа')), - ('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_allocations', to='inventory.stockbatch', verbose_name='Партия')), + ('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')), + ('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')), ], options={ - 'verbose_name': 'Распределение продажи по партиям', - 'verbose_name_plural': 'Распределения продаж по партиям', + 'verbose_name': 'Перемещение', + 'verbose_name_plural': 'Перемещения', + 'ordering': ['-date'], + }, + ), + migrations.CreateModel( + name='TransferBatch', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('document_number', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Номер документа')), + ('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), + ], + options={ + 'verbose_name': 'Документ перемещения', + 'verbose_name_plural': 'Документы перемещения', + 'ordering': ['-created_at'], + }, + ), + migrations.CreateModel( + name='TransferItem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.DecimalField(decimal_places=3, max_digits=10, verbose_name='Количество')), + ], + options={ + 'verbose_name': 'Строка перемещения', + 'verbose_name_plural': 'Строки перемещения', + 'ordering': ['id'], }, ), migrations.CreateModel( @@ -108,73 +224,6 @@ class Migration(migrations.Migration): options={ 'verbose_name': 'Склад', '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( @@ -187,7 +236,6 @@ class Migration(migrations.Migration): ('document_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='Номер документа')), ('notes', models.TextField(blank=True, null=True, verbose_name='Примечания')), ('date', models.DateTimeField(auto_now_add=True, verbose_name='Дата операции')), - ('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='writeoffs', to='inventory.stockbatch', verbose_name='Партия')), ], options={ 'verbose_name': 'Списание', @@ -195,123 +243,4 @@ class Migration(migrations.Migration): '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'), - ), ] diff --git a/myproject/inventory/migrations/0002_add_transfer_models.py b/myproject/inventory/migrations/0002_add_transfer_models.py deleted file mode 100644 index deeb22e..0000000 --- a/myproject/inventory/migrations/0002_add_transfer_models.py +++ /dev/null @@ -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')}, - ), - ] diff --git a/myproject/inventory/migrations/0002_initial.py b/myproject/inventory/migrations/0002_initial.py new file mode 100644 index 0000000..07da123 --- /dev/null +++ b/myproject/inventory/migrations/0002_initial.py @@ -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'), + ), + ] diff --git a/myproject/orders/migrations/0001_initial.py b/myproject/orders/migrations/0001_initial.py index c870286..bf035e4 100644 --- a/myproject/orders/migrations/0001_initial.py +++ b/myproject/orders/migrations/0001_initial.py @@ -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 simple_history.models +from django.conf import settings from django.db import migrations, models @@ -10,31 +12,97 @@ class Migration(migrations.Migration): dependencies = [ ('customers', '0001_initial'), - ('products', '0001_initial'), ('shops', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='Order', + name='Payment', fields=[ ('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='Номер заказа')), - ('delivery_type', models.CharField(choices=[('courier', 'Курьерская доставка'), ('pickup', 'Самовывоз')], default='courier', max_length=20, verbose_name='Тип доставки')), - ('delivery_date', models.DateField(verbose_name='Дата доставки/самовывоза')), - ('delivery_time_start', models.TimeField(help_text='Начало временного интервала', verbose_name='Время от')), - ('delivery_time_end', models.TimeField(help_text='Конец временного интервала', verbose_name='Время до')), + ('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.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='Стоимость доставки')), - ('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='Способ оплаты')), ('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='Анонимная доставка')), + ('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='Анонимная доставка')), ('special_instructions', models.TextField(blank=True, help_text='Комментарии и пожелания к заказу', null=True, verbose_name='Особые пожелания')), ('created_at', models.DateTimeField(auto_now_add=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='Клиент')), ('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='Точка самовывоза')), ], options={ @@ -49,50 +117,13 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quantity', models.PositiveIntegerField(default=1, 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='Дата добавления')), ('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={ 'verbose_name': 'Позиция заказа', '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'), - ), ] diff --git a/myproject/orders/migrations/0002_historicalorder_payment_and_more.py b/myproject/orders/migrations/0002_historicalorder_payment_and_more.py deleted file mode 100644 index 3190d16..0000000 --- a/myproject/orders/migrations/0002_historicalorder_payment_and_more.py +++ /dev/null @@ -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'), - ), - ] diff --git a/myproject/orders/migrations/0002_initial.py b/myproject/orders/migrations/0002_initial.py new file mode 100644 index 0000000..36ab455 --- /dev/null +++ b/myproject/orders/migrations/0002_initial.py @@ -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'), + ), + ] diff --git a/myproject/orders/migrations/0003_historicalorder_recipient_name_and_more.py b/myproject/orders/migrations/0003_historicalorder_recipient_name_and_more.py deleted file mode 100644 index 2bad29c..0000000 --- a/myproject/orders/migrations/0003_historicalorder_recipient_name_and_more.py +++ /dev/null @@ -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='Телефон получателя'), - ), - ] diff --git a/myproject/orders/migrations/0004_orderitem_is_custom_price.py b/myproject/orders/migrations/0004_orderitem_is_custom_price.py deleted file mode 100644 index ae78b9e..0000000 --- a/myproject/orders/migrations/0004_orderitem_is_custom_price.py +++ /dev/null @@ -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='Цена изменена вручную'), - ), - ] diff --git a/myproject/orders/migrations/0005_add_draft_support.py b/myproject/orders/migrations/0005_add_draft_support.py deleted file mode 100644 index c805412..0000000 --- a/myproject/orders/migrations/0005_add_draft_support.py +++ /dev/null @@ -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='Статус заказа'), - ), - ] diff --git a/myproject/orders/models.py b/myproject/orders/models.py index d8fa64b..38df793 100644 --- a/myproject/orders/models.py +++ b/myproject/orders/models.py @@ -5,7 +5,6 @@ from customers.models import Customer, Address from products.models import Product, ProductKit from shops.models import Shop from simple_history.models import HistoricalRecords -import uuid class Order(models.Model): @@ -20,12 +19,11 @@ class Order(models.Model): verbose_name="Клиент" ) - order_number = models.CharField( - max_length=50, + order_number = models.PositiveIntegerField( unique=True, editable=False, verbose_name="Номер заказа", - help_text="Уникальный номер заказа для отображения клиенту" + help_text="Уникальный номер заказа" ) # Тип доставки @@ -254,17 +252,10 @@ class Order(models.Model): def save(self, *args, **kwargs): # Генерируем уникальный номер заказа при создании 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) - 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): """Валидация модели""" super().clean() diff --git a/myproject/products/migrations/0001_initial.py b/myproject/products/migrations/0001_initial.py index 9d444ca..e3908d1 100644 --- a/myproject/products/migrations/0001_initial.py +++ b/myproject/products/migrations/0001_initial.py @@ -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 from django.conf import settings @@ -10,6 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('orders', '0001_initial'), 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='Время удаления')), ('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='Единица измерения')), - ('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='Основная цена')), ('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='В наличии')), @@ -94,9 +95,11 @@ class Migration(migrations.Migration): name='ProductCategoryPhoto', fields=[ ('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='Порядок')), ('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='Категория')), ], options={ @@ -119,14 +122,15 @@ class Migration(migrations.Migration): ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')), ('is_deleted', models.BooleanField(db_index=True, default=False, 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='Метод ценообразования')), - ('cost_price', models.DecimalField(blank=True, decimal_places=2, help_text='Можно задать вручную или вычислить из компонентов', max_digits=10, null=True, verbose_name='Себестоимость')), - ('price', models.DecimalField(blank=True, decimal_places=2, help_text="Цена при методе 'Ручная цена' (бывшее поле fixed_price)", max_digits=10, null=True, verbose_name='Ручная цена')), + ('base_price', models.DecimalField(decimal_places=2, default=0, help_text='Сумма actual_price всех компонентов. Пересчитывается автоматически.', max_digits=10, verbose_name='Базовая цена')), + ('price', models.DecimalField(decimal_places=2, default=0, help_text='Базовая цена с учетом корректировок. Вычисляется автоматически.', max_digits=10, verbose_name='Итоговая цена')), ('sale_price', models.DecimalField(blank=True, decimal_places=2, help_text='Если задана, комплект продается по этой цене', max_digits=10, null=True, verbose_name='Цена со скидкой')), - ('markup_percent', models.DecimalField(blank=True, decimal_places=2, help_text="Для метода 'Себестоимость + процент наценки'", max_digits=5, null=True, verbose_name='Процент наценки')), - ('markup_amount', models.DecimalField(blank=True, decimal_places=2, help_text="Для метода 'Себестоимость + фиксированная наценка'", max_digits=10, null=True, verbose_name='Фиксированная наценка')), + ('price_adjustment_type', models.CharField(choices=[('none', 'Без изменения'), ('increase_percent', 'Увеличить на %'), ('increase_amount', 'Увеличить на сумму'), ('decrease_percent', 'Уменьшить на %'), ('decrease_amount', 'Уменьшить на сумму')], default='none', max_length=20, verbose_name='Тип корректировки цены')), + ('price_adjustment_value', models.DecimalField(decimal_places=2, default=0, help_text='Процент (%) или сумма (руб) в зависимости от типа корректировки', max_digits=10, verbose_name='Значение корректировки')), + ('is_temporary', models.BooleanField(default=False, help_text='Временные комплекты не показываются в каталоге и создаются для конкретного заказа', verbose_name='Временный комплект')), ('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='Удален пользователем')), + ('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={ 'verbose_name': 'Комплект', @@ -137,9 +141,11 @@ class Migration(migrations.Migration): name='ProductKitPhoto', fields=[ ('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='Порядок')), ('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='Комплект')), ], options={ @@ -152,9 +158,11 @@ class Migration(migrations.Migration): name='ProductPhoto', fields=[ ('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='Порядок')), ('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='Товар')), ], options={ @@ -200,7 +208,6 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quantity', models.DecimalField(blank=True, decimal_places=3, max_digits=10, null=True, verbose_name='Количество')), - ('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='Конкретный товар')), ('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='Группа вариантов')), @@ -251,6 +258,42 @@ class Migration(migrations.Migration): model_name='productcategory', 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( model_name='producttag', index=models.Index(fields=['is_deleted'], name='products_pr_is_dele_ea9be0_idx'), @@ -261,7 +304,11 @@ class Migration(migrations.Migration): ), migrations.AddIndex( 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( model_name='product', diff --git a/myproject/products/migrations/0002_alter_product_cost_price.py b/myproject/products/migrations/0002_alter_product_cost_price.py deleted file mode 100644 index 8d1d372..0000000 --- a/myproject/products/migrations/0002_alter_product_cost_price.py +++ /dev/null @@ -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='Себестоимость'), - ), - ] diff --git a/myproject/products/migrations/0003_productcategoryphoto_quality_level_and_more.py b/myproject/products/migrations/0003_productcategoryphoto_quality_level_and_more.py deleted file mode 100644 index 7fb4d2a..0000000 --- a/myproject/products/migrations/0003_productcategoryphoto_quality_level_and_more.py +++ /dev/null @@ -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'), - ), - ] diff --git a/myproject/products/migrations/0004_add_kit_price_adjustment_fields.py b/myproject/products/migrations/0004_add_kit_price_adjustment_fields.py deleted file mode 100644 index f01263c..0000000 --- a/myproject/products/migrations/0004_add_kit_price_adjustment_fields.py +++ /dev/null @@ -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='Итоговая цена'), - ), - ] diff --git a/myproject/products/migrations/0005_remove_kititem_notes.py b/myproject/products/migrations/0005_remove_kititem_notes.py deleted file mode 100644 index 27e19fa..0000000 --- a/myproject/products/migrations/0005_remove_kititem_notes.py +++ /dev/null @@ -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', - ), - ] diff --git a/myproject/products/migrations/0006_productkit_is_temporary_productkit_order_and_more.py b/myproject/products/migrations/0006_productkit_is_temporary_productkit_order_and_more.py deleted file mode 100644 index 42aa7d1..0000000 --- a/myproject/products/migrations/0006_productkit_is_temporary_productkit_order_and_more.py +++ /dev/null @@ -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'), - ), - ] diff --git a/myproject/shops/migrations/0001_initial.py b/myproject/shops/migrations/0001_initial.py index caa644e..35327f6 100644 --- a/myproject/shops/migrations/0001_initial.py +++ b/myproject/shops/migrations/0001_initial.py @@ -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 from django.db import migrations, models diff --git a/myproject/tenants/migrations/0001_initial.py b/myproject/tenants/migrations/0001_initial.py index 7e10a30..82042d6 100644 --- a/myproject/tenants/migrations/0001_initial.py +++ b/myproject/tenants/migrations/0001_initial.py @@ -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.db.models.deletion