#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import tornado.web
from methods.common import *
from methods.db import *
import traceback
import logging
import uuid
import requests
import json
import xmltodict
import time
import pymysql
import datetime
import random
from hashlib import md5
#數(shù)據(jù)庫
MYSQL = dict(
host='127.0.0.1', user='root', passwd='123456', db='kbe', charset="utf8mb4"
)
logger = logging.getLogger(__name__)
conn = pymysql.connect(**MYSQL)
cur_dict = conn.cursor(pymysql.cursors.DictCursor)
cur = conn.cursor()
from hashlib import md5
from requests.packages import urllib3
urllib3.disable_warnings()
###############################################
############# 微信支付配置 #################
###############################################
WeChaPayConfig = {
# 微信支付APP_ID
'APPID' : 'wx91f04ffbf8a23431',
# 微信支付MCH_ID 【登錄賬號】
'MCHID' : '1535411231',
# 微信支付sign_type
'SIGNTYPE' : 'MD5',
# 服務(wù)器IP地址
'SPBILLCREATEIP' : '32.23.11.34',
# 微信支付用途
'BODY' : '費(fèi)用充值',
# 微信KEY值 【API密鑰】
'KEY' : 'ZiwcVpWomDqixQdhRgm5FpBKNXqwasde',
# 微信統(tǒng)一下單URL
'UNIFIEDORDERURL' : 'https://api.mch.weixin.qq.com/pay/unifiedorder',
# 微信查詢訂單URL
'QUERYORDERURL' : 'https://api.mch.weixin.qq.com/pay/orderquery',
# 微信支付回調(diào)API
'CALLBACKAPI' : 'http://xxxx.com/weixinpay_rollback/',
}
def make_payment_info(notify_url=None, out_trade_no=None, total_fee=None,device_info = 'Phone'):
order_info = {'appid': WEIXIN_APP_ID,
'mch_id': WEIXIN_MCH_ID,
'device_info': device_info,
'nonce_str': '',
'sign_type': WEIXIN_SIGN_TYPE,
'body': WEIXIN_BODY,
'out_trade_no': str(out_trade_no),
'total_fee': total_fee,
'spbill_create_ip': WEIXIN_SPBILL_CREATE_IP,
'notify_url': notify_url,
'trade_type': 'APP'}
return order_info
def make_payment_request_wx(notify_url, out_trade_no, total_fee,device_info):
"""
微信統(tǒng)一下單,并返回客戶端數(shù)據(jù)
:param notify_url: 回調(diào)地址
:param out_trade_no: 訂單編號
:param total_fee: 充值金額
:param device_info:設(shè)備信息
:return: app所需結(jié)果數(shù)據(jù)
"""
def generate_call_app_data(params_dict, prepay_id):
"""
客戶端APP的數(shù)據(jù)參數(shù)包裝
"""
request_order_info = {'appid': params_dict['appid'],
'partnerid': params_dict['mch_id'],
'prepayid': prepay_id,
'package': 'Sign=WXPay',
'noncestr': generate_nonce_str(),
'timestamp': str(int(time.time()))}
request_order_info['sign'] = generate_sign(request_order_info)
return request_order_info
def generate_sign(params):
"""
生成md5簽名的參數(shù)
"""
if 'sign' in params:
params.pop('sign')
src = '&'.join(['%s=%s' % (k, v) for k, v in sorted(params.items())]) + '&key=%s' % WEIXIN_KEY
return md5(src.encode('utf-8')).hexdigest().upper()
def generate_nonce_str():
"""
生成隨機(jī)字符串
"""
return str(uuid.uuid4()).replace('-', '')
def generate_request_data(params_dict):
"""
生成統(tǒng)一下單請求所需要提交的數(shù)據(jù)
"""
params_dict['nonce_str'] = generate_nonce_str()
params_dict['sign'] = generate_sign(params_dict)
return xmltodict.unparse({'xml': params_dict}, pretty=True, full_document=False).encode('utf-8')
def make_payment_request(params_dict, unified_order_url):
"""
生成返回給客戶端APP的數(shù)據(jù)參數(shù)
"""
data = generate_request_data(params_dict)
headers = {'Content-Type': 'application/xml'}
res = requests.post(unified_order_url, data=data, headers=headers,verify=False)
if res.status_code == 200:
result = json.loads(json.dumps(xmltodict.parse(res.content)))
if result['xml']['return_code'] == 'SUCCESS':
prepay_id = result['xml']['prepay_id']
return generate_call_app_data(params_dict, prepay_id), result['xml']
else:
return result['xml']['return_msg'], None
print('http錯誤碼:::::::{0}'.format(str(res)))
return None, None
if float(total_fee) < 0.01:
raise Exception('充值金額不能小于0.01')
payment_info = make_payment_info(notify_url=notify_url, out_trade_no=out_trade_no, total_fee=total_fee,device_info=device_info)
res, info = make_payment_request(payment_info, WEIXIN_UNIFIED_ORDER_URL)
print('微信支付 res={0} info={1}'.format(res,info))
return res, info
def create_order_number():
"""
生成訂單號
:return:
"""
date = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
# 生成4為隨機(jī)數(shù)作為訂單號的一部分
random_str = str(random.randint(1, 9999))
random_str = random_str.rjust(4, '0')
rtn = '%s%s' % (date, random_str)
return rtn
def weixin_create_order(money,UserId,itemId):
"""
【API】: 創(chuàng)建訂單,供商戶app調(diào)用
"""
#金額,浮點(diǎn)型
#設(shè)備信息:pid:tm
device_info = str(UserId)
res = {
'code': 1,
'msg': 'error'
}
try:
price = money#0.01 # 0.99元,微信的單位為分,需要轉(zhuǎn)為分
out_trade_no = create_order_number()
order_info, info = make_payment_request_wx(WEIXIN_CALLBACK_API, out_trade_no, int(float(price) * 100),device_info)
if order_info and info:
print('產(chǎn)生訂單返回=======')
print(info)
info['total_amount'] = int(float(price) * 100)
if info['result_code'] == "SUCCESS":
order_info['out_trade_no'] = out_trade_no
res['order_info'] = order_info
if isinstance(order_info,dict):
order_info['pid'] = UserId
order_info['itemId'] = itemId
#待微信服務(wù)器校驗(yàn)后再行入庫
print('客戶端返回')
print(order_info)
#入庫
WeiChatPayAdd(int(UserId), out_trade_no,WEIXIN_MCH_ID,WEIXIN_APP_ID)
return order_info
# 調(diào)用統(tǒng)一創(chuàng)建訂單接口失敗
else:
res['msg'] = info['result_code']
elif order_info:
res['msg'] = order_info
res['code'] = -1
else:
res['code'] = -2
return None
except Exception as e:
# traceback.print_exc()
print(e)
return None
# finally:
# return json.dumps(res)
class WeChatOrderHandler(tornado.web.RequestHandler):
def post(self):
"""客戶端發(fā)來的請求微信訂單"""
def pro(recv):
if recv:
if recv.__contains__('UserId'): #玩家id
userId = str(recv.pop('UserId')[0], encoding='utf-8')
if recv.__contains__('money'): #金額
money = str(recv.get('money')[0], encoding='utf-8')
if recv.__contains__('itemId'): #商品
itemId = str(recv.get('itemId')[0],encoding='utf-8')
print('微信支付參數(shù) pid={0},,money={1}'.format(userId, money))
#這里的post必須是同步阻塞,這里可以存入更多的設(shè)備信息在weixin_create_order的第三個參數(shù)里
response = weixin_create_order(money,userId,itemId)
# """返回到客戶端"""
if response=='':
print('錯誤=====')
else:
#返回到客戶端(必須是異步post請求)
requests.post('http://localhost:30041/wechat', data=response)
self.write('Success')
recv1 = self.request.arguments
from threading import Timer
# 指定1秒后執(zhí)行
t = Timer(1.0, pro,(recv1,))
t.start()