diff --git a/app/__pycache__/__init__.cpython-312.pyc b/app/__pycache__/__init__.cpython-312.pyc index 720495a..79cb13c 100644 Binary files a/app/__pycache__/__init__.cpython-312.pyc and b/app/__pycache__/__init__.cpython-312.pyc differ diff --git a/app/__pycache__/main.cpython-312.pyc b/app/__pycache__/main.cpython-312.pyc index e3f9559..e951125 100644 Binary files a/app/__pycache__/main.cpython-312.pyc and b/app/__pycache__/main.cpython-312.pyc differ diff --git a/app/main.py b/app/main.py index 6671ff3..e6b3ba4 100644 --- a/app/main.py +++ b/app/main.py @@ -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"} \ No newline at end of file