创建充值订单调用不同支付方式业务

parent 8fcd5db0
...@@ -12,8 +12,10 @@ class Errors: ...@@ -12,8 +12,10 @@ class Errors:
TOKEN_INVALID = '9001' TOKEN_INVALID = '9001'
USER_ALREADY_EXISTS = '9002' USER_ALREADY_EXISTS = '9002'
APPLE_VOCHER_INVALID = '9003'
MSG = { MSG = {
TOKEN_INVALID: 'TOKEN失效', TOKEN_INVALID: 'TOKEN失效',
USER_ALREADY_EXISTS: '用户已经存在', USER_ALREADY_EXISTS: '用户已经存在',
APPLE_VOCHER_INVALID: '苹果证书无效'
} }
...@@ -63,5 +63,4 @@ def add_errorhandler(app): ...@@ -63,5 +63,4 @@ def add_errorhandler(app):
@app.after_request @app.after_request
def after_request(response): def after_request(response):
response.headers['content-type'] = "application/json"
return response return response
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
import json import json
from flask_restful import Resource, reqparse from flask_restful import Resource, reqparse
from flask import request from flask import request, make_response
from app.api import app from app.api import app
from app.controller.errorhandler import CustomFlaskErr from app.controller.errorhandler import CustomFlaskErr
...@@ -26,21 +26,23 @@ class TopUpOrder(Resource): ...@@ -26,21 +26,23 @@ class TopUpOrder(Resource):
def get(self): def get(self):
""".""" """."""
# raise CustomFlaskErr(Errors.USER_ALREADY_EXISTS) # raise CustomFlaskErr(Errors.USER_ALREADY_EXISTS)
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空') user_id = request.user_id
args = self.parser.parse_args() data = order_service.TopUpOrderService().get_order(user_id)
data = order_service.TopUpOrderService().get_order(args)
resp = request.return_success resp = request.return_success
resp['attributes'] = data resp['attributes'] = data
return resp return resp
def post(self): def post(self):
""".""" """."""
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空')
self.parser.add_argument('amount', type=int, required=True, help='订单总额不能为空') self.parser.add_argument('amount', type=int, required=True, help='订单总额不能为空')
self.parser.add_argument('pay_method', type=int, required=True, help='支付方式不能为空') self.parser.add_argument('pay_method', type=int, required=True, help='支付方式不能为空')
args = self.parser.parse_args() args = self.parser.parse_args()
order_service.TopUpOrderService().create_order(args) args['user_id'] = request.user_id
return request.return_success args['remote_addr'] = request.remote_addr
res = order_service.TopUpOrderService().create_order(args)
resp = make_response(res['body'])
resp.hearders['Content-Type'] = res['header']['Content-Type']
return resp
def put(self, id): def put(self, id):
""".""" """."""
...@@ -60,9 +62,8 @@ class ConsumeOrder(Resource): ...@@ -60,9 +62,8 @@ class ConsumeOrder(Resource):
def get(self): def get(self):
""".""" """."""
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空') user_id = request.user_id
args = self.parser.parse_args() data = order_service.CurriculumOrderService().get_order(user_id)
data = order_service.CurriculumOrderService().get_order(args)
resp = request.return_success resp = request.return_success
resp['attributes'] = data resp['attributes'] = data
return resp return resp
...@@ -73,9 +74,9 @@ class ConsumeOrder(Resource): ...@@ -73,9 +74,9 @@ class ConsumeOrder(Resource):
self.parser.add_argument('prod_id', type=str, required=True, help='商品ID不能为空') self.parser.add_argument('prod_id', type=str, required=True, help='商品ID不能为空')
self.parser.add_argument('prod_name', type=str, required=True, help='商品名称不能为空') self.parser.add_argument('prod_name', type=str, required=True, help='商品名称不能为空')
self.parser.add_argument('prod_quantity', type=int, required=True, help='商品数量不能为空') self.parser.add_argument('prod_quantity', type=int, required=True, help='商品数量不能为空')
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空')
self.parser.add_argument('pay_method', type=int, required=True, help='支付方式不能为空') self.parser.add_argument('pay_method', type=int, required=True, help='支付方式不能为空')
args = self.parser.parse_args() args = self.parser.parse_args()
args['user_id'] = request.user_id
order_service.CurriculumOrderService().create_order(args) order_service.CurriculumOrderService().create_order(args)
return request.return_success return request.return_success
...@@ -97,22 +98,18 @@ class TopUpOrderNotify(Resource): ...@@ -97,22 +98,18 @@ class TopUpOrderNotify(Resource):
def get(self): def get(self):
""".""" """."""
# raise CustomFlaskErr(Errors.USER_ALREADY_EXISTS)
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空')
args = self.parser.parse_args()
data = order_service.TopUpOrderService().get_order(args)
resp = request.return_success resp = request.return_success
resp['data'] = data
return resp return resp
def post(self): def post(self):
""".""" """."""
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空') res_info = request.stream.read(request.content_length or 0).decode()
self.parser.add_argument('amount', type=int, required=True, help='订单总额不能为空') res = order_service.alipayWxPayCheck(res_info)
self.parser.add_argument('pay_method', type=int, required=True, help='支付方式不能为空') if res['success']:
args = self.parser.parse_args() order_service.topUpSuccessAction(res['order_no'])
order_service.TopUpOrderService().create_order(args) resp = make_response(res['body'])
return request.return_success resp.hearders['Content-Type'] = res['header']['Content-Type']
return resp
def put(self, id): def put(self, id):
""".""" """."""
...@@ -132,24 +129,44 @@ class ConsumeOrderNotify(Resource): ...@@ -132,24 +129,44 @@ class ConsumeOrderNotify(Resource):
def get(self): def get(self):
""".""" """."""
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空')
args = self.parser.parse_args()
data = order_service.CurriculumOrderService().get_order(args)
resp = request.return_success resp = request.return_success
resp['data'] = data
return resp return resp
def post(self): def post(self):
""".""" """."""
self.parser.add_argument('prod_type', type=int, required=True, help='商品类型不能为空') res_info = request.stream.read(request.content_length or 0).decode()
self.parser.add_argument('prod_id', type=str, required=True, help='商品ID不能为空') res = order_service.alipayWxPayCheck(res_info)
self.parser.add_argument('prod_name', type=str, required=True, help='商品名称不能为空') if res['success']:
self.parser.add_argument('prod_quantity', type=int, required=True, help='商品数量不能为空') order_service.consumeSucessAction(res['order_no'])
self.parser.add_argument('user_id', type=str, required=True, help='用户ID不能为空') resp = make_response(res['body'])
self.parser.add_argument('pay_method', type=int, required=True, help='支付方式不能为空') resp.hearders['Content-Type'] = res['header']['Content-Type']
args = self.parser.parse_args() return resp
order_service.CurriculumOrderService().create_order(args)
return request.return_success def put(self, id):
"""."""
pass
def delete(self, id):
"""."""
pass
class AccountBalance(Resource):
""""""
def __init__(self):
"""."""
self.parser = reqparse.RequestParser()
def get(self):
"""."""
data = order_service.getAccountBalance()
resp = request.return_success
resp['attributes'] = data
return resp
def post(self):
"""."""
pass
def put(self, id): def put(self, id):
""".""" """."""
......
...@@ -19,3 +19,6 @@ def add_route(api): ...@@ -19,3 +19,6 @@ def add_route(api):
api.add_resource(TopUpOrderNotify, '/tamp_order/micro_shop/topUpOrderNotify') api.add_resource(TopUpOrderNotify, '/tamp_order/micro_shop/topUpOrderNotify')
# 消费订单支付通知 # 消费订单支付通知
api.add_resource(ConsumeOrderNotify, '/tamp_order/micro_shop/consumeOrderNotify') api.add_resource(ConsumeOrderNotify, '/tamp_order/micro_shop/consumeOrderNotify')
# 查询探普币余额
api.add_resource(AccountBalance, '/tamp_order/micro_shop/accountBalance')
...@@ -9,10 +9,17 @@ ...@@ -9,10 +9,17 @@
import time import time
from app.api.engine import tamp_pay_session, tamp_user_session from app.api.engine import tamp_pay_session, tamp_user_session
from app.config.errors import Errors
from app.controller.errorhandler import CustomFlaskErr
from app.model.account_balance import AccountBalance from app.model.account_balance import AccountBalance
from app.model.account_topup_order import AccountTopupOrder from app.model.account_topup_order import AccountTopupOrder
from app.model.curriculum_order import CurriculumOrder from app.model.curriculum_order import CurriculumOrder
from app.model.tamp_user_models import CurriculumPrice, CurriculumColumn, CurriculumRes 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: class TopUpOrderService:
...@@ -20,8 +27,8 @@ class TopUpOrderService: ...@@ -20,8 +27,8 @@ class TopUpOrderService:
def __init__(self): def __init__(self):
pass pass
def get_order(self, args): def get_order(self, user_id):
res = tamp_pay_session.query(AccountTopupOrder).filter(AccountTopupOrder.user_id==args['user_id']).all() res = tamp_pay_session.query(AccountTopupOrder).filter(AccountTopupOrder.user_id == user_id).all()
return [r.to_dict() for r in res] return [r.to_dict() for r in res]
...@@ -29,6 +36,21 @@ class TopUpOrderService: ...@@ -29,6 +36,21 @@ class TopUpOrderService:
args['order_no'] = time.strftime('%Y%m%d', time.localtime(time.time())) + str(int(time.time() * 100000)) args['order_no'] = time.strftime('%Y%m%d', time.localtime(time.time())) + str(int(time.time() * 100000))
args['id'] = AccountTopupOrder.__tablename__ + str(int(time.time() * 100000)) args['id'] = AccountTopupOrder.__tablename__ + str(int(time.time() * 100000))
args['amount'] = args['amount'] * 100 args['amount'] = args['amount'] * 100
args['order_status'] = 0
subject = '探普币充值'
out_trade_no = args['order_no']
notify_path = '/tamp_order/micro_shop/topUpOrderNotify'
if args['pay_method'] == 2:
wx_pay = WXPay(out_trade_no, subject, args['amount'], args['remote_addr'], notify_path=notify_path)
wx_pay.getReturnParams()
elif args['pay_method'] == 3:
total_amount = args['amount'] / 100
res = prePay(subject, out_trade_no, total_amount, notify_path=notify_path)
elif args['pay_method'] == 4:
receipt_data = args.get('receipt_data', '')
if not apple_pay(receipt_data):
raise CustomFlaskErr(Errors.APPLE_VOCHER_INVALID)
args['order_status'] = 1
order_info = AccountTopupOrder(**args) order_info = AccountTopupOrder(**args)
tamp_pay_session.add(order_info) tamp_pay_session.add(order_info)
tamp_pay_session.commit() tamp_pay_session.commit()
...@@ -41,11 +63,11 @@ class CurriculumOrderService: ...@@ -41,11 +63,11 @@ class CurriculumOrderService:
def __init__(self): def __init__(self):
pass pass
def get_order(self, args): def get_order(self, user_id):
""".""" """."""
curriculum_column = tamp_user_session.query(CurriculumColumn).all() curriculum_column = tamp_user_session.query(CurriculumColumn).all()
curriculum_res = tamp_user_session.query(CurriculumRes).all() curriculum_res = tamp_user_session.query(CurriculumRes).all()
res = tamp_pay_session.query(CurriculumOrder).filter(CurriculumOrder.user_id == args['user_id']).all() res = tamp_pay_session.query(CurriculumOrder).filter(CurriculumOrder.user_id == user_id).all()
curriculum_column = {r.id: r.to_dict() for r in curriculum_column} curriculum_column = {r.id: r.to_dict() for r in curriculum_column}
curriculum_res = {r.id: r.to_dict() for r in curriculum_res} curriculum_res = {r.id: r.to_dict() for r in curriculum_res}
orders = [r.to_dict() for r in res] orders = [r.to_dict() for r in res]
...@@ -105,4 +127,59 @@ def consumeSucessAction(order_no): ...@@ -105,4 +127,59 @@ def consumeSucessAction(order_no):
# 幂等校验 # 幂等校验
if curriculum_order.order_status == 1: if curriculum_order.order_status == 1:
return False return False
# tamp_pay_session.query(CurriculumOrder).filter(CurriculumOrder.order_no == ) tamp_pay_session.query(CurriculumOrder).filter(CurriculumOrder.order_no == order_no).update({
\ No newline at end of file 'order_status': 1
})
tamp_pay_session.commit()
def getAccountBalance(user_id):
"""查询探普币余额"""
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 = "<xml>{0}</xml>".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 = '<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> </xml>'
return {'success': success, 'header': header, 'body': body, 'order_no': res['out_trade_no']}
...@@ -86,7 +86,6 @@ def prePay(subject, out_trade_no, total_amount, notify_path='/webservice/notify' ...@@ -86,7 +86,6 @@ def prePay(subject, out_trade_no, total_amount, notify_path='/webservice/notify'
) )
if not result: if not result:
return False return False
print(result)
return result return result
def alipay_transfer(): def alipay_transfer():
......
...@@ -17,19 +17,13 @@ import pickle ...@@ -17,19 +17,13 @@ import pickle
import json import json
import urllib import urllib
def apple_pay(): def apple_pay(receipt_data):
"""苹果支付""" """苹果支付"""
''' '''
"receipt-data":receipt_data, "receipt-data":receipt_data,
"exclude-old-transactions":"true", "exclude-old-transactions":"true",
"password":"a1cdf6f00d3244aa9aa2c1c4a65b7ccf" "password":"a1cdf6f00d3244aa9aa2c1c4a65b7ccf"
''' '''
data = request.get_data()
# print(data)
# data = data.decode('utf8','replace')
data = eval(data)
receipt_data = data["receipt-data"]
receipt_data = urllib.request.unquote(receipt_data) receipt_data = urllib.request.unquote(receipt_data)
print(receipt_data) print(receipt_data)
...@@ -47,12 +41,12 @@ def apple_pay(): ...@@ -47,12 +41,12 @@ def apple_pay():
response = requests.post(AppStore_URL[0], data=dumped_json_string) response = requests.post(AppStore_URL[0], data=dumped_json_string)
if response.status_code == 200: if response.status_code == 200:
if response.json().get("status") == 21007: if response.json().get("status") == 21007:
print("ceshi")
response = requests.post(AppStore_URL[1], data=dumped_json_string) response = requests.post(AppStore_URL[1], data=dumped_json_string)
if response.status_code == 200: if response.status_code == 200:
return response.json() return True
# print(response.json()) return True
return response.json() return False
else:
return response.json()
if __name__ == '__main__':
receipt_data = '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'
apple_pay(receipt_data)
\ No newline at end of file
...@@ -91,6 +91,7 @@ class WXPay(object): ...@@ -91,6 +91,7 @@ class WXPay(object):
'trade_type': self.trade_type, 'trade_type': self.trade_type,
'sign': self.sign 'sign': self.sign
} }
print(self.data)
def dict2xml(self, dict_): def dict2xml(self, dict_):
"""将dict转为要发送到微信服务器的xml格式.""" """将dict转为要发送到微信服务器的xml格式."""
...@@ -117,15 +118,19 @@ class WXPay(object): ...@@ -117,15 +118,19 @@ class WXPay(object):
def getPaySign(self): def getPaySign(self):
""".""" """."""
sign_string = 'appId={0}&nonceStr={1}&package={6}prepay_id={2}&signType={3}&timeStamp={4}&key={5}'.format( sign_string = 'appId={0}&nonceStr={1}&package={6}prepay_id={2}&signType={3}&timeStamp={4}&key={5}'.format(
self.appid, self.nonce_str, self.prepay_id, self.sign_type, self.timeStamp, self.key, 'Sign=WXPay') self.appid, self.nonce_str, self.prepay_id, self.sign_type, self.timeStamp, self.key, 'Sign')
self.paySign = hashlib.md5(sign_string.encode("utf-8")).hexdigest().upper() self.paySign = hashlib.md5(sign_string.encode("utf-8")).hexdigest().upper()
def getReturnParams(self):
"""."""
params = {'app_id': self.appid, 'noncestr': self.nonce_str, 'mch_id': self.mch_id, 'prepay_id': self.prepay_id,
'sign': self.paySign, 'timestamp': self.timeStamp}
return params
if __name__ == '__main__': if __name__ == '__main__':
out_trade_no = '201812102324324134138' out_trade_no = '201812102324324134139'
body = 'APP支付测试' body = 'APP支付测试'
total_fee = 0.01 total_fee = 0.01
remote_addr = '101.95.188.178' remote_addr = '101.95.188.178'
wx = WXPay(out_trade_no, body, total_fee, remote_addr) wx = WXPay(out_trade_no, body, total_fee, remote_addr)
params = {'app_id': wx.appid, 'noncestr': wx.nonce_str, 'mch_id': wx.mch_id, 'prepay_id': wx.prepay_id, 'sign': wx.paySign, 'timestamp': wx.timeStamp} print(wx.getReturnParams())
print(params)
# -----------------------------------------------------------------------------
# File Name: wx_pay.py
# Author: X. Peng
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Functions
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Classes
# -----------------------------------------------------------------------------
import requests
import hashlib
import time
from xml.etree import cElementTree as etree
import random
from urllib import parse
def genNonce_str():
"""."""
sss = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
s = ''
for i in range(32):
s = s + random.choice(sss)
return s
class WXPay(object):
"""微信公众号支付."""
pre_pay_prefix = 'https://open.weixin.qq.com/connect/oauth2/authorize'
appid = ''
redirect_uri_prefix = ''
response_type = 'code'
scope = 'snsapi_base'
@classmethod
def prePay(cls, order_no, redirect_path='/webservice/order'):
pay_url = cls.pre_pay_prefix + '?' + parse.urlencode({
'appid': cls.appid,
'redirect_uri': cls.redirect_uri_prefix + redirect_path,
'response_type': cls.response_type,
'scope': cls.scope,
'state': order_no
}) + '#wechat_redirect'
return pay_url
def __init__(self, code, out_trade_no, body, total_fee, remote_addr, notify_path='/webservice/notify', return_path='/home/order'):
"""."""
self.timeStamp = int(time.time())
self.req_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'
self.appid = ''
self.secret = ''
self.openid = None
self.mch_id = ''
self.nonce_str = genNonce_str()
self.sign = None
self.sign_type = 'MD5'
self.body = body
self.out_trade_no = out_trade_no
self.total_fee = int(total_fee * 100)
self.spbill_create_ip = remote_addr
self.notify_url = self.redirect_uri_prefix + notify_path
self.return_url = self.redirect_uri_prefix + return_path
self.trade_type = 'JSAPI'
self.key = ''
self.prepay_id = None
self.getOpenid(code)
self.getStringSign()
self.getData()
self.getprepay_id()
self.getPaySign()
def getOpenid(self, code):
"""."""
url = 'https://api.weixin.qq.com/sns/oauth2/access_token'
params = {
'appid': self.appid,
'secret': self.secret,
'code': code,
'grant_type': 'authorization_code'
}
res = requests.get(url, params=params)
self.openid = res.json()['openid']
def getStringSign(self):
"""."""
self.string_sign_temp = 'appid={0}&body={1}&mch_id={2}&nonce_str={3}&notify_url={4}&openid={5}&out_trade_no={6}&sign_type={7}&spbill_create_ip={8}&total_fee={9}&trade_type={10}&key={11}'.format(
self.appid,
self.body,
self.mch_id,
self.nonce_str,
self.notify_url,
self.openid,
self.out_trade_no,
self.sign_type,
self.spbill_create_ip,
self.total_fee,
self.trade_type,
self.key
)
def getData(self):
"""."""
self.sign = hashlib.md5(self.string_sign_temp.encode("utf-8")).hexdigest().upper()
self.data = {
'appid': self.appid,
'body': self.body,
'mch_id': self.mch_id,
'nonce_str': self.nonce_str,
'notify_url': self.notify_url,
'openid': self.openid,
'out_trade_no': self.out_trade_no,
'sign_type': self.sign_type,
'spbill_create_ip': self.spbill_create_ip,
'total_fee': self.total_fee,
'trade_type': self.trade_type,
'sign': self.sign
}
def dict2xml(self, dict_):
"""将dict转为要发送到微信服务器的xml格式."""
s = ""
for k, v in dict_.items():
s += "<{0}>{1}</{0}>".format(k, v)
s = "<xml>{0}</xml>".format(s)
return s.encode("utf-8")
def xml2dict(self, content):
"""将从微信服务器接收到的xml转为dict."""
raw = {}
root = etree.fromstring(content)
for child in root:
raw[child.tag] = child.text
return raw
def getprepay_id(self):
"""."""
res = requests.post(self.req_url, data=self.dict2xml(self.data))
res = self.xml2dict(res.content)
self.prepay_id = res['prepay_id']
def getPaySign(self):
"""."""
sign_string = 'appId={0}&nonceStr={1}&package=prepay_id={2}&signType={3}&timeStamp={4}&key={5}'.format(self.appid, self.nonce_str, self.prepay_id, self.sign_type, self.timeStamp, self.key)
self.paySign = hashlib.md5(sign_string.encode("utf-8")).hexdigest().upper()
def getUI(self):
"""."""
text = '''<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>微信支付</title>
</head>
<script src="https://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
function onBridgeReady(){{
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {{
"appId":"{0}", //公众号名称,由商户传入
"timeStamp":"{1}", //时间戳,自1970年以来的秒数
"nonceStr":"{2}", //随机串
"package":"prepay_id={3}",
"signType":"MD5", //微信签名方式
"paySign":"{4}" //微信签名
}},
function(res){{
if(res.err_msg == "get_brand_wcpay_request:ok" ){{
window.location.href='{5}';
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}}
}});
}}
if (typeof WeixinJSBridge == "undefined"){{
if( document.addEventListener ){{
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}}
else if (document.attachEvent){{
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}}
}}
else{{
onBridgeReady();
}}
</script>
<body>
</body>
</html>'''.format(
self.appid,
self.timeStamp,
self.nonce_str,
self.prepay_id,
self.paySign,
self.return_url
)
return text
...@@ -4388,3 +4388,20 @@ WHERE curriculum_order.user_id = %(user_id_1)s ...@@ -4388,3 +4388,20 @@ WHERE curriculum_order.user_id = %(user_id_1)s
2020-11-25 17:39:37 Wed werkzeug INFO * Restarting with stat 2020-11-25 17:39:37 Wed werkzeug INFO * Restarting with stat
2020-11-25 17:39:39 Wed werkzeug WARNING * Debugger is active! 2020-11-25 17:39:39 Wed werkzeug WARNING * Debugger is active!
2020-11-25 17:39:39 Wed werkzeug INFO * Debugger PIN: 191-123-093 2020-11-25 17:39:39 Wed werkzeug INFO * Debugger PIN: 191-123-093
2020-11-25 17:41:11 Wed werkzeug INFO * Detected change in '/Users/pengxiong/Desktop/tamp_course_order/app/service/order_service.py', reloading
2020-11-25 17:41:11 Wed werkzeug INFO * Restarting with stat
2020-11-25 17:41:12 Wed werkzeug WARNING * Debugger is active!
2020-11-25 17:41:12 Wed werkzeug INFO * Debugger PIN: 191-123-093
2020-11-25 17:44:25 Wed werkzeug INFO * Detected change in '/Users/pengxiong/Desktop/tamp_course_order/app/router/version1.py', reloading
2020-11-25 17:44:25 Wed werkzeug INFO * Restarting with stat
2020-11-25 17:44:26 Wed werkzeug WARNING * Debugger is active!
2020-11-25 17:44:26 Wed werkzeug INFO * Debugger PIN: 191-123-093
2020-11-25 17:44:38 Wed werkzeug INFO 172.168.0.47 - - [25/Nov/2020 17:44:38] "GET /tamp_order/micro_shop/topUpOrder HTTP/1.1" 400 -
2020-11-25 17:44:54 Wed werkzeug INFO 172.168.0.47 - - [25/Nov/2020 17:44:54] "GET /tamp_order/micro_shop/topUpOrder HTTP/1.1" 200 -
2020-11-25 17:44:57 Wed werkzeug INFO 172.168.0.47 - - [25/Nov/2020 17:44:57] "GET /tamp_order/micro_shop/topUpOrder HTTP/1.1" 400 -
2020-11-25 17:45:19 Wed werkzeug INFO * Detected change in '/Users/pengxiong/Desktop/tamp_course_order/app/router/version1.py', reloading
2020-11-25 17:45:19 Wed werkzeug INFO * Restarting with stat
2020-11-25 17:45:20 Wed werkzeug WARNING * Debugger is active!
2020-11-25 17:45:20 Wed werkzeug INFO * Debugger PIN: 191-123-093
2020-11-25 17:51:48 Wed werkzeug INFO * Detected change in '/Users/pengxiong/Desktop/tamp_course_order/app/router/version1.py', reloading
2020-11-25 17:51:49 Wed werkzeug INFO * Restarting with stat
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment