支付寶支付功能, 建立訂單並生成支付連接的接口, 後端支付寶異步回調接口

支付寶支付功能

  1. 閱讀支付寶開放平臺的電腦網站支付文檔前端

    1. 支付寶服務器同步回調一次結果給前端
    2. 支付寶服務器最多異步回調8次結果給後端, 若是後端返回success, 則支付寶服務器結束異步回調
  2. 在github上搜索alipay, 選擇星最多的sdk, 而後安裝: pip install python-alipay-sdk --upgradepython

  3. 下載支付寶官方提供的一鍵生成 RSA 密鑰工具, 生成應用公鑰和應用私鑰, 將應用公鑰添加到支付寶開放平臺, 而後獲取支付寶公鑰ios

  4. 二次封裝網頁支付sdkgit

    '''
    # ...\luffyapi\luffyapi\libs\alipay\web_pay.py
    from alipay import AliPay
    from .settings import *
    
    alipay = AliPay(
        # 真實appid則debug爲False, 沙箱appid則debug爲True
        appid=APP_ID,
        debug=DEBUG,
    
        app_notify_url=None,
        app_private_key_string=APP_PRIVATE_KEY_STRING,
        alipay_public_key_string=ALIPAY_PUBLIC_KEY_STRING,
        sign_type=SIGN,
    )
    
    
    # ...\luffyapi\luffyapi\libs\alipay\__init__.py
    from .web_pay import alipay
    from .settings import GATEWAY as alipay_gateway  # 支付寶網關接口
    '''

建立訂單並生成支付連接的接口

'''
# ...\luffyapi\luffyapi\apps\order\views.py
...
from rest_framework.generics import CreateAPIView
from rest_framework.permissions import IsAuthenticated


class OrderCreateAPIView(CreateAPIView):
    permission_classes = [IsAuthenticated]  # 設置登陸後才能購買課程
    serializer_class = order_serializers.OrderModelSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, context={'request': request})  # 將request對象傳入OrderModelSerializer類中
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return Response(serializer.pay_url)
        

# ...\luffyapi\luffyapi\apps\order\order_serializers.py
from rest_framework import serializers
from . import models
from ..course.models import Course


class OrderModelSerializer(serializers.ModelSerializer):
    courses = serializers.PrimaryKeyRelatedField(required=True, queryset=Course.objects.all(), many=True)  # 自定義反序列化字段

    class Meta:
        model = models.Order
        fields = ['subject', 'total_amount', 'pay_type', 'courses']
        ...

    def _check_total_amount(self, attrs):
        total_amount = attrs.get('total_amount')  # 獲取前端傳過來的訂單總價

        # 根據訂單中的課程信息統計出實際的訂單總價
        total_amount_temp = 0
        courses = attrs.get('courses')
        for course in courses:
            total_amount_temp += course.price

        # 將前端傳過來的訂單總價與實際的訂單總價進行比對
        if total_amount != total_amount_temp:
            raise serializers.ValidationError({'total_amount': '價格異常'})
        return total_amount

    def _get_out_trade_no(self):
        import time
        temp_no = '%.7f' % time.time()
        out_trade_no = temp_no.replace('.', '')
        return out_trade_no[-13: -1]

    # 從傳入的request對象中獲取用戶對象
    def _get_request_user(self):
        return self.context.get('request').user

    def _get_pay_url(self, out_trade_no, total_amount, subject):
        from luffyapi.libs.alipay import alipay, alipay_gateway
        from django.conf import settings
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=out_trade_no,
            total_amount=str(total_amount),
            subject=subject,
            return_url=settings.RETURN_URL,  # 同步回調的前端接口
            notify_url=settings.NOTIFY_URL  # 異步回調的後端接口
        )
        return alipay_gateway + order_string

	def validate(self, attrs):
        total_amount = self._check_total_amount(attrs)  # 校驗訂單總價
        out_trade_no = self._get_out_trade_no()  # 生成訂單號
        user = self._get_request_user()  # 獲取下單用戶

        pay_url = self._get_pay_url(out_trade_no, total_amount, attrs.get('subject'))  # 生成支付連接
        self.pay_url = pay_url  # 將支付連接綁定給OrderModelSerializer類的pay_url屬性

        # 在訂單表中建立新的訂單記錄時所須要的額外字段數據
        attrs['out_trade_no'] = out_trade_no
        attrs['user'] = user
        return attrs
        
	重寫create方法: 1. 在訂單表中建立新的訂單記錄, 2. 在訂單詳情表中建立新的訂單詳情記錄
    def create(self, validated_data):
        courses = validated_data.pop('courses')  # 將訂單中的課程信息取出額外記錄到訂單詳情表中
        order_obj = models.Order.objects.create(**validated_data)  # 在訂單表中建立新的訂單記錄

        # 在訂單詳情表中建立新訂單詳情記錄
        for course in courses:
            models.OrderDetail.objects.create(order=order_obj, course=course, price=course.price, real_price=course.price)
        return order_obj
'''

後端支付寶異步回調接口

'''
# ...\luffyapi\luffyapi\apps\order\views.py
...
from luffyapi.libs.alipay import alipay
from luffyapi.utils.my_logging import logger


...
class PayResAPIView(APIView):
    # 對前端轉發的支付寶同步回調數據做出響應
    def get(self, request, *args, **kwargs):
        return Response(data='received')

    # 處理支付寶異步回調傳過來的數據
    def post(self, request, *args, **kwargs):
        data = request.data.dict()  # QueryDict類的對象沒有pop方法, 能夠經過".dict()"轉化爲dict類的對象

        # 驗籤
        sign = data.pop('sign')
        result = alipay.verify(data, sign)

        out_trade_no = data.get('out_trade_no')  # 獲取訂單號
        trade_status = data.get("trade_status")  # 獲取交易狀態

        # 根據驗簽結果和交易狀態修改數據庫中的訂單狀態
        if result and trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
            models.Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1)
            logger.critical('訂單號:%s, 交易狀態: %s' % (out_trade_no, trade_status))  # 項目上線後, 沒有控制檯輸出結果, 須要經過日誌記錄訂單支付信息
            return Response('success')
        return Response('failed')
'''

其餘須要注意的點

  1. drf-jwt的JWT_AUTH配置須要寫在drf的REST_FRAMEWORK配置以前github

  2. 前端攜帶tokenweb

    '''
                    this.$axios({
                        ...,
                        headers: {
                            authorization: `jwt ${token}`,
                        }
                    }).then(response => {
                        ...;
                    }).catch(error => {
                        ...;
                    })
    '''
  3. 前端非同站點頁面跳轉: window.open(url, '_self') , _self表示跳轉時不新開標籤頁, 前端同站點頁面跳轉: this.$router.push(url)數據庫

  4. 前端使用 location.search 獲取url中?以及?後的字符串django

  5. 前端字符串裁剪: "cql".substring(1, 2) # qaxios

  6. 前端異常處理語句: try {} catch (e) {}後端

  7. 前端對url編碼數據進行解碼: decodeURLComponet(...)

  8. 碼雲上配置的公鑰私鑰與電腦進行綁定, 支付寶開放平臺配置的公鑰私鑰與項目應用進行綁定

相關文章
相關標籤/搜索