403 lines
20 KiB
Plaintext
403 lines
20 KiB
Plaintext
async def user_action_record(ns={}):
|
|
ns_dic = {
|
|
'id': uuid(),
|
|
'source': '百度智能云',
|
|
'orderid': ns.get('orderid'),
|
|
'ordertype': ns.get('ordertype'),
|
|
'userid': ns.get('userid'),
|
|
'reason': ns.get('reason')
|
|
}
|
|
db = DBPools()
|
|
async with db.sqlorContext('kboss') as sor:
|
|
await sor.C('user_action', ns_dic)
|
|
|
|
async def time_convert(resoucetime=None):
|
|
if not resoucetime:
|
|
return
|
|
utc_time = datetime.datetime.strptime(resoucetime, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc)
|
|
beijing_time = utc_time.astimezone(datetime.timezone(datetime.timedelta(hours=8)))
|
|
return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
async def cal_expire_time(history_time=None, chargeduration=None, unit=None):
|
|
chargeduration = int(chargeduration)
|
|
# 当前时间
|
|
# now = datetime.datetime.now()
|
|
now = datetime.datetime.strptime(history_time, '%Y-%m-%d %H:%M:%S')
|
|
if unit == 'MONTH':
|
|
expire_time = now + dateutil.relativedelta.relativedelta(months=chargeduration)
|
|
elif unit == 'YEAR':
|
|
expire_time = now + dateutil.relativedelta.relativedelta(years=chargeduration)
|
|
else:
|
|
expire_time = None
|
|
if expire_time:
|
|
return str(expire_time)
|
|
else:
|
|
return None
|
|
|
|
async def affirmbz_order(ns={}):
|
|
"""确认支付"""
|
|
order_type = ns.get('order_type')
|
|
sor = ns['sor']
|
|
orgid = await sor.R('bz_order', {'id': ns['orderid']})
|
|
|
|
servicename = orgid[0]['servicename']
|
|
product_url = None
|
|
if ('BCC' in servicename) or ('GPU' in servicename):
|
|
product_url = 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
|
|
|
|
date = await get_business_date(sor=None)
|
|
await sor.U('bz_order',{'id':ns['orderid'],'order_date': date})
|
|
count = await getCustomerBalance(sor, orgid[0]['customerid'])
|
|
if count == None:
|
|
count = 0
|
|
if count - float(orgid[0]['amount']) < 0:
|
|
pricedifference = count - round(orgid[0]['amount'],2)
|
|
return {'status': False, 'msg': '账户余额不足','pricedifference': round(pricedifference,2)}
|
|
await order2bill(ns['orderid'], sor)
|
|
bills = await sor.R('bill', {'orderid': ns['orderid'], 'del_flg': '0'})
|
|
try:
|
|
# 需要加事务
|
|
for i in bills:
|
|
ba = BillAccounting(i)
|
|
r = await ba.accounting(sor)
|
|
dates = datetime.datetime.now()
|
|
await sor.U('bz_order', {'id': ns['orderid'], 'order_status': '1','create_at':dates})
|
|
await sor.U('bill', {'id': ns['orderid'], 'bill_state': '1'})
|
|
order_goods = await sor.R('order_goods', {'orderid': ns['orderid']})
|
|
for j in order_goods:
|
|
# 处理退订逻辑
|
|
if order_type == 'REFUND':
|
|
# 找到资源并更新时间
|
|
resource_find_sql = """select id from customer_goods where resourceid = '%s' and del_flg = '0';""" % j['resourceids']
|
|
resource_find_li = await sor.sqlExe(resource_find_sql, {})
|
|
resource_find_id = resource_find_li[0]['id']
|
|
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'})
|
|
|
|
# 处理续费逻辑
|
|
elif order_type == 'RENEW':
|
|
# 找到资源并更新时间
|
|
resource_find_sql = """select id from customer_goods where resourceid = '%s' and del_flg = '0';""" % j['resourceids']
|
|
resource_find_li = await sor.sqlExe(resource_find_sql, {})
|
|
resource_find_id = resource_find_li[0]['id']
|
|
await sor.U('customer_goods', {'id': resource_find_id, 'start_date': j['resourcestarttime'], 'expire_date': j['resourceendtime']})
|
|
|
|
# 处理购买逻辑
|
|
else:
|
|
product = await sor.R('product', {'id': j['productid']})
|
|
nss = {}
|
|
nss['id'] = uuid()
|
|
# nss['id'] = UUID()
|
|
nss['providerrid'] = product[0]['providerid']
|
|
nss['productname'] = product[0]['name']
|
|
nss['productdesc'] = product[0]['description']
|
|
nss['customerid'] = orgid[0]['customerid']
|
|
nss['productid'] = product[0]['id']
|
|
nss['specdataid'] = j['spec_id']
|
|
nss['orderid'] = orgid[0]['id']
|
|
nss['start_date'] = j['resourcestarttime']
|
|
nss['expire_date'] = j['resourceendtime']
|
|
nss['resourceid'] = j['resourceids']
|
|
|
|
if product_url:
|
|
nss['product_url'] = product_url
|
|
else:
|
|
spec = json.loads(product[0]['spec_note']) if isinstance(product[0]['spec_note'], str) else product[0]['spec_note']
|
|
spec_list_url = [item['value'] for item in spec if item['configName'] == 'listUrl']
|
|
nss['product_url'] = spec_list_url[0] if spec_list_url else 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
|
|
|
|
await sor.C('customer_goods', nss)
|
|
return {'status': True, 'msg': '支付成功'}
|
|
except Exception as error:
|
|
raise error
|
|
|
|
async def baidu_order_process(ns={}):
|
|
"""
|
|
百度支付
|
|
1、获取订单
|
|
2、算出购买的产品折扣
|
|
3、比对账号余额
|
|
"""
|
|
db = DBPools()
|
|
async with db.sqlorContext('kboss') as sor:
|
|
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
|
|
user = await sor.R('users', {'id': ns.get('userid')})
|
|
orgid = await sor.R('organization', {'id': user[0]['orgid']})
|
|
nss = {'uuids': [ns.get('order_id')], 'queryAccountId': baidu_users[0]['baidu_id']}
|
|
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
|
|
url = 'https://billing.baidubce.com/v1/order/getByUuid?%s' % ns_format
|
|
method = 'POST'
|
|
header = {
|
|
"Host": "billing.baidubce.com",
|
|
"ContentType": "application/json;charset=UTF-8"
|
|
}
|
|
header = await get_auth_header(method=method, url=url, header=header)
|
|
async with aiohttp_client.request(
|
|
method=method,
|
|
url=url,
|
|
headers=header,
|
|
json=nss) as res:
|
|
data_ = await res.json()
|
|
orders = data_['orders']
|
|
serviceType = orders[0]['orderItems']
|
|
|
|
# 判断订单item中productType是否有后付费的产品
|
|
for item in orders:
|
|
order_items = item['orderItems']
|
|
for order_info in order_items:
|
|
if order_info['productType'] == 'postpay' and order_info['itemFee']['price'] != 0:
|
|
return {
|
|
'status': False,
|
|
'msg': '暂不支持后付费按量购买, 请联系后台开通'
|
|
}
|
|
# 实付价格
|
|
total_price = 0
|
|
productType = ''
|
|
|
|
# 买/续/退 字段映射
|
|
order_type = orders[0]['type']
|
|
if order_type == 'NEW':
|
|
business_op = 'BUY'
|
|
elif order_type == 'RENEW':
|
|
business_op = 'RENEW'
|
|
elif order_type == 'REFUND':
|
|
business_op = 'BUY_REVERSE'
|
|
else:
|
|
ns_record = {
|
|
'orderid': ns.get('order_id'),
|
|
'ordertype': orders[0]['type'],
|
|
'userid': ns.get('userid'),
|
|
'reason': '支付形式目前仅包含购买,续费,退订'
|
|
}
|
|
await user_action_record(ns_record)
|
|
return {
|
|
'status': False,
|
|
'msg': '线上暂不支持, 请联系售后'
|
|
}
|
|
try:
|
|
# 生成本地订单
|
|
bz_ns = {}
|
|
bz_ns['id'] = uuid()
|
|
bz_ns['order_status'] = '0'
|
|
bz_ns['business_op'] = business_op
|
|
bz_ns['userid'] = ns.get('userid')
|
|
bz_ns['customerid'] = orgid[0]['id']
|
|
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
bz_ns['thirdparty_order'] = ns.get('order_id')
|
|
bz_ns['source'] = '百度智能云'
|
|
bz_ns['originalprice'] = orders[0]['price']
|
|
bz_ns['provider_orderid'] = ns.get('order_id')
|
|
bz_ns['ordertype'] = orders[0]['productType']
|
|
bz_ns['servicename'] = orders[0]['serviceType']
|
|
bz_ns['autoreneworder'] = '1' if orders[0]['autoRenewOrder'] else '0'
|
|
if ns.get('specdataid'):
|
|
bz_ns['specdataid'] = ns['specdataid']
|
|
await sor.C('bz_order', bz_ns)
|
|
for i in serviceType:
|
|
if i['productType'] == 'prepay':
|
|
# 预付费
|
|
productType = 'prepay'
|
|
# financePrice = 0
|
|
# 获取产品id
|
|
product = await sor.R('product', {'providerpid': 'baidu_' + i['serviceType'], 'del_flg': '0'})
|
|
# 获取协议
|
|
saleprotocol = await sor.R('saleprotocol',
|
|
{'bid_orgid': orgid[0]['id'], 'offer_orgid': orgid[0]['parentid'],
|
|
'del_flg': '0'})
|
|
if saleprotocol == []:
|
|
# 等于空就代表这个客户没有特殊折扣,就要找到买方为*的协议
|
|
saleprotocol = await sor.R('saleprotocol', {'bid_orgid': '*', 'offer_orgid': orgid[0]['parentid'],
|
|
'del_flg': '0', 'salemode': '0'})
|
|
product_salemode = await sor.R('product_salemode',
|
|
{'protocolid': saleprotocol[0]['id'], 'productid': product[0]['id'],
|
|
'del_flg': '0'})
|
|
supply_price = i['itemFee']['price'] if i.get('itemFee') else i['financePrice']
|
|
financePrice = abs(supply_price * product_salemode[0]['discount'])
|
|
total_price += financePrice
|
|
|
|
# 添加订单子表
|
|
nss = {}
|
|
nss['id'] = uuid()
|
|
nss['orderid'] = bz_ns['id']
|
|
nss['productid'] = product[0]['id']
|
|
nss['providerid'] = product[0]['providerid']
|
|
if i['count'] > 1:
|
|
nss['list_price'] = abs(i['realCatalogPrice'] / i['count'])
|
|
else:
|
|
nss['list_price'] = abs(i['realCatalogPrice'])
|
|
nss['discount'] = product_salemode[0]['discount']
|
|
nss['quantity'] = i['count']
|
|
nss['price'] = abs(round(nss['list_price'] * product_salemode[0]['discount'], 2))
|
|
# 计算总价
|
|
# nss['amount'] = round(total_price, 2)
|
|
nss['amount'] = abs(round(nss['price'] * nss['quantity'], 2))
|
|
nss['chargemode'] = i.get('productType')
|
|
nss['servicename'] = i.get('serviceType')
|
|
nss['chargeduration'] = i.get('time')
|
|
nss['unit'] = i.get('timeUnit')
|
|
nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else ''
|
|
|
|
# 如果是续费订单 由于没有返回日期, 重新计算日期
|
|
if order_type == 'RENEW':
|
|
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where resourceids = '%s' order by resourceendtime desc;" % \
|
|
nss['resourceids']
|
|
history_time = await sor.sqlExe(history_time_sql, {})
|
|
new_end_time = await cal_expire_time(history_time=history_time[0]['resourceendtime'],
|
|
chargeduration=nss['chargeduration'], unit=nss['unit'])
|
|
# 开始日期不变 更新到期日期
|
|
nss['resourcestarttime'] = history_time[0]['resourcestarttime']
|
|
nss['resourceendtime'] = new_end_time
|
|
else:
|
|
nss['resourcestarttime'] = await time_convert(i.get('resourceStartTime')) if i.get(
|
|
'resourceStartTime') else None
|
|
nss['resourceendtime'] = await time_convert(i.get('resourceEndTime')) if i.get(
|
|
'resourceEndTime') else None
|
|
|
|
await sor.C('order_goods', nss)
|
|
|
|
# 循环后更新订单中总价
|
|
await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)})
|
|
except Exception as e:
|
|
ns_record = {
|
|
'orderid': ns.get('order_id'),
|
|
'ordertype': orders[0]['type'],
|
|
'userid': ns.get('userid'),
|
|
'reason': '发生错误, %s' % str(e)[:100]
|
|
}
|
|
await user_action_record(ns_record)
|
|
import traceback
|
|
with open('baiducloud_err.txt', 'w') as f:
|
|
f.write(str(e)+ traceback.format_exc())
|
|
traceback.print_exc()
|
|
|
|
# 判断用户账户余额是否足够支付
|
|
try:
|
|
count = await getCustomerBalance(sor, orgid[0]['id'])
|
|
if order_type == 'REFUND':
|
|
count = total_price + 0.1
|
|
|
|
if round(total_price,2) <= count:
|
|
#判断预付费或者后付费
|
|
if productType == 'prepay':
|
|
# 调用扣费接口
|
|
affirmbz_order_ns = {
|
|
'sor': sor,
|
|
'orderid': bz_ns['id'],
|
|
'order_type': order_type
|
|
}
|
|
affirmbz_order_res = await affirmbz_order(affirmbz_order_ns)
|
|
if not affirmbz_order_res['status']:
|
|
# if True:
|
|
await sor.rollback()
|
|
ns_record = {
|
|
'orderid': ns.get('order_id'),
|
|
'ordertype': orders[0]['type'],
|
|
'userid': ns.get('userid'),
|
|
'reason': '支付错误, 请联系售后'
|
|
}
|
|
await user_action_record(ns_record)
|
|
return {
|
|
'status': False,
|
|
'msg': '支付错误, 请联系售后'
|
|
}
|
|
|
|
# 调用支付订单接口
|
|
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderId':ns.get('order_id')}
|
|
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
|
|
url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
|
|
method = 'POST'
|
|
header = {
|
|
"Host": "billing.baidubce.com"
|
|
}
|
|
header = await get_auth_header(method=method, url=url, header=header)
|
|
async with aiohttp_client.request(
|
|
method=method,
|
|
url=url,
|
|
headers=header,
|
|
json=paydata) as res:
|
|
data_ = await res.json()
|
|
if data_ == {'success': True}:
|
|
# if True:
|
|
ns_record = {
|
|
'orderid': ns.get('order_id'),
|
|
'ordertype': orders[0]['type'],
|
|
'userid': ns.get('userid'),
|
|
'reason': '购买成功'
|
|
}
|
|
await user_action_record(ns_record)
|
|
return {
|
|
'status': True,
|
|
'orderid': bz_ns['id']
|
|
}
|
|
else:
|
|
await sor.rollback()
|
|
ns_record = {
|
|
'orderid': ns.get('order_id'),
|
|
'ordertype': orders[0]['type'],
|
|
'userid': ns.get('userid'),
|
|
'reason': '支付成功后, order_pay接口错误, 回滚, %s' % str(data_)[:400]
|
|
}
|
|
await user_action_record(ns_record)
|
|
return {
|
|
'status': False,
|
|
'msg': '产品分配排队中, 请联系售后详询'
|
|
}
|
|
else:
|
|
# 取消订单
|
|
await sor.rollback()
|
|
paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]}
|
|
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
|
|
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
|
|
method = 'POST'
|
|
header = {
|
|
"Host": "billing.baidubce.com"
|
|
}
|
|
header = await get_auth_header(method=method, url=url, header=header)
|
|
async with aiohttp_client.request(
|
|
method=method,
|
|
url=url,
|
|
headers=header,
|
|
json=paydata) as res:
|
|
await res.json()
|
|
ns_record = {
|
|
'orderid': ns.get('order_id'),
|
|
'ordertype': orders[0]['type'],
|
|
'userid': ns.get('userid'),
|
|
'reason': '无法购买后付费产品'
|
|
}
|
|
await user_action_record(ns_record)
|
|
return {'status': False, 'msg': '无法购买后付费产品'}
|
|
else:
|
|
#取消订单
|
|
await sor.rollback()
|
|
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderIds':[ns.get('order_id')]}
|
|
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
|
|
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
|
|
method = 'POST'
|
|
header = {
|
|
"Host": "billing.baidubce.com"
|
|
}
|
|
header = await get_auth_header(method=method, url=url, header=header)
|
|
async with aiohttp_client.request(
|
|
method=method,
|
|
url=url,
|
|
headers=header,
|
|
json=paydata) as res:
|
|
await res.json()
|
|
ns_record = {
|
|
'orderid': ns.get('order_id'),
|
|
'ordertype': orders[0]['type'],
|
|
'userid': ns.get('userid'),
|
|
'reason': '该账号余额不足,无法完成购买'
|
|
}
|
|
await user_action_record(ns_record)
|
|
return {'status': False,'msg': '该账号余额不足,无法完成购买'}
|
|
except Exception as e:
|
|
import traceback
|
|
with open('baiducloud_err.txt', 'w') as f:
|
|
f.write(str(e)+ traceback.format_exc())
|
|
traceback.print_exc()
|
|
|
|
|
|
|
|
ret = await baidu_order_process(params_kw)
|
|
return ret |