python苹果支付(服务端)自动订阅版

苹果支付分为沙盒环境和生产环境

苹果验单逻辑

苹果支付过程中离不开一个东西--receipt(凭证)

  1. 服务端接收APP发送的凭证
  2. 服务端拿着凭证到苹果的服务器验单(沙盒、生产)
  3. 服务端解析苹果服务器返回的json receipt收据官方说明文档
  4. 对成功的订单进行操作(需要过滤已经存在的订单)
附收据(拿着凭证成功验单的收据json):

{
    "status":0,
    "environment":"Production",
    "receipt":{
        "receipt_type":"Production",
        "adam_id":1494433742,
        "app_item_id":1494433742,
        "bundle_id":"cn.prod.u2",
        "application_version":"1",
        "download_id":35061442602062,
        "version_external_identifier":835287540,
        "receipt_creation_date":"2020-04-04 08:32:50 Etc/GMT",
        "receipt_creation_date_ms":"1585989170000",
        "receipt_creation_date_pst":"2020-04-04 01:32:50 America/Los_Angeles",
        "request_date":"2020-04-15 08:31:12 Etc/GMT",
        "request_date_ms":"1586939472671",
        "request_date_pst":"2020-04-15 01:31:12 America/Los_Angeles",
        "original_purchase_date":"2020-04-04 08:20:48 Etc/GMT",
        "original_purchase_date_ms":"1585988448000",
        "original_purchase_date_pst":"2020-04-04 01:20:48 America/Los_Angeles",
        "original_application_version":"1",
        "in_app":[
            {
                "quantity":"1",
                "product_id":"vip.u2.18",
                "transaction_id":"150000629315025",
                "original_transaction_id":"150000629315025",
                "purchase_date":"2020-04-04 08:32:14 Etc/GMT",
                "purchase_date_ms":"1585989134000",
                "purchase_date_pst":"2020-04-04 01:32:14 America/Los_Angeles",
                "original_purchase_date":"2020-04-04 08:32:14 Etc/GMT",
                "original_purchase_date_ms":"1585989134000",
                "original_purchase_date_pst":"2020-04-04 01:32:14 America/Los_Angeles",
                "expires_date":"2020-04-07 08:32:14 Etc/GMT",
                "expires_date_ms":"1586248334000",
                "expires_date_pst":"2020-04-07 01:32:14 America/Los_Angeles",
                "web_order_line_item_id":"150000230093835",
                "is_trial_period":"true",
                "is_in_intro_offer_period":"false"
            }
        ]
    },
    "latest_receipt_info":[
        {
            "quantity":"1",
            "product_id":"vip.u2.18",
            "transaction_id":"150000629315025",
            "original_transaction_id":"150000629315025",
            "purchase_date":"2020-04-04 08:32:14 Etc/GMT",
            "purchase_date_ms":"1585989134000",
            "purchase_date_pst":"2020-04-04 01:32:14 America/Los_Angeles",
            "original_purchase_date":"2020-04-04 08:32:14 Etc/GMT",
            "original_purchase_date_ms":"1585989134000",
            "original_purchase_date_pst":"2020-04-04 01:32:14 America/Los_Angeles",
            "expires_date":"2020-04-07 08:32:14 Etc/GMT",
            "expires_date_ms":"1586248334000",
            "expires_date_pst":"2020-04-07 01:32:14 America/Los_Angeles",
            "web_order_line_item_id":"150000230093835",
            "is_trial_period":"true",
            "is_in_intro_offer_period":"false",
            "subscription_group_identifier":"20608590"
        }
    ],
    "latest_receipt":"此处因凭证太长省略",
    "pending_renewal_info":[
        {
            "expiration_intent":"2",
            "auto_renew_product_id":"vip.u2.18",
            "original_transaction_id":"150000629315025",
            "is_in_billing_retry_period":"1",
            "product_id":"vip.u2.18",
            "auto_renew_status":"1"
        }
    ]
}
苹果订阅和非订阅所需要解析的字段可能不同

下面以自动订阅为例

1. 服务端接收APP发送的凭证
苹果支付和微信/支付宝支付逻辑不太一样,
若是支付宝/微信支付,我们首先需要创建预支付订单返回给APP,APP拿着预支付订单号去支付宝微信支付,服务端在等待回调就可以了
苹果支付可以直接验单,无需等待回调(官方提供了回调,可以再官网上面配置)

app发起支付,支付成功后会返回receipt凭证

2.服务端拿着凭证到苹果的服务器验单(沙盒、生产)
app上线需要沙盒环境测试,本人开发也需要沙盒测试,所以代码需要同时兼容沙盒和生产环境

我们可以首先向生产环境发送请求

# 向生产环境发送请求  默认向生产环境发送
PASSWORD = "内购订阅秘钥"
def request_to_product(receipt, num=0, password=None):
    num += 1
    try:
        # url = 'https://sandbox.itunes.apple.com/verifyReceipt'
        url = 'https://buy.itunes.apple.com/verifyReceipt'
        if password:
            data = json.dumps({"receipt-data": receipt, 'password': password})
        else:
            data = json.dumps({"receipt-data": receipt})
        headers = {"Content-type": "application/json"}
        res = requests.post(url=url, data=data, headers=headers, verify=False).text
        return res
    except:
        # 仅验证3次,当请求出错时
        res = 'fail'
        if num < 4:
            res = request_to_product(receipt, num=num, password=PASSWORD)
        return res

返回的json收据中会包含两个字段(参考上面的附录,收据json)

	"status":0,
    "environment":"Production",

status 字段含义

0:"验单成功!"
21000: "未使用HTTPPOST请求方法向AppStore发送请求。",
21001: "此状态代码不再由AppStore发送。",
21002: "该receipt - data属性中的数据格式错误或丢失。",
21003: "收据无法认证。",
21004: "您提供的共享密码与您帐户的文件共享密码不匹配。",
21005: "收据服务器当前不可用。",
21006: "该收据有效,但订阅已过期。当此状态代码返回到您的服务器时,收据数据也会被解码并作为响应的一部分返回。仅针对自动续订的iOS6样式的交易收据返回。",
21007: "该收据来自测试环境,但已发送到生产环境以进行验证。",
21008: "该收据来自生产环境,但是已发送到测试环境以进行验证。",
21009: "内部数据访问错误。稍后再试。",
21010: "找不到或删除了该用户帐户。",

若status == 0,收据获取成功!
若status == 21007 需要再次向测试环境发送请求

# 向沙盒境发送请求
PASSWORD = "内购订阅秘钥"
def request_to_sandbox(receipt, num=0, password=None):
    num += 1 
    try:
        url = 'https://sandbox.itunes.apple.com/verifyReceipt'
        if password:
            data = json.dumps({"receipt-data": receipt, 'password': password})
        else:
            data = json.dumps({"receipt-data": receipt})
        headers = {"Content-type": "application/json"}
        res = requests.post(url=url, data=data, headers=headers, verify=False).text
        return res
    except:
        # 仅验证3次,当请求出错时
        res = 'fail'
        if num < 4:
            res = request_to_sandbox(receipt, num=num, password=PASSWORD)
        return res

因为苹果服务器在国外,可能会有延时,出错时候多请求几次没毛病

3.服务端解析苹果服务器返回的json receipt收据官方说明文档

主要参数(对于订阅而言)

latest_receipt_info:所有订单信息
pending_renewal_info:订阅信息

pending_renewal_info中original_transaction_id是原始订单号,非常重要,我们可以把凭证和这个原始订单号绑定起来,存储起来,留验单使用
其他字段信息看看官方说明文档吧

订单过期时间可以直接使用latest_receipt_info中expires_date_ms字段,因为苹果可能会漏单,所以订阅到期时,可以自动任务拿着存储好的凭证去验单(防止漏单)

后面根据订单添加会员等权限就不啰嗦了。

你可能感兴趣的:(python,支付)