支付寶支付功能, 創建訂單並生成支付鏈接的接口, 后端支付寶異步回調接口


支付寶支付功能

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

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

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

  4. 二次封裝網頁支付sdk

    '''
    # ...\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配置之前

  2. 前端攜帶token

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

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

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

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

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM