Files
octopus/myproject/orders/models/delivery.py
Andrey Smakotin c80e2a5eca 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.
2026-01-27 14:19:33 +03:00

151 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
from django.db import models
from django.core.exceptions import ValidationError
class Delivery(models.Model):
"""
Модель доставки заказа.
Один заказ имеет одну доставку.
"""
# Константы для типов доставки
DELIVERY_TYPE_COURIER = 'courier'
DELIVERY_TYPE_PICKUP = 'pickup'
DELIVERY_TYPE_CHOICES = [
(DELIVERY_TYPE_COURIER, 'Доставка курьером'),
(DELIVERY_TYPE_PICKUP, 'Самовывоз'),
]
# === Связи ===
order = models.OneToOneField(
'orders.Order',
on_delete=models.CASCADE,
related_name='delivery',
verbose_name='Заказ',
help_text='Заказ, к которому относится доставка'
)
# Адрес доставки (только для курьерской доставки)
address = models.ForeignKey(
'orders.Address',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='deliveries',
verbose_name='Адрес доставки',
help_text='Адрес для курьерской доставки. На один адрес может быть много доставок'
)
# Склад для самовывоза (только для самовывоза)
pickup_warehouse = models.ForeignKey(
'inventory.Warehouse',
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='deliveries',
verbose_name='Склад самовывоза',
help_text='Склад для самовывоза заказа'
)
# === Основные поля ===
delivery_type = models.CharField(
max_length=20,
choices=DELIVERY_TYPE_CHOICES,
default=DELIVERY_TYPE_COURIER,
verbose_name='Способ доставки',
db_index=True
)
# Дата и время доставки
delivery_date = models.DateField(
null=True,
blank=True,
verbose_name='Дата доставки',
help_text='Дата, когда должна быть выполнена доставка (обязательна для не-черновиков)'
)
time_from = models.TimeField(
null=True,
blank=True,
verbose_name='Время доставки от',
help_text='Начальное время временного интервала доставки (необязательно)'
)
time_to = models.TimeField(
null=True,
blank=True,
verbose_name='Время доставки до',
help_text='Конечное время временного интервала доставки (необязательно)'
)
cost = models.DecimalField(
max_digits=10,
decimal_places=2,
default=0,
verbose_name='Стоимость доставки',
help_text='Стоимость доставки в рублях. 0 для бесплатной доставки/самовывоза'
)
# === Метаданные ===
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name='Дата создания'
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name='Дата обновления'
)
class Meta:
verbose_name = 'Доставка'
verbose_name_plural = 'Доставки'
ordering = ['-created_at']
indexes = [
models.Index(fields=['delivery_type']),
models.Index(fields=['created_at']),
models.Index(fields=['delivery_date']),
models.Index(fields=['time_from']),
models.Index(fields=['time_to']),
]
def __str__(self):
"""Строковое представление доставки"""
type_display = self.get_delivery_type_display()
return f"{type_display} для заказа #{self.order.order_number}"
def clean(self):
"""Валидация модели"""
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
# Для не-черновиков ранее действовала строгая валидация даты и адреса.
# В рамках новой логики разрешаем сохранять заказы в любом статусе без адреса
# и без обязательной даты доставки. Сохраняем только базовые проверки
# непротиворечивости данных.
# Проверка: время "до" не может быть раньше времени "от" (равные времена разрешены для POS)
if self.time_from and self.time_to and self.time_from > self.time_to:
raise ValidationError({
'time_to': 'Время окончания доставки не может быть раньше времени начала'
})
def save(self, *args, validate=True, **kwargs):
"""Переопределение save для вызова валидации"""
if validate:
self.full_clean()
super().save(*args, **kwargs)