由于自己写的一个小项目有支付功能需求的实现,而支付接入门槛最低的就是支付宝当面付,下面就是如何在django中接入支付宝当面付的过程


当面付资质商家申请

支付宝当面付需要上传店铺照片,工商登记(如不上传交易金额有限制)等信息。
申请链接:https://b.alipay.com/signing/productDetailV2.htm?productId=I1011000290000001003

申请结果在1个工作日之内会有反馈,如果申请成功,可以进行开发者申请。

支付宝开放平台申请

在支付宝开放平台创建应用,选择“网页&移动应用”,选择“支付接入”。

然后有1个工作日的审核时间,审核成功后,进入此应用,设置接口加签

加签过程请参照支付宝官方文档:https://opendocs.alipay.com/open/291/105971#LDsXr

沙箱应用创建(可选)

在应用正式上线之前,可以通过沙箱环境进行测试支付功能是否正常运行。

支付宝沙箱环境设置地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info

同时也要进行加签操作,操作流程与之前创建的应用一致。

Python SDK接入

由于官方的Python SDK依赖的环境一直无法安装,所以使用了第三方的支付SDK:https://github.com/fzlee/alipay

安装SDK

1
2
3
# 安装python-alipay-sdk
pip install python-alipay-sdk --upgrade
# 对于python2, 请安装2.0以下版本: pip install python-alipay-sdk==1.1

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from alipay import AliPay, DCAliPay, ISVAliPay
from alipay.utils import AliPayConfig

app_private_key_string = open("/path/to/your/private/key.pem").read()
alipay_public_key_string = open("/path/to/alipay/public/key.pem").read()

app_private_key_string == """
-----BEGIN RSA PRIVATE KEY-----
base64 encoded content
-----END RSA PRIVATE KEY-----
"""

alipay_public_key_string == """
-----BEGIN PUBLIC KEY-----
base64 encoded content
-----END PUBLIC KEY-----
"""

alipay = AliPay(
appid="",
app_notify_url=None, # 默认回调url
app_private_key_string=app_private_key_string,
# 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
alipay_public_key_string=alipay_public_key_string,
sign_type="RSA2" # RSA 或者 RSA2
debug=False, # 默认False
config=AliPayConfig(timeout=15) # 可选, 请求超时时间
)

其中 debug=False 为正式应用的初始化,如果要使用沙箱环境,则为True,appid 为开放平台中申请应用的 appid,APP私钥和支付宝公钥需要以

1
2
3
-----BEGIN PUBLIC KEY-----
base64 encoded content
-----END PUBLIC KEY-----

这样的格式传入。

使用

当面付分为两种支付方式。

第一种为用户提供付款码,商户识别用户付款码后进行下订单并支付的过程。

第二种为先创建订单,获得支付宝回传的二维码URL后,需要用户在一定时间内通过支付宝扫一扫 扫描二维码进行支付,用户支付完成后,会回传支付结果到下订单时所设置的回传URL中。

因为我需要的是第二种的支付场景,所以下面对第二种方式的接入进行说明。

创建订单
1
2
3
4
5
6
a = alipayStatic.api_alipay_trade_precreate(
subject=subject,
out_trade_no=out_trade_no,
total_amount=price,
notify_url="https://xxxx.xxx/RestfulApi/payReceiveNotify/"
)

创建订单很简单,参数必选项为 标题、商户订单号、总价,其它参数可选。

具体参数和返回参数见官方文档:
https://opendocs.alipay.com/apis/api_1/alipay.trade.precreate?scene=API002020081000013487

返回的code值为”10000”时,创建订单成功。

查询订单
  • 主动查询

    1
    2
    3
    4
    5
    result = alipay.api_alipay_trade_query(out_trade_no="out_trade_no")
    if result.get("trade_status", "") == "TRADE_SUCCESS":
    print("paid")
    else:
    print("not paid...")

    具体参数和返回参数见官方文档:
    https://opendocs.alipay.com/apis/api_1/alipay.trade.query?scene=API002020081000013487

  • 订单状态改变,支付宝回调
    在创建订单时,传入的notify_url参数为回调URL,默认当订单由未支付转为已支付时,会向此url进行回传订单相关信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class PayReceiveNotifyView(APIView):
    def post(self, request):
    try:
    # for django users
    #data = request.dict()
    # for rest_framework users
    data = {}
    for key, value in request.POST.items():
    data[key] = value

    signature = data.pop("sign")

    # verification
    success = alipayStatic.verify(data, signature)
    print(str(success))
    if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
    print(str(data["out_trade_no"]) + "支付成功")
    else:
    print(str(data["out_trade_no"]) + "订单异常, 状态为:" + str(data["trade_status"]))
    return HttpResponse("success")
    except Exception as e:
    print(f"获取支付回调出错:{e}")
    result = 'failure'
    return HttpResponse(result)

    具体回调参数与信息可见:
    https://opendocs.alipay.com/open/194/103296

退款
1
refundResult = alipayStatic.api_alipay_trade_refund(out_trade_no=data["out_trade_no"], refund_amount=100)

完成

以上即是我所用到的将当面付接入Django的过程,第三方sdk已经封装的很完善了,调用也非常的方便。