This commit is contained in:
yumoqing 2025-12-12 13:54:26 +08:00
parent dcf7a239d4
commit 1cbe37d4a3
12 changed files with 224 additions and 3 deletions

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# 统一支付
支持微信支付宝paypal支持
## 支付重要信息
支付重要信息都通过环境变量设置
### 微信支付
### 支付宝
### paypal

16
json/payment_log.json Normal file
View File

@ -0,0 +1,16 @@
{
"tblname": "payment_log",
"title": "充值记录",
"params": {
"sortby": "init_timestamp desc",
"browserfields": {
"exclouded": ["id"],
"logined_userorgid":"customerid",
"alters": {
}
},
"editexclouded": [
"id"
]
}
}

BIN
models/payment_log.xlsx Normal file

Binary file not shown.

4
pyproject.toml Normal file
View File

@ -0,0 +1,4 @@
[build-system]
requires = ["setuptools>=61", "wheel"]
build-backend = "setuptools.build_meta"

15
setup.cfg Normal file
View File

@ -0,0 +1,15 @@
[metadata]
name=pricing
version = 0.0.1
description = A pricing module for online store
author = "yu moqing"
author_email = "yumoqing@gmail.com"
readme = "README.md"
license = "MIT"
[options]
packages = find:
requires_python = ">=3.8"
install_requires =
apppublic
ahserver
sqlor

View File

@ -1,7 +1,8 @@
# init.py
import os
from unipay.notify import get_provider
from unipay.notify import get_provider, get_provider_channel
from ahserver.serverenv import ServerEnv
from paylog import PaymentLog
# 从 env 或配置载入 provider conf这里只示例
CONF = {
@ -40,8 +41,21 @@ async def create_payment(request, params_kw=None):
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)}
@ -86,6 +100,9 @@ async def payment_notify(request, callback, params_kw=None):
# 这里 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"}

View File

@ -6,6 +6,16 @@ from .providers.alipay import AlipayGateway
from .providers.stripe import StripeGateway
# 简单工厂:你可以按需扩展配置注入
def get_provider_channel(name:str):
channels = {
"wechat":"0",
"paypal":"1",
"alipay":"2",
"stripe":"3"
}
return channels.get(name, '9')
def get_provider(name: str, conf: Dict):
if name == "wechat":
return WechatGateway(**conf)

48
unipay/paylog.py Normal file
View File

@ -0,0 +1,48 @@
from sqlor.dbpools import DBPools
class PaymentLog:
def __init__(self, env):
self.db = DBPools()
self.env = env
async def new_log(self, userid, customerid, channel, payment_name, amount, client_ip, currency='CNY'):
dbname = await self.env.get_module_dbname('unipay')
async with self.db.sqlorContext(dbname) as sor:
ns = {
"id": self.env.uuid(),
"customerid": customerid,
"payment_channel": channel,
"payment_name": payment_name,
"payer_client_ip": client_ip,
"currency": currency,
"payment_status": '0',
"init_timestamp": timestampstr(),
"userid": userid
}
await sor.C('payment_log', ns)
return True
return False
async def cancel_log(self, logid):
dbname = await self.env.get_module_dbname('unipay')
async with self.db.sqlorContext(dbname) as sor:
ns = {
"id": logid,
"cancel_timestamp": timestampstr()
}
await sor.U('payment_log', ns)
return True
return False
async def payed_log(self, logid):
dbname = await self.env.get_module_dbname('unipay')
async with self.db.sqlorContext(dbname) as sor:
ns = {
"id": logid,
"payed_timestamp": timestampstr()
}
await sor.U('payment_log', ns)
return True
return False

15
wwwroot/menu.ui Normal file
View File

@ -0,0 +1,15 @@
{
"widgettype":"Menu",
"items":[
{
"name":"recharge",
"label":"充值",
"url":"{{entire_url('recharge.ui')}}"
},
{
"name":"payment_log",
"label":"充值历史",
"url":"{{entire_url('payment_log')}}"
}
]
}

9
wwwroot/recharge.dspy Normal file
View File

@ -0,0 +1,9 @@
url = await create_payment(request)
return {
"widgettype":"Iframe",
"options":{
"url": url,
"height": "100%",
"width":"100%"
}
}

74
wwwroot/recharge.ui Normal file
View File

@ -0,0 +1,74 @@
{
"widgettype":"Form",
"options":{
"width": "100%",
"height": "100%",
"fields":[
{
"name":"provider",
"uitype":"code",
"required":true,
"defautvalue":"wechat",
"label":"充值渠道",
"data":[
{
"value":"wechat",
"text":"微信支付"
},
{
"value":"alipay",
"text":"支付宝"
}
]
},
{
"name":"amount",
"label":"充值金额",
"required":true,
"uitype":"float",
"lenght":18,
"dec":2
},
{
"name":"currency",
"label":"币种",
"uitype":"code",
"defaultvalue":"CNY",
"data":[
{
"value":"CNY",
"text":"人民币"
},
{
"value":"USD",
"text": "美元"
}
]
}
]
},
"binds":[
{
"wid": "self",
"evnet":"submit",
"actiontype":"urlwidget",
"target":"PopupWindow",
"popup_options":{
{% if params_kw._is_mobile %}
"width": "95%",
"height": "95%",
{% else %}
"width": "50%",
"height": "50%",
{% endif %}
"archor":"cc"
},
"options":{
"url":"{{entire_url('recharge.dspy')}}",
"method":"POST",
"params":{}
}
}
]
}