django实现paypal订阅记录
开发者链接 登录开发者
沙箱账号链接 沙箱账号链接
1. 创建沙箱应用
2. 记录 Client ID和 Secret 后面有用 然后点击进去创建回调url和回调事件,可以全选事件也可以选择你需要的
3.拿沙箱账号信息去登录
4.登录后创建订阅产品内容。记住产品id
5.配置django后端信息和创建订阅链接进行支付
import requests
from datetime import datetime
# 配置 PayPal 凭据和环境
PAYPAL_CLIENT_ID_SANDBOX = '沙箱SANDBOX'
PAYPAL_SECRET_KEY_SANDBOX = '沙箱密钥'
PAYPAL_CLIENT_ID_PRODUCTION = '' # 替换为实际生产环境的客户端 ID
PAYPAL_SECRET_KEY_PRODUCTION = '' # 替换为实际生产环境的密钥
PAYPAL_MODE = 'sandbox' # 'sandbox' 或 'live'
PAYPAL_BASE_URL = "https://api.sandbox.paypal.com" if PAYPAL_MODE == "sandbox" else "https://api.paypal.com"
# 工具函数:生成自定义订单号
def generate_order_id():
"""
根据当前时间生成唯一订单号
格式:P-YYYYMMDD-HHMMSS
"""
current_time = datetime.now().strftime("%Y%m%d-%H%M%S")
return f"P-{current_time}"
# 工具函数:获取 PayPal 访问令牌
def get_paypal_access_token():
"""
获取 PayPal API 访问令牌
"""
url = f"{PAYPAL_BASE_URL}/v1/oauth2/token"
auth = (PAYPAL_CLIENT_ID_SANDBOX, PAYPAL_SECRET_KEY_SANDBOX)
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:
raise Exception(f"获取访问令牌失败: {response.text}")
# 创建 PayPal 订阅链接
def create_paypal_subscription_link(plan_id):
"""
使用 PayPal API 创建订阅链接
:param plan_id: 示例计划 ID (如: P-4KL07437GC7241026M5AW2JY)
:return: 订阅链接 URL
"""
try:
# 获取访问令牌
access_token = get_paypal_access_token()
# PayPal 订阅 API URL
subscription_url = f"{PAYPAL_BASE_URL}/v1/billing/subscriptions"
# 自定义订单号
custom_order_id = generate_order_id()
# 构建订阅请求的 payload
payload = {
"plan_id": plan_id,
"custom_id": custom_order_id,
"application_context": {
"brand_name": "Your Brand Name",
"user_action": "SUBSCRIBE_NOW",
"landing_page": "BILLING",
"return_url": f"支付成功跳转的url",
"cancel_url": f"取消支付跳转的url",
}
}
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
# 发送请求以创建订阅
response = requests.post(subscription_url, json=payload, headers=headers)
if response.status_code in [200, 201]:
# 提取审批链接
subscription_data = response.json()
approval_url = next(link["href"] for link in subscription_data["links"] if link["rel"] == "approve")
print(f"订阅链接生成成功: {approval_url}")
return approval_url
else:
print(f"创建订阅链接失败: {response.text}")
return None
except Exception as e:
print(f"创建订阅链接时发生错误: {e}")
return None
# 示例调用
if __name__ == "__main__":
PLAN_ID = "P-4KL07437GC7241026M5AW2JY" # 示例计划 ID
approval_url = create_paypal_subscription_link(PLAN_ID)
if approval_url:
print(f"请访问以下链接以完成订阅: {approval_url}")
else:
print("无法生成订阅链接,请检查配置或 API 调用。")
6.订阅成功后回调
当用户进入approval_url 付款成功后会回调到给个前面创建的回调链接。测试付款的账号也在开发者后台生成自行付款测试。最后后端再根据不同的回调类型操作数据库即可
def paypal_webhook(request):
"""
PayPal Webhook 回调入口
"""
try:
# 解析请求体
webhook_data = json.loads(request.body.decode("utf-8"))
print("[Webhook] 收到数据:", json.dumps(webhook_data, indent=4))
event_type = webhook_data.get("event_type")
resource = webhook_data.get("resource")
webhook_id = webhook_data.get("id")
print(f"[Webhook] 事件类型: {event_type}, Webhook ID: {webhook_id}")
handle_webhook_event(event_type, resource, webhook_id)
except Exception as e:
print(f"[Webhook] 错误: {str(e)}")
return JsonResponse({"code": 500, "message": f"服务器错误: {str(e)}"})
def handle_webhook_event(event_type, resource, webhook_id):
"""
处理 PayPal Webhook 回调事件
:param event_type: 回调事件类型(如 BILLLING.SUBSCRIPTION.ACTIVATED)
:param resource: 事件的资源数据(JSON 格式)
:param webhook_id: PayPal Webhook ID,用于验证请求合法性
"""
print(f"[Webhook 回调] 收到事件: {event_type}, Webhook ID: {webhook_id}")
if event_type == "BILLING.SUBSCRIPTION.ACTIVATED":
# 处理订阅激活事件
print("[Webhook 回调] 事件类型: 订阅已激活")
print(f"[Webhook 回调] 资源数据: {resource}")
handle_subscription_activated(resource, webhook_id)
elif event_type == "BILLING.SUBSCRIPTION.UPDATED":
# 处理订阅更新事件
print("[Webhook 回调] 事件类型: 订阅已更新")
print(f"[Webhook 回调] 资源数据: {resource}")
handle_subscription_updated(resource, webhook_id)
elif event_type == "BILLING.SUBSCRIPTION.CANCELLED":
# 处理订阅取消事件
print("[Webhook 回调] 事件类型: 订阅已取消")
print(f"[Webhook 回调] 资源数据: {resource}")
handle_subscription_cancelled(resource, webhook_id)
elif event_type == "PAYMENT.SALE.COMPLETED":
# 处理付款完成事件
print("[Webhook 回调] 事件类型: 付款已完成")
print(f"[Webhook 回调] 资源数据: {resource}")
handle_payment_completed(resource, webhook_id)
else:
# 未知的事件类型
print(f"[Webhook 回调] 未知事件类型: {event_type}")
print(f"[Webhook 回调] 资源数据: {resource}")
7.最后为了安全性建议在生产环境对回调进行验签再操作。有其它疑问可以互相交流