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

View File

@ -2,6 +2,7 @@ from sqlor.dbpools import DBPools
from appPublic.timeUtils import timestampstr
from appPublic.log import debug, exception
from appPublic.dictObject import DictObject
from ahserver.serverenv import ServerEnv
class PaymentLog:
def __init__(self, env):
@ -68,4 +69,40 @@ class PaymentLog:
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
from typing import Any, Dict, Optional
from appPublic.log import debug, exception
from appPublic.dictObject import DictObject
import aiohttp
from cryptography.hazmat.primitives import hashes
@ -205,13 +206,16 @@ class AlipayGateway(Gateway):
unsigned_str = self._build_sign_content(params)
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)
return {
ret = {
"verified": ok,
"provider": "alipay",
"data": params,
}
return DictObject(**ret)

View File

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