ai_v/services/alipay_service.py
公司git 1196809c6a feat(payment): 添加订单状态同步功能和主动查询接口
- 在 app.py 中集成定时任务,每分钟同步最近30分钟内待支付订单状态
- 定时任务调用支付宝接口更新订单状态及用户积分,记录日志
- payment.py 新增主动查询订单接口,支持用户手动触发订单状态同步
- 添加订单简单查询API,返回订单当前状态信息
- 支付异步通知日志记录优化,改为系统日志记录
- 配置文件中调整支付宝回调地址使用 HTTPS 协议
- alipay_service.py 增加支付宝订单状态查询方法,支持主动轮询订单状态
2026-01-23 17:40:23 +08:00

98 lines
4.0 KiB
Python
Raw 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.

from alipay import AliPay
from flask import current_app
import os
import logging
logger = logging.getLogger(__name__)
class AlipayService:
def __init__(self):
self.app_id = current_app.config.get('ALIPAY_APP_ID')
self.private_key = current_app.config.get('ALIPAY_APP_PRIVATE_KEY')
self.public_key = current_app.config.get('ALIPAY_PUBLIC_KEY')
self.return_url = current_app.config.get('ALIPAY_RETURN_URL')
self.notify_url = current_app.config.get('ALIPAY_NOTIFY_URL')
self.debug = current_app.config.get('ALIPAY_DEBUG', True)
def get_alipay_client(self):
"""获取支付宝客户端实例"""
return AliPay(
appid=self.app_id,
app_notify_url=self.notify_url,
app_private_key_string=self.private_key,
alipay_public_key_string=self.public_key,
sign_type="RSA2",
debug=self.debug
)
def create_order_url(self, out_trade_no, total_amount, subject):
"""生成支付链接 (电脑网站支付)"""
alipay = self.get_alipay_client()
order_string = alipay.api_alipay_trade_page_pay(
out_trade_no=out_trade_no,
total_amount=str(total_amount),
subject=subject,
return_url=self.return_url,
notify_url=self.notify_url
)
# 拼接支付网关 (使用最新的支付宝沙箱域名)
gateway = "https://openapi-sandbox.dl.alipaydev.com/gateway.do" if self.debug else "https://openapi.alipay.com/gateway.do"
return f"{gateway}?{order_string}"
def verify_notify(self, data, signature):
"""验证通知签名"""
try:
if not signature or not data:
logger.error("签名或数据为空")
return False
# 创建数据副本
verify_data = data.copy()
# python-alipay-sdk 的 verify 方法会自动处理 sign 的移除
# 但为了保险,我们手动移除它,保留其他所有字段
verify_data.pop('sign', None)
verify_data.pop('sign_type', None)
alipay = self.get_alipay_client()
# 对于同步回调sign_type 实际上是参与签名的(某些版本/接口)
# 对于异步通知sign_type 通常不参与签名
# alipay.verify 会根据情况处理 sign_type
result = alipay.verify(verify_data, signature)
if not result:
logger.error("签名验证失败")
logger.error(f"待验证数据: {verify_data}")
logger.error(f"签名值: {signature}")
logger.error(f"使用的公钥前50位: {self.public_key[:50]}...")
# 检查公钥是否可能是应用公钥而非支付宝公钥
if self.private_key and self.public_key:
logger.warning("提示:如果签名持续验证失败,请确认 ALIPAY_PUBLIC_KEY 是“支付宝公钥”而非“应用公钥”")
else:
logger.info("签名验证成功")
return result
except Exception as e:
logger.error(f"验证签名时发生异常: {str(e)}", exc_info=True)
return False
def query_order_status(self, out_trade_no):
"""查询订单状态 - 主动查询支付宝获取真实支付状态"""
try:
alipay = self.get_alipay_client()
# 调用支付宝订单查询接口
result = alipay.api_alipay_trade_query(out_trade_no=out_trade_no)
if result:
logger.info(f"订单查询成功: {out_trade_no}, 状态: {result.get('trade_status')}")
return result
else:
logger.warning(f"订单查询返回为空: {out_trade_no}")
return None
except Exception as e:
logger.error(f"查询订单状态异常: {str(e)}", exc_info=True)
return None