[Android] 定期購読（Purchases.subscriptions）レシートの例

Android（GooglePlay）の定期購読の継続時、実際には課金されなくてもレシートが発行される場合がありました。
正常の流れも含め各パターンのレシートの形を記録しておきます。

# レシートパターン

このような状況の例です。

* 購読期間は1ヶ月
* 3/15　購読を開始
* 4/15　(1)継続できた (2)しなかった (3)できなかった


## (1) 正常に継続課金された場合

4/15〜

```js
{
  "kind": "androidpublisher#subscriptionPurchase",
  "startTimeMillis": "1552575600000",       // 3/15（継続レシートの場合も初回の購読開始日時）
  "expiryTimeMillis": "1557846000000",      // 5/15
  "autoRenewing": true,
  "priceCurrencyCode": "JPY",
  "priceAmountMicros": "120000000",
  "countryCode": "JP",
  "developerPayload": "",
  "paymentState": 1,
  "orderId": "GPA.1234-5678-9012-34567..0", // 継続用の新しいorderId
  "purchaseType": 0
}
```

## (2) 購読中にユーザがキャンセルした場合

4/1にキャンセル

### 有効期限が切れる前

〜4/15

```js
{
 "kind": "androidpublisher#subscriptionPurchase",
 "startTimeMillis": "1552575600000",            // 3/15
 "expiryTimeMillis": "1555254000000",           // 4/15
 "autoRenewing": false,                         // キャンセルにより自動更新がOFFになっている
 "priceCurrencyCode": "JPY",
 "priceAmountMicros": "120000000",
 "countryCode": "JP",
 "developerPayload": "",
 "paymentState": 1,
 "cancelReason": 0,                             // ユーザによるキャンセル => 0
 "userCancellationTimeMillis": "1554044400000", // 4/1（キャンセル日時）
 "orderId": "GPA.1234-5678-9012-34567",
 "purchaseType": 0
}
```

### 有効期限が切れた後

4/15〜

```js
{
  "kind": "androidpublisher#subscriptionPurchase",
  "startTimeMillis": "1552575600000",            // 3/15
  "expiryTimeMillis": "1555254000000",           // 4/15
  "autoRenewing": false,
  "priceCurrencyCode": "JPY",
  "priceAmountMicros": "120000000",
  "countryCode": "JP",
  "developerPayload": "",
  "cancelReason": 0,
  "userCancellationTimeMillis": "1554044400000", // 4/1（キャンセル日時）
  "orderId": "GPA.1234-5678-9012-34567",         // 初回のレシートのまま
  "purchaseType": 0
}
```

有効期限をすぎると、 `paymentState` パラメータがなくなっています。


## (3) カード不承認で継続課金できなかった場合

4/15〜

```js
{
  "kind": "androidpublisher#subscriptionPurchase",
  "startTimeMillis": "1552575600000",    // 3/15
  "expiryTimeMillis": "1555254000000",   // 4/15
  "autoRenewing": true,                  // キャンセルしていないので、自動更新はONのまま
  "priceCurrencyCode": "JPY",
  "priceAmountMicros": "120000000",
  "countryCode": "JP",
  "developerPayload": "",
  "paymentState": 1,
  "orderId": "GPA.1234-5678-9012-34567", // 初回のレシートのまま
  "purchaseType": 0
}
```

### 不承認状態でキャンセルした場合

4/16にキャンセル

```js
{
 "kind": "androidpublisher#subscriptionPurchase",
 "startTimeMillis": "1552575600000",            // 3/15
 "expiryTimeMillis": "1555254000000",           // 4/15
 "autoRenewing": false,                         // キャンセルしたので自動更新がOFFになった
 "priceCurrencyCode": "JPY",
 "priceAmountMicros": "120000000",
 "countryCode": "JP",
 "developerPayload": "",
 "cancelReason": 0,                             // ユーザによるキャンセル => 0
 "userCancellationTimeMillis": "1555340400000", // 4/16（キャンセル日時）
 "orderId": "GPA.1234-5678-9012-34567..0",      // ※※※ 新しいorderIdが発行されている！！！ ※※※
 "purchaseType": 0
}
```

有効期間中にキャンセルして自動更新を止めた場合は新しいレシートが作られませんが、
事前に自動更新を止めず、かつ支払い不備で継続できない状態のときにキャンセルをおこなうと、 **新しいレシートが発行されます。**

レシートの発行をトリガーに購読処理をしてしまわないよう、注意が必要です。


# `paymentState`

正しく課金され、有効なレシートには `paymentState` のパラメータが付加されます。
このパラメータの有無で購読処理を切り分けるのが良い気がします。

> The payment state of the subscription. Possible values are:
> 0. Payment pending
> 1. Payment received
> 2. Free trial
> 3. Pending deferred upgrade/downgrade

参考: [Purchases.subscriptions  |  Google Play Developer API  |  Google Developers](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions#resource-representations)

どのような場合にPayment Pendingになるのかは詳しくありませんが、不承認からのキャンセルによって課金がされなかった場合は `paymentState` パラメータ自体が返ってきませんので、存在チェックが課金可否の分岐となりそうです。
試用期間（Free trial）を設定しているappではその限りではありません。
サービスによって切り分ける必要があります。


# テストについて

テストアカウントで定期購読をおこなうと、ストアアプリの「定期購入」の画面に「カードを不承認にする／承認にもどす」設定項目があらわれます。
ここの切り替えにより、不承認状態のレシートや、不承認からキャンセルした場合、再度承認した場合、などのレシートの状態をテストすることができます。


# まとめ

新規 `orderId` でレシートが発行されたからといって実際に課金されたとは限らない、というお話でした。

ドキュメントからストア仕様をすべて把握し切るのはほぼ不可能です。
検証はガシガシ触ってみるに限ります◎