客戶提交餐點訂單後,您可以將訂單更新訊息傳送給「Google 訂餐」服務通知我們。
以下是傳送訂單更新的常見原因:
- 訂單商品預計出貨時間或變更。
- 訂單的狀態會隨之變更。
- 訂單已履行。
- 訂單中包含的選單項目價格有所變更。
- 客戶可透過新方式管理訂單,例如客戶服務或餐廳電話號碼。
- 訂單收據隨即在線上。
下一節將說明如何透過訂單更新,解決這些不同的情況。
轉換訂單狀態
訂單可能會有六個可能的狀態。這些狀態及其可能的轉換作業如下圖所示:
客戶首次提交訂單時,訂單金額會處於 CREATED
、CONFIRMED
或 REJECTED
的狀態。只要狀態轉換有效,您就可以傳送訂單更新訊息以更新訂單狀態。當合作夥伴的平台無法立即確認或拒絕訂單時,會使用 CREATED
狀態。例如,客戶透過運送匯總器訂購時。放送集結網站會收到 Google 的貨品交付資訊,且集結網站會將資訊傳送給餐廳。餐廳收到並確認訂單供應情形後,狀態可為 CONFIRMED
,否則為 REJECTED
。
CONFIRMED
狀態的訂單會移至 IN_PREPARATION
狀態。視訂單使用的是自取或外送而定,請使用 READY_FOR_PICKUP
或 IN_TRANSIT
狀態。餐點外送或取貨後,訂單會設為 FULFILLED
狀態。
如果您允許客戶取消訂單,則可使用 CANCELLED
狀態。您可以在 CREATED
、CONFIRMED
、IN_PREPARATION
、READY_FOR_PICKUP
或 IN_TRANSIT
狀態中取消訂單。您的「Google 訂單」服務應根據取消政策和取消時的狀態提供退款。
「Google 訂餐」服務可能不支援所有可用狀態和轉換。不過,訂單的最終狀態必須為 FULFILLED
、REJECTED
或 CANCELLED
。
提供預估出貨時間
您可以提供使用者預估可取貨 (或送達) 的預計時間範圍。使用 FoodOrderUpdateExtension
的 estimatedFulfillmentTimeIso8601
欄位,提供客戶訂單自取或外送時間的預估時間。
在下列時間傳送 estimatedFulfillmentTimeIso8601
:
- 如果有預估時間,最好使用
CREATED
或CONFIRMED
狀態。 - 預計時間變更 (例如將預估時間更新為
IN_TRANSIT
時) 以更準確。
為有效管理使用者期望,請謹慎保守預估,並提供日期和時間 (而非固定日期和時間)。您應該盡可能考慮各種因素 (例如路況),舉例來說,假設預估送達時間為下午 1 點,則您可以將預估時間為下午 12 點 45 分至晚上 1 點 15 分。
提供訂單管理動作
傳送訂單更新時,您可以將資源提供給客戶,以 OrderManagementAction
的形式協助客戶管理訂單。客戶下訂單後,他們可能會需要你或餐廳,以便追蹤進度、進行變更或取消訂單。
OrderManagementAction
可讓客戶直接透過裝置傳送電子郵件、通話或連結至網址。請使用傳送至使用者電子郵件確認確認電子郵件中的 OrderManagementAction
相同的資訊。
訂單管理動作包括下列類型:
CUSTOMER_SERVICE
:向客戶提供與客服聯絡的動作。如要更新訂單,必填這個管理動作類型。EMAIL
:為客戶提供操作,將電子郵件傳送至指定的電子郵件地址。CALL
:鼓勵客戶致電你提供的電話號碼。VIEW_DETAIL
:為客戶提供操作,以便查看訂單詳細資料。
每筆訂單更新都必須含有至少一項訂單管理動作。不過,提供的訂單管理動作會因訂單狀態而異。舉例來說,當訂單處於 CONFIRMED
狀態時,CUSTOMER_SERVICE
動作便可以指向您的客戶服務電話號碼。該訂單的狀態更新為 IN_TRANSIT
時,CUSTOMER_SERVICE
動作可以指向出貨餐廳的電話號碼。
正在傳送訂單動態
您可以使用 AsyncOrderUpdateRequestMessage
訊息類型,將訂單更新傳送至「Google 訂餐」服務。Google 會透過 AsyncOrderUpdateResponseMessage
回應。例如,如要告知客戶訂單商品有效且已接受,您可以傳送 AsyncOrderUpdateRequestMessage
將訂單狀態變更為 CONFIRMED
標籤和 Accepted by restaurant
。
設定訂單更新訊息
傳送 AsyncOrderUpdateRequestMessage
至 Google 時,您必須使用 OrderUpdate
欄位加入訂單狀態相關資訊。
以下範例顯示各種訂單狀態的 AsyncOrderUpdateRequestMessage
範例:
已確認
這個範例中的訂單更新要求範例會通知使用者,說明使用者已透過收據確認訂單,以及預計送達時間。
{ "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." } ] } } } }
已取消
這個範例顯示訂單更新要求,告知使用者訂單取消原因。
{ "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" } } } ] } } }
意涵
這個範例顯示訂單更新要求範例,讓使用者知道食物目前正在準備中。
{ "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" } } } }
準備就緒
這個範例顯示訂單更新要求範例,讓使用者知道餐點已可取貨。
{ "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" } } } }
印度
這個範例顯示訂單更新要求,告知使用者訂單商品正在配送,且預計送達時間。
{ "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" } } } }
已完成
以下範例顯示訂單更新要求,通知使用者訂單商品已取貨或送達:
{ "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" } } } ] } } }
如需不同用途的訂單更新要求範例,請參閱實作進階訂單更新。
產生授權權杖並傳送訊息
訂單更新需要授權權杖,以便「透過 Google 訂餐」服務確認訊息來自「Google 訂餐」網路服務。
如要為專案導入訂單更新,請按照下列步驟操作:
- 產生授權權杖的步驟如下:
- 使用 Google 驗證程式庫讀取您的服務帳戶檔案中的憑證。
- 使用以下 API 範圍的要求權杖:
https://www.googleapis.com/auth/actions.fulfillment.conversation
- 使用這個權杖將通過驗證的 HTTP POST 要求傳送至下列端點:
https://actions.googleapis.com/v2/conversations:send
- 將
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 驗證程式庫。
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 回應。如果發生問題 (例如格式不正確),Google 就會傳回錯誤。