Alexa スキル内課金　第1回　スキル内課金の仕組みとスキル内商品レコード作成、読み込み

#はじめに
日本でもスキル内課金が解禁されましたので、今回はAlexaのスキル内課金の作り方を説明します。
スキル内課金を試してみようとスキルをつくり、記事用にも作ろうとしていました。いったん途中で誤って投稿してしまいましたが、削除しての出し直し記事です。
今回は、スキル内課金の仕組みとスキル内課金レコードの作成と、その読み込み方法を説明します。

#今回実施する内容
今回は、スキル内課金の仕組みとスキル内課金レコードの作成と、その読み込み方法を説明します。
コンソールログに以下を表示させます。

```json:console.logの表示を整形したもの
現在登録済みのスキル内商品： 
[
  {
    "productId":"amzn1.adg.product.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  　"referenceName":"課金商品",
    "type":"ENTITLEMENT",
    "name":"課金商品",
    "summary":"説明です。",
    "entitled":"NOT_ENTITLED",
    "entitlementReason":"NOT_PURCHASED",
    "purchasable":"PURCHASABLE",
    "activeEntitlementCount":0,
    "purchaseMode":"TEST"
  }
]
```

#環境
OS:Windows 10 JP
Alexaスキル言語：Node.js
Editor：Visual Studio Code
Alexa developer console

#参考
・[Alexaスキルを使用した商品の販売](https://developer.amazon.com/ja/docs/custom-skills/sell-products-in-an-alexa-skill.html)
Alexzオフィシャルドキュメントの説明です。

・[AlexaサービスAPIの呼び出し](https://ask-sdk-for-nodejs.readthedocs.io/ja/latest/Calling-Alexa-Service-APIs.html)
Node.jsでスキル内課金サービスのAPIへアクセスする説明です。

#用語
##スキル内課金 (ISP)
スキルの中の課金の仕組みこと。
In-skill Purchasing

#前提条件
特になし

#スキル内課金の概要
スキル内課金の導入にあたり、スキル内課金を実現するための仕組みの概念図を示します。
![スキル内課金イメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/6ac6698a-3efa-e564-90fe-4ae3cdd62d04.jpeg)



まずはじめに上記の図はオリジナルで作成したものであり、アマゾンの更新のものではありませんので、参考程度に考えてください。

スキル内課金の大本は、**スキル内商品**レコードにあります。
その内容は、

 - 商品名
 - 商品ID
 - 商品の説明
 - 商品価格
 - 商品の購入可否
 - 商品の購入情報

など多くの情報が、**スキル内商品**レコードに保存されます。
**スキル内商品**レコードは、Amazon developer consoleやASK CLIで作成できます。

**スキル**は、この**スキル内商品**レコードの情報を使い、購入しているか判断し、

- 未購入ならば、**レコメンド**。
- 購入済みならば、**スキル内商品の提供**

をします。

**Alexa**は、スキル経由で購入や返金を依頼され、

- ユーザーとの購入・キャンセルなどの対話（スキルを介さない対話）
- 課金処理（Amazon課金サーバへの購入通知
- 返金処理
- スキルへの購入結果の通知

を行います。

**ユーザーとの購入の対話**は、**スキルを介さない**で実施されます。
この**スキルを介さない**が大きな特徴のひとつです。
従来であれば、Alexaの仕事は、ユーザーとの対話において、言語の認識して、それをIntentという形にしてスキルに渡すことや、スキルからのResponseを言語に変えてユーザーに会話の形で渡すのが主な仕事でした。
しかし、スキル内課金においては、スキルから**購入処理**を要求すると、その後はAlexaがユーザーと対話して、購入や購入取り消しなどの対話を行い、その結果をスキルに返すという動作になります。
もちろん、Alexaが商品のことを知っているわけではないため、**スキル内商品**レコードに基づいて処理を行います。

課金の仕組み自体は、どんなスキル内商品でもプロセスは同じで、

- それを開発者が毎回書くのは面倒
- 同じ処理のほうがユーザーにとっては新設
- アマゾンでPrime会員には割引などアマゾンによる柔軟な対応ができる

など、開発者にとっても、アマゾンにとっても、ユーザーにとってもメリットがあるようにしているのかなと思います。
といってもよいことばかりではなく、このために開発者はいろんな制限の中でスキル開発をしないといけないというのがでてきており、例えば、「商品の金額については、スキル内では触れてはならない」などですが、色々とあって、慣れるまでは面倒そうです。

#スキル内課金の作成
##スキル内商品レコードの作成
スキル内商品のレコードは、ASK CLIでも作成できるようですが、今回は、Alexa developer consoleから作成します。
スキル内商品レコードには、

| 種類 | 概要 |
|:-:|:--|
|買い切り型   |1回購入すればずっと利用可能なタイプ。有効期限なし。|
|サブスクリプション型|一定期間利用可能なタイプ。|
|消費型|1回利用可能なタイプ。|

があります。
今回は**「買い切り型」**のスキル内商品レコードを作成します。

1. Alexa developer consoleで、スキル内課金を作成するスキルのビルド画面を開く。
2. 左側目のメニューから**「スキル内商品」**を選択し、****を開く。
    ![メニュー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/89b14c4a-2c2a-61e2-538b-91efb7933810.jpeg)
    ◆スキル内商品画面
    ![スキル内商品画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/a0db04e2-0aec-0fc5-87c5-4779514af85c.jpeg)
    
    スキル内商品画面では、
    ・ リンクした商品
    ・ リンク可能な商品
    ・ スキル内商品を作成ボタン
    など（赤枠のもの）が表示されます。
    これは開発者の全体のスキルで共通で利用されるスキル内商品が表示されます。ただしリンク済みの商品はでません。
    リンクした商品は、このスキルに関連付けられたスキルが表示されます。
    リンク可能な商品は、スキル内商品レコードを作成したもので、まだどのスキルにも関連付けされていないものが表示されます。

3. **「スキル内商品を作成」**ボタンを押す。
下図のような作成するスキル内商品の名称入力と種類を選択する画面が表示される。
![タイプ選択.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/36281c02-57ad-4223-71f3-4b11ed1f69ea.jpeg)

4. スキル内商品に適当な名称（ここでは、課金商品）をつけ、「買い切り型」を選択し、「スキル内商品を作成」ボタンを押下する。
    以下のような画面が表示される。以下に従って入力する。
    ![スキル内商品情報１.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/396ababa-912d-4175-c108-7000c83d0e68.jpeg)
    
    ・課金商品
    ここは、上記で**記載した名称「課金商品」**にしたものが記載される。

    ・商品ID
    自動で割当らえる識別子。入力は不要。

    ・参照名
    上記で**記載した名称「課金商品」にしたものが記載される。

    ・サポートされる言語の「新しい言語を追加」
    次項で説明する。

    ・価格設定と購入可能状況
    どこで販売するかですが、まずは日本だと思いますので、「Amazon.co.jp」を選択し、価格を設定する。
    買い切り型とサブスクリプション型の場合、**99円～9,999円**の範囲で設定可能。
    消費型の場合、**99円～999円**の範囲で設定可能。

    ・料金のカテゴリー
    以下のカテゴリーから選択。
    - 情報サービス
    - 定期刊行物
    - ソフトウェア
    - ストリーミングオーディオ
    - ストリーミングラジオ
    - ビデオ

    いまいち、よくわからない分類で、どう使われるのかわかりません。

    ・テスト手順
    アマゾンの試験車むけに使い方の説明を記載する。

5. サポートされる言語の「新しい言語を追加」ボタンを押下し、**「日本語(日本)」**を選択すると、以下の画面が表示される。以下に従って入力する。

    ![スキル内商品情報2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/7d4315e7-1c51-9b45-046c-9658ccea1313.jpeg)

    ・表示名
    スキル内商品の商品名として利用する名称をつける。

    ・説明
    スキル内商品の説明を記載し、この情報は、Alexaがユーザーと対話するときに利用される。

    ・詳細な説明
    さらに詳細な説明を記載する。今のところ、Alexaがユーザーとの対話で使っているようには見えないが、おそらく使われることになると思われる。

    ・このスキル内商品の小さいアイコン
    ・このスキル内商品の大きいアイコン
    スキル内商品のアイコンですが、いまのところどこで使うのか不明。Web上で出るスキルアイコンとは別で、スキル内商品向けですが、どこで出てくるのかな。

    ・購入プロンプトの説明
    購入したときに利用される音声メッセージを記載する。

    ・購入確認の説明
    購入した時にスキルアプリで表示されるメッセージを記載する。    

    ここで、設定した値は、スキルからアクセスすることができます。取得方法は別途記載します。
    以下のような情報になります。

    ```json:inSkillProducts
    [
        {
            "productId":"amzn1.adg.product.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
            "referenceName":"課金商品",
            "type":"ENTITLEMENT",
            "name":"課金商品",
            "summary":"説明です。",
            "entitled":"NOT_ENTITLED",
            "entitlementReason":"NOT_PURCHASED",
            "purchasable":"PURCHASABLE",
            "activeEntitlementCount":0,
            "purchaseMode":"TEST"
        }
    ]
    ```

    |要素名|スキル内商品レコード上の名前|説明|
    |:--|:--|:--|
    |productId|商品ID|自動で割り当てられる一意な値。|
    |referenceName|参照名|参照となる名称。基本的にnameと同じにする。|
    |name|表示名|スキル内で表示される商品名。|
    |summary|説明|商品の説明。|
    |entitled|なし|スキル内商品の権利を示す。ENTITLED、または、NOT_ENTITLED|
    |purchasable|なし|購入可能かどうかを示す。PURCHASABLE、またはNOT_PURCHASABLE|
    |activeEntitlementCount|なし|購入した個数。消費型で使用。|
    |purchaseMode|なし|試験中か運用中かを示す。TEST、まてゃLIVE|



6. すべて入力したら、「保存」する。
7. すべて入力できていると、スキルとリンクするか聞かれるため、リンクすると、「リンクした商品」に表示されるようになる。なお、記載内容は変更できるため、途中で間違えても大丈夫です。
おそらく、公開された後も自由に変更できるように思います。（再度更新する時に一緒に更新されると思います）

##Node.jsからスキル内課金レコードへのアクセス

Node.jsからスキル内レコードへは、以下のMonetizationServiceClient APIを通じてアクセスします。
**スキル内商品**レコードで作成したように、商品は、地域(locale)ごとに管理されるため、localeを設定したうえで、情報を取得します。
[AlexaサービスAPIの呼び出し](https://ask-sdk-for-nodejs.readthedocs.io/ja/latest/Calling-Alexa-Service-APIs.html)に記載されている内容をベースに記載します。

```js:index.jsの一部
const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    const locale = handlerInput.requestEnvelope.request.locale;
    const ms = handlerInput.serviceClientFactory.getMonetizationServiceClient();
    return ms.getInSkillProducts(locale).then((result) => {
      console.log(`現在登録済みのスキル内商品： ${JSON.stringify(result.inSkillProducts)}`);
      return handlerInput.responseBuilder
        .speak("スキル内課金へようこそ")
        .withSimpleCard("スキル内課金", "スキル内課金へようこそ")
        .getResponse();
    });
  },
};
```

上記を記載したうえで、このスキルを起動すると、console出力に以下が表示されます。

```
現在登録済みのスキル内商品： [{"productId":"amzn1.adg.product.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX","referenceName":"課金商品","type":"ENTITLEMENT","name":"課金商品","summary":"説明です。","entitled":"NOT_ENTITLED","entitlementReason":"NOT_PURCHASED","purchasable":"PURCHASABLE","activeEntitlementCount":0,"purchaseMode":"TEST"}]
```

ちょっとわかりづらいため、整形して表示します。

```json:console.logの表示を整形したもの
現在登録済みのスキル内商品： 
[
  {
    "productId":"amzn1.adg.product.XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
  　"referenceName":"課金商品",
    "type":"ENTITLEMENT",
    "name":"課金商品",
    "summary":"説明です。",
    "entitled":"NOT_ENTITLED",
    "entitlementReason":"NOT_PURCHASED",
    "purchasable":"PURCHASABLE",
    "activeEntitlementCount":0,
    "purchaseMode":"TEST"
  }
]
```

スキル内商品レコードの内容が取得できたことがわかります。
ソースコードについて、少し説明します。
`const locale = handlerInput.requestEnvelope.request.locale;`
は、地域を取得しています。今回だと、スキル内商品作成で日本を選択しましたので、`jp-JP`になります。
`const ms = handlerInput.serviceClientFactory.getMonetizationServiceClient();`
これは、MonetizationServiceClientの定数を設定しています。
`return ms.getInSkillProducts(locale).then((result) => {`
ここで、地域が「jp-JP」のスキル内商品レコードをすべて取得して、resultに入れています。
`console.log(`現在登録済みのスキル内商品： ${JSON.stringify(result.inSkillProducts)}`);`
その内容を、consoleに出力しただけです。今回はレコードが一つしか作成していないため、上記のようになりました。

スキル内商品レコードについては、上のほうで述べましたので特筆することはありませんが、作成したばかりの状態では、以下のように、未購入(NOT_PURCHASED)であり資格はなく(NOT_ENTITLED)、個数は0で、購入可能(PURCHASABLE)だということです。
また、スキル内課金の状態が、TEST状態ということもわかります。

```json
    "entitled":"NOT_ENTITLED",
    "entitlementReason":"NOT_PURCHASED",
    "purchasable":"PURCHASABLE",
    "activeEntitlementCount":0,
    "purchaseMode":"TEST"
```

#おわりに
今回は、以下を実施しました。

- スキル内課金の概要説明
- スキル内商品レコードの作成
- スキル内商品レコードのNode.jsからのアクセス

次回以降は、Alexaによるユーザーとのスキル内商品購入のやり方を説明やスキル内商品レコードの使い方について説明していきたいと思います。