ai_admin/WebAdmin/ali_pay.py
2024-09-20 04:29:09 +00:00

332 lines
13 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import traceback
from decimal import Decimal
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.domain.AlipayTradeAppPayModel import AlipayTradeAppPayModel
from alipay.aop.api.domain.AlipayTradePagePayModel import AlipayTradePagePayModel
from alipay.aop.api.request.AlipayTradePagePayRequest import AlipayTradePagePayRequest
from alipay.aop.api.request.AlipayTradeAppPayRequest import AlipayTradeAppPayRequest
from .models import Order, User, Plan
from datetime import datetime
from alipay.aop.api.domain.AlipayTradeWapPayModel import AlipayTradeWapPayModel
from alipay.aop.api.request.AlipayTradeWapPayRequest import AlipayTradeWapPayRequest
import requests
from decimal import Decimal, getcontext
# 设置 Decimal 的精度
getcontext().prec = 28
def get_usd_to_cny_rate():
a = 7.2
return a
def get_alipay_client_config(client_type='pc'):
"""
根据环境和客户端类型返回支付宝配置
"""
alipay_client_config = AlipayClientConfig()
if settings.ALIPAY_DEBUG:
print('请求沙箱支付')
alipay_client_config.server_url = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do'
if client_type == 'pc':
alipay_client_config.app_id = settings.ALIPAY_APP_ID_SANDBOX_PC
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_SANDBOX_PC
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_SANDBOX_PC
elif client_type == 'mobile':
alipay_client_config.app_id = settings.ALIPAY_APP_ID_SANDBOX_MOBILE
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_SANDBOX_MOBILE
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_SANDBOX_MOBILE
else:
print('请求生产支付')
alipay_client_config.server_url = 'https://openapi.alipay.com/gateway.do'
if client_type == 'pc':
alipay_client_config.app_id = settings.ALIPAY_APP_ID_PRODUCTION_PC
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_PRODUCTION_PC
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_PRODUCTION_PC
elif client_type == 'mobile':
alipay_client_config.app_id = settings.ALIPAY_APP_ID_PRODUCTION_MOBILE
alipay_client_config.app_private_key = settings.ALIPAY_APP_PRIVATE_KEY_PRODUCTION_MOBILE
alipay_client_config.alipay_public_key = settings.ALIPAY_PUBLIC_KEY_PRODUCTION_MOBILE
return alipay_client_config
def convert_cny_to_usd(price_cny):
"""
将人民币价格转换为美元价格
:param price_cny: 人民币价格
:return: 美元价格,保留两位小数
"""
# 获取美元对人民币的汇率
usd_to_cny_rate = get_usd_to_cny_rate()
print("原价:", price_cny)
print("汇率:", usd_to_cny_rate)
return (Decimal(price_cny) * Decimal(usd_to_cny_rate)).quantize(Decimal('0.00'))
@csrf_exempt
def create_alipay_order(request):
"""
创建支付宝订单并生成支付链接(电脑端)
"""
try:
# 检查用户是否已登录
if not request.user.is_authenticated:
print("用户未登录")
return JsonResponse({"code": 401, "message": "用户未登录"})
# 获取前端传递的数据
data = json.loads(request.body)
print(f"接收到的请求数据: {data}")
plan_title = data.get('title')
price = Decimal(data.get('price')) # 将价格转换为 Decimal 类型
plan_id = data.get('id')
# 从数据库获取对应的套餐信息
plan = Plan.objects.get(id=plan_id)
print(f"数据库中获取的套餐信息: {plan}")
if not plan:
print("套餐信息不存在")
return JsonResponse({"code": 400, "message": "套餐信息不存在"})
# 检查汇率是否有效
# 获取美元对人民币的汇率
usd_to_cny_rate = get_usd_to_cny_rate()
if not usd_to_cny_rate:
print("无法进行价格转换,汇率不可用")
return JsonResponse({"code": 500, "message": "汇率不可用,无法创建订单"})
# 将套餐的人民币价格转换为美元价格
plan_price_usd = convert_cny_to_usd(plan.price)
# 将人民币价格转换为美元价格
price_usd = convert_cny_to_usd(price)
# 比较转换后的美元价格
if not price_usd or plan_price_usd != price_usd:
print(f"{plan_price_usd}套餐信息不匹配或价格不正确{price_usd}")
return JsonResponse({"code": 400, "message": "套餐信息不匹配或价格不正确"})
final_price = price_usd
# 获取当前用户信息
user = request.user
# 生成订单
order_id = f"order_{datetime.now().strftime('%Y%m%d%H%M%S')}_{user.id}"
order = Order.objects.create(
order_id=order_id,
user=user,
plan=plan,
username=user.username,
amount=final_price,
payment_method='alipay',
status='pending'
)
print(f"创建的订单信息: {order}")
# 获取支付宝电脑端客户端配置
alipay_client_config = get_alipay_client_config(client_type='pc')
client = DefaultAlipayClient(alipay_client_config=alipay_client_config)
# 构造支付宝支付请求对象
model = AlipayTradePagePayModel()
model.out_trade_no = order_id # 订单ID
model.total_amount = str(final_price) # 订单金额
model.subject = plan_title # 商品名称
model.product_code = "FAST_INSTANT_TRADE_PAY" # 产品码
print(f"生成订单请求体: {model}")
request = AlipayTradePagePayRequest(biz_model=model)
request.notify_url = settings.ALIPAY_NOTIFY_URL # 异步通知URL
request.return_url = settings.ALIPAY_RETURN_URL # 同步返回URL
print(f"回调地址: {settings.ALIPAY_NOTIFY_URL}")
response = client.page_execute(request, http_method="GET")
print(f"支付宝请求响应: {response}")
# 返回支付URL
return JsonResponse({"code": 200, "message": "订单创建成功", "data": {'alipay_url': response}})
except Exception as e:
print(f"创建订单时出错: {traceback.format_exc()}")
return JsonResponse({"code": 500, "message": f"创建订单时出错: {str(e)}"})
@csrf_exempt
def create_alipay_h5_order(request):
"""
创建支付宝H5订单并生成支付链接
"""
try:
# 检查用户是否已登录
if not request.user.is_authenticated:
return JsonResponse({"code": 401, "message": "用户未登录"})
# 获取前端传递的数据
data = json.loads(request.body)
plan_id = data.get('id')
plan_title = data.get('title')
price = Decimal(data.get('price')) # 将价格转换为 Decimal 类型
# 获取对应套餐信息
plan = Plan.objects.get(id=plan_id)
if not plan:
return JsonResponse({"code": 400, "message": "套餐信息不存在"})
# 检查汇率是否有效
# 获取美元对人民币的汇率
usd_to_cny_rate = get_usd_to_cny_rate()
if not usd_to_cny_rate:
print("无法进行价格转换,汇率不可用")
return JsonResponse({"code": 500, "message": "汇率不可用,无法创建订单"})
# 将套餐的人民币价格转换为美元价格
plan_price_usd = convert_cny_to_usd(plan.price)
# 将人民币价格转换为美元价格
price_usd = convert_cny_to_usd(price)
# 比较转换后的美元价格
if not price_usd or plan_price_usd != price_usd:
return JsonResponse({"code": 400, "message": "套餐信息不匹配或价格不正确"})
final_price = price_usd
# 创建订单
user = request.user
order_id = f"order_{datetime.now().strftime('%Y%m%d%H%M%S')}_{user.id}"
order = Order.objects.create(
order_id=order_id,
user=user,
plan=plan,
username=user.username,
amount=final_price,
payment_method='alipay',
status='pending'
)
# 获取支付宝H5客户端配置
alipay_client_config = get_alipay_client_config(client_type='mobile')
client = DefaultAlipayClient(alipay_client_config=alipay_client_config)
# 构造支付宝H5支付请求对象
model = AlipayTradeWapPayModel()
model.out_trade_no = order_id
model.total_amount = str(final_price)
model.subject = plan_title
model.product_code = "QUICK_WAP_WAY"
request = AlipayTradeWapPayRequest(biz_model=model)
request.notify_url = settings.ALIPAY_NOTIFY_URL # 异步通知URL
request.return_url = settings.ALIPAY_RETURN_URL # 同步返回URL
# 执行请求获取支付宝H5支付跳转链接
response = client.page_execute(request, http_method="GET")
return JsonResponse({"code": 200, "message": "订单创建成功", "data": {'alipay_url': response}})
except Exception as e:
return JsonResponse({"code": 500, "message": f"创建H5订单时出错: {str(e)}"})
def update_user_membership(order):
"""
更新用户积分信息
"""
try:
# 验证订单状态是否为成功
if order.status not in ("completed", "TRADE_SUCCESS", "TRADE_FINISHED"):
print("订单未成功")
return False
# 从订单中获取关联的套餐信息
plan = order.plan
# 检查汇率是否有效
# 获取美元对人民币的汇率
usd_to_cny_rate = get_usd_to_cny_rate()
if not usd_to_cny_rate:
print("无法进行价格转换,汇率不可用")
return False
# 将订单金额从美元转换回人民币
order_amount_cny = order.amount
# 确保订单的套餐与实际套餐详情匹配
if not plan or convert_cny_to_usd(plan.price) != order_amount_cny:
print(f"订单的套餐信息与实际套餐不匹配plan.price{plan.price}---")
return False
# 获取用户信息
user = order.user
# 更新用户的积分
user.points += plan.credits_per_month
user.save()
print(f"用户 {user.username} 的积分已更新")
return True
except Exception as e:
print(f"更新用户积分信息时出错: {e}")
return False
@csrf_exempt
def alipay_notify(request):
"""
支付宝异步通知处理,验证支付结果
"""
try:
data = request.POST.dict()
print(f"接收到的异步通知数据: {data}")
# 直接使用返回的数据处理逻辑
order_id = data.get('out_trade_no')
trade_status = data.get('trade_status')
print(f"订单ID: {order_id}, 支付状态: {trade_status}")
try:
order = Order.objects.get(order_id=order_id)
except Order.DoesNotExist:
print(f"订单 {order_id} 不存在")
return JsonResponse({"code": 400, "message": "订单不存在"})
if trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
order.status = 'completed'
order.save()
print(f"订单 {order_id} 支付成功")
update_user_membership(order)
return JsonResponse({"code": 200, "message": "支付成功"})
else:
order.status = 'failed'
order.save()
print(f"订单 {order_id} 支付失败或未成功")
return JsonResponse({"code": 400, "message": "支付未成功或失败"})
except Exception as e:
print(f"处理异步通知时出错: {traceback.format_exc()}")
return JsonResponse({"code": 500, "message": f"处理异步通知时出错: {str(e)}"})
@csrf_exempt
def alipay_return(request):
"""
支付宝同步返回处理,用于用户支付后的页面跳转
"""
try:
data = request.GET.dict()
print(f"接收到的同步返回数据: {data}")
# 直接使用返回的数据处理逻辑
order_id = data.get('out_trade_no')
print(f"订单 {order_id} 支付成功")
return JsonResponse({"code": 200, "message": f"支付成功,订单号:{order_id}"})
except Exception as e:
print(f"处理同步返回时出错: {traceback.format_exc()}")
return JsonResponse({"code": 500, "message": f"处理同步返回时出错: {str(e)}"})