diff --git a/myproject/customers/templates/customers/customer_detail.html b/myproject/customers/templates/customers/customer_detail.html index aa7ad78..41e3e1e 100644 --- a/myproject/customers/templates/customers/customer_detail.html +++ b/myproject/customers/templates/customers/customer_detail.html @@ -82,6 +82,82 @@ + +
+
+
+
Операции с кошельком клиента
+
+
+
+ +
+
Пополнение кошелька
+
+ {% csrf_token %} +
+ + +
+
+
+ + +
+ +
+
+ + +
+
Возврат / списание с кошелька
+
+ {% csrf_token %} +
+ + + Макс: {{ customer.wallet_balance|floatformat:2 }} руб. +
+
+ + +
+ +
+
+
+
+ Все операции с кошельком автоматически логируются в истории транзакций ниже. +
+
+
+
+
diff --git a/myproject/customers/urls.py b/myproject/customers/urls.py index 08b2b30..2fffff9 100644 --- a/myproject/customers/urls.py +++ b/myproject/customers/urls.py @@ -9,6 +9,8 @@ urlpatterns = [ path('/', views.customer_detail, name='customer-detail'), path('/edit/', views.customer_update, name='customer-update'), path('/delete/', views.customer_delete, name='customer-delete'), + path('/wallet/deposit/', views.wallet_deposit, name='wallet-deposit'), + path('/wallet/withdraw/', views.wallet_withdraw, name='wallet-withdraw'), # AJAX API endpoints path('api/search/', views.api_search_customers, name='api-search-customers'), diff --git a/myproject/customers/views.py b/myproject/customers/views.py index b271983..f241d2b 100644 --- a/myproject/customers/views.py +++ b/myproject/customers/views.py @@ -1,13 +1,14 @@ from django.shortcuts import render, get_object_or_404, redirect from django.contrib import messages from django.core.paginator import Paginator -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, PermissionDenied from django.db.models import Q from django.http import JsonResponse from django.views.decorators.http import require_http_methods from django.contrib.auth.decorators import login_required import phonenumbers import json +from decimal import Decimal from .models import Customer from .forms import CustomerForm @@ -484,3 +485,72 @@ def api_create_customer(request): 'success': False, 'error': f'Ошибка сервера: {str(e)}' }, status=500) + + +@login_required +@require_http_methods(["POST"]) +def wallet_deposit(request, pk): + """Пополнение кошелька клиента""" + if not request.user.is_staff: + raise PermissionDenied("У вас нет прав для изменения баланса кошелька клиента.") + + customer = get_object_or_404(Customer, pk=pk) + + if customer.is_system_customer: + messages.error(request, 'Операции с кошельком недоступны для системного клиента.') + return redirect('customers:customer-detail', pk=pk) + + amount_str = request.POST.get('amount') or '' + description = (request.POST.get('description') or '').strip() + + try: + amount = Decimal(amount_str.replace(',', '.')) + except Exception: + messages.error(request, 'Некорректное значение суммы для пополнения.') + return redirect('customers:customer-detail', pk=pk) + + try: + customer.adjust_wallet(amount, description, request.user) + messages.success(request, f'Кошелёк клиента пополнен на {amount:.2f} руб.') + except ValueError as e: + messages.error(request, str(e)) + except ValidationError as e: + messages.error(request, '; '.join(e.messages) if hasattr(e, 'messages') else str(e)) + + return redirect('customers:customer-detail', pk=pk) + + +@login_required +@require_http_methods(["POST"]) +def wallet_withdraw(request, pk): + """Возврат / списание с кошелька клиента""" + if not request.user.is_staff: + raise PermissionDenied("У вас нет прав для изменения баланса кошелька клиента.") + + customer = get_object_or_404(Customer, pk=pk) + + if customer.is_system_customer: + messages.error(request, 'Операции с кошельком недоступны для системного клиента.') + return redirect('customers:customer-detail', pk=pk) + + amount_str = request.POST.get('amount') or '' + description = (request.POST.get('description') or '').strip() + + try: + amount = Decimal(amount_str.replace(',', '.')) + except Exception: + messages.error(request, 'Некорректное значение суммы для списания.') + return redirect('customers:customer-detail', pk=pk) + + # Для списания делаем сумму отрицательной + withdraw_amount = -amount + + try: + customer.adjust_wallet(withdraw_amount, description, request.user) + messages.success(request, f'С кошелька клиента списано {amount:.2f} руб.') + except ValueError as e: + messages.error(request, str(e)) + except ValidationError as e: + messages.error(request, '; '.join(e.messages) if hasattr(e, 'messages') else str(e)) + + return redirect('customers:customer-detail', pk=pk)