Alexa Shopping Actions を使って Amazon の商品を購入するスキルを作る


# Alexa Shopping Actions とは

カスタムスキル内でAmazonの商品が販売できるというもの。
スキルを使用しながら、スキルが推奨する商品を購入したり、Amazonのショッピングカートに商品を追加することができます。

[![動作確認](http://img.youtube.com/vi/wY_yJbgEYaA/0.jpg)](http://www.youtube.com/watch?v=wY_yJbgEYaA)

# 何ができるのか？

スキル内でお勧めした商品をユーザーのショッピングカートに追加できます。これは後にショッピングカートにアクセスし自身で購入処理をする必要があります。もう一つは、スキル内でお勧めした商品を購入できます。スキルセッション中にユーザーの意思を確認した後、購入が確定されます。

> 購入ワークフローには、有効な支払いタイプ、配送先住所、顧客のAmazonアカウントに関連付けられた音声PIN承認など、さまざまなチェックが組み込まれています。

|No.|アクション|説明| 
|:--|:--|:--|
|1|商品をカートに入れる|購入はされない。カートに入れるだけ|
|2|商品を購入する|音声PIN認証などで商品を購入することができる|
|3|商品の返金|Shopping Actionではできない|


# 実装方法は

Shopping Actionは、skill connections を使用しており、`AddToShoppingCart`タスクと、`BuyShoppingProducts`タスクが用意されています。

実装はめちゃくちゃ簡単。サンプルをコピるだけで動きます。


#### ショッピングカートに追加する場合

商品をカートに入れる`AddToShoppingCart`タスクを`.addDirective` に追加します。

#### 商品を購入する場合

商品を購入する`BuyShoppingProducts`タスクを`.addDirective` に追加します。


#### 返金する場合

商品の返金の場合は、skill connections ではなく、別途、返金インテントを作成して対応します。





スキルからは商品の削除ができない。


# スキルにShopping Actionを追加する


#### スキルマニフェスト

`"isAlexaShoppingActionsEnabled": true,`

```
"privacyAndCompliance": {
    "allowsPurchases": false,
    "containsAds": false,
    "isChildDirected": false,
    "isExportCompliant": true,
    "isAlexaShoppingActionsEnabled": true,
    "locales": {
       "en-US": {}
    },
    "usesPersonalInfo": false
}
```


#### スキル側の実装

インテントを追加する。

AddToShoppingCartIntent

```
  "intents": [
      {
          "name": "AddToShoppingCartIntent",
          "samples": [
              "カートに入れる",
              "カートに入れてください",
              "カートへ"
          ]
      },
```

BuyShoppingProductsIntent

```
  "intents": [
      {
          "name": "BuyShoppingProductsIntent",
          "samples": [
              "購入",
              "購入します",
              "買います"
          ]
      },
```


RefundIntent

```
  "intents": [
      {
          "name": "RefundIntent",
          "samples": [
              "購入をやめる",
              "やめたい"
          ]
      },
```

#### Lambda側の実装

##### AddToShoppingCart action

`.addDirective`に以下を設定。
[リファレンス](https://developer.amazon.com/en-US/docs/alexa/alexa-shopping/alexa-shopping-actions-for-alexa-skills-api-reference.html#addtoshoppingcart-action)

```javascript:AddToShoppingCart
 const AddToShoppingCartIntentHandler = {
     canHandle(handlerInput) {
         return util.parseIntent(handlerInput) === 'AddToShoppingCartIntent';
     },
     handle(handlerInput) {

            return handlerInput.responseBuilder
            .speak(actionText)
            .addDirective({
              'type': 'Connections.StartConnection',
              'uri': 'connection://AMAZON.AddToShoppingCart/1',
              'input': {
                   'products' : [
                     {
                       'asin' : 'B01962MDHA'
                     }
                   ]
                },
              'token': 'AddToShoppingCartToken'
            })
            .getResponse();
```

##### BuyShoppingProducts action

`.addDirective`に以下を設定。
[リファレンス](https://developer.amazon.com/en-US/docs/alexa/alexa-shopping/alexa-shopping-actions-for-alexa-skills-api-reference.html#buyshoppingproducts-action)

<font color="OrangeRed">※`BuyShoppingProducts action` はテストでもバンバン購入できてしまうようなので、テストしたらキャンセルを忘れずに。</font>

```javascript:BuyShoppingProducts
 const BuyShoppingProductsIntentHandler = {
     canHandle(handlerInput) {
         return util.parseIntent(handlerInput) === 'BuyShoppingProductsIntent';
     },
     handle(handlerInput) {

            return handlerInput.responseBuilder
            .speak(actionText)
            .addDirective({
              'type': 'Connections.StartConnection',
              'uri': 'connection://AMAZON.BuyShoppingProducts/1',
              'input': {
                   'products' : [
                     {
                       'asin' : 'B01962MDHA'
                     }
                   ]
                },
              'token': 'PurchaseProductToken'
            })
            .getResponse();
        }
```

##### 返金

```Javascript:RefundHandler 
 const RefundIntentHandler = {
     canHandle(handlerInput) {
         return util.parseIntent(handlerInput) === 'RefundIntent';
     },
     handle(handlerInput) {
         return handlerInput.responseBuilder
         .speak("注文を確認またはキャンセルするには、Amazonアカウントの注文セクションにアクセスしてください。")
         .getResponse();
     },
 }
```


#### Skill connections のレスポンスを処理する

`status.code` はあくまでもSkill connectionsの成功、失敗であり、ユーザーが商品を購入したか、キャンセルしたかのステータスを取得することは、今のところできません。

```javascript
const SessionResumedRequestHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'SessionResumedRequest';
    },
    handle(handlerInput) {
        let request = handlerInput.requestEnvelope.request;

        if (request.cause) {
             const code = status.code;

             switch(code) {
                 case '200':
                      :
```

# テスト

珍しく、テスト観点がドキュメントに記載されています。
[あなたのスキルをテストする](https://developer.amazon.com/en-US/docs/alexa/alexa-shopping/steps-to-create-a-skill-that-uses-alexa-shopping-actions.html#test)

なんかこれが面倒そうだなぁ。この処理を入れないと審査通らないようです。

> Don't continue to recommend a product that received a success response.

おわり