客户提交订餐后,您可以将订单更新消息发送给 以端到端下单服务告知我们相应变更。
以下是发送订单更新的一些常见原因:
- 订单的预计履单时间可供查看或发生了变化。
- 订单状态会发生变化。
- 无法再履行订单。
- 订单中所含菜品的价格已更改。
- 客户可以通过新方式管理订单,例如客户服务 或餐馆电话号码
- 您可以查看订单收据。
接下来的部分将详细介绍如何应对这些不同情况 使用订单更新功能
正在转换订单状态
订单有六种可能的状态。这些状态及其可能的转换 如下图所示:
当客户首次提交订单时,订单的起始状态是
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
状态的订单。
端到端下单服务应该会发放退款,具体取决于您的
取消政策和取消时的付款状态。
您的端到端订餐服务不必支持所有可用状态
和过渡。不过,订单的最终状态必须为 FULFILLED
,
REJECTED
或 CANCELLED
。
提供预计履单时间
您可以向用户提供其订单的预计时间范围
供客户自提(或送货上门)。使用 estimatedFulfillmentTimeIso8601
字段
提供FoodOrderUpdateExtension
的预计时间范围,
客户订购的商品可随时自提或送货上门。
在以下时间发送 estimatedFulfillmentTimeIso8601
:
- 当预计时间可用时,最好按照
CREATED
或CONFIRMED
状态。 - 当预计时间发生变化时,例如更新
订单金额为
IN_TRANSIT
时,准确性会更高。
为了有效管理用户期望,估算时应保守一些, 提供日期和时间范围,而不是固定的日期和时间。您应该 尽量将路况等因素考虑在内。对于 例如,您可以发送下午 12:45(下限)到下午 1:15(上限)的估算值, 已绑定)订单的预计送达时间为下午 1:00。
提供订单管理操作
发送订单更新时,您可以为客户提供帮助资源
它们以 OrderManagementAction
的形式管理订单。在
客户下单,他们可能需要联系您或餐馆
履行订单,从而跟踪进度、进行更改或取消订单。
借助 OrderManagementAction
,客户可以发送电子邮件、致电或链接到
网址。在
OrderManagementAction
,如您发送给
用户。
订单管理操作包括以下几种类型:
CUSTOMER_SERVICE
:为客户提供用于联系客户的操作 服务。对于订单更新,此管理操作类型是必须执行的。EMAIL
:为客户提供一项操作,让其发送电子邮件到所提供的 电子邮件地址。CALL
:为客户提供一项操作,让其拨打所提供的电话号码。VIEW_DETAIL
:为客户提供一项操作以查看其详细信息 订单。
每项订单更新必须至少包含一项订单管理操作。不过,
提供的订单管理操作可能会因订单的状态而异。
例如,当订单处于 CONFIRMED
状态时,CUSTOMER_SERVICE
操作可以指向您的客户服务电话号码。订单状态
更新了 IN_TRANSIT
,CUSTOMER_SERVICE
操作可以指向
履单餐厅的电话号码。
正在发送订单更新
您使用 AsyncOrderUpdateRequestMessage
消息类型发送订单
对端到端订购服务的更新。Google 会返回
AsyncOrderUpdateResponseMessage
。例如,如果您希望
客户其订单有效且被接受,您可以发送
AsyncOrderUpdateRequestMessage
,用于将订单状态更改为 CONFIRMED
标签为 Accepted by restaurant
。
设置订单更新消息
向 Google 发送AsyncOrderUpdateRequestMessage
时,必须包含
订单状态信息(使用 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" } } } ] } } }
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" } } } }
已完成
此示例展示了一个会通知用户的订单更新请求示例 订单已自提或送达:
{ "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" } } } ] } } }
如需查看不同使用情形下订单更新请求的更多示例,请参阅 实现高级订单更新。
生成授权令牌并发送消息
订单更新需要授权令牌,以便端到端订单 服务可以验证消息是否来自您的“订餐端到端”网络服务。
如需为项目实现订单更新,请按以下步骤操作:
- 请按照以下步骤生成授权令牌:
<ph type="x-smartling-placeholder">
- </ph>
- 使用 Google Auth 库从您的服务中读取凭据 账号文件。
- 使用以下 API 范围的请求令牌:
https://www.googleapis.com/auth/actions.fulfillment.conversation
- 使用此令牌向
以下端点:
https://actions.googleapis.com/v2/conversations:send
- 在请求中,将
Content-Type
标头设置为application/json
。
以下示例演示了如何实现订单更新:
Node.js
此代码使用适用于 Node.js 的 Google auth 库。
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 auth 库。
/** * 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 会返回错误。