# -*- encoding: utf-8 -*-
# -----------------------------------------------------------------------------
# @File Name : order_service.py
# @Time : 2020/11/18 下午3:35
# @Author : X. Peng
# @Email : acepengxiong@163.com
# @Software : PyCharm
# -----------------------------------------------------------------------------
import datetime
import time
from sqlalchemy import and_
from sqlalchemy.testing import in_
from app.api.engine import TAMP_SQL, tamp_pay_engine, tamp_user_engine
from app.config.errors import Errors
from app.controller.errorhandler import CustomFlaskErr
from app.model.account_balance import AccountBalance
# from app.model.account_topup_order import AccountTopupOrder
from app.model.curriculum_order import OrderFlow
from app.model.tamp_user_models import CurriculumPrice, CurriculumColumn, CurriculumRes
from xml.etree import cElementTree as etree
from app.utils.alipay.alipayWap import prePay
from app.utils.apple_pay import apple_pay
from app.utils.wxpay.wx_app_pay import WXPay
class TopUpOrderService:
""""""
def __init__(self):
pass
def get_order(self, args):
pageNumber = args['pageNumber']
pageSize = args['pageSize']
user_id = args['user_id']
offset = (pageNumber - 1)*pageSize
with TAMP_SQL(tamp_user_engine) as tamp_user:
tamp_user_session = tamp_user.session
totalSize = tamp_user_session.query(OrderFlow.id).filter(
and_(OrderFlow.createby == user_id, OrderFlow.ab_type == '6', OrderFlow.ab_status == 'SUCCESS')).count()
res = tamp_user_session.query(OrderFlow).filter(and_(OrderFlow.createby == user_id, OrderFlow.ab_type == '6', OrderFlow.ab_status == 'SUCCESS')).order_by(
OrderFlow.createtime.desc()).offset(offset).limit(pageSize)
res = [r.to_dict() for r in res]
allowed = {'id', 'ab_ordernum', 'transaction_serial_no', 'ab_payment', 'ab_pay_mode', 'createtime', 'pay_time', 'complete_time', 'ab_type'}
for r in res:
keys = set(r.keys()) - allowed
for key in keys:
del r[key]
return {
'content': res,
'pageNum': pageNumber,
'pageSize': pageSize,
'totalSize': totalSize
}
def create_order(self, args):
args['ab_ordernum'] = time.strftime('%Y%m%d', time.localtime(time.time())) + str(int(time.time() * 100000))
args['id'] = OrderFlow.__tablename__ + str(int(time.time() * 100000))
args['amount'] = args['amount'] * 100
args['ab_status'] = 'WAIT'
subject = '探普币充值'
out_trade_no = args['ab_ordernum']
notify_path = '/tamp_order/micro_shop/topUpOrderNotify'
pay_params = None
if args['pay_method'] == 5:
# 微信支付
wx_pay = WXPay(out_trade_no, subject, args['amount'], args['remote_addr'], notify_path=notify_path)
params = wx_pay.getReturnParams()
pay_params = params
elif args['pay_method'] == 6:
# 支付宝支付
total_amount = args['amount'] / 100
res = prePay(subject, out_trade_no, total_amount, notify_path=notify_path)
pay_params = res
elif args['pay_method'] == 7:
# 苹果支付
# 入参校验
receipt_data = args.get('receipt_data', '')
product_id = args.get('product_id', '')
if not receipt_data:
raise CustomFlaskErr(Errors.INPUT_PARAMS_ERROR)
if not product_id:
raise CustomFlaskErr(Errors.INPUT_PARAMS_ERROR)
apple_pay_res = apple_pay(receipt_data, product_id)
if not apple_pay_res['success']:
raise CustomFlaskErr(Errors.APPLE_VOCHER_INVALID)
args['transaction_serial_no'] = apple_pay_res.get('transaction_id', '')
with TAMP_SQL(tamp_user_engine) as tamp_user, TAMP_SQL(tamp_pay_engine) as tamp_pay:
tamp_user_session, tamp_pay_session = tamp_user.session, tamp_pay.session
if tamp_user_session.query(OrderFlow).filter(OrderFlow.transaction_serial_no == args['transaction_serial_no']).all():
raise CustomFlaskErr(Errors.APPLE_VOCHER_USED)
args['ab_status'] = 'SUCCESS'
if not tamp_pay_session.query(AccountBalance).filter(AccountBalance.user_id == args['user_id']).all():
tamp_pay_session.add(AccountBalance(id=AccountBalance.__tablename__+str(int(time.time()*100000)), user_id=args['user_id'], apple_balance=args['amount']))
else:
tamp_pay_session.query(AccountBalance).filter(
AccountBalance.user_id == args['user_id']).update({
'apple_balance': AccountBalance.apple_balance + args['amount']
})
args.pop('remote_addr', '')
args.pop('receipt_data', '')
args.pop('product_id', '')
args['ab_payment'] = args.pop('amount', '')
args['ab_pay_mode'] = args.pop('pay_method', '')
args['createby'] = args.pop('user_id', '')
args['ab_type'] = '6'
order_info = OrderFlow(**args)
with TAMP_SQL(tamp_user_session) as tamp_user:
tamp_user_session = tamp_user.session
tamp_user_session.add(order_info)
return pay_params
class CurriculumOrderService:
"""消费订单"""
def __init__(self):
pass
def get_order(self, args):
"""."""
pageNumber = args['pageNumber']
pageSize = args['pageSize']
user_id = args['user_id']
offset = (pageNumber - 1) * pageSize
with TAMP_SQL(tamp_user_engine) as tamp_user:
tamp_user_session = tamp_user.session
curriculum_column = tamp_user_session.query(CurriculumColumn.id, CurriculumColumn.title, CurriculumColumn.cover, CurriculumColumn.info).all()
curriculum_res = tamp_user_session.query(CurriculumRes.id, CurriculumRes.title, CurriculumRes.cover, CurriculumRes.teacher_name).all()
totalSize = tamp_user_session.query(OrderFlow).filter(
and_(OrderFlow.createby == user_id, OrderFlow.ab_type != '6', OrderFlow.ab_status == 'SUCCESS')
).count()
res = tamp_user_session.query(OrderFlow).filter(
and_(OrderFlow.createby == user_id, OrderFlow.ab_type != '6', OrderFlow.ab_status == 'SUCCESS')
).order_by(OrderFlow.createtime.desc()).offset(offset).limit(pageSize)
curriculum_column = {r[0]: {'title': r[1], 'cover': r[2], 'info': r[3]} for r in curriculum_column}
curriculum_res = {r[0]: {'title': r[1], 'cover': r[2], 'info': r[3]} for r in curriculum_res}
orders = [r.to_dict() for r in res if r.to_dict()['ab_status'] == 'SUCCESS']
temp_orders = []
for order in orders:
prod_type = order.get('ab_type', '')
prod_id = order.get('ab_proid', '')
if prod_type == '1':
order = {**order, **curriculum_column.get(prod_id, None)}
temp_orders.append(order)
elif prod_type in ['3', '4', '5']:
order = {**order, **curriculum_res.get(prod_id, None)}
temp_orders.append(order)
temp_orders = temp_orders[offset: offset+pageSize]
allowed = {'id', 'title', 'cover', 'info', 'ab_type', 'ab_payment', 'ab_pay_mode', 'ab_ordernum', 'transaction_serial_no', 'pay_method', 'createtime', 'pay_time', 'complete_time',
'ab_status'}
for r in temp_orders:
keys = set(r.keys()) - allowed
for key in keys:
del r[key]
return {
'content': temp_orders,
'pageNum': pageNumber,
'pageSize': pageSize,
'totalSize': totalSize
}
def create_order(self, args):
"""。"""
with TAMP_SQL(tamp_user_engine) as tamp_user, TAMP_SQL(tamp_pay_engine) as tamp_pay:
tamp_user_session, tamp_pay_session = tamp_user.session, tamp_pay.session
args['ab_ordernum'] = time.strftime('%Y%m%d', time.localtime(time.time())) + str(int(time.time() * 100000))
amount = tamp_user_session.query(CurriculumPrice.price).filter(CurriculumPrice.rel_id == args['ab_proid']).first()[0]
if not amount:
raise CustomFlaskErr(Errors.PROD_NOPRICE)
args['id'] = OrderFlow.__tablename__ + str(int(time.time() * 100000))
args['ab_payment'] = amount
args['ab_status'] = 'WAIT'
subject = args.get('prod_name', '')
out_trade_no = args['ab_ordernum']
notify_path = '/tamp_order/micro_shop/topUpOrderNotify'
pay_params = None
# 该用户是否重复购买同一商品
repeat_buy = tamp_user_session.query(OrderFlow.id).filter(and_(OrderFlow.createby == args['user_id']),
OrderFlow.ab_proid == args['ab_proid'],
OrderFlow.ab_status == 'SUCCESS').all()
if repeat_buy:
raise CustomFlaskErr(Errors.REPEAT_BUY)
if args['ab_pay_mode'] == 4:
# 探普币支付
if args['env'] == 'ios':
res = tamp_pay_session.query(AccountBalance.apple_balance).filter(
AccountBalance.user_id == args['user_id']).first()
if not res:
raise CustomFlaskErr(Errors.TANGPU_BALANCE_NOT_ENOUGH)
elif res[0] < args['ab_payment']:
raise CustomFlaskErr(Errors.TANGPU_BALANCE_NOT_ENOUGH)
else:
tamp_pay_session.query(AccountBalance.apple_balance).filter(
AccountBalance.user_id == args['user_id']).update({
'apple_balance': AccountBalance.apple_balance - args['ab_payment']
})
args['ab_status'] = 'SUCCESS'
elif args['env'] == 'android':
res = tamp_pay_session.query(AccountBalance.android_balance).filter(
AccountBalance.user_id == args['user_id']).first()
if not res:
raise CustomFlaskErr(Errors.TANGPU_BALANCE_NOT_ENOUGH)
elif res[0] < args['ab_payment']:
raise CustomFlaskErr(Errors.TANGPU_BALANCE_NOT_ENOUGH)
else:
tamp_pay_session.query(AccountBalance.android_balance).filter(
AccountBalance.user_id == args['user_id']).update({
'android_balance': AccountBalance.android_balance - args['ab_payment']
})
args['ab_status'] = 'SUCCESS'
elif args['ab_pay_mode'] == 5:
# 微信支付
wx_pay = WXPay(out_trade_no, subject, args['ab_payment'], args['remote_addr'], notify_path=notify_path)
params = wx_pay.getReturnParams()
pay_params = params
elif args['ab_pay_mode'] == 6:
# 支付宝支付
total_amount = args['ab_payment'] / 100
res = prePay(subject, out_trade_no, total_amount, notify_path=notify_path)
pay_params = res
args['createby'] = args.pop('user_id', '')
args.pop('prod_name', '')
args.pop('env', '')
args.pop('remote_addr', '')
order_info = OrderFlow(**args)
tamp_user_session.add(order_info)
return pay_params
def topUpSuccessAction(order_no):
"""."""
with TAMP_SQL(tamp_user_engine) as tamp_user, TAMP_SQL(tamp_pay_engine) as tamp_pay:
tamp_user_session, tamp_pay_session = tamp_user.session, tamp_pay.session
topup_order = tamp_user_session.query(OrderFlow).filter(OrderFlow.ab_ordernum == order_no).first()
if not topup_order:
raise CustomFlaskErr(Errors.NO_ORDERS)
else:
topup_order = topup_order.to_dict()
# 幂等校验
if topup_order.get('ab_status', '') == 'SUCCESS':
return False
tamp_user_session.query(OrderFlow).filter(OrderFlow.ab_ordernum == order_no).update({
'ab_status': 'SUCCESS',
'pay_time': datetime.datetime.now(),
'complete_time': datetime.datetime.now()
})
# 账户充值
account_topup_order = tamp_user_session.query(OrderFlow).filter(OrderFlow.ab_ordernum == order_no).first().to_dict()
user_id = account_topup_order.get('createby', '')
ab_payment = account_topup_order.get('ab_payment', '')
# 安卓支付宝,微信支付
if not tamp_pay_session.query(AccountBalance).filter(AccountBalance.user_id == user_id).all():
tamp_pay_session.add(AccountBalance(id=AccountBalance.__tablename__ + str(int(time.time()*10000)), user_id=user_id, android_balance=ab_payment))
else:
tamp_pay_session.query(AccountBalance).filter(AccountBalance.user_id == user_id).update({
'android_balance': AccountBalance.android_balance + ab_payment
})
def consumeSucessAction(order_no):
"""."""
with TAMP_SQL(tamp_user_engine) as tamp_user:
tamp_user_session = tamp_user.session
curriculum_order = tamp_user_session.query(OrderFlow).filter(OrderFlow.ab_ordernum == order_no).first()
if not curriculum_order:
raise CustomFlaskErr(Errors.NO_ORDERS)
else:
curriculum_order = curriculum_order.to_dict()
# 幂等校验
if curriculum_order.get('ab_status', '') == 'SUCCESS':
return False
tamp_user_session.query(OrderFlow).filter(OrderFlow.ab_ordernum == order_no).update({
'ab_status': 'SUCCESS',
'pay_time': datetime.datetime.now(),
'complete_time': datetime.datetime.now()
})
def getAccountBalance(user_id):
"""查询探普币余额"""
with TAMP_SQL(tamp_pay_engine) as tamp_pay:
tamp_pay_session = tamp_pay.session
account_balance = tamp_pay_session.query(AccountBalance).filter(AccountBalance.user_id == user_id).first()
if not account_balance:
return {'user_id': user_id, 'android_balance': 0, 'apple_balance': 0}
else:
return account_balance.to_dict()
def xml2dict(content):
"""将从微信服务器接收到的xml转为dict."""
raw = {}
root = etree.fromstring(content)
for child in root:
raw[child.tag] = child.text
return raw
def dict2xml(dict_):
"""将dict转为要发送到微信服务器的xml格式."""
s = ""
for k, v in dict_.items():
s += "<{0}>{1}{0}>".format(k, v)
s = "{0}".format(s)
return s.encode("utf-8")
def alipayWxPayCheck(res_info):
"""支付宝,微信支付异步通知"""
success = False
body = None
header = {'Content-Type': 'application/text'}
res = {}
if 'trade_status' in res_info:
# 支付宝支付
res_info = res_info.split('&')
for ss in res_info:
key, value = ss.split('=')
res[key] = value
if res['trade_status'] == 'TRADE_SUCCESS':
success = True
body = 'success'.encode()
else:
# 微信支付
res = xml2dict(res_info)
if res['result_code'] == 'SUCCESS' and res['return_code'] == 'SUCCESS':
success = True
header = {'Content-Type': 'application/xml'}
body = ' '
return {'success': success, 'header': header, 'body': body, 'order_no': res['out_trade_no']}
def getAllOrders(args):
"""."""
pageNumber = args['pageNumber']
pageSize = args['pageSize']
user_id = args['user_id']
offset = (pageNumber - 1) * pageSize
with TAMP_SQL(tamp_user_engine) as tamp_user:
tamp_user_session = tamp_user.session
# 全部订单
curriculum_column = tamp_user_session.query(CurriculumColumn.id, CurriculumColumn.title, CurriculumColumn.cover,
CurriculumColumn.info).all()
curriculum_res = tamp_user_session.query(CurriculumRes.id, CurriculumRes.title, CurriculumRes.cover,
CurriculumRes.teacher_name).all()
totalSize = tamp_user_session.query(OrderFlow).filter(
and_(OrderFlow.createby == user_id, OrderFlow.ab_status == 'SUCCESS')
).count()
res = tamp_user_session.query(OrderFlow).filter(
and_(OrderFlow.createby == user_id, OrderFlow.ab_status == 'SUCCESS')
).order_by(OrderFlow.ab_type.desc(), OrderFlow.createtime.desc()).offset(offset).limit(pageSize)
res = tamp_user_session.query(OrderFlow).filter(OrderFlow.createby == user_id).order_by(
OrderFlow.ab_type.desc(), OrderFlow.createtime.desc()
).offset(offset).limit(pageSize)
curriculum_column = {r[0]: {'title': r[1], 'cover': r[2], 'info': r[3]} for r in curriculum_column}
curriculum_res = {r[0]: {'title': r[1], 'cover': r[2], 'info': r[3]} for r in curriculum_res}
orders = [r.to_dict() for r in res if r.to_dict()['ab_status'] == 'SUCCESS']
temp_orders = []
for order in orders:
prod_type = order.get('ab_type', '')
prod_id = order.get('ab_proid', '')
if prod_type == '6':
temp_orders.append(order)
elif prod_type == '1':
order = {**order, **curriculum_column.get(prod_id, None)}
temp_orders.append(order)
elif prod_type in ['3', '4', '5']:
order = {**order, **curriculum_res.get(prod_id, None)}
temp_orders.append(order)
else:
temp_orders.append(order)
allowed = {'id', 'title', 'cover', 'info', 'ab_type', 'ab_payment', 'ab_pay_mode', 'ab_ordernum',
'transaction_serial_no', 'pay_method', 'createtime', 'pay_time', 'complete_time',
'ab_status'}
for r in temp_orders:
keys = set(r.keys()) - allowed
for key in keys:
del r[key]
return {
'content': temp_orders,
'pageNum': pageNumber,
'pageSize': pageSize,
'totalSize': totalSize
}