Рефакторинг: отделение Delivery от Order, обязательные поля доставки, исправление доменов
- Отделена модель Delivery от Order (OneToOne связь) - Добавлены обязательные поля delivery_date, time_from, time_to в Delivery - Delivery обязательна при создании заказа (кроме черновиков) - Добавлены методы calculate_total() и reset_delivery_cost() в Order - Добавлена валидация полей доставки в OrderForm - Исправлено создание доменов - убран порт из домена в БД - Исправлен редирект после установки пароля (правильный формат URL) - Исправлена ошибка NoReverseMatch в navbar для public схемы - Удалены все старые миграции (база создается с нуля) - Обновлены views для работы с новой моделью Delivery
This commit is contained in:
@@ -8,7 +8,7 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models, transaction
|
||||
from decimal import Decimal
|
||||
from .models import Order, OrderItem, Address, OrderStatus, Transaction, PaymentMethod
|
||||
from .models import Order, OrderItem, Address, OrderStatus, Transaction, PaymentMethod, Delivery
|
||||
from .forms import OrderForm, OrderItemFormSet, OrderItemForm, OrderStatusForm, TransactionForm
|
||||
from .filters import OrderFilter
|
||||
from .services.address_service import AddressService
|
||||
@@ -22,7 +22,7 @@ def order_list(request):
|
||||
"""
|
||||
# Базовый queryset с оптимизацией запросов
|
||||
orders = Order.objects.select_related(
|
||||
'customer', 'delivery_address', 'pickup_warehouse', 'status' # Добавлен 'status' для избежания N+1
|
||||
'customer', 'delivery', 'delivery__address', 'delivery__pickup_warehouse', 'status' # Добавлен 'status' для избежания N+1
|
||||
).all()
|
||||
|
||||
# Применяем фильтры через django-filter
|
||||
@@ -48,7 +48,7 @@ def order_list(request):
|
||||
def order_detail(request, order_number):
|
||||
"""Детальная информация о заказе"""
|
||||
order = get_object_or_404(
|
||||
Order.objects.select_related('customer', 'delivery_address', 'pickup_warehouse', 'modified_by', 'status')
|
||||
Order.objects.select_related('customer', 'delivery', 'delivery__address', 'delivery__pickup_warehouse', 'modified_by', 'status')
|
||||
.prefetch_related('items__product', 'items__product_kit', 'transactions__created_by', 'transactions__payment_method'),
|
||||
order_number=order_number
|
||||
)
|
||||
@@ -108,15 +108,6 @@ def order_create(request):
|
||||
# Если покупатель является получателем
|
||||
order.recipient = None
|
||||
|
||||
# Обрабатываем адрес доставки
|
||||
if order.is_delivery:
|
||||
address = AddressService.process_address_from_form(order, form.cleaned_data)
|
||||
if address:
|
||||
# Если адрес не существует в БД, сохраняем его
|
||||
if not address.pk:
|
||||
address.save()
|
||||
order.delivery_address = address
|
||||
|
||||
# Статус берём из формы (в том числе может быть "Черновик")
|
||||
order.modified_by = request.user
|
||||
|
||||
@@ -127,10 +118,53 @@ def order_create(request):
|
||||
formset.instance = order
|
||||
formset.save()
|
||||
|
||||
# Пересчитываем стоимость доставки если она не установлена вручную
|
||||
delivery_cost = form.cleaned_data.get('delivery_cost')
|
||||
if not delivery_cost or delivery_cost <= 0:
|
||||
order.reset_delivery_cost()
|
||||
# Проверяем, является ли заказ черновиком
|
||||
is_draft = order.status and order.status.code == 'draft'
|
||||
|
||||
# Создаем Delivery (обязательно, кроме черновиков)
|
||||
if not is_draft:
|
||||
# Получаем данные из формы (уже провалидированы)
|
||||
delivery_type = form.cleaned_data.get('delivery_type')
|
||||
delivery_date = form.cleaned_data.get('delivery_date')
|
||||
time_from = form.cleaned_data.get('time_from')
|
||||
time_to = form.cleaned_data.get('time_to')
|
||||
delivery_cost = form.cleaned_data.get('delivery_cost', Decimal('0'))
|
||||
pickup_warehouse = form.cleaned_data.get('pickup_warehouse')
|
||||
|
||||
# Проверяем наличие обязательных полей
|
||||
if not all([delivery_type, delivery_date, time_from, time_to]):
|
||||
raise ValidationError('Необходимо заполнить все поля доставки')
|
||||
|
||||
# Обрабатываем адрес для курьерской доставки
|
||||
address = None
|
||||
|
||||
if delivery_type == Delivery.DELIVERY_TYPE_COURIER:
|
||||
# Для курьерской доставки нужен адрес
|
||||
address = AddressService.process_address_from_form(order, form.cleaned_data)
|
||||
if not address:
|
||||
raise ValidationError('Для курьерской доставки необходимо указать адрес')
|
||||
if not address.pk:
|
||||
address.save()
|
||||
elif delivery_type == Delivery.DELIVERY_TYPE_PICKUP:
|
||||
# Для самовывоза нужен склад
|
||||
if not pickup_warehouse:
|
||||
raise ValidationError('Для самовывоза необходимо выбрать склад')
|
||||
|
||||
# Создаем Delivery
|
||||
delivery = Delivery.objects.create(
|
||||
order=order,
|
||||
delivery_type=delivery_type,
|
||||
delivery_date=delivery_date,
|
||||
time_from=time_from,
|
||||
time_to=time_to,
|
||||
address=address,
|
||||
pickup_warehouse=pickup_warehouse,
|
||||
cost=delivery_cost if delivery_cost else Decimal('0')
|
||||
)
|
||||
|
||||
# Пересчитываем стоимость доставки если она не установлена вручную
|
||||
if not delivery.cost or delivery.cost <= 0:
|
||||
order.reset_delivery_cost()
|
||||
|
||||
# Пересчитываем итоговую стоимость
|
||||
order.calculate_total()
|
||||
@@ -233,25 +267,59 @@ def order_update(request, order_number):
|
||||
# Если покупатель является получателем
|
||||
order.recipient = None
|
||||
|
||||
# Обрабатываем адрес доставки
|
||||
if order.is_delivery:
|
||||
address = AddressService.process_address_from_form(order, form.cleaned_data)
|
||||
if address:
|
||||
# Если адрес не существует в БД, сохраняем его
|
||||
if not address.pk:
|
||||
address.save()
|
||||
order.delivery_address = address
|
||||
else:
|
||||
# Если режим "без адреса", очищаем адрес
|
||||
order.delivery_address = None
|
||||
else:
|
||||
# Если не доставка, очищаем адрес
|
||||
order.delivery_address = None
|
||||
|
||||
order.modified_by = request.user
|
||||
order.save()
|
||||
formset.save()
|
||||
|
||||
# Проверяем, является ли заказ черновиком
|
||||
is_draft = order.status and order.status.code == 'draft'
|
||||
|
||||
# Создаем или обновляем Delivery (обязательно, кроме черновиков)
|
||||
if not is_draft:
|
||||
# Получаем данные из формы (уже провалидированы)
|
||||
delivery_type = form.cleaned_data.get('delivery_type')
|
||||
delivery_date = form.cleaned_data.get('delivery_date')
|
||||
time_from = form.cleaned_data.get('time_from')
|
||||
time_to = form.cleaned_data.get('time_to')
|
||||
delivery_cost = form.cleaned_data.get('delivery_cost', Decimal('0'))
|
||||
pickup_warehouse = form.cleaned_data.get('pickup_warehouse')
|
||||
|
||||
# Проверяем наличие обязательных полей
|
||||
if not all([delivery_type, delivery_date, time_from, time_to]):
|
||||
raise ValidationError('Необходимо заполнить все поля доставки')
|
||||
|
||||
# Обрабатываем адрес для курьерской доставки
|
||||
address = None
|
||||
|
||||
if delivery_type == Delivery.DELIVERY_TYPE_COURIER:
|
||||
# Для курьерской доставки нужен адрес
|
||||
address = AddressService.process_address_from_form(order, form.cleaned_data)
|
||||
if not address:
|
||||
raise ValidationError('Для курьерской доставки необходимо указать адрес')
|
||||
if not address.pk:
|
||||
address.save()
|
||||
elif delivery_type == Delivery.DELIVERY_TYPE_PICKUP:
|
||||
# Для самовывоза нужен склад
|
||||
if not pickup_warehouse:
|
||||
raise ValidationError('Для самовывоза необходимо выбрать склад')
|
||||
|
||||
# Создаем или обновляем Delivery
|
||||
delivery, created = Delivery.objects.update_or_create(
|
||||
order=order,
|
||||
defaults={
|
||||
'delivery_type': delivery_type,
|
||||
'delivery_date': delivery_date,
|
||||
'time_from': time_from,
|
||||
'time_to': time_to,
|
||||
'address': address,
|
||||
'pickup_warehouse': pickup_warehouse,
|
||||
'cost': delivery_cost if delivery_cost else Decimal('0')
|
||||
}
|
||||
)
|
||||
elif hasattr(order, 'delivery'):
|
||||
# Если заказ стал черновиком, удаляем Delivery
|
||||
order.delivery.delete()
|
||||
|
||||
# Пересчитываем итоговую стоимость
|
||||
order.calculate_total()
|
||||
order.update_payment_status()
|
||||
|
||||
Reference in New Issue
Block a user