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)