170 lines
4.5 KiB
Python

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()
self.env = env
async def new_log(self,
userid, customerid, channel,
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,
amount, feerate,
client_ip, currency=currency)
return None
async def sor_new_log(self, sor,
userid, customerid, channel,
amount, feerate,
client_ip, currency='CNY'):
debug(f"{userid=}, {customerid=}, {amount=},{feerate=},{client_ip=}")
ns = {
"id": self.env.uuid(),
"customerid": customerid,
"channelid": channel,
"payment_name": RECHARGE,
"payer_client_ip": client_ip,
"amount_total": amount,
"pay_feerate": feerate,
"pay_fee": feerate * amount,
"currency": 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
}
await sor.C('payment_log', ns.copy())
return DictObject(**ns)
async def cancel_log(self, logid):
dbname = 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)
recs = await sor.R('payment_log', {"id": logid})
if len(recs) > 0:
return recs[0]
return None
return None
async def payed_log(self, logid):
dbname = self.env.get_module_dbname('unipay')
async with self.db.sqlorContext(dbname) as sor:
ns = {
"id": logid,
"payment_status":'1',
"payed_timestamp": timestampstr()
}
await sor.U('payment_log', ns)
recs = await sor.R('payment_log', {"id": logid})
if len(recs) > 0:
return recs[0]
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
})
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.e_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
env = ServerEnv()
db = DBPools()
dbname = env.get_module_dbname('unipay')
async with db.sqlorContext(dbname) as sor:
recs = await sor.R('payment_log', {'id': logid, 'payment_status': '0'})
if len(recs) < 1:
e = Exception(f'{logid} not found {data=} or accounted')
exception(f'{e}')
raise e
r = recs[0]
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,
'payment_status': '1',
'payed_timestamp': timestampstr(),
'channel_trade_id': trade_id
})
return True
exception(f'{db.e_except}')
return False