Упрощена система номеров заказов: переход на числовые номера
- Изменено поле order_number с CharField на PositiveIntegerField - Удален метод generate_order_number() - Упрощен метод save() - автоинкремент на основе максимального значения - Номера заказов теперь хранятся как числа (1, 2, 3, ...) без форматирования - Удалены все миграции для чистого старта 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.10 on 2025-10-30 21:24
|
||||
# Generated by Django 5.0.10 on 2025-11-09 22:18
|
||||
|
||||
import django.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',
|
||||
|
||||
Reference in New Issue
Block a user