import requests from django.conf import settings from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from datetime import datetime from .models import Order, Plan, User import json from .base import logger def get_paypal_access_token(): """获取 PayPal 访问令牌""" print("正在获取 PayPal 访问令牌...") # 根据配置文件选择 PayPal URL paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com" url = f"{paypal_base_url}/v1/oauth2/token" auth = ( settings.PAYPAL_CLIENT_ID_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.PAYPAL_CLIENT_ID_PRODUCTION, settings.PAYPAL_SECRET_KEY_SANDBOX if settings.PAYPAL_MODE == 'sandbox' else settings.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: access_token = response.json().get('access_token') logger.info(f"[支付执行] 获取的访问令牌: {access_token}") print(f"获取的访问令牌: {access_token}") return access_token else: logger.error(f"[支付执行] 获取 PayPal 访问令牌失败: {response.text}") print(f"获取 PayPal 访问令牌失败: {response.text}") return None @csrf_exempt def create_paypal_payment(request): """创建 PayPal 支付""" if request.method == 'POST': try: print("创建 PayPal 支付开始...") data = json.loads(request.body) plan_id = data.get('plan_id') payment_method = data.get('payment_method', 'paypal') # 获取当前用户信息 user = request.user # 验证用户和计划是否存在 if not user.is_authenticated: print("用户未认证") return JsonResponse({"code": 401, "message": "用户未认证", "data": {}}) try: plan = Plan.objects.get(id=plan_id) print(f"找到的套餐: {plan.title}") except Plan.DoesNotExist: print("套餐不存在") return JsonResponse({"code": 400, "message": "套餐不存在", "data": {}}) access_token = get_paypal_access_token() if not access_token: return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}}) # 配置支付请求 url = f"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": f"{settings.PAYPAL_RETURN_URL}", "cancel_url": f"{settings.PAYPAL_CANCEL_URL}" }, "transactions": [{ "item_list": { "items": [{ "name": plan.title, "sku": str(plan.id), "price": str(plan.price), "currency": "USD", "quantity": 1 }] }, "amount": { "total": str(plan.price), "currency": "USD" }, "description": f"购买 {plan.title} 计划" }] } print(f"支付请求Payload: {json.dumps(payload, indent=2)}") response = requests.post(url, headers=headers, json=payload) if response.status_code == 201: payment_id = response.json().get('id') approval_url = None for link in response.json().get('links', []): if link.get('rel') == "approval_url": approval_url = link.get('href') break # 检查订单是否已经存在,防止重复创建订单 if Order.objects.filter(order_id=payment_id).exists(): return JsonResponse({"code": 400, "message": "订单已存在", "data": {}}) # 创建订单并使用PayPal返回的paymentId作为order_id order = Order.objects.create( order_id=payment_id, # 使用PayPal的支付ID作为订单ID user=user, username=user.username, plan=plan, amount=plan.price, payment_method=payment_method, status='pending' ) print(f"订单创建成功,订单ID: {order.order_id}") if approval_url: print(f"支付批准URL: {approval_url}") return JsonResponse({"code": 200, "message": "支付创建成功", "data": {"approval_url": approval_url}}) else: print("未找到支付批准URL") return JsonResponse({"code": 400, "message": "未找到支付批准URL", "data": {}}) else: print(f"支付创建失败: {response.status_code}, {response.json()}") return JsonResponse({"code": 400, "message": "支付创建失败", "data": response.json()}) except json.JSONDecodeError: print("请求体不是有效的JSON") return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}}) except Exception as e: print(f"支付创建过程中发生异常: {str(e)}") return JsonResponse({"code": 500, "message": f"支付创建过程中发生异常: {str(e)}", "data": {}}) else: return JsonResponse({"code": 405, "message": "方法不允许", "data": {}}) @csrf_exempt def execute_paypal_payment(request): """执行 PayPal 支付""" if request.method == 'POST': try: logger.info("[支付执行] 接收到来自前端的 POST 请求,开始处理支付...") # 解析请求体 data = json.loads(request.body) payment_id = data.get('paymentId') payer_id = data.get('PayerID') logger.info(f"[支付执行] 请求内容: paymentId={payment_id}, PayerID={payer_id}") print(f"请求内容: paymentId={payment_id}, PayerID={payer_id}") if not payment_id or not payer_id: logger.error("[支付执行] 缺少支付ID或付款人ID") return JsonResponse({"code": 400, "message": "缺少支付ID或付款人ID", "data": {}}) # 获取订单信息 try: order = Order.objects.get(order_id=payment_id) logger.info(f"[支付执行] 获取到的订单信息: {order}") except Order.DoesNotExist: logger.error("[支付执行] 订单不存在") return JsonResponse({"code": 400, "message": "订单不存在", "data": {}}) # 检查订单是否已经支付 if order.status == 'completed': logger.info(f"[支付执行] 订单 {payment_id} 已支付,无需再次执行") print(f"订单 {payment_id} 已支付,无需再次执行") return JsonResponse({"code": 400, "message": "订单已支付", "data": {}}) # 获取 PayPal 访问令牌 access_token = get_paypal_access_token() if not access_token: logger.error("[支付执行] 无法获取支付访问令牌") return JsonResponse({"code": 500, "message": "无法获取支付访问令牌", "data": {}}) logger.info(f"[支付执行] 获取到的 PayPal 访问令牌: {access_token}") # 设置 PayPal API 请求的 URL 和头部信息 paypal_base_url = "https://api.sandbox.paypal.com" if settings.PAYPAL_MODE == 'sandbox' else "https://api.paypal.com" url = f"{paypal_base_url}/v1/payments/payment/{payment_id}/execute" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {access_token}" } payload = { "payer_id": payer_id } logger.info(f"[支付执行] 发送支付请求,URL: {url}, 请求头: {headers}, 请求体: {payload}") print(f"发送支付请求,URL: {url}, 请求体: {payload}") # 执行 PayPal 支付请求 response = requests.post(url, headers=headers, json=payload) # 打印 PayPal API 请求的响应 logger.info(f"[支付执行] PayPal API 响应状态码: {response.status_code}") print(f"PayPal API 响应状态码: {response.status_code}") logger.info(f"[支付执行] PayPal API 响应内容: {response.json()}") print(f"PayPal API 响应内容: {response.json()}") # 判断支付是否成功 if response.status_code == 200: payment_data = response.json() if payment_data['state'] == 'approved': logger.info(f"[支付执行] 支付成功,订单状态更新为 'approved'") # 确保订单未完成过 if order.status != 'completed': order.status = 'completed' order.updated_at = datetime.now() order.save() # 获取用户当前积分并进行累加 user = order.user current_points = user.points if user.points else 0 # 防止积分为 None added_points = order.plan.credits_per_month user.points = current_points + added_points user.save() # 打印用户当前积分、购买的套餐和增加的积分 logger.info(f"[支付执行] 用户 {user.username} 当前积分: {current_points}") logger.info(f"[支付执行] 购买的套餐: {order.plan.title}") logger.info(f"[支付执行] 增加的积分: {added_points}") logger.info(f"[支付执行] 用户新的总积分: {user.points}") print(f"用户 {user.username} 当前积分: {current_points}") print(f"购买的套餐: {order.plan.title}") print(f"增加的积分: {added_points}") print(f"新的总积分: {user.points}") return JsonResponse({"code": 200, "message": "支付成功,积分已更新", "data": {}}) else: logger.info(f"[支付执行] 订单 {payment_id} 已支付,无需再次更新积分") return JsonResponse({"code": 400, "message": "订单已支付,积分不重复增加", "data": {}}) else: logger.error(f"[支付执行] 支付未完成,状态为: {payment_data['state']}") print(f"支付未完成,状态为: {payment_data['state']}") return JsonResponse({"code": 400, "message": "支付状态未完成", "data": payment_data}) else: logger.error(f"[支付执行] 支付执行失败,状态码: {response.status_code}") print(f"支付执行失败,状态码: {response.status_code}") return JsonResponse({"code": 400, "message": "支付执行失败", "data": response.json()}) except json.JSONDecodeError: logger.error("[支付执行] 请求体不是有效的 JSON 格式") return JsonResponse({"code": 400, "message": "请求体不是有效的JSON", "data": {}}) except Exception as e: logger.error(f"[支付执行] 支付执行过程中发生异常: {str(e)}") print(f"支付执行过程中发生异常: {str(e)}") return JsonResponse({"code": 500, "message": f"支付执行过程中发生异常: {str(e)}", "data": {}}) else: logger.error(f"[支付执行] 请求方法 {request.method} 不被允许") return JsonResponse({"code": 405, "message": "方法不允许", "data": {}})