import logging import traceback from typing import Any from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import extend_schema, extend_schema_view from rest_framework import status from rest_framework.request import Request from rest_framework.response import Response from rest_framework.views import APIView from engine.payments.docs.drf.views import DEPOSIT_SCHEMA, LIMITS_SCHEMA from engine.payments.gateways import UnknownGatewayError from engine.payments.models import Transaction from engine.payments.serializers import ( DepositSerializer, LimitsSerializer, TransactionProcessSerializer, ) from engine.payments.utils.gateways import get_limits logger = logging.getLogger(__name__) @extend_schema_view(**DEPOSIT_SCHEMA) class DepositView(APIView): __doc__ = _( "This class provides an API endpoint to handle deposit transactions.\n" "It supports the creation of a deposit transaction after validating the " "provided data. If the user is not authenticated, an appropriate response " "is returned. On successful validation and execution, a response " "with the transaction details is provided." ) def post( self, request: Request, *args: list[Any], **kwargs: dict[Any, Any] ) -> Response: logger.debug(request.__dict__) serializer = DepositSerializer(data=request.data) serializer.is_valid(raise_exception=True) if not request.user.is_authenticated: return Response(data=serializer.errors, status=status.HTTP_401_UNAUTHORIZED) # noinspection PyUnresolvedReferences transaction = Transaction.objects.create( balance=request.user.payments_balance, # ty: ignore[unresolved-attribute] amount=serializer.validated_data["amount"], currency="EUR", ) return Response( TransactionProcessSerializer(transaction).data, status=status.HTTP_303_SEE_OTHER, ) @extend_schema(exclude=True) class CallbackAPIView(APIView): __doc__ = _( "Handles incoming callback requests to the API.\n" "This class processes and routes incoming HTTP POST requests to the appropriate " "pgateway handler based on the provided gateway parameter. It is designed to handle " "callback events coming from external systems and provide an appropriate HTTP response " "indicating success or failure." ) def post( self, request: Request, *args: list[Any], **kwargs: dict[Any, Any] ) -> Response: try: transaction = Transaction.objects.get(uuid=str(kwargs.get("uuid"))) if not transaction.gateway: raise UnknownGatewayError( _(f"Transaction {transaction.uuid} has no gateway") ) gateway_integration = transaction.gateway.get_integration_class_object( raise_exc=True ) if not gateway_integration: raise UnknownGatewayError( _(f"Gateway {transaction.gateway} has no integration") ) gateway_integration.process_callback(request.data) return Response(status=status.HTTP_202_ACCEPTED) except Exception as e: return Response( status=status.HTTP_500_INTERNAL_SERVER_ERROR, data={"error": str(e), "detail": traceback.format_exc()}, ) @extend_schema_view(**LIMITS_SCHEMA) class LimitsAPIView(APIView): __doc__ = _( "This endpoint returns minimal and maximal allowed deposit amounts across available gateways." ) def get( self, request: Request, *args: list[Any], **kwargs: dict[Any, Any] ) -> Response: min_amount, max_amount = get_limits() data = {"min_amount": min_amount, "max_amount": max_amount} return Response(LimitsSerializer(data).data, status=status.HTTP_200_OK)