Python+Django实现微信支付

微信支付

在实现这个功能之前,你需要在微信开放平台注册账号并激活。在平台里创建一个应用,得到app_id和weixin_key等关键信息。

创建微信支付请求

申请完成后,我们尝试创建微信支付的请求。

def create_weixin_request(product_id, trade_no, body, total_fee, client_ip):
    total_fee = int(total_fee * 100)
    nonce_str = __get_random_sign(32) # 获取随机字符串函数
    stringA = "appid="+APP_ID+"&body="+BODY + body + "&mch_id="+MCH_ID+"&nonce_str="+nonce_str + "&notify_url="+NOTIFY_URL + \
        "&out_trade_no="+trade_no+"&product_id="+product_id+"&spbill_create_ip="+client_ip+"&total_fee=" + str(total_fee) + \
        "&trade_type="+TRADE_TYPE
    stringSignTemp = stringA + "&key="+WEIXIN_KEY
    sign = __get_md5_sign(stringSignTemp) # 加密
    data = "<xml><appid><![CDATA["+APP_ID+"]]></appid><body><![CDATA["+BODY+body+"]]></body><mch_id><![CDATA["+MCH_ID + \
        "]]></mch_id><nonce_str><![CDATA["+nonce_str+"]]></nonce_str><notify_url><![CDATA["+NOTIFY_URL + \
        "]]></notify_url><out_trade_no><![CDATA["+trade_no+"]]></out_trade_no><product_id><![CDATA["+product_id + \
        "]]></product_id><spbill_create_ip><![CDATA["+client_ip+"]]></spbill_create_ip><total_fee><![CDATA[" + \
        str(total_fee) + "]]></total_fee><trade_type><![CDATA[NATIVE]]></trade_type><sign>" + \
        sign+"</sign></xml>"
    return nonce_str, data

获取微信支付二维码

def get_weixin_qrcode(data):
    import urllib3
    urllib3.disable_warnings()
    http = urllib3.PoolManager()
    r = http.request('POST', WEIXIN_PAY_URL, headers={
                     'Content-Type': 'text/xml'}, fields={'data': data})
    result_xml = bytes.decode(r.data)
    import xml.etree.ElementTree as ET
    tree = ET.fromstring(result_xml)
    return tree[-1].text

以上两个函数都是在购买的视图函数中进行调用

def purchase(request, product):
    user_id = TYPE_MARK + str(request.user.id)
    user_product = CATEGORY_MARK + str(request.user.id)
    if request.method == 'GET':
        request.session[user_id] = str(time.time())
        request.session[user_product] = product
        price = PRICES.get(product)
        rebate = REBATE.get(product)
        years = 1
        if price:
            return render(request, 'purchase.html', locals())
        else:
            return server_error(request)
    elif request.method == 'POST':
        if request.is_ajax():
            purchase_user = request.session.get(user_id, None)
            purchase_product = request.session.get(user_product, None)
            if not purchase_user:
                return JsonResponse({'error': '订单购买人有误,请重新下单。'})
            elif purchase_product != product:
                return JsonResponse({'error': '订单产品有误,请重新下单。'})
            if request.user.has_vip_permission():
                return JsonResponse({'error': '您的VIP权限尚未过期,请勿重复下单。'})

            total_fee = int(request.POST.get('totalFee'))
            is_rebate = request.POST.get('isRebate') == 'true'
            years = int(request.POST.get('years'))

            price = PRICES.get(product)
            rebate = REBATE.get(product) if is_rebate else 0
            compute_total_fee = (
                price * years - rebate) if is_rebate else (price * years)
            checks = compute_total_fee == total_fee

            if checks:
                client_ip = request.META['REMOTE_ADDR']
                order = Orders.purchase(
                    product, price, years, 'W', request.user, rebate=rebate)
                # 测试订单处理
                from persona.product_settings import SOURCE_HOSTS as PROD_HOST
                if SOURCE_HOSTS != PROD_HOST:
                    order.modify(totalFee=0.01)
                    number = 'T' + order.number
                    order.modify(number=number)
                (nonce_str, data) = create_weixin_request(order.product.name,
                                                     order.number, order.product.displayName, order.totalFee, client_ip)
                qrcode = get_weixin_qrcode(data)
                if qrcode.find('weixin://wxpay/') >= 0:
                    order.modify(paymentRnd=nonce_str)
                    return JsonResponse({'qrcode': qrcode, 'number': order.number, 'total_fee': total_fee})
                else:
                    order.delete()
                    return JsonResponse({'error': qrcode})
            else:
                return JsonResponse({'error': '订单总价有误,请重新下单。'})
        else:
            return server_error(request)

二维码通过js进行呈现

<script type="text/javascript">
        var mrUpdatePrice = (function () {
            var priceElements = document.querySelectorAll('.js-price');
            var hideSignup = document.querySelectorAll('.js-pricing-charge-description');
            var sign = document.querySelector('.js-rmb-sign');
            var price = Number($("#price").val());
            var rebate = Number($("#rebate").val());
            var prices = ['免费体验'];
            var years = $('.js-years-per-order');
            var titleText = '<h4>微信支付</h4><p>订单提交成功,请完成支付。</p>'
            $("#customSwitch1").click(function () {
                if ($(priceElements).text() != '免费体验') {
                    if ($("#customSwitch1")[0].checked) {
                        $(priceElements).text(Number($(priceElements).text()) - rebate)
                    } else {
                        $(priceElements).text(Number($(priceElements).text()) + rebate)
                    }
                }
            })

            $("#buy").on('click', function () {
                var currentUrl = location.pathname
                var totalFee = Number($('.js-price').text());
                var yearsNum = Number(years.text());
                $('#anew-buy').attr('href',currentUrl)
                $('#pay-ques').attr('href',currentUrl)
                data = {
                    'totalFee': totalFee, 
                    'isRebate': $("#customSwitch1")[0].checked,
                    'years': yearsNum,
                };
                $.ajax({
                    type: "POST",
                    url: currentUrl,
                    data: data,
                    dataType: "JSON",
                    success: function (data) {
                        if (data.qrcode != undefined) {
                            $("#pay-message").removeClass('hide');
                            $('#title').html(titleText);
                            $('#price-dom').addClass('hide');
                            $('#totalprice').html('<p>订单编号:'+ data.number +'</p>'+
                                '<p>应付金额 <span class="text-primary">¥'+data.total_fee +'</span> 元</p>');
                            $('#price-dom').next().removeClass('mt-5');
                            $("#title").parent().removeClass('mb-4');
                            new QRCode(document.getElementById("qrcode"), data.qrcode);
                            $('#cost').addClass('hide')
                            $('#cost-code').removeClass('hide')

                            var orderNumber = data.number;
                            var timesRun = 0;
                            setTimeout(function () {
                                var isPayRequest = false;
                                var interval = setInterval(function () {
                                    if (isPayRequest) {
                                        $("#order-modal").modal("show");
                                        clearInterval(interval);
                                    }
                                    if (!isPayRequest) {
                                        $.ajax({
                                            url: "/orders/status",
                                            type: "POST",
                                            data: { "number": orderNumber },
                                            dataType: "json",
                                            success: function (data) {
                                                if (data.status == "success") {
                                                    isPayRequest = true;
                                                }
                                            }
                                        });
                                    }
                                    timesRun += 1;
                                    if (timesRun === 30) {
                                        clearInterval(interval);
                                    }
                                }, 1000);
                            }, 20)
                        } else if (data.error != undefined) {
                            $('#error-msg').text(data.error)
                            if (data.error.indexOf("VIP") >= 0) {
                                $("#anew-buy").addClass('hide');
                            } else {
                                $("#anew-buy").removeClass('hide');
                            }
                            $('#error-modal').modal('show');
                        }
                    }
                });
           
            })

            var updatePrice = function (data) {
                if (sign) {
                    sign.classList[data.from < 1 ? 'add' : 'remove']('d-none');
                }
                theme.mrUtil.forEach(priceElements, function (index, element) {
                    if (data.from >= 1) {
                        if ($("#customSwitch1")[0].checked) {
                            element.textContent = price * data.from - rebate;
                        } else {
                            element.textContent = price * data.from;
                        }
                        $('.js-pricing-charge-description').text('每年可创建5个项目,运行60次分析');
                        $('#exp').addClass('hide')
                        $('#buy').removeClass('hide')
                    } else {
                        element.textContent = prices[data.from];
                        $('.js-years-per-order').text(1);
                        $('.js-years-word').text('月');
                        $('.js-pricing-charge-description').text('可创建1个项目,运行1次基线分析');
                        $('#buy').addClass('hide')
                        $('#exp').removeClass('hide')
                    }
                });
            };
            return updatePrice;
        })();
    </script>

扫描二维码后,支付函数

@csrf_exempt
def pay(request):
    if request.method == 'POST':
        response = HttpResponse()
        import xml.etree.ElementTree as et
        return_xml = bytes.decode(request.body)
        tree = et.fromstring(return_xml)
        return_code = tree.find("return_code").text
        _return_number = tree.find("out_trade_no").text
        # 测试订单不作处理
        if _return_number.find('T') >= 0:
            response.status_code = 200
            return response
        if return_code == 'FAIL':
            result = '支付失败'
            _send_order_email("test@163.com", "", _return_number, xml=return_xml, error=result)
        elif return_code == 'SUCCESS':
            _return_nonce_str = tree.find("nonce_str").text
            _return_total_fee = tree.find("total_fee").text
            order = Orders.check_weixin_order(
                _return_number, _return_total_fee, _return_nonce_str)
            if order:
                if order.dateOfPayment and order.dateOfPayment < datetime.now():
                    response.status_code = 302
                else:
                    order.modify(dateOfPayment=datetime.now())
                    order.by.subscribe(order.product.name, order.product.amount)
                    _send_order_email(order.by.account, order.product.displayName, _return_number)
                    _send_order_email("test@163.com", order.product.displayName, _return_number)
                    response.status_code = 200
            else:
                _send_order_email("test@163.com", "", _return_number, xml=return_xml, error="找不到订单")
                response.status_code = 400
        return response
    return Http404
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Django实现微信支付功能,需要遵循以下步骤: 1. 在微信商户平台注册账号并开通微信支付功能。 2. 安装 `wechatpy` 包,这是一个专门用于微信支付Python库。 3. 在 `settings.py` 文件中添加以下代码: ```python WECHAT_APPID = 'your-appid' WECHAT_MCH_ID = 'your-merchant-id' WECHAT_MCH_KEY = 'your-merchant-key' WECHAT_NOTIFY_URL = 'your-notify-url' ``` 这些参数可以在微信商户平台上找到。 4. 创建一个 `Payment` 模型,用于存储支付订单信息。示例代码: ```python from django.db import models class Payment(models.Model): out_trade_no = models.CharField(max_length=32, unique=True) total_fee = models.IntegerField() body = models.CharField(max_length=100) openid = models.CharField(max_length=32) trade_type = models.CharField(max_length=16) prepay_id = models.CharField(max_length=64) nonce_str = models.CharField(max_length=32) created_time = models.DateTimeField(auto_now_add=True) ``` `out_trade_no` 是订单号,`total_fee` 是支付金额,`body` 是订单描述,`openid` 是用户的微信openid,`trade_type` 是交易类型,`prepay_id` 是预支付订单ID,`nonce_str` 是随机字符串,`created_time` 是订单创建时间。 5. 编写视图函数,用于处理支付请求和回调通知。示例代码: ```python from django.http import JsonResponse from wechatpy.pay import WeChatPay from .models import Payment from . import settings wechat_pay = WeChatPay( appid=settings.WECHAT_APPID, mch_id=settings.WECHAT_MCH_ID, api_key=settings.WECHAT_MCH_KEY, ) def pay(request): openid = request.GET.get('openid') total_fee = request.GET.get('total_fee') body = request.GET.get('body') out_trade_no = 'your-out-trade-no' # 调用微信支付API result = wechat_pay.order.create( trade_type='JSAPI', body=body, total_fee=total_fee, notify_url=settings.WECHAT_NOTIFY_URL, openid=openid, out_trade_no=out_trade_no, ) # 保存支付订单信息 Payment.objects.create( out_trade_no=out_trade_no, total_fee=total_fee, body=body, openid=openid, trade_type=result['trade_type'], prepay_id=result['prepay_id'], nonce_str=result['nonce_str'], ) # 返回支付参数 jsapi_params = wechat_pay.jsapi.get_jsapi_params(result['prepay_id']) return JsonResponse(jsapi_params) def notify(request): xml_data = request.body.decode('utf-8') result = wechat_pay.parse_payment_result(xml_data) out_trade_no = result['out_trade_no'] payment = Payment.objects.get(out_trade_no=out_trade_no) # 更新订单状态 payment.status = 'SUCCESS' payment.transaction_id = result['transaction_id'] payment.time_end = result['time_end'] payment.save() return HttpResponse('SUCCESS') ``` `pay` 视图函数用于创建预支付订单并返回支付参数,`notify` 视图函数用于处理支付回调通知并更新订单状态。 6. 在微信公众号中实现支付功能,需要调用 `wx.chooseWXPay` 函数。示例代码: ```javascript wx.chooseWXPay({ appId: 'your-appid', timestamp: 'your-timestamp', nonceStr: 'your-noncestr', package: 'prepay_id=your-prepayid', signType: 'MD5', paySign: 'your-paysign', success: function(res) { // 支付成功 }, fail: function(res) { // 支付失败 } }); ``` 以上就是在Django实现微信支付功能的步骤和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值