This commit is contained in:
yumoqing 2025-12-18 12:16:47 +08:00
parent 8acd2cf0c0
commit 64a2a89929
5 changed files with 65 additions and 24 deletions

Binary file not shown.

View File

@ -3,7 +3,7 @@ import os
from appPublic.log import debug,exception from appPublic.log import debug,exception
from ahserver.serverenv import ServerEnv from ahserver.serverenv import ServerEnv
from .notify import get_provider, get_provider_channel from .notify import get_provider, get_provider_channel
from .paylog import PaymentLog from .paylog import PaymentLog, unipay_accounting
from .payfee import get_pay_fee, sor_get_pay_fee, get_paychannels, get_pay_feerate from .payfee import get_pay_fee, sor_get_pay_fee, get_paychannels, get_pay_feerate
# 从 env 或配置载入 provider conf这里只示例 # 从 env 或配置载入 provider conf这里只示例
@ -124,32 +124,31 @@ async def refund_payment(request, params_kw=None):
raise e raise e
# 回调入口:你可把厂商回调用各自 endpoint 再转发到这里,或在厂商控制台按各自 URL 配置 # 回调入口:你可把厂商回调用各自 endpoint 再转发到这里,或在厂商控制台按各自 URL 配置
async def payment_notify(request, callback, params_kw=None): async def payment_notify(request, params_kw=None):
if params_kw is None: if params_kw is None:
params_kw = request.params_kw params_kw = request.params_kw
data = params_kw
provider = params_kw.provider provider = params_kw.provider
headers = dict(request.headers)
body = await request.text()
try:
if PROVIDERS[provider] is None: if PROVIDERS[provider] is None:
e = Exception(f'{provider} cannot pay') e = Exception(f'{provider} cannot pay')
exception(f'{e}') exception(f'{e}')
raise e return
try:
headers = dict(request.headers)
body = await request.text()
data = await PROVIDERS[provider].handle_notify(headers, body) data = await PROVIDERS[provider].handle_notify(headers, body)
# 这里 data 应包含标准化字段out_trade_no/status/attach 等 except Exception as e:
# TODO: 业务幂等处理 e = Exception(f'{provider} cannot pay')
# 返回厂商要求的固定成功响应 exception(f'{e}')
logid = data['out_trade_no'] return
logid = data.params.out_trade_no
pl = PaymentLog(request._run_ns) pl = PaymentLog(request._run_ns)
plog = await pl.payed_log(logid) plog = await pl.payed_log(logid)
await callback(request, data) await unipay_accounting(request, data)
if provider == "wechat": if provider == "wechat":
return {"code":"SUCCESS", "message":"OK"} return {"code":"SUCCESS", "message":"OK"}
else: else:
return "OK" return "OK"
except Exception as e:
return web.Response(status=500, text=str(e))
# callback url= "/unipay/notify/{provider}" # callback url= "/unipay/notify/{provider}"

View File

@ -2,6 +2,7 @@ from sqlor.dbpools import DBPools
from appPublic.timeUtils import timestampstr from appPublic.timeUtils import timestampstr
from appPublic.log import debug, exception from appPublic.log import debug, exception
from appPublic.dictObject import DictObject from appPublic.dictObject import DictObject
from ahserver.serverenv import ServerEnv
class PaymentLog: class PaymentLog:
def __init__(self, env): def __init__(self, env):
@ -68,4 +69,40 @@ class PaymentLog:
return None return None
return None return None
async def unipay_accounting(request, data):
logid = data.params.out_trade_no
trade_id = data.params.trade_no
env = request._run_ns
db = DBPools()
dbname = env.get_module_dbname('unipay')
async with db.sqlorContext(dbname) as sor:
recs = await sor.R('payment_log', {'id', logid})
if len(recs) < 1:
e = Exception(f'{logid} not found {data=}')
exception(f'{e}')
raise e
r = recs[0]
if r.status == '2':
e = Exception(f'{logid} payment_log status({r.status}) is already accounted')
exception(f'{e}')
return True
if r.status != '1':
e = Exception(f'{logid} payment_log status({r.status}) not correct')
exception(f'{e}')
return False
await env.recharge_accounting(sor,
r.customerid,
'RECHARGE',
r.id,
await env.get_business_date(sor),
r.amount_total,
r.pay_feerate
)
await sor.U('payment_log', {'id': logid,
'status': '2',
'channel_trade_id': trade_id
})
return True
exception(f'{db.e_except}')
return False

View File

@ -6,6 +6,7 @@ import hashlib
import urllib.parse import urllib.parse
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from appPublic.log import debug, exception from appPublic.log import debug, exception
from appPublic.dictObject import DictObject
import aiohttp import aiohttp
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
@ -205,13 +206,16 @@ class AlipayGateway(Gateway):
unsigned_str = self._build_sign_content(params) unsigned_str = self._build_sign_content(params)
if not sign: if not sign:
return {"verified": False, "msg": "no sign"} e = Exception(f'notify/alipay: verify failed')
exception(f'{e}')
raise e
ok = self._verify(unsigned_str, sign) ok = self._verify(unsigned_str, sign)
return { ret = {
"verified": ok, "verified": ok,
"provider": "alipay", "provider": "alipay",
"data": params, "data": params,
} }
return DictObject(**ret)

View File

@ -1,5 +1,6 @@
debug(f'/unipay/notify/alipay/index.dspy:{params_kw}') debug(f'/unipay/notify/alipay/index.dspy:{params_kw}')
ns = params_kw.copy() ns = params_kw.copy()
ns.provider = 'alipay' ns.provider = 'alipay'
return await payment_notify(request, recharge_accounting, params_kw=ns) return await payment_notify(request, params_kw=ns)