From e4ff61c4bd61b6b19f0028de5055ac4a45da7e75 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Wed, 27 Aug 2025 13:13:19 +0500 Subject: [PATCH] add: add atmos callback api --- config/settings/base.py | 1 + config/urls.py | 1 + core/apps/common/views.py | 1 + core/apps/payment/__init__.py | 0 core/apps/payment/admin.py | 3 + core/apps/payment/apps.py | 6 ++ core/apps/payment/migrations/__init__.py | 0 core/apps/payment/models.py | 3 + core/apps/payment/tests.py | 3 + core/apps/payment/urls.py | 7 +++ core/apps/payment/views.py | 72 ++++++++++++++++++++++++ 11 files changed, 97 insertions(+) create mode 100644 core/apps/payment/__init__.py create mode 100644 core/apps/payment/admin.py create mode 100644 core/apps/payment/apps.py create mode 100644 core/apps/payment/migrations/__init__.py create mode 100644 core/apps/payment/models.py create mode 100644 core/apps/payment/tests.py create mode 100644 core/apps/payment/urls.py create mode 100644 core/apps/payment/views.py diff --git a/config/settings/base.py b/config/settings/base.py index 9c431e5..fa9cbdf 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -28,6 +28,7 @@ INSTALLED_APPS = [ 'core.apps.accounts', 'core.apps.orders', 'core.apps.common', + 'core.apps.payment', ] MIDDLEWARE = [ diff --git a/config/urls.py b/config/urls.py index c5bc0be..3756ecd 100644 --- a/config/urls.py +++ b/config/urls.py @@ -32,6 +32,7 @@ urlpatterns = [ path('accounts/', include('core.apps.accounts.urls')), path('common/', include('core.apps.common.urls')), path('orders/', include('core.apps.orders.urls')), + path('payment/', include('core.apps.payment.urls')), ] )) ] diff --git a/core/apps/common/views.py b/core/apps/common/views.py index 8b8c444..81d2eee 100644 --- a/core/apps/common/views.py +++ b/core/apps/common/views.py @@ -2,6 +2,7 @@ from rest_framework import generics from rest_framework.response import Response from core.apps.common import models, serializers +from core.apps.payment.views import get_client_ip class SiteConfigApiView(generics.GenericAPIView): diff --git a/core/apps/payment/__init__.py b/core/apps/payment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/payment/admin.py b/core/apps/payment/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/core/apps/payment/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/core/apps/payment/apps.py b/core/apps/payment/apps.py new file mode 100644 index 0000000..c6790be --- /dev/null +++ b/core/apps/payment/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PaymentConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core.apps.payment' diff --git a/core/apps/payment/migrations/__init__.py b/core/apps/payment/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/payment/models.py b/core/apps/payment/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/core/apps/payment/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/core/apps/payment/tests.py b/core/apps/payment/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/core/apps/payment/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/core/apps/payment/urls.py b/core/apps/payment/urls.py new file mode 100644 index 0000000..36cc7be --- /dev/null +++ b/core/apps/payment/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from .views import AtmosCallbackApiView + +urlpatterns = [ + path('callback/', AtmosCallbackApiView.as_view()), +] \ No newline at end of file diff --git a/core/apps/payment/views.py b/core/apps/payment/views.py new file mode 100644 index 0000000..2cbaf41 --- /dev/null +++ b/core/apps/payment/views.py @@ -0,0 +1,72 @@ +import hashlib + +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status + +from core.apps.orders.models import Order + +API_KEY = "ATMOS_API_KEY" +ALLOWED_ATMOS_IPS = ["185.8.212.47"] + + +def get_client_ip(request): + x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") + if x_forwarded_for: + ip = x_forwarded_for.split(",")[0] + else: + ip = request.META.get("REMOTE_ADDR") + return ip + + +class AtmosCallbackApiView(APIView): + authentication_classes = [] + permission_classes = [] + + def post(self, request): + client_ip = get_client_ip(request) + if client_ip not in ALLOWED_ATMOS_IPS: + return Response({"status": 0, "message": "IP ruxsat etilmagan"}, status=403) + data = request.data + if not data: + return Response( + {'success': 0, "message": "Request body required"}, + status=status.HTTP_200_OK + ) + + store_id = data.get("store_id") + transaction_id = data.get("transaction_id") + invoice = data.get("invoice") + amount = data.get("amount") + sign = data.get("sign") + + check_string = f"{store_id}{transaction_id}{invoice}{amount}{API_KEY}" + generated_sign = hashlib.sha256(check_string.encode()).hexdigest() + + if generated_sign != sign: + return Response( + {"status": 0, "message": f"Инвойс с номером {invoice} отсутствует в системе"}, + status=status.HTTP_200_OK + ) + + try: + order = Order.objects.get(id=invoice) + except Order.DoesNotExist: + return Response( + {"status": 0, "message": f"Инвойс с номером {invoice} отсутствует в системе"}, + status=status.HTTP_200_OK + ) + + if str(order.total_price) != str(amount): + return Response( + {"status": 0, "message": f"Инвойс с номером {invoice} отсутствует в системе"}, + status=status.HTTP_200_OK + ) + + order.is_paid = True + order.save() + + return Response( + {"status": 1, "message": "Успешно"}, + status=status.HTTP_200_OK + )