diff --git a/myproject/orders/forms.py b/myproject/orders/forms.py
index df2c7c6..a4efacf 100644
--- a/myproject/orders/forms.py
+++ b/myproject/orders/forms.py
@@ -303,6 +303,8 @@ class OrderForm(forms.ModelForm):
# Инициализируем поля доставки из существующей Delivery
if self.instance.pk and hasattr(self.instance, 'delivery'):
delivery = self.instance.delivery
+
+ # Устанавливаем значения через fields.initial для правильной работы виджетов
self.fields['delivery_type'].initial = delivery.delivery_type
self.fields['delivery_date'].initial = delivery.delivery_date
self.fields['time_from'].initial = delivery.time_from
@@ -310,6 +312,19 @@ class OrderForm(forms.ModelForm):
self.fields['pickup_warehouse'].initial = delivery.pickup_warehouse
self.fields['delivery_cost'].initial = delivery.cost
+ # Также устанавливаем через self.initial для совместимости
+ self.initial['delivery_type'] = delivery.delivery_type
+ self.initial['delivery_date'] = delivery.delivery_date
+ self.initial['time_from'] = delivery.time_from
+ self.initial['time_to'] = delivery.time_to
+ self.initial['pickup_warehouse'] = delivery.pickup_warehouse
+ self.initial['delivery_cost'] = delivery.cost
+
+ # Для DateInput с type='date' нужно установить значение в формате YYYY-MM-DD
+ if delivery.delivery_date:
+ # Устанавливаем значение напрямую в виджете
+ self.fields['delivery_date'].widget.attrs['value'] = delivery.delivery_date.strftime('%Y-%m-%d')
+
# Если выбран самовывоз, но склад не указан - выбираем склад по умолчанию
if delivery.delivery_type == Delivery.DELIVERY_TYPE_PICKUP and not delivery.pickup_warehouse:
default_warehouse = Warehouse.objects.filter(
@@ -322,38 +337,26 @@ class OrderForm(forms.ModelForm):
# Инициализируем поля адреса, если есть адрес доставки
if delivery.address:
- # Проверяем, есть ли этот адрес в истории клиента
+ # При редактировании всегда используем режим "новый", чтобы можно было редактировать адрес
+ # Инициализируем queryset для истории адресов (для выбора из истории, если нужно)
if self.instance.customer:
customer_addresses = Address.objects.filter(
deliveries__order__customer=self.instance.customer
+ ).exclude(
+ deliveries__order=self.instance # Исключаем адрес текущего заказа
).distinct()
- if delivery.address in customer_addresses:
- # Адрес есть в истории - используем режим "история"
- self.fields['address_mode'].initial = 'history'
- self.fields['address_from_history'].queryset = customer_addresses
- self.fields['address_from_history'].initial = delivery.address.pk
- else:
- # Адреса нет в истории - используем режим "новый" и заполняем поля
- self.fields['address_mode'].initial = 'new'
- self.fields['address_street'].initial = delivery.address.street
- self.fields['address_building_number'].initial = delivery.address.building_number
- self.fields['address_apartment_number'].initial = delivery.address.apartment_number
- self.fields['address_entrance'].initial = delivery.address.entrance
- self.fields['address_floor'].initial = delivery.address.floor
- self.fields['address_intercom_code'].initial = delivery.address.intercom_code
- self.fields['address_delivery_instructions'].initial = delivery.address.delivery_instructions
- self.fields['address_confirm_with_recipient'].initial = delivery.address.confirm_address_with_recipient
- else:
- # Нет клиента - просто заполняем поля
- self.fields['address_mode'].initial = 'new'
- self.fields['address_street'].initial = delivery.address.street
- self.fields['address_building_number'].initial = delivery.address.building_number
- self.fields['address_apartment_number'].initial = delivery.address.apartment_number
- self.fields['address_entrance'].initial = delivery.address.entrance
- self.fields['address_floor'].initial = delivery.address.floor
- self.fields['address_intercom_code'].initial = delivery.address.intercom_code
- self.fields['address_delivery_instructions'].initial = delivery.address.delivery_instructions
- self.fields['address_confirm_with_recipient'].initial = delivery.address.confirm_address_with_recipient
+ self.fields['address_from_history'].queryset = customer_addresses
+
+ # Всегда используем режим "новый" для редактирования, чтобы можно было редактировать
+ self.initial['address_mode'] = 'new'
+ self.initial['address_street'] = delivery.address.street
+ self.initial['address_building_number'] = delivery.address.building_number
+ self.initial['address_apartment_number'] = delivery.address.apartment_number
+ self.initial['address_entrance'] = delivery.address.entrance
+ self.initial['address_floor'] = delivery.address.floor
+ self.initial['address_intercom_code'] = delivery.address.intercom_code
+ self.initial['address_delivery_instructions'] = delivery.address.delivery_instructions
+ self.initial['address_confirm_with_recipient'] = delivery.address.confirm_address_with_recipient
def clean(self):
"""Валидация формы заказа, включая обязательные поля доставки"""
diff --git a/myproject/orders/models/delivery.py b/myproject/orders/models/delivery.py
index c8a5454..6fa408b 100644
--- a/myproject/orders/models/delivery.py
+++ b/myproject/orders/models/delivery.py
@@ -121,6 +121,16 @@ class Delivery(models.Model):
"""Валидация модели"""
super().clean()
+ # Для черновиков пропускаем строгую валидацию
+ if self.order and self.order.status and hasattr(self.order.status, 'code') and self.order.status.code == 'draft':
+ # Для черновиков только проверяем время, если оно указано
+ if self.time_from and self.time_to and self.time_from >= self.time_to:
+ raise ValidationError({
+ 'time_to': 'Время окончания доставки должно быть позже времени начала'
+ })
+ return
+
+ # Для не-черновиков полная валидация
# Проверка: для курьерской доставки должен быть адрес
if self.delivery_type == self.DELIVERY_TYPE_COURIER:
if not self.address:
diff --git a/myproject/orders/services/address_service.py b/myproject/orders/services/address_service.py
index f737de7..85d47b6 100644
--- a/myproject/orders/services/address_service.py
+++ b/myproject/orders/services/address_service.py
@@ -95,7 +95,22 @@ class AddressService:
if not name or not phone:
return None
- # Проверяем, есть ли уже такой получатель в БД
+ # Если у заказа уже есть получатель - обновляем его вместо создания нового
+ # Загружаем заказ из БД, чтобы получить актуального получателя
+ if order.pk:
+ try:
+ # Order уже импортирован в начале файла
+ db_order = Order.objects.select_related('recipient').get(pk=order.pk)
+ if db_order.recipient:
+ # Обновляем существующего получателя
+ db_order.recipient.name = name
+ db_order.recipient.phone = phone
+ # Сохранять будем в views.py, здесь просто возвращаем объект
+ return db_order.recipient
+ except Order.DoesNotExist:
+ pass
+
+ # Проверяем, есть ли уже такой получатель в БД (по имени и телефону)
existing_recipient = Recipient.objects.filter(
name=name,
phone=phone
diff --git a/myproject/orders/templates/orders/order_form.html b/myproject/orders/templates/orders/order_form.html
index 0208a3b..989598d 100644
--- a/myproject/orders/templates/orders/order_form.html
+++ b/myproject/orders/templates/orders/order_form.html
@@ -585,25 +585,6 @@
-
-
@@ -935,6 +938,22 @@ document.addEventListener('DOMContentLoaded', function() {
+
@@ -1099,8 +1118,17 @@ document.addEventListener('DOMContentLoaded', function() {
// Обработчики событий
if (otherRecipientCheckbox) {
otherRecipientCheckbox.addEventListener('change', toggleOtherRecipientBlock);
- // Инициализация при загрузке
- toggleOtherRecipientBlock();
+ // Инициализация при загрузке - проверяем checked состояние
+ // Используем DOMContentLoaded чтобы убедиться, что DOM полностью загружен
+ // Но также проверяем сразу, если DOM уже загружен
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', function() {
+ toggleOtherRecipientBlock();
+ });
+ } else {
+ // DOM уже загружен
+ toggleOtherRecipientBlock();
+ }
}
recipientSourceRadios.forEach(radio => {
diff --git a/myproject/orders/views.py b/myproject/orders/views.py
index 3956316..cfc7773 100644
--- a/myproject/orders/views.py
+++ b/myproject/orders/views.py
@@ -121,30 +121,53 @@ def order_create(request):
# Проверяем, является ли заказ черновиком
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')
-
- # Проверяем наличие обязательных полей (время необязательно)
+ # Получаем данные из формы (уже провалидированы)
+ 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')
+
+ # Обрабатываем адрес для курьерской доставки (даже для черновиков, если указан)
+ address = None
+ if delivery_type == Delivery.DELIVERY_TYPE_COURIER:
+ # Для курьерской доставки обрабатываем адрес, если он указан
+ address = AddressService.process_address_from_form(order, form.cleaned_data)
+ if address and not address.pk:
+ address.save()
+
+ # Создаем или обновляем Delivery
+ # Для черновиков создаем Delivery без обязательных проверок, чтобы сохранить адрес
+ if is_draft:
+ # Для черновиков создаем Delivery, если есть хотя бы адрес или данные доставки
+ if address or delivery_type or pickup_warehouse:
+ # Для черновиков используем значения по умолчанию, если не указаны
+ from django.utils import timezone
+ draft_delivery_type = delivery_type or Delivery.DELIVERY_TYPE_COURIER
+ draft_delivery_date = delivery_date or timezone.now().date()
+
+ Delivery.objects.update_or_create(
+ order=order,
+ defaults={
+ 'delivery_type': draft_delivery_type,
+ 'delivery_date': draft_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')
+ }
+ )
+ else:
+ # Для не-черновиков проверяем обязательные поля
if not delivery_type or not delivery_date:
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:
@@ -259,9 +282,8 @@ def order_update(request, order_number):
# Обрабатываем получателя
recipient = AddressService.process_recipient_from_form(order, form.cleaned_data)
if recipient:
- # Если получатель не существует в БД, сохраняем его
- if not recipient.pk:
- recipient.save()
+ # Сохраняем получателя: если новый - создаем, если существующий - обновляем
+ recipient.save() # Django автоматически определит create или update
order.recipient = recipient
else:
# Если покупатель является получателем
@@ -274,30 +296,56 @@ def order_update(request, order_number):
# Проверяем, является ли заказ черновиком
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')
-
- # Проверяем наличие обязательных полей (время необязательно)
+ # Получаем данные из формы (уже провалидированы)
+ 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')
+
+ # Обрабатываем адрес для курьерской доставки (даже для черновиков, если указан)
+ address = None
+ if delivery_type == Delivery.DELIVERY_TYPE_COURIER:
+ # Для курьерской доставки обрабатываем адрес, если он указан
+ address = AddressService.process_address_from_form(order, form.cleaned_data)
+ if address and not address.pk:
+ address.save()
+
+ # Создаем или обновляем Delivery
+ # Для черновиков создаем Delivery без обязательных проверок, чтобы сохранить адрес
+ if is_draft:
+ # Для черновиков создаем Delivery, если есть хотя бы адрес или данные доставки
+ if address or delivery_type or pickup_warehouse:
+ # Для черновиков используем значения по умолчанию, если не указаны
+ from django.utils import timezone
+ draft_delivery_type = delivery_type or Delivery.DELIVERY_TYPE_COURIER
+ draft_delivery_date = delivery_date or timezone.now().date()
+
+ Delivery.objects.update_or_create(
+ order=order,
+ defaults={
+ 'delivery_type': draft_delivery_type,
+ 'delivery_date': draft_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()
+ else:
+ # Для не-черновиков проверяем обязательные поля
if not delivery_type or not delivery_date:
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:
@@ -316,9 +364,6 @@ def order_update(request, order_number):
'cost': delivery_cost if delivery_cost else Decimal('0')
}
)
- elif hasattr(order, 'delivery'):
- # Если заказ стал черновиком, удаляем Delivery
- order.delivery.delete()
# Пересчитываем итоговую стоимость
order.calculate_total()