# -*- 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( 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.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': 'Для самовывоза адрес не указывается' }) # Проверка: время "до" должно быть позже времени "от" if self.time_from and self.time_to and self.time_from >= self.time_to: raise ValidationError({ 'time_to': 'Время окончания доставки должно быть позже времени начала' }) def save(self, *args, **kwargs): """Переопределение save для вызова валидации""" self.full_clean() super().save(*args, **kwargs)