72 lines
2.8 KiB
Python
72 lines
2.8 KiB
Python
import json
|
||
import hmac
|
||
import hashlib
|
||
import requests
|
||
import time
|
||
import random
|
||
from urllib.parse import quote
|
||
|
||
# ================= 您的配置(请核对) =================
|
||
APP_ID = "wx2517043ca3f39677"
|
||
APP_SECRET = "056060b6b13379622f4871acf8dfacc6" # <--- 必须填写
|
||
OFFER_ID = "1450521456"
|
||
APPKEY = "4cQkc13i7rkFNbubUJ63ijP2MMCrpB45" # 现网AppKey
|
||
ENV = 0 # 现网环境
|
||
PRODUCT_ID = "spgm1001"
|
||
OPENID = "ohZdR3fHwVHgQXPSEyIax9Fxqew8"
|
||
OUT_TRADE_NO = f"TEST{int(time.time())}{random.randint(100,999)}"
|
||
# =====================================================
|
||
|
||
# 1. 获取 access_token
|
||
def get_access_token(appid, secret):
|
||
url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}"
|
||
resp = requests.get(url, timeout=10).json()
|
||
if "access_token" in resp:
|
||
return resp["access_token"]
|
||
else:
|
||
raise Exception(f"获取token失败: {resp}")
|
||
|
||
print("正在获取 access_token...")
|
||
token = get_access_token(APP_ID, APP_SECRET)
|
||
print(f"access_token 获取成功: {token[:20]}...")
|
||
|
||
# 2. 准备查询订单接口参数
|
||
uri = "/xpay/query_order"
|
||
post_data = {
|
||
"offer_id": OFFER_ID,
|
||
"openid": OPENID,
|
||
"out_trade_no": OUT_TRADE_NO,
|
||
"env": ENV
|
||
}
|
||
body = json.dumps(post_data, separators=(',', ':'), ensure_ascii=False)
|
||
|
||
# 3. 严格按照官方算法计算 pay_sig
|
||
msg = uri + "&" + body
|
||
pay_sig = hmac.new(APPKEY.encode('utf-8'), msg.encode('utf-8'), hashlib.sha256).hexdigest()
|
||
print(f"计算的 pay_sig: {pay_sig}")
|
||
|
||
# 4. 调用查询订单接口(签名放在 URL 参数中,已验证有效)
|
||
request_url = f"https://api.weixin.qq.com{uri}?access_token={token}&pay_sig={pay_sig}"
|
||
headers = {"Content-Type": "application/json"}
|
||
print(f"请求 URL: {request_url}")
|
||
resp = requests.post(request_url, data=body, headers=headers, timeout=10)
|
||
result = resp.json()
|
||
print("微信返回:")
|
||
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||
|
||
# 5. 结论分析
|
||
errcode = result.get("errcode", -1)
|
||
if errcode == 0:
|
||
print("\n🎉 查询订单成功!您的 Offer ID、AppKey、签名算法完全正确。")
|
||
print("问题出在客户端,请检查:")
|
||
print("1. 手机微信版本是否最新(8.0.68+)")
|
||
print("2. 小程序基础库是否 ≥ 2.19.2")
|
||
print("3. 前端 wx.requestVirtualPayment 的 signData 是否为字符串")
|
||
print("4. 是否在真机 Android/iOS 上扫码测试,而不是开发者工具")
|
||
elif errcode == 268490002:
|
||
print("\n❌ 签名错误,请核对 AppKey 是否与后台环境一致。")
|
||
elif "OFFER_ID_INVALID" in result.get("errmsg", ""):
|
||
print("\n💀 仍然报 OFFER_ID_INVALID,这是微信侧的未解之谜。")
|
||
print("请将本脚本完整输出截图,联系微信客服,要求技术团队核查 offer_id 内部状态。")
|
||
else:
|
||
print(f"\n其他错误,错误码: {errcode},信息: {result.get('errmsg')}") |