Features: 1) Add LimitsType GraphQL object and payments_limits query to expose deposit limits; 2) Introduce LimitsSerializer and LimitsAPIView for retrieving minimal and maximal deposit amounts; 3) Implement get_limits utility to calculate deposit boundaries dynamically;
Fixes: 1) Add missing `LimitsSerializer` import in `drf.views` module; Extra: 1) Update `.gitignore` to exclude `queries`; 2) Refactor schema and views to integrate new limits functionality.
This commit is contained in:
parent
5b3a8aedbe
commit
87ba06ff0c
8 changed files with 67 additions and 5 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -167,4 +167,5 @@ cypress/screenshots/
|
||||||
test.ipynb
|
test.ipynb
|
||||||
|
|
||||||
# Production stuff
|
# Production stuff
|
||||||
.initialized
|
.initialized
|
||||||
|
queries
|
||||||
|
|
@ -83,6 +83,8 @@ from engine.core.utils import get_project_parameters
|
||||||
from engine.core.utils.languages import get_flag_by_language
|
from engine.core.utils.languages import get_flag_by_language
|
||||||
from engine.core.utils.messages import permission_denied_message
|
from engine.core.utils.messages import permission_denied_message
|
||||||
from engine.payments.graphene.mutations import Deposit
|
from engine.payments.graphene.mutations import Deposit
|
||||||
|
from engine.payments.graphene.object_types import LimitsType
|
||||||
|
from engine.payments.utils.gateways import get_limits
|
||||||
from engine.vibes_auth.filters import UserFilter
|
from engine.vibes_auth.filters import UserFilter
|
||||||
from engine.vibes_auth.graphene.mutations import (
|
from engine.vibes_auth.graphene.mutations import (
|
||||||
ActivateUser,
|
ActivateUser,
|
||||||
|
|
@ -105,6 +107,7 @@ logger = logging.getLogger(__name__)
|
||||||
class Query(ObjectType):
|
class Query(ObjectType):
|
||||||
parameters = Field(ConfigType)
|
parameters = Field(ConfigType)
|
||||||
languages = List(LanguageType)
|
languages = List(LanguageType)
|
||||||
|
payments_limits = Field(LimitsType)
|
||||||
products = DjangoFilterConnectionField(ProductType, filterset_class=ProductFilter)
|
products = DjangoFilterConnectionField(ProductType, filterset_class=ProductFilter)
|
||||||
orders = DjangoFilterConnectionField(OrderType, filterset_class=OrderFilter)
|
orders = DjangoFilterConnectionField(OrderType, filterset_class=OrderFilter)
|
||||||
users = DjangoFilterConnectionField(UserType, filterset_class=UserFilter)
|
users = DjangoFilterConnectionField(UserType, filterset_class=UserFilter)
|
||||||
|
|
@ -140,6 +143,11 @@ class Query(ObjectType):
|
||||||
|
|
||||||
return languages
|
return languages
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_payments_limits(_parent, _info):
|
||||||
|
min_amount, max_amount = get_limits()
|
||||||
|
return {"min_amount": min_amount, "max_amount": max_amount}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_products(_parent, info, **kwargs):
|
def resolve_products(_parent, info, **kwargs):
|
||||||
if info.context.user.is_authenticated and kwargs.get("uuid"):
|
if info.context.user.is_authenticated and kwargs.get("uuid"):
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from drf_spectacular.utils import extend_schema
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
|
|
||||||
from engine.core.docs.drf import error
|
from engine.core.docs.drf import error
|
||||||
from engine.payments.serializers import DepositSerializer, TransactionProcessSerializer
|
from engine.payments.serializers import DepositSerializer, TransactionProcessSerializer, LimitsSerializer
|
||||||
|
|
||||||
DEPOSIT_SCHEMA = {
|
DEPOSIT_SCHEMA = {
|
||||||
"post": extend_schema(
|
"post": extend_schema(
|
||||||
|
|
@ -20,3 +20,17 @@ DEPOSIT_SCHEMA = {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LIMITS_SCHEMA = {
|
||||||
|
"get": extend_schema(
|
||||||
|
tags=[
|
||||||
|
"payments",
|
||||||
|
],
|
||||||
|
summary=_("payment limits"),
|
||||||
|
description=_("retrieve minimal and maximal allowed deposit amounts across available gateways"),
|
||||||
|
responses={
|
||||||
|
status.HTTP_200_OK: LimitsSerializer,
|
||||||
|
status.HTTP_401_UNAUTHORIZED: error,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@ from graphene_django import DjangoObjectType
|
||||||
from engine.payments.models import Balance, Transaction
|
from engine.payments.models import Balance, Transaction
|
||||||
|
|
||||||
|
|
||||||
|
class LimitsType(graphene.ObjectType):
|
||||||
|
min_amount = graphene.Float()
|
||||||
|
max_amount = graphene.Float()
|
||||||
|
|
||||||
|
|
||||||
class TransactionType(DjangoObjectType):
|
class TransactionType(DjangoObjectType):
|
||||||
process = GenericScalar()
|
process = GenericScalar()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,3 +29,8 @@ class TransactionProcessSerializer(ModelSerializer): # type: ignore [type-arg]
|
||||||
model = Transaction
|
model = Transaction
|
||||||
fields = ("process", "order_hr_id", "order_uuid")
|
fields = ("process", "order_hr_id", "order_uuid")
|
||||||
read_only_fields = ("process", "order_hr_id", "order_uuid")
|
read_only_fields = ("process", "order_hr_id", "order_uuid")
|
||||||
|
|
||||||
|
|
||||||
|
class LimitsSerializer(Serializer): # type: ignore [type-arg]
|
||||||
|
min_amount = FloatField(read_only=True)
|
||||||
|
max_amount = FloatField(read_only=True)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
from engine.payments.views import CallbackAPIView, DepositView
|
from engine.payments.views import CallbackAPIView, DepositView, LimitsAPIView
|
||||||
from engine.payments.viewsets import TransactionViewSet
|
from engine.payments.viewsets import TransactionViewSet
|
||||||
|
|
||||||
app_name = "payments"
|
app_name = "payments"
|
||||||
|
|
@ -12,5 +12,6 @@ payment_router.register(prefix=r"transactions", viewset=TransactionViewSet, base
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(r"", include(payment_router.urls)),
|
path(r"", include(payment_router.urls)),
|
||||||
path(r"deposit/", DepositView.as_view()),
|
path(r"deposit/", DepositView.as_view()),
|
||||||
|
path(r"limits/", LimitsAPIView.as_view()),
|
||||||
path(r"<str:uuid>/callback/", CallbackAPIView.as_view()),
|
path(r"<str:uuid>/callback/", CallbackAPIView.as_view()),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,18 @@ def get_gateways_integrations(name: str | None = None) -> list[Type[AbstractGate
|
||||||
class_name = gateway.integration_path.split(".")[-1]
|
class_name = gateway.integration_path.split(".")[-1]
|
||||||
gateways_integrations.append(create_object(module_name, class_name))
|
gateways_integrations.append(create_object(module_name, class_name))
|
||||||
return gateways_integrations
|
return gateways_integrations
|
||||||
|
|
||||||
|
|
||||||
|
def get_limits() -> tuple[float, float]:
|
||||||
|
from django.db.models import Min, Max
|
||||||
|
|
||||||
|
qs = Gateway.objects.can_be_used().filter(can_be_used=True)
|
||||||
|
|
||||||
|
if not qs.exists():
|
||||||
|
return 0.0, 0.0
|
||||||
|
|
||||||
|
agg = qs.aggregate(min_limit=Min("minimum_transaction_amount"), max_limit=Max("maximum_transaction_amount"))
|
||||||
|
|
||||||
|
min_limit = float(agg.get("min_limit") or 0.0)
|
||||||
|
max_limit = float(agg.get("max_limit") or 0.0)
|
||||||
|
return min_limit, max_limit
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@ from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from engine.payments.docs.drf.views import DEPOSIT_SCHEMA
|
from engine.payments.docs.drf.views import DEPOSIT_SCHEMA, LIMITS_SCHEMA
|
||||||
from engine.payments.gateways import UnknownGatewayError
|
from engine.payments.gateways import UnknownGatewayError
|
||||||
from engine.payments.models import Transaction
|
from engine.payments.models import Transaction
|
||||||
from engine.payments.serializers import DepositSerializer, TransactionProcessSerializer
|
from engine.payments.serializers import DepositSerializer, TransactionProcessSerializer, LimitsSerializer
|
||||||
|
from engine.payments.utils.gateways import get_limits
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -67,3 +68,15 @@ class CallbackAPIView(APIView):
|
||||||
return Response(
|
return Response(
|
||||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR, data={"error": str(e), "detail": traceback.format_exc()}
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR, data={"error": str(e), "detail": traceback.format_exc()}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema_view(**LIMITS_SCHEMA)
|
||||||
|
class LimitsAPIView(APIView):
|
||||||
|
__doc__ = _( # type: ignore [assignment]
|
||||||
|
"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)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue