非同期注文の更新

お客様が注文を送信した後、注文の更新メッセージを注文エンドツーエンド サービスに送信して、変更を通知できます。

注文の更新を送信する一般的な理由は次のとおりです。

  • 注文の納品予定日時が判明した、または変更された。
  • 注文のステータスが変更される。
  • 注文を処理できなくなりました。
  • 注文に含まれるメニューアイテムの価格が変更された。
  • お客様が注文を管理するための新しい方法(カスタマー サポートやレストランの電話番号など)がある。
  • 注文の領収書が表示されます。

以降のセクションでは、注文の更新を使用してこれらのさまざまなシナリオに対処する方法について詳しく説明します。

注文ステータスの移行

注文には、次の 6 つのステータスがあります。これらの状態と可能な遷移を次の図に示します。

注文ステータスの遷移

お客様が初めて注文を送信すると、注文のステータスは CREATEDCONFIRMEDREJECTED から始まります。ステータスの遷移が有効であれば、注文の更新メッセージを送信して注文のステータスを更新できます。CREATED ステータスは、パートナーのプラットフォームが注文をすぐに確認または拒否できない場合に使用されます。ユースケースの一例として、配送アグリゲータを通じてお客様が注文する場合が挙げられます。配達アグリゲータは Google から配達を受け取り、アグリゲータはレストランに情報を送信します。レストランが注文の在庫状況を受け取って確認すると、ステータスは CONFIRMED になります。それ以外の場合は REJECTED になります。

CONFIRMED 状態の注文は、次に IN_PREPARATION 状態に移行します。注文が受け取りか配達かによって、次に READY_FOR_PICKUP または IN_TRANSIT のステータスを使用します。料理が配達または受け取られた場合、注文は FULFILLED 状態に設定されます。

お客様が注文をキャンセルできるようにする場合は、CANCELLED 状態を使用できます。注文は、CREATEDCONFIRMEDIN_PREPARATIONREADY_FOR_PICKUPIN_TRANSIT のいずれかの状態のときにキャンセルできます。注文エンドツーエンド サービスは、キャンセル ポリシーとキャンセル時の支払いの状態に応じて払い戻しを行う必要があります。

注文エンドツーエンド サービスで、利用可能なすべての状態と遷移をサポートする必要はありません。ただし、注文の最終ステータスは FULFILLEDREJECTEDCANCELLED のいずれかにする必要があります。

納品予定日時の提供

注文の受け取り(または配達)が可能な時間帯をお客様に伝えることができます。FoodOrderUpdateExtensionestimatedFulfillmentTimeIso8601 フィールドを使用して、お客様の注文商品が受け取り可能になる、または配送される予定日時を指定します。

estimatedFulfillmentTimeIso8601 は次のタイミングで送信します。

  • 推定所要時間が利用可能になったとき(理想的には、注文のステータスが CREATED または CONFIRMED の場合)。
  • 推定時間が変更された場合(注文が IN_TRANSIT のときに推定時間をより正確に更新する場合など)。

ユーザーの期待に効果的に応えるには、見積もりを控えめにし、固定の日時ではなく日時範囲を提示します。可能であれば、交通状況などの変動を考慮する必要があります。たとえば、配達予定時刻が午後 1 時の場合、午後 12 時 45 分(下限)から午後 1 時 15 分(上限)の見積もり時間を送信できます。

注文管理アクションの提供

注文の更新を送信する際に、OrderManagementAction の形式で、注文の管理に役立つリソースをお客様に提供できます。お客様は注文後、注文の進捗状況の確認、変更、キャンセルのために、お客様ご自身または注文を処理するレストランに問い合わせる必要があります。

OrderManagementAction を使用すると、お客様はデバイスから直接メールを送信したり、電話をかけたり、URL にリンクしたりできます。OrderManagementAction には、ユーザーに送信する注文確認メールと同じ情報を使用します。

注文管理アクションには、次の種類があります。

  • CUSTOMER_SERVICE: カスタマー サービスに問い合わせるアクションをお客様に提供します。この管理アクション タイプは、注文の更新に必須です。
  • EMAIL: 指定されたメールアドレスにメールを送信するアクションをお客様に提供します。
  • CALL: 指定された電話番号に電話をかけるようお客様に伝えます。
  • VIEW_DETAIL: 注文の詳細を表示するアクションをお客様に提供します。

注文の更新には、注文管理アクションを少なくとも 1 つ含める必要があります。ただし、提供される注文管理アクションは、注文のステータスによって異なる場合があります。たとえば、注文のステータスが CONFIRMED の場合、CUSTOMER_SERVICE アクションはカスタマー サービスの電話番号を参照できます。その注文ステータスが IN_TRANSIT に更新されると、CUSTOMER_SERVICE アクションはフルフィルメント レストランの電話番号を参照できます。

注文の更新情報の送信

AsyncOrderUpdateRequestMessage メッセージ タイプを使用して、注文の更新を Ordering End-to-End サービスに送信します。Google は AsyncOrderUpdateResponseMessage で応答します。たとえば、注文が有効で承認されたことをお客様に通知する場合は、AsyncOrderUpdateRequestMessage を送信して、注文のステータスを CONFIRMED に変更し、ラベルを Accepted by restaurant に設定します。

注文の更新図

注文更新メッセージを設定する

Google に AsyncOrderUpdateRequestMessage を送信する場合は、OrderUpdate フィールドを使用して注文のステータスに関する情報を含める必要があります。

次の例は、注文のステータスごとに AsyncOrderUpdateRequestMessage の例を示しています。

CONFIRMED

この例は、注文が確定したことを領収書と配達予定日とともにユーザーに通知する注文更新リクエストのサンプルを示しています。

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "CONFIRMED",
        "label": "Provider confirmed"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime": "2017-07-17T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "2017-07-17T13:00:00Z/2017-07-17T13:30:00Z"
      }
    }
  }
}
    

拒否

この例は、注文が拒否されたことをユーザーに通知する注文更新リクエストのサンプルを示しています。

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "REJECTED",
        "label": "Order rejected"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "rejectionInfo": {
        "type": "UNKNOWN",
        "reason": "Sorry, the restaurant cannot take your order right now."
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
      "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
      "foodOrderErrors": [
        {
        "error": "NO_CAPACITY",
        "description": "Sorry, the restaurant cannot take your order right now."
        }
      ]
      }
    }
  }
}
    

CANCELLED

この例は、注文がキャンセルされたことをキャンセル理由とともにユーザーに通知する注文更新リクエストのサンプルを示しています。

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "CANCELLED",
        "label": "Order cancelled"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "cancellationInfo": {
        "reason": "Customer requested"
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ]
    }
  }
}
    

IN_PREPARATION

この例は、料理が現在準備中であることをユーザーに通知する注文更新リクエストのサンプルを示しています。

{
  "isInSandbox":true,
  "customPushMessage":{
    "orderUpdate":{
      "actionOrderId":"sample_action_order_id",
      "orderState":{
        "state":"IN_PREPARATION",
        "label":"Order is being prepared"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime":"2018-04-15T11:30:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension":{
        "@type":"type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601":"PT20M"
      }
    }
  }
}
    

READY_FOR_PICKUP

この例は、料理が受け取り可能であることをユーザーに通知する注文更新リクエストのサンプルを示しています。

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "READY_FOR_PICKUP",
        "label": "Order is ready for pickup"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime": "2018-04-15T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "PT20M"
      }
    }
  }
}
    

IN_TRANSIT

この例は、注文が配送中であることをユーザーに通知し、配達予定日時を示す注文更新リクエストのサンプルを示しています。

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "IN_TRANSIT",
        "label": "Order is on the way"
      },
      "inTransitInfo": {
        "updatedTime": "2017-07-17T12:00:00Z"
      },
      "updateTime": "2017-07-17T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "PT20M"
      }
    }
  }
}
  

FULFILLED

この例は、注文の集荷または配達をユーザーに通知する注文更新リクエストのサンプルを示しています。

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
      "state": "FULFILLED",
      "label": "Order delivered"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "fulfillmentInfo": {
        "deliveryTime": "2017-05-10T02:30:00.000Z"
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ]
    }
  }
}
    

さまざまなユースケースでの注文更新リクエストの例については、高度な注文更新を実装するをご覧ください。

承認トークンを生成してメッセージを送信する

注文の更新には認証トークンが必要です。これにより、Ordering End-to-End サービスは、メッセージが Ordering End-to-End ウェブサービスから送信されたことを確認できます。

プロジェクトの注文の更新を実装する手順は次のとおりです。

  1. 次の手順で認可トークンを生成します。
    1. Google Auth ライブラリを使用して、サービス アカウント ファイルから認証情報を読み取ります。
    2. 次の API スコープを使用してトークンをリクエストします。https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. このトークンを使用して、次のエンドポイント https://actions.googleapis.com/v2/conversations:send に認証済みの HTTP POST リクエストを送信します。
  3. リクエストの一部として Content-Type ヘッダーを application/json に設定します。

次の例は、注文の更新を実装する方法を示しています。

Node.js

このコードでは、Node.js 用の Google 認証ライブラリを使用しています。

const {auth} = require('google-auth-library')
const request = require('request');
// The service account client secret file downloaded from the Google Cloud Console
const serviceAccountJson = require('./service-account.json')
// order-update.json is a file that contains the payload
const jsonBody = require('./order-update.json')

/**
 * Get the authorization token using a service account.
 */
async function getAuthToken() {
  let client = auth.fromJSON(serviceAccountJson)
  client.scopes = ['https://www.googleapis.com/auth/actions.fulfillment.conversation']
  const tokens = await client.authorize()
  return tokens.access_token;
}

/**
 * Send an order update request
 */
async function sendOrderUpdate() {
  const token = await getAuthToken()
  request.post({
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`
    },
    url: 'https://actions.googleapis.com/v2/conversations:send',
    body: jsonBody,
    json: true
  },
  (err, res, body) => {
    if (err) { return console.log(err); }
    console.log(`Response: ${JSON.stringify(res)}`)
  })
}
    

Python

このコードでは、Python 用の Google Auth ライブラリを使用します。

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
import json

# service-account.json is the service account client secret file downloaded from the
# Google Cloud Console
credentials = service_account.Credentials.from_service_account_file(
    'service-account.json')

scoped_credentials = credentials.with_scopes(
    ['https://www.googleapis.com/auth/actions.fulfillment.conversation'])

authed_session = AuthorizedSession(scoped_credentials)

# order-update.json is a file that contains the payload
json_payload=json.load(open('order-update.json'))

response = authed_session.post(
    'https://actions.googleapis.com/v2/conversations:send',
    json=json_payload)
    

Java

このコードでは、Java 用の Google 認証ライブラリを使用しています。

/**
 * Get the authorization token using a service account.
 */
private static String getAuthToken() {
  InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json");
  ServiceAccountCredentials.Builder credentialsSimpleBuilder =
      ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder();
  credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/actions.fulfillment.conversation"));
  AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken();
  return accessToken.getTokenValue();
}

/**
 * Send an order update request
 */
public void sendOrderUpdate() {
  String authToken = getAuthToken();
  // Execute POST request
  executePostRequest("https://actions.googleapis.com/v2/conversations:send",
      authToken, "update_order_example.json",);
}
    

エラーなく注文の更新が成功した場合、Google は空のペイロードを含む HTTP 200 レスポンスを返します。更新の形式が正しくないなどの問題がある場合は、エラーが返されます。