url('ic/order/(?P<order_id>.+)/payment/', views_front.PaymentView.as_view()), # 元器件微信支付
url('ic/wechatpay/', views_front.Wxpay_Result.as_view()), # 订单支付成功回调
# 二、定义两个函数用来转换文本类型
def trans_dict_to_xml(data_dict):
"""
定义字典转XML的函数
:param data_dict:
:return:
"""
data_xml = []
for k in sorted(data_dict.keys()): # 遍历字典排序后的key
v = data_dict.get(k) # 取出字典中key对应的value
if k == 'detail' and not v.startswith('<![CDATA['): # 添加XML标记
v = '<![CDATA[{}]]>'.format(v)
data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
return '<xml>{}</xml>'.format(''.join(data_xml)) # 返回XML
def trans_xml_to_dict(data_xml):
"""
定义XML转字典的函数
:param data_xml:
:return:
"""
soup = BeautifulSoup(data_xml, features='xml')
xml = soup.find('xml') # 解析XML
if not xml:
return {}
data_dict = dict([(item.name, item.text) for item in xml.find_all()])
return data_dict
# 三、后台传order_id与open_id给到前台
import random
import string
from math import floor
from datetime import datetime, timedelta
from wechatpy.utils import timezone
class PaymentView(APIView):
"""微信支付"""
def get(self, request, order_id):
open_id = request.query_params.get('openid')
try:
order = OrderInfo.objects.get(order_id=order_id,
pay_method=OrderInfo.PAY_METHODS_ENUM['WEXIN'],
status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'])
except OrderInfo.DoesNotExist:
return Response({'message': '订单信息有误'}, status=status.HTTP_400_BAD_REQUEST)
wechatpay = WeChatPay(
appid=settings.APPID,
api_key=settings.API_KEY,
mch_id=settings.MCH_ID,
mch_cert=os.path.join(os.path.dirname(os.path.abspath(__file__)), "../keys/apiclient_cert.pem"),
mch_key=os.path.join(os.path.dirname(os.path.abspath(__file__)), "../keys/apiclient_key.pem"),
timeout=300
)
total_fee = floor(order.total_amount * 100)
now = datetime.fromtimestamp(time.time(), tz=timezone('Asia/Shanghai'))
hours_later = now + timedelta(seconds=60)
pay_data = wechatpay.order.create(
trade_type="JSAPI",
body='百度%s' % order_id,
total_fee=total_fee,
notify_url='http://www.baidu.com/ic/wechatpay/', # 微信支付成功后的回调地址,一定要能被外网访问到, 注:“http://www.baidu.com” =》域名,“ic/wechatpay”=》接口。
user_id=open_id,
out_trade_no="JSAPI" + order_id,
product_id=1,
time_expire=hours_later
)
timestamp = str(int(time.time()))
nonce_str = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(15))
params = wechatpay.jsapi.get_jsapi_params(
prepay_id=pay_data['prepay_id'],
timestamp=timestamp,
nonce_str=nonce_str,
)
signature = wechatpay.jsapi.get_jsapi_signature(
prepay_id=pay_data['prepay_id'],
timestamp=timestamp,
nonce_str=nonce_str,
)
params['signature'] = signature
return Response(params)
class Wxpay_Result(APIView):
"""
微信支付结果回调通知路由
"""
def post(self, request, *args, **kwargs):
"""
微信支付成功后会自动回调
"""
a = request.body.decode('utf-8')
data_dict = trans_xml_to_dict(a) # 回调数据转字典
wechatpay = WeChatPay(
appid=settings.APPID,
api_key=settings.API_KEY,
mch_id=settings.MCH_ID,
mch_cert=os.path.join(os.path.dirname(os.path.abspath(__file__)), "../keys/apiclient_cert.pem"),
mch_key=os.path.join(os.path.dirname(os.path.abspath(__file__)), "../keys/apiclient_key.pem"),
timeout=300
)
sign = wechatpay.check_signature(data_dict)
if data_dict['return_code'] == 'SUCCESS' and sign:
'''
检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成 功。
'''
OrderInfo.objects.filter(order_id=data_dict['out_trade_no'][5:]).update(
status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'])
# 处理支付成功逻辑
# 返回接收结果给微信,否则微信会每隔8分钟发送post请求
return HttpResponse(trans_dict_to_xml({'return_code': 'SUCCESS', 'return_msg': 'OK'}))
return HttpResponse(trans_dict_to_xml({'return_code': 'FAIL', 'return_msg': 'SIGNERROR'}))
# 如有错误还请指出,感谢!!!!