bugfix
This commit is contained in:
parent
dcf7a239d4
commit
1cbe37d4a3
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# 统一支付
|
||||||
|
|
||||||
|
支持微信,支付宝,paypal支持
|
||||||
|
|
||||||
|
## 支付重要信息
|
||||||
|
支付重要信息都通过环境变量设置
|
||||||
|
|
||||||
|
### 微信支付
|
||||||
|
|
||||||
|
### 支付宝
|
||||||
|
|
||||||
|
### paypal
|
||||||
|
|
||||||
16
json/payment_log.json
Normal file
16
json/payment_log.json
Normal 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
BIN
models/payment_log.xlsx
Normal file
Binary file not shown.
4
pyproject.toml
Normal file
4
pyproject.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
15
setup.cfg
Normal file
15
setup.cfg
Normal 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
|
||||||
Binary file not shown.
@ -1,7 +1,8 @@
|
|||||||
# init.py
|
# init.py
|
||||||
import os
|
import os
|
||||||
from unipay.notify import get_provider
|
from unipay.notify import get_provider, get_provider_channel
|
||||||
from ahserver.serverenv import ServerEnv
|
from ahserver.serverenv import ServerEnv
|
||||||
|
from paylog import PaymentLog
|
||||||
|
|
||||||
# 从 env 或配置载入 provider conf(这里只示例)
|
# 从 env 或配置载入 provider conf(这里只示例)
|
||||||
CONF = {
|
CONF = {
|
||||||
@ -40,8 +41,21 @@ async def create_payment(request, params_kw=None):
|
|||||||
if provider not in PROVIDERS:
|
if provider not in PROVIDERS:
|
||||||
return {"error":"unknown provider"}
|
return {"error":"unknown provider"}
|
||||||
try:
|
try:
|
||||||
res = await PROVIDERS[provider].create_payment(data)
|
pl = PaymentLog(request._run_ns)
|
||||||
return res
|
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:
|
except Exception as e:
|
||||||
return {"error": str(e)}
|
return {"error": str(e)}
|
||||||
|
|
||||||
@ -86,6 +100,9 @@ async def payment_notify(request, callback, params_kw=None):
|
|||||||
# 这里 data 应包含标准化字段:out_trade_no/status/attach 等
|
# 这里 data 应包含标准化字段:out_trade_no/status/attach 等
|
||||||
# TODO: 业务幂等处理
|
# TODO: 业务幂等处理
|
||||||
# 返回厂商要求的固定成功响应
|
# 返回厂商要求的固定成功响应
|
||||||
|
logid = data['out_trade_no']
|
||||||
|
pl = PaymentLog(request._run_ns)
|
||||||
|
await pl.payed_log(logid)
|
||||||
await callback(request, data)
|
await callback(request, data)
|
||||||
if provider == "wechat":
|
if provider == "wechat":
|
||||||
return {"code":"SUCCESS", "message":"OK"}
|
return {"code":"SUCCESS", "message":"OK"}
|
||||||
|
|||||||
@ -6,6 +6,16 @@ from .providers.alipay import AlipayGateway
|
|||||||
from .providers.stripe import StripeGateway
|
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):
|
def get_provider(name: str, conf: Dict):
|
||||||
if name == "wechat":
|
if name == "wechat":
|
||||||
return WechatGateway(**conf)
|
return WechatGateway(**conf)
|
||||||
|
|||||||
48
unipay/paylog.py
Normal file
48
unipay/paylog.py
Normal 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
15
wwwroot/menu.ui
Normal 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
9
wwwroot/recharge.dspy
Normal 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
74
wwwroot/recharge.ui
Normal 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":{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user