233 lines
9.5 KiB
Python
233 lines
9.5 KiB
Python
from django.shortcuts import render
|
|
|
|
# Create your views here.
|
|
from rest_framework.views import APIView
|
|
from rest_framework.response import Response
|
|
from rest_framework.permissions import IsAuthenticated
|
|
import gopay
|
|
from gopay.enums import TokenScope, Language
|
|
import os
|
|
from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample, OpenApiParameter
|
|
from .serializers import (
|
|
GoPayCreatePaymentRequestSerializer,
|
|
GoPayPaymentCreatedResponseSerializer,
|
|
GoPayStatusResponseSerializer,
|
|
GoPayRefundRequestSerializer,
|
|
GoPayCaptureRequestSerializer,
|
|
GoPayCreateRecurrenceRequestSerializer,
|
|
)
|
|
|
|
|
|
class GoPayClientMixin:
|
|
"""Shared helpers for configuring GoPay client and formatting responses."""
|
|
def get_gopay_client(self):
|
|
gateway_url = os.getenv("GOPAY_GATEWAY_URL", "https://gw.sandbox.gopay.com/api")
|
|
return gopay.payments({
|
|
"goid": os.getenv("GOPAY_GOID"),
|
|
"client_id": os.getenv("GOPAY_CLIENT_ID"),
|
|
"client_secret": os.getenv("GOPAY_CLIENT_SECRET"),
|
|
"gateway_url": gateway_url,
|
|
"scope": TokenScope.ALL,
|
|
"language": Language.CZECH,
|
|
})
|
|
|
|
def _to_response(self, sdk_response):
|
|
# The GoPay SDK returns a response object with has_succeed(), json, errors, status_code
|
|
try:
|
|
if hasattr(sdk_response, "has_succeed") and sdk_response.has_succeed():
|
|
return Response(getattr(sdk_response, "json", {}))
|
|
status = getattr(sdk_response, "status_code", 400)
|
|
errors = getattr(sdk_response, "errors", None)
|
|
if errors is None and hasattr(sdk_response, "json"):
|
|
errors = sdk_response.json
|
|
if errors is None:
|
|
errors = {"detail": "GoPay request failed"}
|
|
return Response({"errors": errors}, status=status)
|
|
except Exception as e:
|
|
return Response({"errors": str(e)}, status=500)
|
|
|
|
|
|
class GoPayPaymentView(GoPayClientMixin, APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
tags=["GoPay"],
|
|
summary="Create GoPay payment",
|
|
description="Creates a GoPay payment and returns gateway URL and payment info.",
|
|
request=GoPayCreatePaymentRequestSerializer,
|
|
responses={
|
|
200: OpenApiResponse(response=GoPayPaymentCreatedResponseSerializer, description="Payment created"),
|
|
400: OpenApiResponse(description="Validation error or SDK error"),
|
|
},
|
|
examples=[
|
|
OpenApiExample(
|
|
"Create payment",
|
|
value={
|
|
"amount": 123.45,
|
|
"currency": "CZK",
|
|
"order_number": "order-001",
|
|
"order_description": "Example GoPay payment",
|
|
"return_url": "https://yourfrontend.com/success",
|
|
"notify_url": "https://yourbackend.com/gopay/notify",
|
|
"preauthorize": False,
|
|
},
|
|
request_only=True,
|
|
)
|
|
]
|
|
)
|
|
def post(self, request):
|
|
amount = request.data.get("amount")
|
|
currency = request.data.get("currency", "CZK")
|
|
order_number = request.data.get("order_number", "order-001")
|
|
order_description = request.data.get("order_description", "Example GoPay payment")
|
|
return_url = request.data.get("return_url", "https://yourfrontend.com/success")
|
|
notify_url = request.data.get("notify_url", "https://yourbackend.com/gopay/notify")
|
|
preauthorize = bool(request.data.get("preauthorize", False))
|
|
|
|
if not amount:
|
|
return Response({"error": "Amount is required"}, status=400)
|
|
|
|
payments = self.get_gopay_client()
|
|
|
|
payment_data = {
|
|
"payer": {
|
|
"allowed_payment_instruments": ["PAYMENT_CARD"],
|
|
"default_payment_instrument": "PAYMENT_CARD",
|
|
"allowed_swifts": ["FIOB"],
|
|
"contact": {
|
|
"first_name": getattr(request.user, "first_name", ""),
|
|
"last_name": getattr(request.user, "last_name", ""),
|
|
"email": getattr(request.user, "email", ""),
|
|
},
|
|
},
|
|
"amount": int(float(amount) * 100), # GoPay expects amount in cents
|
|
"currency": currency,
|
|
"order_number": order_number,
|
|
"order_description": order_description,
|
|
"items": [
|
|
{"name": "Example Item", "amount": int(float(amount) * 100)}
|
|
],
|
|
"callback": {"return_url": return_url, "notify_url": notify_url},
|
|
"preauthorize": preauthorize,
|
|
}
|
|
|
|
resp = payments.create_payment(payment_data)
|
|
return self._to_response(resp)
|
|
|
|
|
|
class GoPayPaymentStatusView(GoPayClientMixin, APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
tags=["GoPay"],
|
|
summary="Get GoPay payment status",
|
|
parameters=[OpenApiParameter(name="payment_id", required=True, type=int, location=OpenApiParameter.PATH)],
|
|
responses={200: OpenApiResponse(response=GoPayStatusResponseSerializer, description="Payment status")},
|
|
)
|
|
def get(self, request, payment_id: int):
|
|
payments = self.get_gopay_client()
|
|
resp = payments.get_status(payment_id)
|
|
return self._to_response(resp)
|
|
|
|
|
|
class GoPayRefundPaymentView(GoPayClientMixin, APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
tags=["GoPay"],
|
|
summary="Refund GoPay payment",
|
|
parameters=[OpenApiParameter(name="payment_id", required=True, type=int, location=OpenApiParameter.PATH)],
|
|
request=GoPayRefundRequestSerializer,
|
|
responses={200: OpenApiResponse(description="Refund processed")},
|
|
)
|
|
def post(self, request, payment_id: int):
|
|
amount = request.data.get("amount") # optional for full refund
|
|
payments = self.get_gopay_client()
|
|
if amount is None or amount == "":
|
|
# Full refund
|
|
resp = payments.refund_payment(payment_id)
|
|
else:
|
|
resp = payments.refund_payment(payment_id, int(float(amount) * 100))
|
|
return self._to_response(resp)
|
|
|
|
|
|
class GoPayCaptureAuthorizationView(GoPayClientMixin, APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
tags=["GoPay"],
|
|
summary="Capture GoPay authorization",
|
|
parameters=[OpenApiParameter(name="payment_id", required=True, type=int, location=OpenApiParameter.PATH)],
|
|
request=GoPayCaptureRequestSerializer,
|
|
responses={200: OpenApiResponse(description="Capture processed")},
|
|
)
|
|
def post(self, request, payment_id: int):
|
|
amount = request.data.get("amount") # optional for partial capture
|
|
payments = self.get_gopay_client()
|
|
if amount is None or amount == "":
|
|
resp = payments.capture_authorization(payment_id)
|
|
else:
|
|
resp = payments.capture_authorization(payment_id, int(float(amount) * 100))
|
|
return self._to_response(resp)
|
|
|
|
|
|
class GoPayVoidAuthorizationView(GoPayClientMixin, APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
tags=["GoPay"],
|
|
summary="Void GoPay authorization",
|
|
parameters=[OpenApiParameter(name="payment_id", required=True, type=int, location=OpenApiParameter.PATH)],
|
|
responses={200: OpenApiResponse(description="Authorization voided")},
|
|
)
|
|
def post(self, request, payment_id: int):
|
|
payments = self.get_gopay_client()
|
|
resp = payments.void_authorization(payment_id)
|
|
return self._to_response(resp)
|
|
|
|
|
|
class GoPayCreateRecurrenceView(GoPayClientMixin, APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
tags=["GoPay"],
|
|
summary="Create GoPay recurrence",
|
|
parameters=[OpenApiParameter(name="payment_id", required=True, type=int, location=OpenApiParameter.PATH)],
|
|
request=GoPayCreateRecurrenceRequestSerializer,
|
|
responses={200: OpenApiResponse(description="Recurrence created")},
|
|
)
|
|
def post(self, request, payment_id: int):
|
|
amount = request.data.get("amount")
|
|
currency = request.data.get("currency", "CZK")
|
|
order_number = request.data.get("order_number", "recur-001")
|
|
order_description = request.data.get("order_description", "Recurring payment")
|
|
if not amount:
|
|
return Response({"error": "Amount is required"}, status=400)
|
|
payments = self.get_gopay_client()
|
|
recurrence_payload = {
|
|
"amount": int(float(amount) * 100),
|
|
"currency": currency,
|
|
"order_number": order_number,
|
|
"order_description": order_description,
|
|
}
|
|
resp = payments.create_recurrence(payment_id, recurrence_payload)
|
|
return self._to_response(resp)
|
|
|
|
|
|
class GoPayPaymentInstrumentsView(GoPayClientMixin, APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
tags=["GoPay"],
|
|
summary="Get GoPay payment instruments",
|
|
parameters=[OpenApiParameter(name="currency", required=False, type=str, location=OpenApiParameter.QUERY)],
|
|
responses={200: OpenApiResponse(description="Available payment instruments returned")},
|
|
)
|
|
def get(self, request):
|
|
currency = request.query_params.get("currency", "CZK")
|
|
goid = os.getenv("GOPAY_GOID")
|
|
if not goid:
|
|
return Response({"error": "GOPAY_GOID is not configured"}, status=500)
|
|
payments = self.get_gopay_client()
|
|
resp = payments.get_payment_instruments(goid, currency)
|
|
return self._to_response(resp) |