unipay/unipay/init.py
2025-12-12 13:54:26 +08:00

127 lines
4.1 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.

# init.py
import os
from unipay.notify import get_provider, get_provider_channel
from ahserver.serverenv import ServerEnv
from paylog import PaymentLog
# 从 env 或配置载入 provider conf这里只示例
CONF = {
"wechat": {
"mchid": os.getenv("WXP_MCHID",""),
"serial_no": os.getenv("WXP_SERIAL",""),
"privkey_pem": open(os.getenv("WXP_PRIVKEY","./merchant_private_key.pem"),"rb").read(),
"platform_pub_pem": open(os.getenv("WXP_PLATFORM_PUB","./platform_pub.pem"),"rb").read(),
"api_v3_key": os.getenv("WXP_API_V3_KEY","").encode()
},
"paypal": {
"client_id": os.getenv("PP_ID",""),
"client_secret": os.getenv("PP_SECRET",""),
"sandbox": True
},
"alipay": {
"app_id": os.getenv("ALIPAY_APPID",""),
"privkey_pem": open(os.getenv("ALIPAY_PRIV","./alipay_priv.pem"),"rb").read(),
"alipay_pub_pem": open(os.getenv("ALIPAY_PUB","./alipay_pub.pem"),"rb").read(),
"sandbox": True
},
"stripe": {
"api_key": os.getenv("STRIPE_KEY","")
}
}
PROVIDERS = {}
# 下单接口(统一)
async def create_payment(request, params_kw=None):
if params_kw is None:
params_kw = request.paams_kw
data = params_kw
provider = data.get("provider")
if provider not in PROVIDERS:
return {"error":"unknown provider"}
try:
pl = PaymentLog(request._run_ns)
channel = get_provider_channel(provider)
userid = await get_suer()
orgid = await get_userorgid()
client_ip = request['client_ip']
# userid, customerid, channel, payment_name, amount, client_ip, currency='CNY'
payment_name = data.payment_name or "充值",
amount = data.amount
currency = data.currency
id = await pl.new_log(userid, orgid, payment_name, amount, client_ip, currency=currency)
if id:
data.out_trade_no = id
res = await PROVIDERS[provider].create_payment(data)
return res
raise Exception('write payment_log error')
except Exception as e:
return {"error": str(e)}
# 查询
async def query_payment(request, params_kw=None):
if params_kw is None:
params_kw = request.paams_kw
data = params_kw
provider = data.get("provider")
if provider not in PROVIDERS:
return {"error":"unknown provider"}
try:
res = await PROVIDERS[provider].query(data)
return res
except Exception as e:
return {"error": str(e)}
# 退款
async def refund_payment(request, params_kw=None):
if params_kw is None:
params_kw = request.paams_kw
data = params_kw
provider = data.get("provider")
if provider not in PROVIDERS:
return {"error":"unknown provider"}
try:
res = await PROVIDERS[provider].refund(data)
return res
except Exception as e:
return {"error": str(e)}
# 回调入口:你可把厂商回调用各自 endpoint 再转发到这里,或在厂商控制台按各自 URL 配置
async def payment_notify(request, callback, params_kw=None):
if params_kw is None:
params_kw = request.paams_kw
data = params_kw
provider = params_kw.provider
headers = dict(request.headers)
body = await request.text()
try:
data = await PROVIDERS[provider].handle_notify(headers, body)
# 这里 data 应包含标准化字段out_trade_no/status/attach 等
# TODO: 业务幂等处理
# 返回厂商要求的固定成功响应
logid = data['out_trade_no']
pl = PaymentLog(request._run_ns)
await pl.payed_log(logid)
await callback(request, data)
if provider == "wechat":
return {"code":"SUCCESS", "message":"OK"}
else:
return "OK"
except Exception as e:
return web.Response(status=500, text=str(e))
# callback url= "/unipay/notify/{provider}"
def load_unipay():
PROVIDERS["wechat"] = get_provider("wechat", CONF["wechat"]),
PROVIDERS["paypal"] = get_provider("paypal", CONF["paypal"]),
PROVIDERS["alipay"] = get_provider("alipay", CONF["alipay"]),
PROVIDERS["stripe"] = get_provider("stripe", CONF["stripe"])
env = ServerEnv()
env.payment_notify = payment_notify
env.create_payment = create_payment
env.query_payment = query_payment
env.refund_payment = refund_payment