Python_美多商城(支付)_9

支付

提示:

  • 如果用户选择的支付方式是 "支付宝" ,在点击《去支付》时对接支付宝的支付系统。

支付宝介绍

支付宝开放平台入口

  • https://open.alipay.com/platform/home.htm

Python_美多商城(支付)_9_第1张图片

1. 创建应用和沙箱环境

1.创建应用

Python_美多商城(支付)_9_第2张图片

2.沙箱环境

支付宝提供给开发者的模拟支付的环境。跟真实环境是分开的。

  • 沙箱应用:https://openhome.alipay.com/platform/appDaily.htm?tab=info

Python_美多商城(支付)_9_第3张图片

沙箱账号:https://openhome.alipay.com/platform/appDaily.htm?tab=account

Python_美多商城(支付)_9_第4张图片

2. 支付宝开发文档

  • 文档主页:https://openhome.alipay.com/developmentDocument.htm
  • 电脑网站支付产品介绍:https://docs.open.alipay.com/270
  • 电脑网站支付快速接入:https://docs.open.alipay.com/270/105899/
  • API列表:https://docs.open.alipay.com/270/105900/
  • SDK文档:https://docs.open.alipay.com/270/106291/
  • Python支付宝SDK:https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
    • SDK安装:pip install python-alipay-sdk --upgrade

3. 电脑网站支付流程

Python_美多商城(支付)_9_第5张图片

4. 配置RSA2公私钥

提示:

  • 美多商城私钥加密数据,美多商城公钥解密数据。
  • 支付宝私钥加密数据,支付宝公钥解密数据。

Python_美多商城(支付)_9_第6张图片

1.生成美多商城公私钥

$ openssl
$ OpenSSL> genrsa -out app_private_key.pem 2048  # 制作私钥RSA2
$ OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem # 导出公钥

$ OpenSSL> exit

2.配置美多商城公私钥

  • 配置美多商城私钥

    • 新建子应用payment,在该子应用下新建文件夹keys用于存储公私钥。
    • 将制作的美多商城私钥app_private_key.pem拷贝到keys文件夹中。
  • 配置美多商城公钥

    • payment.keys.app_public_key.pem文件中内容上传到支付宝。

3.配置支付宝公钥

  • 将支付宝公钥内容拷贝到payment.keys.alipay_public_key.pem文件中。

-----BEGIN PUBLIC KEY-----
支付宝公钥内容
-----END PUBLIC KEY-----

配置公私钥结束后

========================================================

对接支付宝系统

订单支付功能

提示:

  • 订单支付触发页面:《order_success.html》 和 《user_center_order.html》
  • 我们实现订单支付功能时,只需要向支付宝获取登录链接即可,进入到支付宝系统后就是用户向支付宝进行支付的行为。

Python_美多商城(支付)_9_第7张图片

1.请求方式

选项 方案
请求方法 GET
请求地址 /payment/(?P\d+)/

2.请求参数:路径参数

参数名 类型 是否必传 说明
order_id int 订单编号

3.响应结果:JSON

字段 说明
code 状态码
errmsg 错误信息
alipay_url 支付宝登录链接

4.后端接口定义和实现

# 测试账号:[email protected]
class PaymentView(LoginRequiredJSONMixin, View):
    """订单支付功能"""

    def get(self,request, order_id):
        # 查询要支付的订单
        user = request.user
        try:
            order = OrderInfo.objects.get(order_id=order_id, user=user, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'])
        except OrderInfo.DoesNotExist:
            return http.HttpResponseForbidden('订单信息错误')

        # 创建支付宝支付对象
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
            sign_type="RSA2",
            debug=settings.ALIPAY_DEBUG
        )

        # 生成登录支付宝连接
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id,
            total_amount=str(order.total_amount),
            subject="美多商城%s" % order_id,
            return_url=settings.ALIPAY_RETURN_URL,
        )

        # 响应登录支付宝连接
        # 真实环境电脑网站支付网关:https://openapi.alipay.com/gateway.do? + order_string
        # 沙箱环境电脑网站支付网关:https://openapi.alipaydev.com/gateway.do? + order_string
        alipay_url = settings.ALIPAY_URL + "?" + order_string
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'alipay_url': alipay_url})

5.支付宝SDK配置参数

ALIPAY_APPID = '2016082100308405'
ALIPAY_DEBUG = True
ALIPAY_URL = 'https://openapi.alipaydev.com/gateway.do'
ALIPAY_RETURN_URL = 'http://www.meiduo.site:8000/payment/status/'

=================================

保存订单支付结果

1. 支付结果数据说明

  • 用户订单支付成功后,支付宝会将用户重定向到 http://www.meiduo.site:8000/payment/status/,并携带支付结果数据。

  • 参考统一收单下单并支付页面接口:https://docs.open.alipay.com/270/alipay.trade.page.pay

Python_美多商城(支付)_9_第8张图片

提示:

我们需要将订单编号交易流水号进行关联存储,方便用户和商家后续使用。

2. 定义支付结果模型类

class Payment(BaseModel):
    """支付信息"""
    order = models.ForeignKey(OrderInfo, on_delete=models.CASCADE, verbose_name='订单')
    trade_id = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name="支付编号")

    class Meta:
        db_table = 'tb_payment'
        verbose_name = '支付信息'
        verbose_name_plural = verbose_name

3. 保存订单支付结果

1.请求方式

选项 方案
请求方法 GET
请求地址 /payment/status/

2.请求参数:路径参数

参考统一收单下单并支付页面接口中的《页面回跳参数》

3.响应结果:HTML

pay_success.html

4.后端接口定义和实现

注意:保存订单支付结果的同时,还需要修改订单的状态为待评价

# 测试账号:[email protected]
class PaymentStatusView(View):
    """保存订单支付结果"""

    def get(self, request):
        # 获取前端传入的请求参数
        query_dict = request.GET
        data = query_dict.dict()
        # 获取并从请求参数中剔除signature
        signature = data.pop('sign')

        # 创建支付宝支付对象
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"),
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"),
            sign_type="RSA2",
            debug=settings.ALIPAY_DEBUG
        )
        # 校验这个重定向是否是alipay重定向过来的
        success = alipay.verify(data, signature)
        if success:
            # 读取order_id
            order_id = data.get('out_trade_no')
            # 读取支付宝流水号
            trade_id = data.get('trade_no')
            # 保存Payment模型类数据
            Payment.objects.create(
                order_id=order_id,
                trade_id=trade_id
            )

            # 修改订单状态为待评价
            OrderInfo.objects.filter(order_id=order_id, status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']).update(
                status=OrderInfo.ORDER_STATUS_ENUM["UNCOMMENT"])

            # 响应trade_id
            context = {
                'trade_id':trade_id
            }
            return render(request, 'pay_success.html', context)
        else:
            # 订单支付失败,重定向到我的订单
            return http.HttpResponseForbidden('非法请求')

5.渲染支付成功页面信息

订单支付成功

您的订单已成功支付,支付交易号:{{ trade_id }}

您可以在【用户中心】->【我的订单】查看该订单

Python_美多商城(支付)_9_第9张图片

=============================================

评价订单商品

提示:

点击《我的订单》页面中的《待评价》按钮,进入到订单商品评价页面。

评价订单商品

1. 展示商品评价页面

Python_美多商城(支付)_9_第10张图片

1.请求方式

选项 方案
请求方法 GET
请求地址 /orders/comment/

2.请求参数:查询参数

参数名 类型 是否必传 说明
order_id int 订单编号

3.响应结果:HTML

goods_judge.html

4.后端接口定义和实现

class OrderCommentView(LoginRequiredMixin, View):
    """订单商品评价"""

    def get(self, request):
        """展示商品评价页面"""
        # 接收参数
        order_id = request.GET.get('order_id')
        # 校验参数
        try:
            OrderInfo.objects.get(order_id=order_id, user=request.user)
        except OrderInfo.DoesNotExist:
            return http.HttpResponseNotFound('订单不存在')

        # 查询订单中未被评价的商品信息
        try:
            uncomment_goods = OrderGoods.objects.filter(order_id=order_id, is_commented=False)
        except Exception:
            return http.HttpResponseServerError('订单商品信息出错')

        # 构造待评价商品数据
        uncomment_goods_list = []
        for goods in uncomment_goods:
            uncomment_goods_list.append({
                'order_id':goods.order.order_id,
                'sku_id':goods.sku.id,
                'name':goods.sku.name,
                'price':str(goods.price),
                'default_image_url':goods.sku.default_image.url,
                'comment':goods.comment,
                'score':goods.score,
                'is_anonymous':str(goods.is_anonymous),
            })

        # 渲染模板
        context = {
            'uncomment_goods_list': uncomment_goods_list
        }
        return render(request, 'goods_judge.html', context)

2. 评价订单商品

Python_美多商城(支付)_9_第11张图片

1.请求方式

选项 方案
请求方法 POST
请求地址 /orders/comment/

2.请求参数:查询参数

参数名 类型 是否必传 说明
order_id int 订单编号

3.响应结果:JSON

字段 说明
code 状态码
errmsg 错误信息

4.后端接口定义和实现

class OrderCommentView(LoginRequiredMixin, View):
    """订单商品评价"""

    def get(self, request):
        """展示商品评价页面"""
        ......

    def post(self, request):
        """评价订单商品"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        order_id = json_dict.get('order_id')
        sku_id = json_dict.get('sku_id')
        score = json_dict.get('score')
        comment = json_dict.get('comment')
        is_anonymous = json_dict.get('is_anonymous')
        # 校验参数
        if not all([order_id, sku_id, score, comment]):
            return http.HttpResponseForbidden('缺少必传参数')
        try:
            OrderInfo.objects.filter(order_id=order_id, user=request.user, status=OrderInfo.ORDER_STATUS_ENUM['UNCOMMENT'])
        except OrderInfo.DoesNotExist:
            return http.HttpResponseForbidden('参数order_id错误')
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('参数sku_id错误')
        if is_anonymous:
            if not isinstance(is_anonymous, bool):
                return http.HttpResponseForbidden('参数is_anonymous错误')

        # 保存订单商品评价数据
        OrderGoods.objects.filter(order_id=order_id, sku_id=sku_id, is_commented=False).update(
            comment=comment,
            score=score,
            is_anonymous=is_anonymous,
            is_commented=True
        )

        # 累计评论数据
        sku.comments += 1
        sku.save()
        sku.spu.comments += 1
        sku.spu.save()

        # 如果所有订单商品都已评价,则修改订单状态为已完成
        if OrderGoods.objects.filter(order_id=order_id, is_commented=False).count() == 0:
            OrderInfo.objects.filter(order_id=order_id).update(status=OrderInfo.ORDER_STATUS_ENUM['FINISHED'])

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '评价成功'})

===========================================

详情页展示评价信息

Python_美多商城(支付)_9_第12张图片

1.请求方式

选项 方案
请求方法 POST
请求地址 /comments/(?P\d+)/

2.请求参数:查询参数

参数名 类型 是否必传 说明
sku_id int 商品SKU编号

3.响应结果:JSON

字段 说明
code 状态码
errmsg 错误信息
comment_list[ ] 评价列表
username 发表评价的用户
comment 评价内容
score 分数
{
    "code":"0",
    "errmsg":"OK",
    "comment_list":[
        {
            "username":"itcast",
            "comment":"这是一个好手机!",
            "score":4
        }
    ]
}

4.后端接口定义和实现

class GoodsCommentView(View):
    """订单商品评价信息"""

    def get(self, request, sku_id):
        # 获取被评价的订单商品信息
        order_goods_list = OrderGoods.objects.filter(sku_id=sku_id, is_commented=True).order_by('-create_time')[:30]
        # 序列化
        comment_list = []
        for order_goods in order_goods_list:
            username = order_goods.order.user.username
            comment_list.append({
                'username': username[0] + '***' + username[-1] if order_goods.is_anonymous else username,
                'comment':order_goods.comment,
                'score':order_goods.score,
            })
        return http.JsonResponse({'code':RETCODE.OK, 'errmsg':'OK', 'comment_list': comment_list})

5.渲染商品评价信息

  • [[comment.comment]]
  • 商品评价([[ comments.length ]])
  • ¥{{ sku.price }} [[ comments.length ]]人评价

    提示:订单商品评价完成后,一个订单的流程就结束了,订单状态修改为已完成

    Python_美多商城(支付)_9_第13张图片

    你可能感兴趣的:(Python_美多商城(支付)_9)