使用二维码进行支付宝交易

This commit is contained in:
2026-07-09 19:50:40 +08:00
parent 0826b0749d
commit 51edcf9fce
2 changed files with 101 additions and 8 deletions

View File

@@ -234,6 +234,90 @@ def build_wap_pay_url(out_trade_no, amount, subject, body='', club_id=None, expi
return f"{cfg['GATEWAY']}?{query_string}"
# ==================== 当面付二维码precreate====================
def build_precreate_qr(out_trade_no, amount, subject, body='', club_id=None, expire_minutes=30):
"""
调用 alipay.trade.precreate 生成当面付二维码链接。
与 wap.pay 不同precreate 是服务器主动 POST 调用,返回 qr_code 链接,
由商户自行生成二维码展示;用户用支付宝 APP 扫码完成支付。
适用于微信小程序等无法跳转 alipay:// scheme 的环境。
返回:
dict: {'qr_code': 'https://qr.alipay.com/...', 'out_trade_no': ...}
失败抛异常。
"""
import requests
cfg = get_alipay_config(club_id)
biz_content = {
'out_trade_no': out_trade_no,
'total_amount': str(amount),
'subject': subject or '订单支付',
'body': body or '',
'timeout_express': f'{expire_minutes}m',
}
params = {
'app_id': cfg['APP_ID'],
'method': 'alipay.trade.precreate',
'charset': 'utf-8',
'sign_type': 'RSA2',
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
'version': '1.0',
'biz_content': json.dumps(biz_content, separators=(',', ':'), ensure_ascii=False),
'notify_url': cfg['NOTIFY_URL'],
}
# 签名sign_type 参与签名,与 wap.pay 一致)
sign_content = _build_sign_content(params)
params['sign'] = sign_rsa2(sign_content, cfg['APP_PRIVATE_KEY'])
# 服务器主动调用网关
resp = requests.post(cfg['GATEWAY'], data=params, timeout=10)
try:
result = resp.json()
except Exception:
raise Exception(f"支付宝 precreate 返回非 JSON: {resp.text[:500]}")
biz_resp = result.get('alipay_trade_precreate_response', {})
code = biz_resp.get('code', '')
if code == '10000':
return {
'qr_code': biz_resp.get('qr_code', ''),
'out_trade_no': biz_resp.get('out_trade_no', out_trade_no),
}
# 失败:拼接完整错误信息
sub_code = biz_resp.get('sub_code', '')
sub_msg = biz_resp.get('sub_msg', '')
raise Exception(
f"支付宝预下单失败: code={code}, msg={biz_resp.get('msg', '')}, "
f"sub_code={sub_code}, sub_msg={sub_msg}"
)
def qr_link_to_base64(qr_link):
"""
把二维码链接内容转成 PNG base64 data URI供前端 image 直接展示)。
依赖 qrcode + Pillow缺失时抛 ImportError 提示安装。
"""
import io
import base64
try:
import qrcode
except ImportError:
raise ImportError("缺少 qrcode 库,请执行: pip install qrcode[pil]")
img = qrcode.make(qr_link)
buf = io.BytesIO()
img.save(buf, format='PNG')
return 'data:image/png;base64,' + base64.b64encode(buf.getvalue()).decode('ascii')
# ==================== 辅助 ====================
def club_id_from_order(order_id):