This commit is contained in:
eric
2025-12-17 06:36:07 -06:00
parent 5abfc71ba7
commit b739553f06
3 changed files with 62 additions and 100 deletions

Binary file not shown.

View File

@@ -1,122 +1,84 @@
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware
import requests
import hashlib
from urllib.parse import urlencode, unquote
import time
"""
JSAPI 支付
"""
key = "zA2hBU6pv6CIBzkW" # 填写通信密钥
mchid = "1561724891" # 特写商户号
# memos 配置
# MEMOS_API = "https://memos.hackrobot.org/api/v1/users"
# MEMOS_TOKEN = "eyJhbGciOiJIUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiaGFja3JvYm90IiwiaXNzIjoibWVtb3MiLCJzdWIiOiIxIiwiYXVkIjpbInVzZXIuYWNjZXNzLXRva2VuIl0sImlhdCI6MTc1NzQwNTE0OX0.Idn7kBlxE-CoSOXwWuZ1tHGIRKHAIeDyXSafGS5OHsg"
MEMOS_API = "https://qun.hackrobot.cn/api/v1/users"
MEMOS_TOKEN = "eyJhbGciOiJIUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiaGFja3JvYm90IiwiaXNzIjoibWVtb3MiLCJzdWIiOiIxIiwiYXVkIjpbInVzZXIuYWNjZXNzLXRva2VuIl0sImlhdCI6MTc1NzQwNTE0OX0.Idn7kBlxE-CoSOXwWuZ1tHGIRKHAIeDyXSafGS5OHsg"
# 构造签名函数
def sign(attributes):
attributes_new = {k: attributes[k] for k in sorted(attributes.keys())}
return (hashlib.md5((unquote(urlencode(attributes_new)) + "&key=" +
key).encode(encoding="utf-8")).hexdigest().upper())
class Item(BaseModel):
event: str
EventGroupMsg: None = None
prirobot_wxidce: None = None
type: None = None
# event
# "":"EventGroupMsg",//事件标示(当前值为群消息事件)
# "robot_wxid":"wxid_5hxa04j4z6pg22",//机器人wxid
# "robot_name":"",//机器人昵称,一般为空
# "type":1,//1/文本消息 3/图片消息 34/语音消息 42/名片消息 43/视频 47/动态表情 48/地理位置 49/分享链接 2000/转账 2001/红包 2002/小程序 2003/群邀请
# "from_wxid":"18900134932@chatroom",//群id群消息事件才有
# "from_name":"微群测",//群名字
# "final_from_wxid":"sundreamer",//发该消息的用户微信id
# "final_from_name":"遗忘悠剑o",//微信昵称
# "to_wxid":"wxid_5hxa04j4z6pg22",//接收消息的人id一般是机器人收到了也有可能是机器人发出的消息别人收到了那就是别人
# "msg":"图片https://b3logfile.com/bing/20201024.jpg",//消息内容(string/array) 使用时候根据不同的事件标示来定义这个值,字符串类型或者数据类型
# "money":0.01 //金额,只有"EventReceivedTransfer"事件才有该参数
import urllib.parse
import random
import string
app = FastAPI()
# 允许所有来源跨域访问(不推荐用于生产环境)
origins = ["*"]
# 设置CORS跨域资源共享策略
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允许所有来源
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"], # 允许所有方法
allow_headers=["*"], # 允许所有请求头
allow_methods=["*"],
allow_headers=["*"],
)
# ==================== XorPay 配置 ====================
AID = "8220" # 你的 aid
SECRET = "afcacd99570945f88de62624aaa3578e" # 你的 app secret
CASHIER_URL = f"https://xorpay.com/api/cashier/{AID}" # 收银台接口
# ====================================================
@app.get("/")
async def root():
return JSONResponse(content={"message": "Hello World"})
# 官方推荐签名方式(严格无分隔符拼接)
def xorpay_sign(name: str, pay_type: str, price: str, order_id: str, notify_url: str) -> str:
raw = name + pay_type + price + order_id + notify_url + SECRET
return hashlib.md5(raw.encode('utf-8')).hexdigest().lower()
@app.post("/payh5")
async def payh5(item: dict):
print('item', item)
# 时间戳
timenew = str(int(time.time()))
order = {
"mchid": mchid,
"body": timenew, # 订单标题
"out_trade_no": timenew, # 订单号
"total_fee": item['total_fee'], # 金额,单位:分
# "openid": "o7LFAwWu3OhSrs49-1x5cSlFm0D8", # 通过openid接口获取到的openid
# "notify_url": ""
# "callback_url":'https://aiimg.hackrobot.cn/api'
print('payh5 item:', item)
total_fee_yuan = f"{item['total_fee'] / 100:.2f}"
random_suffix = ''.join(random.choices(string.hexdigits.lower(), k=8))
order_id = f"order_{int(time.time())}_{random_suffix}"
type_map = {
"book": "购买书籍",
"meetup": "活动报名",
"video": "视频解锁",
"vip": "VIP会员充值",
}
name = type_map.get(item.get('type'), "商品支付")
notify_url = "https://www.hackrobot.cn".rstrip("/")
# 临时不传 return_url避免 ngrok 干扰
# return_url = item.get('callback_url')
params = {
"name": name,
"pay_type": "jsapi",
"price": total_fee_yuan,
"order_id": order_id,
"notify_url": notify_url,
}
order["callback_url"] = item['callback_url']
order["openid"] = item['openid']
order["sign"] = sign(order)
# if return_url:
# params["return_url"] = return_url
request_url = "https://payjs.cn/api/jsapi"
# 返回结果中包含`jsapi`字段该字段的值即是前端发起时所需的6个支付参数
headers = {"content-type": "application/x-www-form-urlencoded"}
response = requests.post(request_url, data=order, headers=headers)
print('response.json()----',response.json())
if response:
print(response.json())
return response.json()
params["sign"] = xorpay_sign(
params["name"],
params["pay_type"],
params["price"],
params["order_id"],
params["notify_url"]
)
print("生成的参数:", params)
class CreateUserRequest(BaseModel):
username: str = None
password: str = None
@app.post("/create_user")
async def create_user(item: CreateUserRequest):
timenew = str(int(time.time()))
memos_data = {
"username": item.username or f"user{timenew}",
"password": item.password or "123456",
"role": "USER",
"state": "NORMAL"
# 返回参数字典,前端用 form POST
return {
"status": "ok",
"xorpay_params": params,
"xorpay_url": f"https://xorpay.com/api/cashier/{AID}"
}
memos_headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {MEMOS_TOKEN}"
}
memos_resp = requests.post(MEMOS_API, json=memos_data, headers=memos_headers)
memos_result = memos_resp.json()
print('memos_result-',memos_result)
return memos_result
# 异步通知回调
@app.post("/xorpay_notify")
async def xorpay_notify(request: dict):
print("XorPay 异步通知:", request)
# TODO: 正式上线后加验签和订单处理
return {"status": "ok"}