Square Webhook не дает подтверждения, если платеж выполнен или не для Python-DjangoPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Square Webhook не дает подтверждения, если платеж выполнен или не для Python-Django

Сообщение Anonymous »

Я сталкиваюсь с критической проблемой, в которой мой бэкэнд django не может получить подтверждение от Square о том, был ли оплата завершен.
Вот подробности среды для справки:

[*] python: 3.13.2
django: 5.1.6. /> Square SDK: 43.0.0.20250618 < /li>
< /ul>
Сводка задачи: < /strong> < /p>
Поток процесса оплаты заключается в следующем: < /p>

. /> Это успешно генерирует страницу оформления в квадрате, где пользователь завершает платеж. Настроенный (https://api.mydomain.com/api/wallet/webhooks/square/) должен автоматически запускать Square, чтобы подтвердить оплату. Я проверил журналы сервера и постоянно получаю 401 несанкционированный ответ от попыток вызова Webhook Square. Информация:

Ниже приведен код бэкэнд, который я в настоящее время использую для обработки запросов CreateSquareorder, SquareWebHookView и VerifySquareorder. Я следил за последними руководящими принципами и лучшими практиками в соответствии с квадратной документацией: < /p>
import uuid
from decimal import Decimal
from django.utils import timezone
from django.conf import settings
from dateutil.relativedelta import relativedelta
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework import status
from square import Square
from square.environment import SquareEnvironment
import hmac
import hashlib
import base64
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from rest_framework.request import Request
from rest_framework.parsers import JSONParser
from users.models import CustomUser
from subscription.models import Subscription
from wallet.models import Wallet, Transaction, SecurityDeposit

DOMAIN = settings.DOMAIN
SQUARE_ACCESS_TOKEN = settings.SQUARE_ACCESS_TOKEN
SQUARE_LOCATION_ID = settings.SQUARE_LOCATION_ID
SQUARE_ENVIRONMENT = SquareEnvironment.PRODUCTION
SQUARE_WEBHOOK_SIGNATURE_KEY = settings.SQUARE_WEBHOOK_SIGNATURE_KEY

class CreateSquareOrder(APIView):
permission_classes = [IsAuthenticated]

def post(self, request):
user = request.user
amount = request.data.get("amount")
plan = request.data.get("plan")

if not amount or not plan:
return Response({"error": "Amount and plan are required"}, status=status.HTTP_400_BAD_REQUEST)

try:
client = Square(token=SQUARE_ACCESS_TOKEN, environment=SQUARE_ENVIRONMENT)
idempotency_key = str(uuid.uuid4())

response = client.checkout.payment_links.create(
idempotency_key=idempotency_key,
order={
"location_id": SQUARE_LOCATION_ID,
"line_items": [
{
"name": f"Plan {plan}",
"quantity": "1",
"base_price_money": {
"amount": int(float(amount) * 100),
"currency": "AUD"
}
}
],
"metadata": {
"user_id": str(user.id),
"plan": str(plan),
"amount": str(amount),
"purpose": "subscription"
}
},
checkout_options={
"redirect_url": f"{DOMAIN}/square-success",
"cancel_url": f"{DOMAIN}/square-cancel"
}
)

if response.errors:
return Response({
"error": "Failed to create Square checkout",
"details": response.errors
}, status=400)

return Response({"checkout_url": response.payment_link.url})

except Exception as e:
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@method_decorator(csrf_exempt, name='dispatch')
class SquareWebhookView(APIView):
permission_classes = []
def post(self, request):
signature = request.headers.get("X-Square-Signature", "")
request_body = request.body.decode()

if not is_valid_square_signature(signature, request_body, SQUARE_WEBHOOK_SIGNATURE_KEY):
return Response({"error": "Invalid signature"}, status=401)

event_type = request.data.get("type", "")
data = request.data.get("data", {}).get("object", {})
payment = data.get("payment", {})
payment_id = payment.get("id")
status_ = payment.get("status")

if event_type == "payment.updated" and status_ == "COMPLETED":
try:
new_request = Request(request._request, data={'payment_id': payment_id}, parsers=[JSONParser()])
return VerifySquareOrder().post(new_request)
except Exception as e:
print(f"Error processing payment webhook: {e}")
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

return Response(status=200)

def is_valid_square_signature(signature, request_body, signature_key):
key_bytes = bytes(signature_key, 'utf-8')
body_bytes = bytes(request_body, 'utf-8')
hmac_hash = hmac.new(key_bytes, body_bytes, hashlib.sha256).digest()
computed_signature = base64.b64encode(hmac_hash).decode()
return hmac.compare_digest(signature, computed_signature)

class VerifySquareOrder(APIView):
permission_classes = [AllowAny]

def post(self, request):
try:
payment_id = request.data.get("payment_id")
if not payment_id:
return Response({"error": "Payment ID is required"}, status=400)

client = Square(token=SQUARE_ACCESS_TOKEN, environment=SQUARE_ENVIRONMENT)
payment_response = client.payments.get_payment(payment_id=payment_id)

if payment_response.errors:
print(f"Square Payment API Errors: {payment_response.errors}")
return Response({"error": "Failed to retrieve Square payment", "details": payment_response.errors}, status=400)

payment_data = payment_response.payment
if payment_data.status != "COMPLETED":
return Response({"error": f"Payment not completed. Current status: {payment_data.status}"}, status=400)

order_id = payment_data.order_id
if not order_id:
return Response({"error": "Order ID not found for this payment."}, status=400)

order_response = client.orders.retrieve_order(order_id=order_id, location_id=SQUARE_LOCATION_ID)
if order_response.errors:
print(f"Square Order API Errors: {order_response.errors}")
return Response({"error": "Failed to retrieve Square order associated with payment", "details": order_response.errors}, status=400)

order_data = order_response.order
metadata = order_data.metadata

if not metadata:
return Response({"error": "Order metadata not found."}, status=400)

user = CustomUser.objects.get(id=metadata["user_id"])
wallet, _ = Wallet.objects.get_or_create(user=user)

amount = Decimal(metadata["amount"])
plan = int(metadata["plan"])
description = f"Square - {metadata.get('purpose', 'subscription')} [order_id:{order_id}, payment_id:{payment_id}]"

# Here i will create records that i need in my website

return Response({"message": "Payment verified and subscription activated."})

except CustomUser.DoesNotExist:
print("User not found based on metadata user_id.")
return Response({"error": "User specified in Square order metadata not found."}, status=404)
except Exception as e:
print(f"Error verifying Square order: {e}")
return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
< /code>
Что мне нужно: < /strong> < /p>

Не могли бы вы убедиться, почему Square возвращает ошибку 401 для URL -адреса WebHook? Процесс проверки платежей и синхронизации данных для всех пользователей. < /li>
< /ul>
Я бы признателен за вашу помощь и предложения. Спасибо, ребята,

Подробнее здесь: https://stackoverflow.com/questions/796 ... -to-python
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»