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