This commit is contained in:
yumoqing 2025-12-20 20:47:08 +08:00
parent 5748eb7d76
commit cfd7fea195
5 changed files with 189 additions and 8 deletions

View File

@ -11,6 +11,36 @@
},
"editexclouded": [
"id"
],
"toolbar":{
"tools":[
{
"name":"refund",
"label":"退费",
"url":"{{entire_url('../refund.ui')}}"
}
]
},
"binds":[
"wid":"self",
"event":"refund",
"actiontype":"urlwidget",
"target":"PopupWindow",
"popup_options":{
{% if params_kw._is_mobile %}
"width":"100%",
"height":"90%",
{% else %}
"width": "40%",
"height":"80%",
{% endif %}
"archor": "cc"
},
"options":{
"url":"{{entire_url('../refund.ui')}}",
"params": {
}
}
]
}
}

View File

@ -69,7 +69,7 @@ async def create_payment(request, params_kw=None):
amount = data.amount
currency = data.currency
plog = await pl.new_log(userid, orgid, provider,
payment_name, amount,
amount,
fee, client_ip, currency=currency)
if plog:
data.out_trade_no = plog.id
@ -109,16 +109,26 @@ async def query_payment(request, params_kw=None):
async def refund_payment(request, params_kw=None):
if params_kw is None:
params_kw = request.params_kw
data = params_kw
provider = data.get("provider")
data = await get_refundable_plog(request, params_kw.id)
if data is None:
return None
if params_kw.amount >= data.total_amount:
return None
provider = data.channelid
if provider not in PROVIDERS:
return {"error":"unknown provider"}
try:
plog = await new_refund_log(request, data.amount, data.id)
if PROVIDERS[provider] is None:
e = Exception(f'{provider} cannot pay')
exception(f'{e}')
raise e
res = await PROVIDERS[provider].refund(data)
plog.out_trade_no = plog.origin_id
plog.out_request_no = plog.id
plog.total_amount = params_kw.amount
plog.refund_amount = plog.total_amount
plog.notify_url = request.env.entire_url(f'notify/{provider}')
res = await PROVIDERS[provider].refund(plog)
return res
except Exception as e:
exception(f'query_payment():{params_kw}, {e}')

View File

@ -1,9 +1,16 @@
from sqlor.dbpools import DBPools
from sqlor.dbpools import DBPools, get_sor_context
from appPublic.timeUtils import timestampstr
from appPublic.log import debug, exception
from appPublic.dictObject import DictObject
from ahserver.serverenv import ServerEnv
RECHARGE="充值"
REFUND ="退费"
payment_names = [
RECHARGE,
REFUND
]
class PaymentLog:
def __init__(self, env):
self.db = DBPools()
@ -11,14 +18,15 @@ class PaymentLog:
async def new_log(self,
userid, customerid, channel,
payment_name, amount, feerate,
amount, feerate,
client_ip, currency='CNY'):
dbname = self.env.get_module_dbname('unipay')
async with self.db.sqlorContext(dbname) as sor:
return await self.sor_new_log(sor, userid, customerid, channel,
payment_name, amount, feerate,
amount, feerate,
client_ip, currency=currency)
return None
async def sor_new_log(self, sor,
userid, customerid, channel,
payment_name, amount, feerate,
@ -28,7 +36,7 @@ class PaymentLog:
"id": self.env.uuid(),
"customerid": customerid,
"channelid": channel,
"payment_name": payment_name,
"payment_name": RECHARGE,
"payer_client_ip": client_ip,
"amount_total": amount,
"pay_feerate": feerate,
@ -72,6 +80,64 @@ class PaymentLog:
return None
return None
async def get_refundable_plog(request, id):
db = DBPools()
env = request._run_ns
orgid = await get_userorgid()
dbname = env.get_module_dbname('unipay')
async with db.sqlorContext(dbname) as sor:
recs = await sor.R('payment_log', {'id':id,
'customerid': orgid,
'payment_status'
})
if len(recs) < 1:
debug(f'id({id}) not exists in payment_log or not belong you')
return None
origin_plog = recs[0]
if origin_plog.payment_status == '0':
debug(f'id({id}) payment status 0')
return None
if origin_plog.origin_id:
debug(f'id({id}) is a refund plog')
return None
recs = await sor.R('payment_log', {'origin_id': id})
amt = origin_plog.total_amount
for l in recs:
amt -= l.total_amount
if amt <= 0:
return None
origin_plog.total_amount = amt
return origin_plog
exception(f'{db.except}')
return None
async def new_refund_log(request, amount, origin_id):
env = ServerEnv()
async with get_sor_context(env, 'unipay') as sor:
recs = await sor.R('payment_log', {'id': origin_id})
if len(recs) < 1:
raise Exception(f'{origin_id} not a payment_log')
ol = recs[0]
ns = {
"id": env.uuid(),
"customerid": ol.customerid,
"channelid": ol.channel,
"payment_name": REFUND,
"payer_client_ip": ol.client_ip,
"amount_total": amount,
"pay_feerate": 0.0,
"pay_fee": 0.0,
"currency": ol.currency,
"payment_status": '0',
"init_timestamp": timestampstr(),
"payed_timestamp": "2000-01-01 00:00:00.001",
"cancel_timestamp": "2000-01-01 00:00:00.001",
"userid": userid,
"origin_id": origin_id
}
await sor.C('payment_log', ns.copy())
return DictObject(**ns)
async def unipay_accounting(request, data):
logid = data.out_trade_no
trade_id = data.trade_no

20
wwwroot/refund.dspy Normal file
View File

@ -0,0 +1,20 @@
# refund.dspy
debug(f'refund.dspy: {params_kw=}')
params_kw.amount = float(params_kw.amount)
plog = await get_refundable_plog(request, parmas_kw.id)
if plog is None:
return {
"widgettype": "Text",
"options":{
"i18n":true,
"width":"100%",
"wrap":true,
"otext":"不可退费"
}
}
if params_kw.amount > plog.total_amount:
return {
}
plog.total_amount = params_kw.amount

55
wwwroot/refund.ui Normal file
View File

@ -0,0 +1,55 @@
{% if params_kw.id %}
{% set plog = get_refundable_plog(request, params_kw.id) %}
{% if plog %}
{
"widgettype":"Form",
"options":{
"description":"输入退费金额,缺省为本最多可退金额",
"width": "100%",
"fields":[
{
"name":"id",
"uitype":"hide",
"value":"{{plog.id}}"
},
{
"name": "amount",
"label": "退费金额",
"uitype":"float",
"defaultvalue": {{plog.amount}}
}
]
},
"binds":[
{
"wid":"self",
"event":"submit",
"actiontype":"urlwidget",
"target": "self",
"options":{
"url":"{{entire_url('refund.dspy')}}"
}
}
]
}
{% else %}
{
"widgettype":"Text",
"options":{
"i18n":true,
"width":"100%",
"otext":"本地充值已退费",
"wrap": true
}
}
{% endif %}
{% else %}
{
"widgettype": "Text",
"options":{
"i18n": true
"width": "100%",
"otext": "需要选定一条记录"
}
}
{% endif %}