支付宝支付和退款

1. 业务逻辑
准备

  1. 使用沙箱提供的商家环境

    沙箱环境:是支付宝提供给开发者的模拟支付的环境

    沙箱应用:https://docs.open.alipay.com/200/105311

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

 支付宝开发者文档:

    文档主页:https://openhome.alipay.com/developmentDocument.htm

    产品介绍:https://docs.open.alipay.com/270

    快速接入:https://docs.open.alipay.com/270/105899/

    SDK:https://docs.open.alipay.com/270/106291/

      python对接支付宝SDK:https://github.com/fzlee/alipay/blob/master/README.zh-hans.m

    API列表:https://docs.open.alipay.com/270/105900/
  2.. 生成密钥对
  3. 将公钥加到商品环境中
  4. 将Alipay提供的公钥加入项目中
    支付功能
  5. 根据order_id查询订单对象
  6. 创建alipay对象
  7. 调用方法,生成url
  8. 返回url
    保存支付状态
  9. 根据返回的url请求支付宝
  10. 支付成功后返回商家回调页面--------->会传回很多Alipay传回来的参数,很多明文,防止别人攻击
  11. 返回商家的同时请求后台服务器------>发送这些参数给后台
  12. 接收参数并且验证,成功则创建订单支付对象返回订单号,否则提示支付失败

2.安装包

pip install python-alipay-sdk --upgrade

3.新建一个payments的app应用

python ../../manage.py startapp payments

4.定义一个模型类,继承自BaseModel(创建时间与修改时间)

 class Payment(BaseModel):
        """
        支付信息
        """
        order = models.ForeignKey(
            OrderInfo, on_delete=models.CASCADE, verbose_name=\'订单\')
        trade_id = models.CharField(
            max_length=100, verbose_name="支付流水号")

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

5.配置密钥

  5.1.登录沙箱

    在payments应用中新建keys目录,用来保存秘钥文件。

     将应用私钥文件app_private_key.pem复制到payment/keys目录下。

  5.1.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

  5.2 保存应用私钥文件

  5.3 查看公钥

cat app_publict_key.pem
# 将公钥内容复制给支付宝沙箱的<应用私钥>,得到支付宝的<支付宝公钥>

  5.4 保存支付宝公钥

  在payments/keys目录下新建alipay_public_key.pem文件,用于保存支付宝的公钥文件。

  将支付宝的公钥内容复制到alipay_public_key.pem文件中

6.配置路由

GET /orders/(?P<order_id>\d+)/payment/

7.在配置文件中配置ailipay的信息

 # 支付宝支付的配置
ALIPAY_APPID = \'xxxxxxxxxxxxx\'
ALIPAY_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, \'apps/payments/alipay/app_private_key.pem\')
ALIPAY_PUBLIC_KEY_PATH = os.path.join(BASE_DIR, \'apps/payments/alipay/alipay_public_key.pem\')
ALIPAY_DEBUG = True
ALIPAY_SUBJECT = \'智学客-订单支付\'
ALIPAY_RETURN_URL = \'http://www.xxx.com/pay_success.html\'
ALIPAY_GATE = \'https://openapi.alipaydev.com/gateway.do?\'

8.定义视图

两个参数: 

      order_id: 订单编号

      alipay_uel: 支付宝支付链接

代码如下:

 class AliPayURLView(APIView):
    def get(self, request, order_id):
        # 1.根据order_id查询订单对象
        try:
            order_obj = OrderInfo.objects.get(pk=order_id)
        except:
            raise Exception("订单号无效")

        # 2.创建alipay对象
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,
            app_private_key_path=settings.ALIPAY_PRIVATE_KEY_PATH,
            alipay_public_key_path=settings.ALIPAY_PUBLIC_KEY_PATH,
            debug=settings.ALIPAY_DEBUG
        )

        # 3.调用方法,生成url
        # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string
        order_string = alipay.api_alipay_trade_page_pay(
            subject=settings.ALIPAY_SUBJECT,
            out_trade_no=order_id,  # 订单编号
            total_amount=str(order_obj.total_amount),  # 支付总金额,类型为Decimal(),不支持序列化,需要强转成str
            return_url=settings.ALIPAY_RETURN_URL  # 支付成功后的回调地址

        )
        # 4.返回url
        return Response({"alipay_url": settings.ALIPAY_GATE + order_string})

  8.1 在payments/urls.py中定义路由规则 

 url(\'^orders/(?P<order_id>\d+)/payment/$\',views.PaymentView.as_view()),

9.保存支付状态

请求方式:PUT /payment/status/?支付宝参数

参数:trade_id:支付宝流水账号

代码实现:

class OrderStatusView(APIView):
    """验证用户是否登录成功"""

    def put(self, request):
        # 1.接收支付宝返回的数据
        data = request.query_params.dict()

        # 2.验证是否支付成功
        # 2.1删除签名,不参与验证
        signature = data.pop("sign")

        # 2.2 创建alipay对象
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,
            app_private_key_path=settings.ALIPAY_PRIVATE_KEY_PATH,
            alipay_public_key_path=settings.ALIPAY_PUBLIC_KEY_PATH,
            debug=settings.ALIPAY_DEBUG
        )

        # 2.3 调用verify(字典,签名)
        success = alipay.verify(data, signature)
        if success:
            # 支付成功
            \'\'\'
            {
                \'total_amount\': \'11388.00\', 支付金额
                \'auth_app_id\': \'2016082100304973\', 应用编号
                \'method\': \'alipay.trade.page.pay.return\',
                \'trade_no\': \'2018110722001420410500545016\',流水号
                \'timestamp\': \'2018-11-07 16:59:20\',时间
                \'app_id\': \'2016082100304973\',应用编号
               \'out_trade_no\': \'20181107160224000000001\',商城的订单编号
               \'charset\': \'utf-8\',编码
               \'seller_id\': \'2088102172415825\',商家编号
               \'version\': \'1.0\'版本
            }
            \'\'\'
            # 1 获取订单号
            order_id = data["out_trade_no"]
            # 2 修改订单状态
            try:
                order_obj = OrderInfo.objects.get(pk=order_id)
            except:
                raise Exception("订单号无效")
            order_obj.status = 2
            order_obj.save()

            # 3.创建订单支付对象
            trade_no = data.get(\'trade_no\')  # 获取流水号
            Payment.objects.create(
                order_id=order_id,
                trade_no=trade_no
            )

            # 4.响应
            return Response({"trade_id": trade_no})
        else:
            raise Exception("支付失败")

  9.1 定义路由规则 

   url(\'^payment/status/$\',views.PaymentStatusView.as_view()),

 退款

class Refund(APIView):

    def post(self,request):

        # 根据当前用户的配置,生成URL,并跳转。
        money = float(request.POST.get('price'))

        orderno = request.POST.get('orderno')


        #实例化支付类
        alipay = get_ali_object()
        #调用退款方法
        order_string = alipay.api_alipay_trade_refund(
        #订单号,一定要注意,这是支付成功后返回的唯一订单号
        out_trade_no=str(orderno),
        #退款金额,注意精确到分,不要超过订单支付总金额
        refund_amount=money,
        #回调网址
        notify_url='http://localhost:8000/md_admin/alipayreturn'
        )
        return HttpResponse(order_string)
posted @ 2022-08-03 16:37  FFLYY  阅读(453)  评论(0编辑  收藏  举报