refactor(orders): relax delivery address and date requirements for non-draft orders

- Updated order creation and update logic to allow saving orders without a delivery address or date, regardless of order status.
- Removed strict validation for delivery fields in the Delivery model, enabling more flexible order handling.
- Adjusted order form to reflect changes in required fields for delivery information.
This commit is contained in:
2026-01-27 14:19:33 +03:00
parent 2aed6f60e5
commit c80e2a5eca
3 changed files with 47 additions and 91 deletions

View File

@@ -132,35 +132,10 @@ class Delivery(models.Model):
}) })
return return
# Для не-черновиков полная валидация # Для не-черновиков ранее действовала строгая валидация даты и адреса.
# В рамках новой логики разрешаем сохранять заказы в любом статусе без адреса
# Проверка: дата доставки обязательна # и без обязательной даты доставки. Сохраняем только базовые проверки
if not self.delivery_date: # непротиворечивости данных.
raise ValidationError({
'delivery_date': 'Для не-черновиков дата доставки обязательна'
})
# Проверка: для курьерской доставки должен быть адрес
if self.delivery_type == self.DELIVERY_TYPE_COURIER:
if not self.address:
raise ValidationError({
'address': 'Для курьерской доставки необходимо указать адрес'
})
if self.pickup_warehouse:
raise ValidationError({
'pickup_warehouse': 'Для курьерской доставки склад не указывается'
})
# Проверка: для самовывоза должен быть склад
if self.delivery_type == self.DELIVERY_TYPE_PICKUP:
if not self.pickup_warehouse:
raise ValidationError({
'pickup_warehouse': 'Для самовывоза необходимо указать склад'
})
if self.address:
raise ValidationError({
'address': 'Для самовывоза адрес не указывается'
})
# Проверка: время "до" не может быть раньше времени "от" (равные времена разрешены для POS) # Проверка: время "до" не может быть раньше времени "от" (равные времена разрешены для POS)
if self.time_from and self.time_to and self.time_from > self.time_to: if self.time_from and self.time_to and self.time_from > self.time_to:

View File

@@ -581,7 +581,7 @@
<div class="row g-3 mb-3"> <div class="row g-3 mb-3">
<div class="col-md-6"> <div class="col-md-6">
<label for="{{ form.address_street.id_for_label }}" class="form-label"> <label for="{{ form.address_street.id_for_label }}" class="form-label">
Улица <span class="text-danger">*</span> Улица
</label> </label>
{{ form.address_street }} {{ form.address_street }}
{% if form.address_street.errors %} {% if form.address_street.errors %}
@@ -590,7 +590,7 @@
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<label for="{{ form.address_building_number.id_for_label }}" class="form-label"> <label for="{{ form.address_building_number.id_for_label }}" class="form-label">
Дом <span class="text-danger">*</span> Дом
</label> </label>
{{ form.address_building_number }} {{ form.address_building_number }}
{% if form.address_building_number.errors %} {% if form.address_building_number.errors %}

View File

@@ -232,7 +232,8 @@ def order_create(request):
address.save() address.save()
# Создаем или обновляем Delivery # Создаем или обновляем Delivery
# Для черновиков создаем Delivery без обязательных проверок, чтобы сохранить адрес # Ранее для не-черновиков адрес курьерской доставки был обязателен.
# Теперь разрешаем сохранять заказ в любом статусе без адреса.
if is_draft: if is_draft:
# Для черновиков создаем Delivery, если есть хотя бы адрес или данные доставки # Для черновиков создаем Delivery, если есть хотя бы адрес или данные доставки
if address or delivery_type or pickup_warehouse or delivery_date: if address or delivery_type or pickup_warehouse or delivery_date:
@@ -249,34 +250,23 @@ def order_create(request):
} }
) )
else: else:
# Для не-черновиков проверяем обязательные поля # Для не-черновиков больше не требуем обязательного адреса.
if not delivery_type or not delivery_date: # Если пользователь вообще не указал тип доставки и дату, просто не создаём Delivery.
raise ValidationError('Необходимо указать способ доставки и дату доставки') if address or delivery_type or pickup_warehouse or delivery_date:
delivery = Delivery.objects.create(
order=order,
delivery_type=delivery_type or Delivery.DELIVERY_TYPE_COURIER,
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 delivery_type == Delivery.DELIVERY_TYPE_COURIER: # Пересчитываем стоимость доставки если она не установлена вручную
# Для курьерской доставки нужен адрес if not delivery.cost or delivery.cost <= 0:
if not address: order.reset_delivery_cost()
raise ValidationError('Для курьерской доставки необходимо указать адрес')
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() order.calculate_total()
@@ -465,7 +455,8 @@ def order_update(request, order_number):
address.save() address.save()
# Создаем или обновляем Delivery # Создаем или обновляем Delivery
# Для черновиков создаем Delivery без обязательных проверок, чтобы сохранить адрес # Ранее для не-черновиков адрес курьерской доставки был обязателен.
# Теперь разрешаем сохранять заказ в любом статусе без адреса.
if is_draft: if is_draft:
# Для черновиков создаем Delivery, если есть хотя бы адрес или данные доставки # Для черновиков создаем Delivery, если есть хотя бы адрес или данные доставки
if address or delivery_type or pickup_warehouse or delivery_date: if address or delivery_type or pickup_warehouse or delivery_date:
@@ -481,39 +472,29 @@ def order_update(request, order_number):
'cost': delivery_cost if delivery_cost else Decimal('0') 'cost': delivery_cost if delivery_cost else Decimal('0')
} }
) )
elif hasattr(order, 'delivery'): elif hasattr(order, 'delivery'):
# Если все данные доставки очищены, удаляем существующую Delivery
order.delivery.delete() order.delivery.delete()
else: else:
# Для не-черновиков проверяем обязательные поля # Для не-черновиков больше не требуем обязательного адреса.
if not delivery_type or not delivery_date: # Если пользователь вообще не указал данные доставки, удаляем Delivery (если она была).
raise ValidationError('Необходимо указать способ доставки и дату доставки') if not (address or delivery_type or pickup_warehouse or delivery_date):
if hasattr(order, 'delivery'):
if delivery_type == Delivery.DELIVERY_TYPE_COURIER: order.delivery.delete()
# Для курьерской доставки нужен адрес else:
if not address: # Создаем или обновляем Delivery с теми данными, что есть.
raise ValidationError('Для курьерской доставки необходимо указать адрес') delivery, created = Delivery.objects.update_or_create(
elif delivery_type == Delivery.DELIVERY_TYPE_PICKUP: order=order,
# Для самовывоза нужен склад defaults={
if not pickup_warehouse: 'delivery_type': delivery_type or Delivery.DELIVERY_TYPE_COURIER,
raise ValidationError('Для самовывоза необходимо выбрать склад') 'delivery_date': delivery_date,
'time_from': time_from,
# Создаем или обновляем Delivery 'time_to': time_to,
delivery, created = Delivery.objects.update_or_create( 'address': address,
order=order, 'pickup_warehouse': pickup_warehouse,
defaults={ 'cost': delivery_cost if delivery_cost else Decimal('0')
'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')
}
)
# Пересчитываем итоговую стоимость # Пересчитываем итоговую стоимость
order.calculate_total() order.calculate_total()
order.update_payment_status() order.update_payment_status()