Bootstrap

django实现贝宝支付收款记录

示例教程代码,可以用作演示 PayPal 支付集成的基本流程。

import requests
import json
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt

# PayPal 配置信息
PAYPAL_MODE = 'sandbox'  # 'sandbox' 或 'live'
PAYPAL_CLIENT_ID_SANDBOX = 'your-sandbox-client-id'
PAYPAL_SECRET_KEY_SANDBOX = 'your-sandbox-secret-key'
PAYPAL_CLIENT_ID_PRODUCTION = 'your-production-client-id'
PAYPAL_SECRET_KEY_PRODUCTION = 'your-production-secret-key'
PAYPAL_RETURN_URL = "https://your-return-url.com"
PAYPAL_CANCEL_URL = "https://your-cancel-url.com"


def get_paypal_access_token():
    """获取 PayPal 访问令牌"""
    paypal_base_url = "https://api.sandbox.paypal.com" if PAYPAL_MODE == 'sandbox' else "https://api.paypal.com"
    url = f"{paypal_base_url}/v1/oauth2/token"

    auth = (
        PAYPAL_CLIENT_ID_SANDBOX if PAYPAL_MODE == 'sandbox' else PAYPAL_CLIENT_ID_PRODUCTION,
        PAYPAL_SECRET_KEY_SANDBOX if PAYPAL_MODE == 'sandbox' else PAYPAL_SECRET_KEY_PRODUCTION,
    )

    headers = {
        "Accept": "application/json",
        "Accept-Language": "en_US",
    }
    data = {"grant_type": "client_credentials"}

    response = requests.post(url, headers=headers, data=data, auth=auth)
    if response.status_code == 200:
        return response.json().get('access_token')
    else:
        print(f"获取 PayPal 访问令牌失败: {response.text}")
        return None


@csrf_exempt
def create_paypal_payment(request):
    """创建 PayPal 支付"""
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            plan_title = data.get('plan_title', 'Default Plan')
            plan_price = data.get('plan_price', 10.0)  # 默认价格为 10.0 USD

            access_token = get_paypal_access_token()
            if not access_token:
                return JsonResponse({"code": 500, "message": "无法获取支付访问令牌"})

            url = f"https://api.sandbox.paypal.com/v1/payments/payment" if PAYPAL_MODE == 'sandbox' else "https://api.paypal.com/v1/payments/payment"
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {access_token}",
            }
            payload = {
                "intent": "sale",
                "payer": {"payment_method": "paypal"},
                "redirect_urls": {
                    "return_url": PAYPAL_RETURN_URL,
                    "cancel_url": PAYPAL_CANCEL_URL,
                },
                "transactions": [{
                    "item_list": {
                        "items": [{
                            "name": plan_title,
                            "price": f"{plan_price:.2f}",
                            "currency": "USD",
                            "quantity": 1,
                        }]
                    },
                    "amount": {"total": f"{plan_price:.2f}", "currency": "USD"},
                    "description": f"购买 {plan_title}",
                }],
            }

            response = requests.post(url, headers=headers, json=payload)

            if response.status_code == 201:
                payment_id = response.json().get('id')
                approval_url = next(
                    (link.get('href') for link in response.json().get('links', []) if link.get('rel') == "approval_url"),
                    None
                )
                return JsonResponse({"code": 200, "message": "支付创建成功", "data": {"approval_url": approval_url}})
            else:
                return JsonResponse({"code": 400, "message": "支付创建失败", "data": response.json()})

        except json.JSONDecodeError:
            return JsonResponse({"code": 400, "message": "请求体不是有效的JSON"})
        except Exception as e:
            return JsonResponse({"code": 500, "message": f"支付创建过程中发生异常: {str(e)}"})
    else:
        return JsonResponse({"code": 405, "message": "方法不允许"})


@csrf_exempt
def execute_paypal_payment(request):
    """执行 PayPal 支付"""
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            payment_id = data.get('paymentId')
            payer_id = data.get('PayerID')

            if not payment_id or not payer_id:
                return JsonResponse({"code": 400, "message": "缺少支付ID或付款人ID"})

            access_token = get_paypal_access_token()
            if not access_token:
                return JsonResponse({"code": 500, "message": "无法获取支付访问令牌"})

            url = f"https://api.sandbox.paypal.com/v1/payments/payment/{payment_id}/execute" if PAYPAL_MODE == 'sandbox' else f"https://api.paypal.com/v1/payments/payment/{payment_id}/execute"
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {access_token}",
            }
            payload = {"payer_id": payer_id}

            response = requests.post(url, headers=headers, json=payload)

            if response.status_code == 200:
                payment_data = response.json()
                if payment_data.get('state') == 'approved':
                    return JsonResponse({"code": 200, "message": "支付成功"})
                else:
                    return JsonResponse({"code": 400, "message": "支付未完成", "data": payment_data})
            else:
                return JsonResponse({"code": 400, "message": "支付执行失败", "data": response.json()})

        except json.JSONDecodeError:
            return JsonResponse({"code": 400, "message": "请求体不是有效的JSON"})
        except Exception as e:
            return JsonResponse({"code": 500, "message": f"支付执行过程中发生异常: {str(e)}"})
    else:
        return JsonResponse({"code": 405, "message": "方法不允许"})

用法说明

  1. 设置 PayPal 配置:将 PAYPAL_CLIENT_ID_SANDBOXPAYPAL_SECRET_KEY_SANDBOX 替换为你的 PayPal 测试应用凭据。
  2. 运行项目:将代码保存到你的 Django 应用中,访问 /create_paypal_payment/ 创建支付,访问 /execute_paypal_payment/ 执行支付。
  3. 测试请求
    • POST /create_paypal_payment/
      {
        "plan_title": "高级会员",
        "plan_price": 20.0
      }
      
    • 支付完成后重定向链接会携带这两个参数,拿这两个参数去请求执行支付接口
    • POST /execute_paypal_payment/
    • {
        "paymentId": "PAYMENT_ID_FROM_PAYPAL",
        "PayerID": "PAYER_ID_FROM_PAYPAL"
      }
      

  

是生产环境建议在加上webhook验证 

;