ipg/apps/pg/views.py
Sayyid Hamid Mahdavi 7a215dc457 bug fix
2026-04-22 21:41:23 +03:30

230 lines
8.7 KiB
Python

from django.contrib import messages
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import UpdateView
from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.views import APIView
from drf_spectacular.utils import extend_schema
from django.shortcuts import render
from utils.commons import calculate_pna_commission
from .constans import StateChoices
from .forms import PaymentRequestForm
from .models import PaymentRequest, get_gateway_class
from .serializers import PaymentRequestSerializer, CommissionSerializer
from ..core.models import BasePGModel
from ..gooyal_oauth2.utils import get_application
from ..users.models import User
class CalculateCommissionView(APIView):
@extend_schema(
request=CommissionSerializer,
responses=CommissionSerializer
)
def post(self, request):
serializer = CommissionSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
amount = serializer.validated_data['amount']
commission = calculate_pna_commission(amount)
serializer = CommissionSerializer({
"amount": amount,
"commission": commission
})
return Response(serializer.data)
class PaymentRequestCreateApiView(generics.CreateAPIView):
permission_classes = [IsAuthenticatedOrTokenHasScope]
serializer_class = PaymentRequestSerializer
required_scopes = ['wallet.wallet:get_balance'] # TODO: is it good scope?
model = PaymentRequest
def perform_create(self, serializer):
user = self.request.user
application = get_application(self.request)
charge_request: PaymentRequest = serializer.save(user=user, application=application)
# TODO: web view
# charge_request.charge_wallet_balance()
class ApplicationPaymentRequestCreateApiView(generics.CreateAPIView):
permission_classes = [IsAuthenticatedOrTokenHasScope]
serializer_class = PaymentRequestSerializer
required_scopes = ['ipg.application:request_user_charge'] # TODO: is it good scope?
model = PaymentRequest
def perform_create(self, serializer):
user_uuid = self.kwargs.get('uuid')
user, created = User.objects.get_or_create(uuid=user_uuid)
application = get_application(self.request)
charge_request: PaymentRequest = serializer.save(user=user, application=application)
# TODO: web view
# charge_request.charge_wallet_balance()
@method_decorator(csrf_exempt, name='dispatch')
class PaymentRequestView(UpdateView):
template_name = 'pg/payment_request.html'
form_class = PaymentRequestForm
# pk_url_kwarg = 'uuid'
slug_field = 'uuid'
slug_url_kwarg = 'uuid'
def get(self, request, *args, **kwargs):
charge_request: PaymentRequest = self.get_object()
# TODO: check more states
# TODO: prevent double
if charge_request.state == StateChoices.FAILED:
return render(request, 'pg/payment_failure.html', {
'object': charge_request
})
# # gateway was setted in api call
# # TODO: double check
# if charge_request.gateway and not charge_request.commission:
# charge_request.save_commission()
# gateway_tool = charge_request.get_gateway_tools()
# gateway_tool.make_request()
# return HttpResponseRedirect(gateway_tool.redirect_url)
application_policy = charge_request.get_policy()
preferred_gateways = application_policy.get_preferred_gateways()
if preferred_gateways:
if application_policy.policy == application_policy.PolicyChoise.RANDOM:
# TODO: move to model
import random
gateway = random.choices(preferred_gateways)
charge_request.set_gateway(gateway)
charge_request.save_commission()
gateway_tool = charge_request.get_gateway_tools()
gateway_tool.make_request()
redirect_url = gateway_tool.get_pg_page_url()
if redirect_url:
return HttpResponseRedirect(redirect_url)
elif len(preferred_gateways) == 1:
gateway = preferred_gateways[0]
charge_request.set_gateway(gateway)
charge_request.save_commission()
gateway_tool = charge_request.get_gateway_tools()
gateway_tool.make_request()
redirect_url = gateway_tool.get_pg_page_url()
if redirect_url:
return HttpResponseRedirect(redirect_url)
else:
return super().get(request, *args, **kwargs)
return render(request, 'pg/payment_failure.html', {
'object': charge_request
})
# # TODO: remove it in future
# def post(self, request, *args, **kwargs):
# charge_request: PaymentRequest = self.get_object()
# tool = charge_request.get_gateway_tools()
# charge_request.refresh_from_db()
# if charge_request.state == StateChoices.FAILED:
# return render(request, 'pg/payment_failure.html', {
# 'object': charge_request
# })
# redirect_url = tool.get_pg_page_url()
# return HttpResponseRedirect(redirect_url)
def get_queryset(self):
# return ChargeRequest.objects.all()
# return Charge.objects.filter(state__in=[StateChoices.CREATED.value, StateChoices.SUCCESS.value])
return PaymentRequest.objects.filter(state__in=[StateChoices.CREATED.value])
def form_valid(self, form):
self.object = form.save()
charge_request: PaymentRequest = self.get_object()
application_policy = charge_request.get_policy()
preferred_gateways = application_policy.get_preferred_gateways()
if preferred_gateways:
for gateway_label in preferred_gateways:
if gateway_label in form.data:
charge_request.set_gateway(gateway_label)
charge_request.save_commission()
tool:BasePGModel = charge_request.get_gateway_tools()
tool.make_request()
redirect_url = tool.get_pg_page_url()
if redirect_url:
if tool.redirect_method == 'GET':
return HttpResponseRedirect(redirect_url)
elif tool.redirect_method == 'POST':
print(redirect_url)
return
else:
pass
messages.error(self.request, 'can not redirect to payment gateway')
messages.info(self.request, 'در پردازش صفحه خطایی وجود دارد.')
# TODO: redirect to error page
return HttpResponseRedirect(reverse('pg:payment-confirm-view', kwargs={'uuid': charge_request.uuid}))
@method_decorator(csrf_exempt, name='dispatch')
class PaymentConfirmView(UpdateView):
# template_name = 'pg/payment_confirm.html'
template_name = 'pg/payment_failure.html'
form_class = PaymentRequestForm
# pk_url_kwarg = 'uuid'
slug_field = 'uuid'
slug_url_kwarg = 'uuid'
def get_queryset(self):
return PaymentRequest.objects.all()
# return Charge.objects.filter(state__in=[StateChoices.CREATED.value, StateChoices.SUCCESS.value])
def get(self, request, *args, **kwargs):
print('get')
print(args)
print(kwargs)
self.object = self.get_object()
tool = self.object.get_gateway_tools()
# state, message = tool.confirm_request(request)
# if state:
# self.template_name = 'pg/payment_success.html'
#
#
# # TODO:
# context = self.get_context_data(object=self.object)
# context['message'] = message
context = self.get_context_data()
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
print("post")
print(request.POST)
print(args)
print(kwargs)
self.object = self.get_object()
if 'redirect-to-app' in request.POST:
response = HttpResponse(status=302)
response['Location'] = self.object.callback_url + f'?state={self.object.state}'
return response
tool = self.object.get_gateway_tools()
state, message = tool.confirm_request(request)
if state:
self.template_name = 'pg/payment_success.html'
context = self.get_context_data(object=self.object)
context['message'] = message
return self.render_to_response(context)