201 lines
6.3 KiB
Python
201 lines
6.3 KiB
Python
|
|
# -*- 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
|