Kamixitong/app/utils/alipay.py

201 lines
6.3 KiB
Python
Raw Normal View History

2025-12-12 11:35:14 +08:00
# -*- coding: utf-8 -*-
"""
支付宝支付工具类
"""
from alipay import AliPay
from flask import current_app
from datetime import datetime
class AlipayHelper:
"""支付宝支付助手类"""
def __init__(self, app=None):
"""
初始化支付宝客户端
:param app: Flask应用实例
"""
self.alipay = None
if app:
self.init_app(app)
def init_app(self, app):
"""
初始化支付宝配置
:param app: Flask应用实例
"""
config = app.config
# 检查必要的配置
required_configs = [
'ALIPAY_APP_ID',
'ALIPAY_PRIVATE_KEY',
'ALIPAY_PUBLIC_KEY',
'ALIPAY_ALIPAY_PUBLIC_KEY'
]
missing_configs = [cfg for cfg in required_configs if not config.get(cfg)]
if missing_configs:
raise ValueError(f"缺少必要的支付宝配置: {', '.join(missing_configs)}")
# 初始化支付宝客户端
self.alipay = AliPay(
appid=config['ALIPAY_APP_ID'],
app_private_key=config['ALIPAY_PRIVATE_KEY'],
alipay_public_key=config['ALIPAY_ALIPAY_PUBLIC_KEY'],
sign_type=config.get('ALIPAY_SIGN_TYPE', 'RSA2'),
charset=config.get('ALIPAY_CHARSET', 'utf-8'),
gateway=config.get('ALIPAY_GATEWAY', 'https://openapi.alipay.com/gateway.do')
)
def create_payment_url(self, order_number, amount, subject, notify_url, return_url):
"""
创建支付宝支付链接
:param order_number: 订单号
:param amount: 支付金额
:param subject: 支付主题
:param notify_url: 异步通知URL
:param return_url: 同步返回URL
:return: 支付链接
"""
if not self.alipay:
raise ValueError("支付宝客户端未初始化")
# 构建订单参数
order_params = {
'out_trade_no': order_number, # 商户订单号
'total_amount': str(amount), # 订单总金额
'subject': subject, # 订单标题
'body': f'订单{order_number}的支付', # 订单描述
'product_code': 'FAST_INSTANT_TRADE_PAY', # 产品代码
}
# 生成支付链接
payment_url = self.alipay.trade_page_pay(
total_amount=str(amount),
subject=subject,
out_trade_no=order_number,
return_url=return_url,
notify_url=notify_url
)
# 构建完整的支付URL
gateway = self.alipay.gateway
full_payment_url = f"{gateway}?{payment_url}"
return full_payment_url
def create_wap_payment_url(self, order_number, amount, subject, notify_url, return_url):
"""
创建手机网站支付链接
:param order_number: 订单号
:param amount: 支付金额
:param subject: 支付主题
:param notify_url: 异步通知URL
:param return_url: 同步返回URL
:return: 支付链接
"""
if not self.alipay:
raise ValueError("支付宝客户端未初始化")
# 生成支付链接
payment_url = self.alipay.trade_wap_pay(
total_amount=str(amount),
subject=subject,
out_trade_no=order_number,
return_url=return_url,
notify_url=notify_url
)
# 构建完整的支付URL
gateway = self.alipay.gateway
full_payment_url = f"{gateway}?{payment_url}"
return full_payment_url
def query_order_status(self, order_number):
"""
查询订单支付状态
:param order_number: 订单号
:return: 订单状态信息
"""
if not self.alipay:
raise ValueError("支付宝客户端未初始化")
try:
result = self.alipay.alipay_trade_query(
out_trade_no=order_number
)
return result
except Exception as e:
current_app.logger.error(f"查询支付宝订单状态失败: {str(e)}")
return None
def verify_notification(self, data, signature):
"""
验证支付宝异步通知签名
:param data: 通知数据
:param signature: 签名
:return: 验证结果
"""
if not self.alipay:
raise ValueError("支付宝客户端未初始化")
try:
# 验证签名
return self.alipay.verify(data, signature)
except Exception as e:
current_app.logger.error(f"验证支付宝通知签名失败: {str(e)}")
return False
def verify_trade_status(self, notify_data):
"""
验证交易状态
:param notify_data: 通知数据
:return: 验证结果和交易状态
"""
if not self.alipay:
raise ValueError("支付宝客户端未初始化")
try:
# 验证签名
if not self.alipay.verify(notify_data, notify_data.get('sign')):
return False, None
# 检查交易状态
trade_status = notify_data.get('trade_status')
if trade_status in ['TRADE_SUCCESS', 'TRADE_FINISHED']:
return True, trade_status
else:
return False, trade_status
except Exception as e:
current_app.logger.error(f"验证支付宝交易状态失败: {str(e)}")
return False, None
def get_trade_state(self, order_number):
"""
获取交易状态
:param order_number: 订单号
:return: 交易状态
"""
result = self.query_order_status(order_number)
if not result:
return None
# 根据支付宝返回的状态码判断
code = result.get('code')
if code == '10000': # 接口调用成功
trade_status = result.get('trade_status')
if trade_status == 'TRADE_SUCCESS':
return 'SUCCESS'
elif trade_status == 'TRADE_FINISHED':
return 'FINISHED'
elif trade_status == 'TRADE_CLOSED':
return 'CLOSED'
elif trade_status == 'WAIT_BUYER_PAY':
return 'WAIT_PAY'
elif code == '40004': # 业务处理失败
return 'NOT_EXIST'
return None