- Исправлены комментарии и форматирование в signals.py - Улучшена читаемость кода в models.py - Обновлены шаблоны форм статусов - Доработаны тесты переходов статусов
116 lines
3.8 KiB
Python
116 lines
3.8 KiB
Python
from django.db import models
|
|
from django.core.exceptions import ValidationError
|
|
from accounts.models import CustomUser
|
|
|
|
|
|
class OrderStatus(models.Model):
|
|
"""
|
|
Статус заказа, управляется отдельно для каждого тенанта.
|
|
Благодаря django-tenants в TENANT_APPS, данные изолированы по схемам.
|
|
"""
|
|
name = models.CharField(
|
|
max_length=100,
|
|
verbose_name="Название статуса"
|
|
)
|
|
|
|
code = models.SlugField(
|
|
unique=True,
|
|
verbose_name="Код статуса",
|
|
help_text="Уникальный идентификатор (например: 'completed', 'cancelled')"
|
|
)
|
|
|
|
label = models.CharField(
|
|
max_length=100,
|
|
verbose_name="Метка для отображения",
|
|
blank=True
|
|
)
|
|
|
|
is_system = models.BooleanField(
|
|
default=False,
|
|
verbose_name="Системный статус",
|
|
help_text="True для встроенных статусов (draft, completed, cancelled)"
|
|
)
|
|
|
|
is_positive_end = models.BooleanField(
|
|
default=False,
|
|
verbose_name="Положительный исход сделки",
|
|
help_text="True если это финальный успешный статус (Выполнен)"
|
|
)
|
|
|
|
is_negative_end = models.BooleanField(
|
|
default=False,
|
|
verbose_name="Отрицательный исход сделки",
|
|
help_text="True если это финальный отрицательный статус (Отменен)"
|
|
)
|
|
|
|
order = models.PositiveIntegerField(
|
|
default=0,
|
|
verbose_name="Порядок отображения"
|
|
)
|
|
|
|
color = models.CharField(
|
|
max_length=7,
|
|
blank=True,
|
|
default='#808080',
|
|
verbose_name="Цвет (hex)",
|
|
help_text="Например: #FF5733"
|
|
)
|
|
|
|
description = models.TextField(
|
|
blank=True,
|
|
verbose_name="Описание"
|
|
)
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
created_by = models.ForeignKey(
|
|
CustomUser,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='created_order_statuses',
|
|
verbose_name="Создано"
|
|
)
|
|
|
|
updated_by = models.ForeignKey(
|
|
CustomUser,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name='updated_order_statuses',
|
|
verbose_name="Последнее изменение"
|
|
)
|
|
|
|
class Meta:
|
|
verbose_name = "Статус заказа"
|
|
verbose_name_plural = "Статусы заказов"
|
|
ordering = ['order', 'name']
|
|
indexes = [
|
|
models.Index(fields=['code']),
|
|
models.Index(fields=['is_system']),
|
|
models.Index(fields=['order']),
|
|
]
|
|
constraints = [
|
|
models.CheckConstraint(
|
|
check=~(models.Q(is_positive_end=True) & models.Q(is_negative_end=True)),
|
|
name='not_both_positive_and_negative_end',
|
|
violation_error_message="Статус не может быть одновременно положительным и отрицательным концом"
|
|
)
|
|
]
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
def clean(self):
|
|
"""Валидация модели перед сохранением"""
|
|
if self.is_positive_end and self.is_negative_end:
|
|
raise ValidationError(
|
|
"Статус не может быть одновременно положительным и отрицательным концом"
|
|
)
|
|
|
|
@property
|
|
def orders_count(self):
|
|
"""Количество заказов в этом статусе"""
|
|
return self.orders.count()
|