Защита удаления заказов и улучшение интерфейса клиентов

Orders:
- Удаление разрешено только для черновиков (draft)
- Запрет удаления заказов с оплатой (amount_paid > 0)
- Кнопка "Удалить" скрыта для недопустимых заказов

Customers:
- Inline-редактирование полей клиента
- Улучшен дизайн карточки клиента
- Добавлена история заказов и кошелька

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-28 23:59:57 +03:00
parent 6c1b1c4aa2
commit 07829f867b
7 changed files with 684 additions and 438 deletions

View File

@@ -174,30 +174,6 @@ def customer_create(request):
return render(request, 'customers/customer_form.html', {'form': form, 'is_creating': True})
def customer_update(request, pk):
"""Редактирование клиента"""
customer = get_object_or_404(Customer, pk=pk)
# Проверяем, не системный ли это клиент
if customer.is_system_customer:
messages.warning(request, 'Системный клиент не может быть изменен. Он создается автоматически и необходим для корректной работы системы.')
return redirect('customers:customer-detail', pk=pk)
if request.method == 'POST':
form = CustomerForm(request.POST, instance=customer)
if form.is_valid():
try:
form.save()
messages.success(request, f'Клиент {customer.full_name} успешно обновлён.')
return redirect('customers:customer-detail', pk=customer.pk)
except ValidationError as e:
messages.error(request, str(e))
else:
form = CustomerForm(instance=customer)
return render(request, 'customers/customer_form.html', {'form': form, 'is_creating': False})
def customer_delete(request, pk):
"""Удаление клиента"""
customer = get_object_or_404(Customer, pk=pk)
@@ -503,6 +479,101 @@ def api_search_customers(request):
})
@require_http_methods(["POST"])
def api_update_customer(request, pk):
"""
AJAX endpoint для обновления отдельного поля клиента (inline-редактирование).
Принимает POST JSON:
{
"field": "name",
"value": "Новое имя"
}
Возвращает JSON:
{
"success": true,
"value": "Новое имя"
}
При ошибке:
{
"success": false,
"error": "Текст ошибки"
}
"""
customer = get_object_or_404(Customer, pk=pk)
# Защита системного клиента
if customer.is_system_customer:
return JsonResponse({
'success': False,
'error': 'Системный клиент не может быть изменён'
}, status=403)
try:
data = json.loads(request.body)
field = data.get('field')
value = data.get('value', '').strip()
# Разрешённые поля для редактирования
allowed_fields = ['name', 'phone', 'email', 'notes']
if field not in allowed_fields:
return JsonResponse({
'success': False,
'error': f'Поле "{field}" недоступно для редактирования'
}, status=400)
# Валидация через форму
form_data = {field: value if value else None}
form = CustomerForm(form_data, instance=customer)
# Проверяем только нужное поле
if field in form.fields:
form.fields[field].required = False
field_value = form.fields[field].clean(value if value else None)
# Обновляем поле
setattr(customer, field, field_value)
customer.save(update_fields=[field, 'updated_at'])
# Возвращаем отформатированное значение
display_value = getattr(customer, field)
if display_value is None:
display_value = ''
elif field == 'phone' and display_value:
display_value = str(display_value)
else:
display_value = str(display_value)
return JsonResponse({
'success': True,
'value': display_value
})
return JsonResponse({
'success': False,
'error': 'Неизвестное поле'
}, status=400)
except json.JSONDecodeError:
return JsonResponse({
'success': False,
'error': 'Некорректный JSON'
}, status=400)
except ValidationError as e:
error_msg = e.message if hasattr(e, 'message') else str(e)
return JsonResponse({
'success': False,
'error': error_msg
}, status=400)
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=400)
@require_http_methods(["POST"])
def api_create_customer(request):
"""