feat: Добавлена функциональность управления заказами и улучшен поиск товаров
Заказы: - Добавлены миграции для исторических записей с полями оплаты и получателя - Расширен admin для заказов с инлайнами товаров/комплектов - Реализованы представления списка, создания, редактирования и удаления заказов - Добавлен шаблон подтверждения удаления заказа - Настроены URL-маршруты для работы с заказами Клиенты: - Добавлена миграция с новыми полями адресов и подтверждений - Обновлена модель клиентов с дополнительными полями - Улучшен admin для работы с клиентами Товары: - Значительно улучшен API поиска товаров с поддержкой фильтрации - Добавлен Select2 виджет для динамического поиска товаров - Создан статический JS файл для интеграции Select2 - Оптимизирована обработка запросов и ответов API Прочее: - Добавлены новые настройки в settings.py - Обновлена навигация в navbar.html - Обновлены URL-маршруты проекта 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
# 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'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
# 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='Телефон получателя'),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user