Добавлена функциональность системного клиента для анонимных покупок
- Добавлено поле is_system_customer в модель Customer с индексом - Системный клиент создается автоматически при создании нового тенанта - Реализована защита системного клиента от редактирования и удаления: - Защита на уровне модели (save/delete методы) - Защита на уровне формы (валидация) - Защита на уровне представлений (проверки с дружественными сообщениями) - Защита в админке (readonly поля, запрет удаления) - Системный клиент скрыт из списков и поиска на фронтенде - Создан информационный шаблон для отображения системного клиента - Исправлена обработка NULL значений для полей email/phone (Django best practice) - Добавлено отображение "Не указано" вместо None в карточке клиента 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -41,15 +41,23 @@ class Customer(models.Model):
|
||||
)
|
||||
|
||||
total_spent = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
default=0,
|
||||
verbose_name="Общая сумма покупок"
|
||||
)
|
||||
|
||||
|
||||
# System customer flag
|
||||
is_system_customer = models.BooleanField(
|
||||
default=False,
|
||||
db_index=True,
|
||||
verbose_name="Системный клиент",
|
||||
help_text="Автоматически созданный клиент для анонимных покупок и наличных продаж"
|
||||
)
|
||||
|
||||
# Additional notes
|
||||
notes = models.TextField(
|
||||
blank=True,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Заметки",
|
||||
help_text="Заметки о клиенте, особые предпочтения и т.д."
|
||||
@@ -168,6 +176,19 @@ class Customer(models.Model):
|
||||
super().clean()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Защита системного клиента от изменений
|
||||
if self.pk and self.is_system_customer:
|
||||
# Получаем оригинальный объект из БД
|
||||
try:
|
||||
original = Customer.objects.get(pk=self.pk)
|
||||
# Проверяем, не пытаются ли изменить критичные поля
|
||||
if original.email != self.email:
|
||||
raise ValidationError("Нельзя изменить email системного клиента")
|
||||
if original.is_system_customer != self.is_system_customer:
|
||||
raise ValidationError("Нельзя изменить флаг системного клиента")
|
||||
except Customer.DoesNotExist:
|
||||
pass
|
||||
|
||||
# Обеспечиваем нормализацию телефона, даже если save вызывается напрямую (не через форму)
|
||||
# На данный момент, если вызов прошел через валидацию формы, телефон уже должен быть нормализован
|
||||
# Но если save вызывается непосредственно в модели, нам все равно нужно нормализовать
|
||||
@@ -189,6 +210,36 @@ class Customer(models.Model):
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
"""Защита системного клиента от удаления"""
|
||||
if self.is_system_customer:
|
||||
raise ValidationError("Нельзя удалить системного клиента. Он необходим для работы системы.")
|
||||
super().delete(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_or_create_system_customer(cls):
|
||||
"""
|
||||
Получить или создать системного клиента для анонимных покупок.
|
||||
|
||||
Системный клиент используется для:
|
||||
- Анонимных покупок в POS системе
|
||||
- Покупок от неизвестных клиентов (проходимость)
|
||||
- Наличных продаж без указания покупателя
|
||||
|
||||
Возвращает:
|
||||
tuple: (customer, created) - объект клиента и флаг создания
|
||||
"""
|
||||
customer, created = cls.objects.get_or_create(
|
||||
email="system@pos.customer",
|
||||
defaults={
|
||||
"name": "АНОНИМНЫЙ ПОКУПАТЕЛЬ (POS)",
|
||||
"is_system_customer": True,
|
||||
"loyalty_tier": "no_discount",
|
||||
"notes": "SYSTEM_CUSTOMER - автоматически созданный клиент для анонимных покупок и наличных продаж",
|
||||
}
|
||||
)
|
||||
return customer, created
|
||||
|
||||
def increment_total_spent(self, amount):
|
||||
"""Увеличивает общую сумму покупок"""
|
||||
self.total_spent = self.total_spent + amount
|
||||
|
||||
Reference in New Issue
Block a user