django2.0调用微信支付接口实现PC端扫码支付

准备工作:

1.微信商户平台申请(具体流程参考网站内给出的步骤):
https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F
2.公众号、商户号

代码实现:

目录结构

django2.0调用微信支付接口实现PC端扫码支付_第1张图片

pay.py 文件
class WeChartPay(object):
    def __init__(
            self,
            appid,
            mch_id,
            spbill_create_ip,
            notify_url,
            body,
            detail,
            trade_type
    ):
        self.appid = appid  # APPID
        self.mch_id = mch_id  # 商户号
        self.spbill_create_ip = spbill_create_ip  # 自己服务器地址
        self.notify_url = notify_url  # 回调地址
        self.body = body  # 商家描述
        self.detail = detail  # 商品描述
        self.trade_type = trade_type  # 扫码支付类型

    def build_data_dict(self, out_trade_no, total_fee):
        data_dict = {
            'appid': self.appid,
            'mch_id': self.mch_id,
            'nonce_str': self.random_str(),  # 随机字符串
            'out_trade_no': out_trade_no,  # 订单编号
            'total_fee': total_fee,  # 订单总金额
            'spbill_create_ip': self.spbill_create_ip,  # 自己服务器的IP地址
            'notify_url': self.notify_url,  # 回调地址,微信支付成功后会回调这个url,告知商户支付结果
            'body': self.body,  # 商品描述
            'detail': self.detail,  # 商品描述
            'trade_type': self.trade_type,  # 扫码支付类型
        }
        return data_dict

    def get_sign(self, data_dict, key):
        """
        签名函数
        :param data_dict: 需要签名的参数,格式为字典
        :param key: 密钥 ,即上面的API_KEY
        :return: 字符串
        """
        params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=False)  # 参数字典倒排序为列表
        params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key
        # 组织参数字符串并在末尾添加商户交易密钥
        md5 = hashlib.md5()  # 使用MD5加密模式
        md5.update(params_str.encode('utf-8'))  # 将参数字符串传入
        sign = md5.hexdigest().upper()  # 完成加密并转为大写
        return sign

    def random_str(self, randomlength=8):
        """
        生成随机字符串
        :param randomlength: 字符串长度
        :return:
        """
        strs = ''
        chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
        length = len(chars) - 1
        random = Random()
        for i in range(randomlength):
            strs += chars[random.randint(0, length)]
        return strs

    def trans_dict_to_xml(self, 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('):  # 添加XML标记
                v = ''.format(v)
            data_xml.append('<{key}>{value}'.format(key=k, value=v))
        return '{}'.format(''.join(data_xml))  # 返回XML

    def trans_xml_to_dict(self, 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
views.py 文件
# 获取一个WeChartPay对象
def get_wecpay_object(uid):
    wecpay = WeChartPay(
        appid=WeChartPayConfig.app_id,
        mch_id=WeChartPayConfig.mch_id,
        spbill_create_ip=WeChartPayConfig.create_ip,
        notify_url=WeChartPayConfig.notify_url+uid+'/',
        body='xxx',   # 可写商户名称或收款方
        detail='xxxx',  # 可写订单名或商品名
        trade_type='NATIVE'
    )
    return wecpay


# 微信充值
def weChart_pay(request,uid):
    money = request.POST.get('money')
    wecpay = get_wecpay_object(uid)
    # order_name()是一个生成随机订单的函数,可自定义
    out_trade_no = order_num('xx',uid)  # 生成一个唯一的订单号(根据自己的订单生成逻辑)
    params = wecpay.build_data_dict(out_trade_no,int(float(money)*100))  # 创建一个请求参数字典

    sign = wecpay.get_sign(params,WeChartPayConfig.api_key)  # 获取签名
    params['sign'] = sign  # 在参数字典中添加签名
    print(params)
    xml = wecpay.trans_dict_to_xml(params)  # 将字典转换为xml
    response = requests.request('post',WeChartPayConfig.ufdoder_url,data=xml)  # 以post方式向微信平台服务器发起请求
    data_dict = wecpay.trans_xml_to_dict(response.content)  # 将请求返回的数据转为字典

    # 如果请求成功
    if data_dict.get('return_code') == 'SUCCESS':
        qrcode_name = out_trade_no + '.png'  # 二维码图片名称(此处使用订单号+’.png‘作为图片名称,你也可以自定义,只要保证唯一即可)
        img = qrcode.make(data_dict.get('code_url'))  # 创建支付二维码
        img.save(r'static' + '/qrcode/' + qrcode_name)  # 保存二维码图片
        return render(request,'user_center/qrcode.html',{'qrcode_img':qrcode_name})
    return HttpResponse('获取微信的code_url失败!')


# 支付成功后回调(微信)
@csrf_exempt
def wec_notify(request,uid):
    wecpay = get_wecpay_object(uid)
    data_dict = wecpay.trans_xml_to_dict(request.body)  # 将回调返回的数据转化为字典
    sign = data_dict.pop('sign')  # 取出签名
    key = WeChartPayConfig.api_key  # 商户密钥
    back_sign = wecpay.get_sign(data_dict,key)  # 计算签名
    if sign == back_sign:
        '''
        若没有进行过业务处理则进行业务处理
        '''

        print('支付成功')
        return HttpResponse('success')
    else:
        '''
        支付失败后业务逻辑
        '''
        return HttpResponse('支付失败')
sittings.py 文件
class WeChartPayConfig(object):
    # 公众账号上的appid
    app_id = ""

    # 商户号
    mch_id = ""

    # 微信商户平台(pay.weixin.qq.com)-->账户设置 -->API安全-->密钥设置,设置完成后把密钥复制过来
    api_key = ""

    app_secrect= ""

    # 微信下单url
    ufdoder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"

    # 微信支付结果回调接口,改为服务器上处理结果的回调方法路径
    notify_url = "http://xxx/"

    # 你的服务器ip
    create_ip = ""

以上代码仅供参考,如若直接商用出现任何后果概不负责。

你可能感兴趣的:(django)