販売者が管理する決済方法で物理的取引を構築する

このガイドでは、サイトが管理する支払い方法を使用して物理的な商品の取引を組み込む Actions プロジェクトの開発プロセスについて説明します。

取引の流れ

Actions プロジェクトで販売者が管理する決済方法を使用して物理取引を処理する場合、次のフローに沿って処理します。

  1. ユーザーのアカウントをリンクする - ユーザーがサービスに保存したお支払い方法を使用できるようにするには、アカウント リンクを使用して、ユーザーの Google アカウントをサービスのアカウントに関連付けます。
  2. 情報を収集する(省略可) - 取引の性質によっては、会話の早い段階でユーザーから次の情報を収集する必要があります。
    1. 取引要件の検証 - 会話の取引セクションの開始時に、ユーザーが取引を行うための要件(カートを構築する前に支払い情報を適切に構成して利用できるようにするなど)を満たしていることを検証します。
    2. 配送先住所をリクエストする - 取引に配送先住所が必要な場合は、ユーザーから配送先住所を収集します。
  3. 注文を作成する - 購入する商品を選ぶ「カート アセンブリ」の手順をユーザーに案内します。
  4. 注文を提案する - カートが完成したら、正しい注文であることをユーザーに確認してもらいます。注文が確認されると、注文の詳細と支払いトークンを含むレスポンスが届きます。
  5. 注文を確定して領収書を送信する - 注文が確定されたら、在庫追跡や他の納品サービスを更新し、ユーザーに領収書を送信します。
  6. 注文の更新情報を送信する - 注文フルフィルメントの有効期間中は、PATCH リクエストを Orders API に送信して、ユーザーに注文の更新情報を提供します。

制限と審査のガイドライン

取引を伴うアクションには追加のポリシーが適用されます。トランザクションを含むアクションの審査には最大 6 週間かかるため、リリース スケジュールを計画する際は、その期間を考慮してください。審査プロセスを簡単にするため、審査のためにアクションを送信する前に、取引に関するポリシーとガイドラインに準拠していることを確認してください。

現物商品を販売するアクションは次の国でのみデプロイできます。

オーストラリア
ブラジル
カナダ
インドネシア
日本
メキシコ
カタール
ロシア
シンガポール
スイス
タイ
トルコ
英国
米国

プロジェクトのビルド

トランザクションの会話の例については、Node.js のトランザクション サンプルをご覧ください。

プロジェクトの設定

アクションを作成するときに、Actions Console でトランザクションを実行することを指定する必要があります。

プロジェクトとフルフィルメントを設定する手順は次のとおりです。

  1. 新しいプロジェクトを作成するか、既存のプロジェクトをインポートします。
  2. [Deploy](デプロイ)> [Directory information](ディレクトリ情報)の順に移動します。
  3. [その他の情報] > [トランザクション] で、[アクションで Transactions API を使用して物理的な商品のトランザクションを実行しますか?] チェックボックスをオンにします。

独自のお支払い方法を使用してユーザーへの請求を行う場合は、ユーザーの Google アカウントを独自のサービスで使用しているアカウントとリンクし、保存されているお支払い方法の取得、提示、請求を行うことをおすすめします。

認証フローの音声ユーザー インターフェースを設計する

本人確認が完了しているかどうか確認してアカウントのリンクのフローを開始する

  1. Actions Console で Actions Builder プロジェクトを開きます。
  2. 新しいシーンを作成し、アクションでアカウントのリンクを開始します。
    1. [Scenes](シーン)をクリックします。
    2. 追加(+)アイコンをクリックして新しいシーンを追加します。
  3. 新しく作成したシーンで、[Conditions] の追加アイコン アイコンをクリックします。
  4. 会話に関連付けられたユーザーが確認済みユーザーかどうかを確認する条件を追加します。チェックが失敗した場合、アクションは会話中にアカウント リンクを実行できないため、アカウント リンクを必要としない機能にアクセスできるようにフォールバックする必要があります。
    1. [Condition] の Enter new expression フィールドに、次のロジックを入力します。 user.verificationStatus != "VERIFIED"
    2. [Transition] で、アカウントのリンクが不要なシーン、またはゲスト専用機能のエントリ ポイントとなるシーンを選択します。

  1. [Conditions] の追加アイコン をクリックします。
  2. ユーザーに ID が関連付けられていない場合に、アカウントのリンクのフローをトリガーする条件を追加します。
    1. [Condition] の Enter new expression フィールドに、次のロジックを入力します。 user.verificationStatus == "VERIFIED"
    2. [移行] で、[アカウントのリンク] システムシーンを選択します。
    3. [保存] をクリックします。

保存後、<SceneName>_AccountLinking という新しいアカウント リンク システムシーンがプロジェクトに追加されます。

アカウントのリンクのシーンをカスタマイズする

  1. [Scenes](シーン)で、アカウント リンクのシステムシーンを選択します。
  2. [プロンプトを送信] をクリックし、アクションが ID にアクセスする必要がある理由をユーザーに説明する短い文を追加します(「設定を保存するため」など)。
  3. [保存] をクリックします。

  1. [条件] で [ユーザーがアカウントのリンクを正常に完了した場合] をクリックします。
  2. ユーザーがアカウントのリンクに同意した場合のフローの動作を設定します。 たとえば、Webhook を呼び出して必要なカスタム ビジネス ロジックを処理し、元のシーンに戻ります。
  3. [保存] をクリックします。

  1. [条件] で、[ユーザーがアカウントのリンクをキャンセルまたは拒否した場合] をクリックします。
  2. ユーザーがアカウントのリンクに同意しなかった場合にフローがどのように進むかを構成します。たとえば、確認応答メッセージを送信し、アカウント リンクを必要としない機能を提供するシーンにリダイレクトします。
  3. [保存] をクリックします。

  1. [条件] で [システムエラーまたはネットワーク エラーが発生した場合] をクリックします。
  2. システムエラーまたはネットワーク エラーが原因でアカウント リンクのフローを完了できない場合のフローの構成。たとえば、確認応答メッセージを送信し、アカウント リンクを必要としない機能を提供するシーンにリダイレクトします。
  3. [保存] をクリックします。

情報を収集する(省略可)

取引要件を確認する(省略可)

ユーザーが購入の意思を示したら、すぐにトランザクションを実行できるようにする必要があります。たとえば、アクションが呼び出されると、「靴の注文または口座残高の確認を行いますか?」と質問します。ユーザーが「靴を注文」と言った場合は、続行できることを確認し、取引を続行できない設定を修正する機会を提供します。そのためには、トランザクション要件のチェックを行うシーンに移行する必要があります。

取引要件の確認シーンを作成する
  1. [Scenes] タブで、TransactionRequirementsCheck という名前の新しいシーンを追加します。
  2. [スロットフィル] で [+] をクリックして新しいスロットを追加します。
  3. [タイプを選択] で、スロットタイプとして actions.type.TransactionRequirementsCheckResult を選択します。
  4. スロット名の欄で、スロットに「TransactionRequirementsCheck」という名前を付けます。
  5. [Customize slot value writeback] チェックボックスを有効にします(デフォルトで有効になっています)。
  6. [保存] をクリックします。

取引要件のチェックでは、次のいずれかの結果が返されます。

  • 要件が満たされると、セッション パラメータに成功条件が設定され、ユーザーの注文の作成に進むことができます。
  • 1 つ以上の要件を満たすことができない場合、セッション パラメータには失敗条件が設定されます。この場合は、会話をトランザクション エクスペリエンスから切り離すか、会話を終了する必要があります。
    • 障害状態の原因となったエラーがユーザーによって修正できる場合は、デバイスにプロンプトが表示され、問題を解決するようユーザーに促します。会話が音声のみのサーフェスで行われている場合、ユーザーのスマートフォンへのハンドオフが開始されます。

取引要件チェックの結果を処理する

  1. [Scenes] タブで、新しく作成した TransactionRequirementsCheck シーンを選択します。
  2. [Condition] で、[+] をクリックして新しい条件を追加します。
  3. テキスト フィールドに次の条件構文を入力して、成功条件を確認します。

    scene.slots.status == "FINAL" && session.params.TransactionRequirementsCheck.resultType == "CAN_TRANSACT"
    
  4. 追加した条件にカーソルを合わせ、上矢印をクリックして if scene.slots.status == "FINAL" の前に配置します。

  5. [プロンプトを送信] を有効にし、取引を行う準備ができたことをユーザーに伝える簡単なプロンプトを表示します。

    candidates:
      - first_simple:
          variants:
            - speech: >-
                You are ready to purchase physical goods.
    
  6. [Transition] で別のシーンを選択し、ユーザーが会話を続けてトランザクションの処理を続行できるようにします。

  7. 条件 else if scene.slots.status == "FINAL" を選択します。

  8. [プロンプトを送信] を有効にし、取引ができないことをユーザーに伝える簡単なプロンプトを表示します。

    candidates:
      - first_simple:
          variants:
            - speech: Transaction requirements check failed.
    
  9. ユーザーが取引できない場合は、[移行] で [会話を終了] を選択して会話を終了します。

配送先住所をリクエストする(省略可)

取引に配送先住所が必要な場合は、ユーザーにリクエストする必要があります。これは、合計金額や配達/受け取り場所を判断したり、ユーザーがサービス提供地域内にいることを確認する際にも役立ちます。そのためには、ユーザーに配送先住所を求めるシーンに移行する必要があります。

配送先住所のシーンを作成

  1. [Scenes] タブで、DeliveryAddress という名前の新しいシーンを追加します。
  2. [スロットフィル] で [+] をクリックして新しいスロットを追加します。
  3. [タイプを選択] で、スロットタイプとして actions.type.DeliveryAddressValue を選択します。
  4. スロット名の欄で、スロットに「TransactionDeliveryAddress」という名前を付けます。
  5. [Customize slot value writeback] チェックボックスを有効にします(デフォルトで有効になっています)。
  6. [保存] をクリックします。

スロットを設定するときに reason を指定すると、住所を取得するアシスタントのリクエストの前に文字列が表示されます。デフォルトの理由文字列は「注文の送信先を確認する」です。そのため、アシスタントがユーザーに「注文の配送先を確認するため、配送先住所が必要です」と尋ねます。

  • 画面表示が使用できるサーフェスの場合、ユーザーは取引に使用する住所を選択します。また、住所をまだ指定していない場合は、新しい住所を入力できます。
  • 音声のみのサーフェスでは、アシスタントは取引のデフォルトの住所を共有する許可をユーザーに求めます。これまで住所を入力したことがない場合、会話はスマートフォンにハンドオフされ、入力されます。

配送先住所の結果を処理する手順は次のとおりです。

  1. [Scenes] タブで、新しく作成した DeliveryAddress シーンを選択します。
  2. [Condition] で、[+] をクリックして新しい条件を追加します。
  3. テキスト フィールドに次の条件構文を入力して、成功条件を確認します。

    scene.slots.status == "FINAL" && session.params.TransactionDeliveryAddress.userDecision == "ACCEPTED"
    
  4. 追加した条件にカーソルを合わせ、上矢印をクリックして if scene.slots.status == "FINAL" の前に配置します。

  5. [プロンプトを送信] を有効にして、住所を受け取ったことをユーザーに知らせる簡単なプロンプトを表示します。

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Great! Your order will be delivered to
                $session.params.TransactionDeliveryAddress.location.postalAddress.locality
                $session.params.TransactionDeliveryAddress.location.postalAddress.administrativeArea
                $session.params.TransactionDeliveryAddress.location.postalAddress.regionCode
                $session.params.TransactionDeliveryAddress.location.postalAddress.postalCode
    
  6. [Transition] で、別のシーンを選択して、ユーザーが会話を続けられるようにします。

  7. 条件 else if scene.slots.status == "FINAL" を選択します。

  8. [プロンプトを送信] を有効にし、取引ができないことをユーザーに伝える簡単なプロンプトを表示します。

    candidates:
      - first_simple:
          variants:
            - speech: I failed to get your delivery address.
    
  9. ユーザーが取引できない場合は、[移行] で [会話を終了] を選択して会話を終了します。

注文を作成する

必要なユーザー情報を入手したら、ユーザーが注文を行うカート アセンブリを構築します。カート アセンブリのフローは、アクションごとにプロダクトまたはサービスに応じて若干異なります。

最も基本的なカート構成では、ユーザーがリストからアイテムを選択して注文に追加しますが、ユーザー エクスペリエンスを簡素化するように会話を設計することもできます。「はい」か「いいえ」で答えられる簡単な質問によって、ユーザーが最新の購入品を再注文できるカート アセンブリ エクスペリエンスを構築できます。また、上位の「注目」や「おすすめ」のアイテムのカルーセルまたはリストカードを表示することもできます。

リッチ レスポンスを使用して、ユーザーの選択肢を視覚的に提示することをおすすめしますが、ユーザーが音声だけでカートを作成できるように会話を設計することもできます。高品質のカート アセンブリ エクスペリエンスのベスト プラクティスと例については、トランザクションの設計ガイドラインをご覧ください。

注文を作成する

会話を通じて、ユーザーが購入したいと思うアイテムを収集し、Order オブジェクトを作成する必要があります。

Order には少なくとも次のものが含まれている必要があります。

  • buyerInfo - 商品を購入しようとしているユーザーに関する情報。
  • transactionMerchant - 注文を処理した販売者に関する情報。
  • contents - lineItems として列挙される注文の実際の内容。
  • priceAttributes - 注文に関する料金の詳細(割引や税金を適用した注文の合計費用を含む)。

カートを作成するには、Order レスポンス ドキュメントをご覧ください。注文に応じて異なるフィールドが必要になる場合があります。

次のサンプルコードは、省略可能なフィールドを含む完全な注文を示しています。

const order = {
  createTime: '2019-09-24T18:00:00.877Z',
  lastUpdateTime: '2019-09-24T18:00:00.877Z',
  merchantOrderId: orderId, // A unique ID String for the order
  userVisibleOrderId: orderId,
  transactionMerchant: {
    id: 'http://www.example.com',
    name: 'Example Merchant',
  },
  contents: {
    lineItems: [
      {
        id: 'LINE_ITEM_ID',
        name: 'Pizza',
        description: 'A four cheese pizza.',
        priceAttributes: [
          {
            type: 'REGULAR',
            name: 'Item Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 8990000,
            },
            taxIncluded: true,
          },
          {
            type: 'TOTAL',
            name: 'Total Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 9990000,
            },
            taxIncluded: true,
          },
        ],
        notes: [
          'Extra cheese.',
        ],
        purchase: {
          quantity: 1,
          unitMeasure: {
            measure: 1,
            unit: 'POUND',
          },
          itemOptions: [
            {
              id: 'ITEM_OPTION_ID',
              name: 'Pepperoni',
              prices: [
                {
                  type: 'REGULAR',
                  state: 'ACTUAL',
                  name: 'Item Price',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
                {
                  type: 'TOTAL',
                  name: 'Total Price',
                  state: 'ACTUAL',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
              ],
              note: 'Extra pepperoni',
              quantity: 1,
              subOptions: [],
            },
          ],
        },
      },
    ],
  },
  buyerInfo: {
    email: 'janedoe@gmail.com',
    firstName: 'Jane',
    lastName: 'Doe',
    displayName: 'Jane Doe',
  },
  priceAttributes: [
    {
      type: 'SUBTOTAL',
      name: 'Subtotal',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 9990000,
      },
      taxIncluded: true,
    },
    {
      type: 'DELIVERY',
      name: 'Delivery',
      state: 'ACTUAL',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 2000000,
      },
      taxIncluded: true,
    },
    {
      type: 'TAX',
      name: 'Tax',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 3780000,
      },
      taxIncluded: true,
    },
    {
      type: 'TOTAL',
      name: 'Total Price',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 15770000,
      },
      taxIncluded: true,
    },
  ],
  followUpActions: [
    {
      type: 'VIEW_DETAILS',
      title: 'View details',
      openUrlAction: {
        url: 'http://example.com',
      },
    },
    {
      type: 'CALL',
      title: 'Call us',
      openUrlAction: {
        url: 'tel:+16501112222',
      },
    },
    {
      type: 'EMAIL',
      title: 'Email us',
      openUrlAction: {
        url: 'mailto:person@example.com',
      },
    },
  ],
  termsOfServiceUrl: 'http://www.example.com',
  note: 'Sale event',
  promotions: [
    {
      coupon: 'COUPON_CODE',
    },
  ],
  purchase: {
    status: 'CREATED',
    userVisibleStatusLabel: 'CREATED',
    type: 'FOOD',
    returnsInfo: {
      isReturnable: false,
      daysToReturn: 1,
      policyUrl: 'http://www.example.com',
    },
    fulfillmentInfo: {
      id: 'FULFILLMENT_SERVICE_ID',
      fulfillmentType: 'DELIVERY',
      expectedFulfillmentTime: {
        timeIso8601: '2019-09-25T18:00:00.877Z',
      },
      location: location,
      price: {
        type: 'REGULAR',
        name: 'Delivery Price',
        state: 'ACTUAL',
        amount: {
          currencyCode: 'USD',
          amountInMicros: 2000000,
        },
        taxIncluded: true,
      },
      fulfillmentContact: {
        email: 'johnjohnson@gmail.com',
        firstName: 'John',
        lastName: 'Johnson',
        displayName: 'John Johnson',
      },
    },
    purchaseLocationType: 'ONLINE_PURCHASE',
  },
};

注文とプレゼンテーションのオプションを作成する

ユーザーが注文を確定する前に、提案された注文カードが表示されます。順序や表示に関するさまざまなオプションを設定することで、このカードのユーザーへの表示方法をカスタマイズできます。

配送先住所が必要な注文の場合、注文と表示のオプションは次のとおりです(注文確認カードにユーザーのメールアドレスも含まれます)。

const orderOptions = {
      'requestDeliveryAddress': true,
      'userInfoOptions': {
        'userInfoProperties': ['EMAIL']
      }
    };

const presentationOptions = {
      'actionDisplayName': 'PLACE_ORDER'
    };

支払いパラメータを作成する

paymentParameters オブジェクトには、ユーザーの注文時のお支払い方法を記述するフィールドを含む merchantPaymentOption が含まれます。Visa クレジット カードを使用した支払いパラメータの例を次に示します。

const paymentParamenters = {
      'merchantPaymentOption': {
        'defaultMerchantPaymentMethodId': '12345678',
        'managePaymentMethodUrl': 'https://example.com/managePayment',
        'merchantPaymentMethod': [{
          'paymentMethodDisplayInfo': {
            'paymentMethodDisplayName': 'VISA **** 1234',
            'paymentType': 'PAYMENT_CARD'
          },
          'paymentMethodGroup': 'Payment method group',
          'paymentMethodId': '12345678',
          'paymentMethodStatus': {
            'status': 'STATUS_OK',
            'statusMessage': 'Status message'
          }
        }]
      }
    };

セッション パラメータに注文データを保存

フルフィルメントから、注文データを session パラメータに保存します。order オブジェクトは、同じセッションのシーン全体で使用されます。

conv.session.params.order = {
    '@type': 'type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec',
    order: order,
    orderOptions: orderOptions,
    presentationOptions: presentationOptions,
    paymentParameters: paymentParameters
};

注文内容を表示する

注文を作成したら、その注文をユーザーに提示して、注文を承認または拒否する必要があります。 そのためには、トランザクションの判断を行うシーンに移行する必要があります。

Transaction Decision シーンを作成する

  1. [Scenes] タブで、TransactionDecision という名前の新しいシーンを追加します。
  2. [スロットフィル] で [+] をクリックして新しいスロットを追加します。
  3. [タイプを選択] で、スロットタイプとして actions.type.TransactionDecisionValue を選択します。
  4. スロット名の欄で、スロットに「TransactionDecision」という名前を付けます。
  5. [Customize slot value writeback] チェックボックスを有効にします(デフォルトで有効になっています)。
  6. [スロットを構成] で、プルダウンから [セッション パラメータを使用] を選択します。
  7. [スロットの設定] で、注文の保存に使用するセッション パラメータの名前をテキスト フィールド(例: $session.params.order)に入力します。
  8. [保存] をクリックします。

TransactionDecisionValue スロットを埋めるために、アシスタントは組み込みエクスペリエンスを開始し、渡された Order をカート プレビュー カードに直接レンダリングします。ユーザーは「注文して」と言う、取引を拒否する、クレジット カードや住所などのお支払い方法を変更する、注文内容の変更をリクエストするなどの操作を行えます。

ユーザーはこの時点で注文内容の変更をリクエストできます。この場合は、フルフィルメントでカート アセンブリのエクスペリエンスが完了した後に注文変更リクエストを処理できるようにする必要があります。

取引決定結果を処理する

TransactionDecisionValue スロットが埋まると、取引の決定に対するユーザーの回答がセッション パラメータに保存されます。この値には次のものが含まれます。

  • ORDER_ACCEPTED,
  • ORDER_REJECTED,
  • DELIVERY_ADDRESS_UPDATED,
  • CART_CHANGE_REQUESTED
  • USER_CANNOT_TRANSACT.

トランザクションの判定結果を処理するには:

  1. [Scenes] タブで、新しく作成した TransactionDecision シーンを選択します。
  2. [Condition] で、[+] をクリックして新しい条件を追加します。
  3. テキスト フィールドに次の条件構文を入力して、成功条件を確認します。

    scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  4. 追加した条件にカーソルを合わせ、上矢印をクリックして if scene.slots.status == "FINAL" の前に配置します。

  5. [プロンプトを送信] を有効にし、注文が完了したことをユーザーに知らせる簡単なプロンプトを表示します。

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction completed! Your order
                $session.params.TransactionDecision.order.merchantOrderId is all
                set!
    
  6. [移行] で [会話を終了] を選択して会話を終了します。

  7. [Condition] で、[+] をクリックして新しい条件を追加します。

  8. テキスト フィールドに次の条件構文を入力して、失敗条件を確認します。

      scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_REJECTED"
    
  9. 追加した条件にカーソルを合わせ、上矢印をクリックして if scene.slots.status == "FINAL" の前に配置します。

  10. [プロンプトを送信] を有効にし、注文が拒否されたことをユーザーに知らせる簡単なプロンプトを表示します。

    candidates:
      - first_simple:
          variants:
            - speech: Look like you don't want to order anything. Goodbye.
    
  11. [移行] で [会話を終了] を選択して会話を終了します。

  12. 条件 else if scene.slots.status == "FINAL" を選択します。

  13. [プロンプトを送信] を有効にし、取引ができないことをユーザーに伝える簡単なプロンプトを表示します。

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction failed with status
                $session.params.TransactionDecision.transactionDecision
    
  14. ユーザーが取引を行えない場合は、[移行] で [会話を終了] を選択して会話を終了します。

注文を確定して領収書を送る

TransactionDecisionValue スロットが ORDER_ACCEPTED の結果を返したら、注文を「確認」するために必要な処理(独自のデータベースに保持してユーザーに請求するなど)を直ちに実行する必要があります。

このレスポンスで会話を終了できますが、会話を続けるために単純なレスポンスを含める必要があります。この最初の orderUpdate を指定すると、ユーザーにはレスポンスの残りとともに、「折りたたまれた領収書カード」が表示されます。このカードには、ユーザーが注文履歴に表示される領収書が反映されます。

注文確認の際、注文オブジェクトに userVisibleOrderId を含めることができます。これは、注文に関してユーザーに表示される ID です。このフィールドには merchantOrderId を再利用できます。

OrderUpdate オブジェクトの一部にはフォローアップ アクション オブジェクトを含める必要があります。このオブジェクトは、ユーザーがアシスタントの注文履歴で確認できる注文詳細の下部に URL ボタンとして表示されます。

  • 少なくとも注文ごとに VIEW_DETAILS フォローアップ アクションを指定する必要があります。これには、モバイルアプリまたはウェブサイト上の注文内容へのディープリンクを含める必要があります。
  • また、アクションの会話に領収書カードだけでなく、取引を実施するためのすべての法的要件を満たす正式な領収書をメールで送信する必要があります。

初回注文の更新情報を送信するには:

  1. [Scenes] タブで TransactionDecision シーンを選択します。
  2. [条件] で、成功結果 ORDER_ACCEPTED をチェックする条件を選択します。

      scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  3. この条件で [Webhook の呼び出し] を有効にして、インテント ハンドラ名(update_order など)を指定します。

  4. Webhook コードで、初回注文更新を送信するインテント ハンドラを追加します。

    app.handle('update_order', conv => {
      const currentTime = new Date().toISOString();
      let order = conv.session.params.TransactionDecision.order;
      conv.add(new OrderUpdate({
        'updateMask': {
          'paths': [
            'purchase.status',
            'purchase.user_visible_status_label'
          ]
        },
        'order': {
          'merchantOrderId': order.merchantOrderId,
          'lastUpdateTime': currentTime,
          'purchase': {
            'status': 'CONFIRMED',
            'userVisibleStatusLabel': 'Order confirmed'
          },
        },
        'reason': 'Reason string
      }));
    });
    

注文の更新情報を送信する

全期間を通じて、注文のステータスをユーザーに通知し続ける必要があります。HTTP PATCH リクエストを注文ステータスと詳細とともに Orders API に送信して、ユーザーの注文の更新情報を送信します。

Orders API に非同期リクエストを設定する

Orders API に対する注文更新リクエストはアクセス トークンで承認されます。Orders API に注文の更新を PATCH するには、Actions Console プロジェクトに関連付けられた JSON サービス アカウント キーをダウンロードして、そのサービス アカウント キーを署名なしトークンと交換します。署名なしトークンは、HTTP リクエストの Authorization ヘッダーに渡すことができます。

サービス アカウント キーを取得するには、次の手順に従います。

  1. Google Cloud コンソールで、メニューの 単に お知らせください 所有の可能です デフォルトの [API とサービス] > 認証情報 > 認証情報の作成 > サービス アカウント キー
  2. [サービス アカウント] で [新しいサービス アカウント] を選択します。
  3. サービス アカウントを service-account に設定します。
  4. [役割] を [プロジェクト] > [オーナー] に設定します。
  5. キータイプを [JSON] に設定します。
  6. [作成] を選択します。
  7. 非公開の JSON サービス アカウント キーがローカルマシンにダウンロードされます。

注文を更新するコードで、Google API クライアント ライブラリと "https://www.googleapis.com/auth/actions.order.developer" スコープを使用して、サービスキーを署名なしトークンと交換できます。インストール手順と例については、GitHub ページの API クライアント ライブラリをご覧ください。

鍵交換の例については、Node.js サンプルorder-update.js をご覧ください。

注文の更新情報を送信する

サービス アカウント キーを OAuth 署名なしトークンと交換したら、注文の更新を承認済みの PATCH リクエストとして Orders API に送信できます。

Orders API の URL: PATCH https://actions.googleapis.com/v3/orders/${orderId}

リクエストに次のヘッダーを指定します。

  • "Authorization: Bearer token" は、サービス アカウント キーを交換した OAuth 署名なしトークンに置き換えます。
  • "Content-Type: application/json".

PATCH リクエストは、次の形式の JSON 本文を使用します。

{ "orderUpdate": OrderUpdate }

OrderUpdate オブジェクトは、次の最上位フィールドで構成されます。

  • updateMask - 更新する注文のフィールド。注文ステータスを更新するには、値を purchase.status, purchase.userVisibleStatusLabel に設定します。
  • order - 更新の内容。注文の内容を更新する場合は、更新した Order オブジェクトに値を設定します。注文のステータスを更新する場合(たとえば、"CONFIRMED" から "SHIPPED" に)、オブジェクトには次のフィールドがあります。

    • merchantOrderId - Order オブジェクトで設定したのと同じ ID。
    • lastUpdateTime - この更新のタイムスタンプ。
    • purchase - 次のものを含むオブジェクト。
      • status - PurchaseStatus での注文のステータス(「SHIPPED」や「DELIVERED」など)。
      • userVisibleStatusLabel - 注文ステータスの詳細を示すユーザー向けのラベル。「ご注文の商品は発送され、現在配送中です」など。
  • userNotification オブジェクト。なお、このオブジェクトを含めても、ユーザーのデバイスに通知が表示されるとは限りません。

次のサンプルコードは、注文のステータスを DELIVERED に更新する OrderUpdate の例を示しています。

// Import the 'googleapis' module for authorizing the request.
const {google} = require('googleapis');
// Import the 'request-promise' module for sending an HTTP POST request.
const request = require('request-promise');
// Import the OrderUpdate class from the client library.
const {OrderUpdate} = require('@assistant/conversation');

// Import the service account key used to authorize the request.
// Replacing the string path with a path to your service account key.
// i.e. const serviceAccountKey = require('./service-account.json')

// Create a new JWT client for the Actions API using credentials
// from the service account key.
let jwtClient = new google.auth.JWT(
    serviceAccountKey.client_email,
    null,
    serviceAccountKey.private_key,
    ['https://www.googleapis.com/auth/actions.order.developer'],
    null,
);

// Authorize the client
let tokens = await jwtClient.authorize();

// Declare order update
const orderUpdate = new OrderUpdate({
    updateMask: {
      paths: [
        'purchase.status',
        'purchase.user_visible_status_label'
      ]
    },
    order: {
      merchantOrderId: orderId, // Specify the ID of the order to update
      lastUpdateTime: new Date().toISOString(),
      purchase: {
        status: 'DELIVERED',
        userVisibleStatusLabel: 'Order delivered',
      },
    },
    reason: 'Order status updated to delivered.',
});

// Set up the PATCH request header and body,
// including the authorized token and order update.
let options = {
  method: 'PATCH',
  uri: `https://actions.googleapis.com/v3/orders/${orderId}`,
  auth: {
    bearer: tokens.access_token,
  },
  body: {
    header: {
      isInSandbox: true,
    },
    orderUpdate,
  },
  json: true,
};

// Send the PATCH request to the Orders API.
try {
  await request(options);
} catch (e) {
  console.log(`Error: ${e}`);
}
購入ステータスを設定する

注文更新の status には、注文の現在の状態を記述する必要があります。アップデートの order.purchase.status フィールドで、次のいずれかの値を使用します。

  • CREATED - ユーザーが注文を承諾しています。アクションからみると、バックエンドで手動処理が必要な状態です。
  • CONFIRMED - 注文は有効で、納品へ向け処理中です。
  • IN_PREPARATION - 注文の発送または配達の準備中(料理の調理や商品の梱包など)。
  • READY_FOR_PICKUP - 注文を受け取る準備ができています。
  • DELIVERED - 受取人への配達が完了しました。
  • OUT_OF_STOCK - 注文の 1 つ以上の商品が在庫切れです。
  • CHANGE_REQUESTED - ユーザーが注文の変更をリクエストし、変更の処理中です。
  • RETURNED - 配送後にユーザーから返品されました。
  • REJECTED - 注文を処理または請求できない場合。あるいは、注文を有効にできない場合。
  • CANCELLED - ユーザーが注文をキャンセルしました。

取引に関連する各ステータスについて、注文の更新情報を送信する必要があります。たとえば、トランザクションで注文後に注文を記録するために手動処理が必要な場合は、その追加処理が完了するまで CREATED 注文更新を送信します。すべての注文でステータス値が必要になるとは限りません。

プロジェクトをテストする

プロジェクトをテストするときは、Actions Console でサンドボックス モードを有効にして、お支払い方法を請求せずにアクションをテストできます。サンドボックス モードを有効にする手順は次のとおりです。

  1. Actions Console で、ナビゲーションの [Test] をクリックします。
  2. [設定] をクリックします。
  3. [開発サンドボックス] オプションを有効にします。

現物取引の場合は、サンプルで isInSandbox フィールドを true に設定することもできます。この操作は、Actions Console でサンドボックス モードの設定を有効にすることと同じです。isInSandbox を使用するコード スニペットを確認するには、注文の更新を送信するをご覧ください。

トラブルシューティング

テスト中に問題が発生した場合は、取引に関するトラブルシューティングの手順をご覧ください。