Добавлена валидация уникальности email и phone для клиентов
Изменения: - Добавлено ограничение unique=True для поля email в модели Customer - Email теперь поддерживает NULL значения (несколько клиентов могут быть без email) - Добавлены методы clean_email() и clean_phone() в CustomerForm для валидации - Переписан API endpoint api_create_customer для использования формы вместо прямого создания - Создано две миграции: сначала разрешение NULL, затем добавление unique constraint - В текущей БД преобразованы пустые строки email в NULL (4 записи) Это исправляет: - Возможность создания дубликатов клиентов с одинаковыми email/phone - Работает как в веб-форме, так и в модальном окне создания заказа - Устранена уязвимость race condition через использование DB constraints 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -380,67 +380,54 @@ def api_create_customer(request):
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
|
||||
name = data.get('name', '')
|
||||
phone = data.get('phone')
|
||||
email = data.get('email', '')
|
||||
# Нормализуем данные
|
||||
name = data.get('name', '').strip() if data.get('name') else ''
|
||||
phone = data.get('phone', '').strip() if data.get('phone') else ''
|
||||
email = data.get('email', '').strip() if data.get('email') else ''
|
||||
|
||||
# Нормализуем строки (может быть None из JavaScript)
|
||||
name = name.strip() if name else ''
|
||||
phone = phone.strip() if phone else ''
|
||||
email = email.strip() if email else ''
|
||||
# Подготавливаем данные для формы
|
||||
form_data = {
|
||||
'name': name,
|
||||
'phone': phone if phone else None,
|
||||
'email': email if email else None,
|
||||
}
|
||||
|
||||
# Используем форму для валидации и создания
|
||||
form = CustomerForm(data=form_data)
|
||||
|
||||
if form.is_valid():
|
||||
# Сохраняем клиента через форму (автоматически вызывает все валидации)
|
||||
customer = form.save()
|
||||
|
||||
phone_display = str(customer.phone) if customer.phone else ''
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'id': customer.pk,
|
||||
'name': customer.name,
|
||||
'phone': phone_display,
|
||||
'email': customer.email if customer.email else '',
|
||||
}, status=201)
|
||||
else:
|
||||
# Собираем ошибки валидации
|
||||
errors = []
|
||||
for field, field_errors in form.errors.items():
|
||||
for error in field_errors:
|
||||
errors.append(error)
|
||||
|
||||
# Возвращаем первую ошибку
|
||||
error_message = errors[0] if errors else 'Ошибка валидации данных'
|
||||
|
||||
# Валидация: имя обязательно
|
||||
if not name:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Имя клиента обязательно'
|
||||
'error': error_message
|
||||
}, status=400)
|
||||
|
||||
# Нормализуем телефон если он указан
|
||||
if phone:
|
||||
phone = normalize_query_phone(phone)
|
||||
|
||||
# Проверяем, не существует ли уже клиент с таким телефоном
|
||||
if phone and Customer.objects.filter(phone=phone).exists():
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Клиент с таким номером телефона уже существует'
|
||||
}, status=400)
|
||||
|
||||
# Проверяем, не существует ли уже клиент с таким email
|
||||
if email and Customer.objects.filter(email=email).exists():
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Клиент с таким email уже существует'
|
||||
}, status=400)
|
||||
|
||||
# Создаем нового клиента
|
||||
customer = Customer.objects.create(
|
||||
name=name,
|
||||
phone=phone if phone else None,
|
||||
email=email if email else None
|
||||
)
|
||||
|
||||
phone_display = str(customer.phone) if customer.phone else ''
|
||||
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'id': customer.pk,
|
||||
'name': customer.name,
|
||||
'phone': phone_display,
|
||||
'email': customer.email,
|
||||
}, status=201)
|
||||
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': 'Некорректный JSON'
|
||||
}, status=400)
|
||||
except ValidationError as e:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
'error': str(e)
|
||||
}, status=400)
|
||||
except Exception as e:
|
||||
return JsonResponse({
|
||||
'success': False,
|
||||
|
||||
Reference in New Issue
Block a user