56- 项目 -18 - 用户中心-订单页

一. 用户中心-订单页

        1. 编辑用户中心-订单页类视图
# user / views.py

import re
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.core.mail import send_mail
from django.core.paginator import Paginator
from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.urls import reverse
# 显示异常,但不会报错
from django.views.generic import View
from user.models import User, Address
from goods.models import GoodsSKU
from order.models import OrderInfo, OrderGoods

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, SignatureExpired
from apps.celery_tasks.tasks import send_register_activer_email
from util.mixin import LoginRequiredMixin

# /user/order
class UserOrderView(LoginRequiredMixin, View):
    """用户中心 - 订单页"""

    def get(self, request, page):
        """显示"""
        # 获取用户的订单信息
        user = request.user
        orders = OrderInfo.objects.filter(user=user).order_by('-create_time')

        # 遍历获取订单商品的信息
        for order in orders:
            # 根据order_id查询订单商品信息
            order_skus = OrderGoods.objects.filter(order_id=order.order_id)

            # 遍历order_skus计算商品的小计
            for order_sku in order_skus:
                # 计算小计
                amount = order_sku.count * order_sku.price
                # 动态给order_sku增加属性amount,保存订单商品的小计
                order_sku.amount = amount

            # 动态给order增加属性,保存订单状态标题
            order.status_name = OrderInfo.ORDER_STATUS[order.order_status]

            # 动态给order增加属性,保存订单商品的信息
            order.order_skus = order_skus

        # 分页
        paginator = Paginator(orders, 1)

        # 获取page页的内容
        try:
            page = int(page)
        except Exception as e:
            page = 1
        if page > paginator.num_pages:  # 判断是否大于总结书
            page = 1

        # 获取第 page页 的Page实例对象
        order_page = paginator.page(page)

        # todo: 进行页码的控制,页面上最多显示5个页码
        # 1. 总页数小于5页,页面上显示所有页码
        # 2. 如果当前页是前3页,显示1-5页
        # 3. 如果当前页是后3页,显示后5页
        # 4. 其他情况,  显示当前页的前2页,当前页,当前页后2页
        num_pages = paginator.num_pages
        if num_pages < 5:
            pages = range(1, num_pages + 1)
        elif page <= 3:
            pages = range(1, 6)
        elif num_pages - page <= 2:
            pages = range(num_pages - 4, num_pages + 1)
        else:
            pages = range(page - 2, page + 3)

        # 组织上下文
        context = {
            'order_page': order_page,
            'pages': pages,
            # page:'order': 用户中心显示的那个页面
            'page': 'order'
        }
        # 使用模板
        return render(request, 'user_center_order.html', context)
        2. 编辑用户中心-订单页路由
# user / urls.py

from django.conf.urls import url
from apps.user.views import RegisterView, ActiveView, LoginView, UserInfoView, UserOrderView, UserSiteView, LogoutView

app_name = "user"  # 指定命名空间
urlpatterns = [
    ...
    url(r'^order/(?P<page>\d+)$', UserOrderView.as_view(), name='order'),  # 用户中心-订单页

]
        3. 编辑用户中心-订单页模型

                (user_center_order.html)准备中...

二. 支付宝简介

        1. 登录支付宝开发平台

                             支付宝开放平台icon-default.png?t=N7T8https://openhome.alipay.com/

        2. 使用沙箱应用模拟支付
        3. API-> 支付->电脑网站支付->开发文档

                

三. 订单支付-网站对接支付宝流程图

四. 订单支付-订单支付代码配置

        python封装的sdk文档: https://github.com/fzlee/alipay/blob/master/README.zh-hans.md

        1. 卸载pycrypt包
pip uninstall pycrypt
        2. 安装python-alipay-sdk --upgrade
pip install python-alipay-sdk --upgrade
        3. 电脑上安装openssl(生成秘钥)
                (1). 进入官网

                        Shining Light Productions - Home

                (2). 安装

               
                (3). 配置环境变量

        4. 黑窗口输入指令生成公钥和私钥
# 1. 进入 openssl
    openssl

# 2. 输入指令,在哪执行就会在哪生成文件
    genrsa -out app_private_key.pem   2048 # 私钥
    rsa -in app_private_key.pem -pubout -out app_public_key.pem # 导出公钥

# 3. 退出 openssl
    exit
            5. 更新沙箱环境自定义公钥
                复制电脑生成的公钥替换沙箱原有的自定义公钥

        6.  查看支付宝公钥保存到项目中

                (1). 新建文件 order子应用 / alipay_public_key.pem

                (2). 复制沙箱环境的自定义公钥到项目中

                (3). 增加首尾两行代码

        7. 将电脑生成的私钥拷贝到项目中

                order子应用下 / app_private_key.pem

五. 创建订单-支付后台

        1. 定义支付类
# order /views.py

from datetime import datetime

from django.http import JsonResponse
from django.shortcuts import render, redirect
from goods.models import GoodsSKU
from user.models import Address
from order.models import OrderInfo, OrderGoods
# Create your views here.
# /order/place
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection
from util.mixin import LoginRequiredMixin

from django.db import transaction

from django.conf import settings
import os
from alipay import AliPay

# ajax post
# 前端传递的参数: 订单id(order_id)
# order /pay
class OrderPayView(View):
    """订单支付"""

    def post(self, request):
        """订单支付"""
        # 用户是否登录
        user = request.user
        if not user.is_authenticated:
            return JsonResponse({"res": 0, "errmsg": "用户未登录"})

        # 接收参数
        order_id = request.POST.get("order_id")

        # 校验参数
        if not order_id:
            return JsonResponse({"res": 1, "errmsg": "无效的订单id"})

        try:
            order = OrderInfo.objects.get(order_id=order_id,
                                          user=user,
                                          pay_method=3,
                                          order_status=1)
        except OrderInfo.DoesNotExist:
            return JsonResponse({"res": 2, "errmsg": "订单错误"})

        # 业务处理: 使用python skd调用支付宝的支付接口
        # 初始化
        alipay = AliPay(
            appid="xxxxxxxx",# 沙箱应用里的APPID
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(settings.BASE_DIR, 'apps/order/app_private_key.pem'),  # 私钥
            # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥
            alipay_public_key_path=os.path.join(settings.BASE_DIR, 'apps/order/alipay_public_key.pem'),
            sign_type='RSA2',  # RSA 或者 RSA2
            debug=True  # 默认False,沙箱改为True
        )

        # 调用支付接口
        # 电脑网站支付,需要跳转到:https://openapi.alipaydev.com/gateway.do? + order_string
        total_pay = order.total_price + order.transit_price
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id,  # 订单id
            total_amount=str(total_pay),  # 支付总金额
            subject="天天生鲜%s" % order_id,  # 标题
            return_url=None,
            notify_url=None  # 可选,不填则使用默认 notify url
        )

        # 返回应答
        pay_url = "https://openapi-sandbox.dl.alipaydev.com/gateway.do?" + order_string
        return JsonResponse({"res": 3, "pay_url":pay_url})
        2. 定义支付路由
from django.conf.urls import url
from order.views import OrderPlaceView,OrderCommitView,OrderPayView
app_name="order"
urlpatterns = [
    ...

    url('^pay$',OrderPayView.as_view(),name='pay'), # 订单支付
]
        3. 定义支付模板 

                准备中...

六. 创建订单-前端js

 <script>
        $('.oper_btn').click(function () {
            // 获取status
            status = $(this).attr('status')
            if (status == 1) {
                // 进行支付
                // 获取订单id
                order_id = $(this).attr('order_id')
                csrf = $('input[name="csrfmiddlewaretoken"]').val() // 获取csrf的value
                // 组织参数
                params = {"order_id": order_id, "csrfmiddlewaretoken": csrf}
                // 发起ajax post请求,访问/order/pay,传递参数:order_id
                $.post('/order/pay', params, function (data) {
                    if (data.res == 3) {
                        // 引导用户到支付页面
                        window.open(data.pay_url)
                    } else {
                        alert(data.errmsg)
                    }

                })

            } else {
                // 其他情况
            }
        })
    </script>

七. 完成支付操作 

        1. 点击去付款

        2. 登录沙箱账号中买家账号

        3. 完成支付

八. 订单支付-获取支付结果

        1. 定义查看结果视图类
# order /views.py

# ajax post
# 前端传递的参数: 订单id(order_id)
# /order/check
class CheckPayView(View):
    """查看订单支付的结果"""

    def post(self, request):
        """查询支付结果"""
        # 用户是否登录
        user = request.user
        if not user.is_authenticated:
            return JsonResponse({"res": 0, "errmsg": "用户未登录"})

        # 接收参数
        order_id = request.POST.get("order_id")

        # 校验参数
        if not order_id:
            return JsonResponse({"res": 1, "errmsg": "无效的订单id"})

        try:
            order = OrderInfo.objects.get(order_id=order_id,
                                          user=user,
                                          pay_method=3,
                                          order_status=1)
        except OrderInfo.DoesNotExist:
            return JsonResponse({"res": 2, "errmsg": "订单错误"})

        # 业务处理: 使用python skd调用支付宝的支付接口
        # 初始化
        alipay = AliPay(
            appid="xxxxxxxx",  # 沙箱应用里的APPID
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(settings.BASE_DIR, 'apps/order/app_private_key.pem'),  # 私钥
            # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥
            alipay_public_key_path=os.path.join(settings.BASE_DIR, 'apps/order/alipay_public_key.pem'),
            sign_type='RSA2',  # RSA 或者 RSA2
            debug=True  # 默认False,沙箱改为True
        )

        # 调用支付宝的交易查询接口
        while True:
            # 一定要将 alipay.api_alipay_trade_query 中的沙箱 url 改成新版的支付宝沙箱url,否则会报错
            response = alipay.api_alipay_trade_query(order_id)

            # 返回的字典格式
            # response = {
            #         "trade_no": "2017032121001004070200176844", # 支付宝交易号
            #         "code": "10000",  # 接口调用是否成功
            #         "invoice_amount": "20.00",
            #         "open_id": "20880072506750308812798160715407",
            #         "fund_bill_list": [
            #             {
            #                 "amount": "20.00",
            #                 "fund_channel": "ALIPAYACCOUNT"
            #             }
            #         ],
            #         "buyer_logon_id": "csq***@sandbox.com",
            #         "send_pay_date": "2017-03-21 13:29:17",
            #         "receipt_amount": "20.00",
            #         "out_trade_no": "out_trade_no15",
            #         "buyer_pay_amount": "20.00",
            #         "buyer_user_id": "2088102169481075",
            #         "msg": "Success",
            #         "point_amount": "0.00",
            #         "trade_status": "TRADE_SUCCESS", # 支付结果
            #         "total_amount": "20.00"
            # }

            code = response.get('code')
            if code == '10000' and response.get('trade_status') == 'TRADE_SUCCESS':
                # 支付成功
                # 获取支付宝交易号
                trade_no = response.get('trade_no')
                # 更新订单状态
                order.trade_no = trade_no
                order.order_status = 4  # 待评价
                order.save()
                # 返回结果
                return JsonResponse({"res": 3, "message": "支付成功"})

            elif code == '40004' or (code == '10000' and response.get('trade_status') == 'WAIT_BUYER_PAY'):
                # 等待买家付款
                # 40004: 业务处理失败,可能一会就会成功
                import time
                time.sleep(5)
                continue
            else:
                # 支付错误
                return JsonResponse({"res": 4, "message": "支付失败"})
        2. 定义路由
from django.conf.urls import url
from order.views import OrderPlaceView,OrderCommitView,OrderPayView,CheckPayView
app_name="order"
urlpatterns = [
    ...
    url('^check$',CheckPayView.as_view(),name='check'), # 查询支付交易结果
]
        3. 前端js显示支付成功

                user_center_order.html

 <script>
           // 更改 状态 
           $('.oper_btn').each(function () {
            // 获取支付状态
            status = $(this).attr('status')
            if (status == 1) {
                $(this).text('去支付')
            } else if (status == 4) {
                $(this).text('去评价')
            } else if (status == 5) {
                $(this).text('已完成')
            }
        })


         $('.oper_btn').click(function () {
            // 获取status
            status = $(this).attr('status')
            // 获取订单id
            order_id = $(this).attr('order_id')
            if (status == 1) {
                // 进行支付
                csrf = $('input[name="csrfmiddlewaretoken"]').val() // 获取csrf的value
                // 组织参数
                params = {"order_id": order_id, "csrfmiddlewaretoken": csrf}
                // 发起ajax post请求,访问/order/pay,传递参数:order_id
                $.post('/order/pay', params, function (data) {
                    if (data.res == 3) {
                        // 引导用户到支付页面
                        window.open(data.pay_url)
                        // 浏览器访问/order/check, 获取支付交易的结果
                        // ajax post 传递参数: order_id
                        $.post('/order/check', params, function (data) {
                            if (data.res == 3) {
                                alert("支付成功")
                                // 刷新页面
                                location.reload()
                            } else {
                                alert(data.errmsg)
                            }
                        })
                    } else {
                        alert(data.errmsg)
                    }
                })

            } else if (status == 4) {
                // 其他情况
                // 跳转到评价页面
                location.href = '/order/comment/' + order_id
            }
        })
    </script>

九. 订单评论

        1. 定义视图类
# order / views.py

class CommentView(View):
    """订单评论"""

    def get(self, request, order_id):
        """提供订单评论页面"""
        user = request.user

        # 校验数据
        if not order_id:
            return redirect(reverse('user:order'))

        try:
            order = OrderInfo.objects.get(order_id=order_id, user=user)
        except OrderInfo.DoesNotExist:
            return redirect(reverse('user:order'))

        # 根据订单的状态获取订单的状态标题
        order.status_name = OrderInfo.ORDER_STATUS[order.order_status]

        # 获取订单商品的信息
        order_skus = OrderGoods.objects.filter(order_id=order_id)
        for order_sku in order_skus:
            # 计算商品小计
            amount = order_sku.count * order_sku.price
            # 动态给order_sku增加属性amount,保存商品小计
            order_sku.amount = amount
        # 动态给order增加属性order_skus,保存订单商品信息
        order.order_skus = order_skus

        # 使用模板
        return render(request, 'order_comment.html', {"order": order})

    def post(self, request, order_id):
        """处理评论内容"""
        user = request.user

        # 校验数据
        if not order_id:
            return redirect(reverse('user:order'))

        try:
            order = OrderInfo.objects.get(order_id=order_id, user=user)
        except OrderInfo.DoesNotExist:
            return redirect(reverse('user:order'))

        # 获取评论条数
        total_count = request.POST.get('total_count')
        total_count = int(total_count)

        # 循环获取订单中商品的评论内容
        for i in range(1, total_count + 1):
            # 获取评论的商品id
            sku_id = request.POST.get('sku_%d' % i)  # sku_1 sku_2 ...
            # 获取评论的商品的内容
            content = request.POST.get('content_%d' % i, '')  # cotent_1 cotent_2
            try:
                order_goods = OrderGoods.objects.get(order=order, sku_id=sku_id)
            except OrderGoods.DoesNotExist:
                continue

            order_goods.comment = content
            order_goods.save()

        order.order_status = 5  # 已完成
        order.save()

        return redirect(reverse('user:order', kwargs={"page": 1}))
        2. 定义路由
from django.conf.urls import url
from order.views import OrderPlaceView, OrderCommitView, OrderPayView, CheckPayView,CommentView

app_name = "order"
urlpatterns = [
    ...
    url('^comment/(?P<order_id>.+)$', CommentView.as_view(), name='comment'),  # 订单评论
]
        3. 定义模板

               准备中...

                

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值