From cfd7fea195c496a28b21620d8b393dcf4b324a33 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sat, 20 Dec 2025 20:47:08 +0800 Subject: [PATCH] bugfix --- json/payment_log.json | 30 ++++++++++++++++++ unipay/init.py | 18 ++++++++--- unipay/paylog.py | 74 ++++++++++++++++++++++++++++++++++++++++--- wwwroot/refund.dspy | 20 ++++++++++++ wwwroot/refund.ui | 55 ++++++++++++++++++++++++++++++++ 5 files changed, 189 insertions(+), 8 deletions(-) create mode 100644 wwwroot/refund.dspy create mode 100644 wwwroot/refund.ui diff --git a/json/payment_log.json b/json/payment_log.json index 6b94237..776d526 100644 --- a/json/payment_log.json +++ b/json/payment_log.json @@ -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": { + } + } ] } } diff --git a/unipay/init.py b/unipay/init.py index d10f142..4a49bfb 100644 --- a/unipay/init.py +++ b/unipay/init.py @@ -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}') diff --git a/unipay/paylog.py b/unipay/paylog.py index 680a856..1f67c54 100644 --- a/unipay/paylog.py +++ b/unipay/paylog.py @@ -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 diff --git a/wwwroot/refund.dspy b/wwwroot/refund.dspy new file mode 100644 index 0000000..36e50bb --- /dev/null +++ b/wwwroot/refund.dspy @@ -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 + diff --git a/wwwroot/refund.ui b/wwwroot/refund.ui new file mode 100644 index 0000000..336e08f --- /dev/null +++ b/wwwroot/refund.ui @@ -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 %}