本指南将逐步介绍如何开发 Actions 项目 使用 Orders API 进行预订。
交易流程
当 Actions 项目处理预留时,它会 采用以下流程:
- 验证交易要求(可选)- 使用交易 需求小助手,确保能 用户能否进行交易。
- 建立订单 - 引导用户完成 "购物车组装"在这里构建预留的详细信息
- 提议订单 -“购物车”页面则提议预订“订单”更改为 以便确认其正确无误。如果预订得到确认 收到包含预留详情的响应
- 敲定订单并发送收据 - 订单已确认后,更新 并向用户发送收据。
- 发送订单更新 - 在预订的整个有效期内, 将 PATCH 请求发送到 Orders API。
限制和查看指南
请注意,使用 和 Orders API。我们最多可能需要 6 周时间来审核 Action 因此在规划发布时间表时,请将这部分时间考虑在内。 为了简化审核流程,请确保您遵守 交易政策和准则 然后再提交 Action 以供审核。
您只能在以下国家/地区部署使用 Orders API 的 Action:
| 澳大利亚 巴西 加拿大 印度尼西亚 | 日本 墨西哥 卡塔尔 俄罗斯 | 新加坡 瑞士 泰国 土耳其 英国 美国 | 
构建您的项目
有关交易对话的详尽示例,请参阅我们的事务处理 Node.js 中的示例。
设置
创建 Action 时,你必须指定要执行交易 在 Actions 控制台中操作。
如需设置项目和执行方式,请执行以下操作:
- 创建新项目或导入现有项目。
- 导航到部署 >目录信息。
- 在其他信息 >交易 >选中 使用 Transaction API 执行实体商品的交易?”。  
验证交易要求(可选)
用户表示想要设置预订后,您应该立即选中 他们能够请求预订例如,在被调用时,您的 Action 可能会 询问:“要预订座位吗?”如果用户说“是”,您应该 确保他们可以继续操作,并给他们机会来修正所有设置 阻止客户继续处理交易为此,您应该 过渡到执行事务要求检查的场景。
创建交易要求检查场景
- 在 Scenes 标签页中,添加一个名为
TransactionRequirementsCheck。
- 在槽填充下,点击 + 以添加新槽。
- 在选择类型下,选择 actions.type.TransactionRequirementsCheckResult作为广告位类型
- 在槽名称字段中,将槽命名为 TransactionRequirementsCheck。
- 选中自定义槽值回写复选框(默认处于启用状态)。
- 点击保存。  
事务要求检查会产生以下结果之一:
- 如果满足这些要求,系统就会成功设置会话参数 您可以继续构建用户订单。
- 如果不能满足一项或多项要求,则会话参数为
带有失败条件的集合。在这种情况下,您应围绕
或结束对话。
- 如果用户可以更正导致失败状态的任何错误, 系统会提示他们在设备上解决这些问题。如果 对话是在纯语音平台上进行的, 向用户的电话发起调用
 
处理交易要求检查结果
- 从 Scenes 标签页中,选择您新创建的场景
TransactionRequirementsCheck个场景。
- 在条件下,点击 + 以添加新条件。
- 在文本字段中,输入以下条件语法,以检查 成功条件: - scene.slots.status == "FINAL" && session.params.TransactionRequirementsCheck.resultType == "CAN_TRANSACT"
- 将光标悬停在您刚刚添加的条件上,然后点击向上箭头 并将其放置在 - if scene.slots.status == "FINAL"之前。
- 启用 Send prompts,并提供简单的提示让用户知道 他们已准备好进行交易: - candidates: - first_simple: variants: - speech: >- Looks like you're good to go!.
- 在过渡下选择其他场景,以便用户继续操作 对话并继续进行交易。  
- 选择条件 - else if scene.slots.status == "FINAL"。
- 启用 Send prompts,并提供简单的提示让用户知道 他们无法进行交易: - candidates: - first_simple: variants: - speech: Transaction requirements check failed.
- 在转换下,选择结束对话以结束对话 如果用户无法进行交易。  
创建订单
获得所需的用户信息后,即可构建“购物车” 组装"引导用户进行预订。每个 Action 的购物车装配流程将视情况略有不同 服务。
在基本的购物车组装体验中,用户从列表中选择要添加的选项 但您可以设计对话来简化 用户体验。例如,打造购物车组装体验, 通过简单的“是”或“非”问题来安排每月预订。 您还可以向用户显示“推荐”的轮播界面或列表卡片 预留。
我们建议使用富响应来 不仅要直观地呈现用户的选项 而且要妥善设计对话 用户只需使用语音即可构建购物车。一些最佳实践和 购物车组装体验示例,请参阅设计准则。
创建一个订单
在整个对话过程中,收集用户的预订详情,然后
构建一个 Order 对象。
您的 Order 必须至少包含以下内容:
- buyerInfo- 购买用户的相关信息。
- transactionMerchant- 协助完成订单的商家的相关信息。
- contents- 列为- lineItems的订单的实际内容。
请参阅 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: 'Dinner reservation',
         description: 'A world of flavors all in one destination.',
         reservation: {
           status: 'PENDING',
           userVisibleStatusLabel: 'Reservation is pending.',
           type: 'RESTAURANT',
           reservationTime: {
             timeIso8601: '2020-01-16T01:30:15.01Z',
           },
           userAcceptableTimeRange: {
             timeIso8601: '2020-01-15/2020-01-17',
           },
           partySize: 6,
           staffFacilitators: [
             {
               name: 'John Smith',
             },
           ],
           location: {
             zipCode: '94086',
             city: 'Sunnyvale',
             postalAddress: {
               regionCode: 'US',
               postalCode: '94086',
               administrativeArea: 'CA',
               locality: 'Sunnyvale',
               addressLines: [
                 '222, Some other Street',
               ],
             },
           },
         },
       },
     ],
   },
   buyerInfo: {
     email: 'janedoe@gmail.com',
     firstName: 'Jane',
     lastName: 'Doe',
     displayName: 'Jane Doe',
   },
   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'
 };
创建顺序和展示选项
const orderOptions = {
      'requestDeliveryAddress': false,
    };
const presentationOptions = {
      'actionDisplayName': 'RESERVE'
    };
在会话参数中保存订单数据
在 fulfillment 中,将订单数据保存到会话参数中。顺序 对象将用于同一会话的各个场景。
conv.session.params.order = {
    '@type': 'type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec',
    order: order,
    orderOptions: orderOptions,
    presentationOptions: presentationOptions
};
提议订单
创建预订订单后,您必须将其呈现给用户 确认或拒绝为此,您应该过渡到执行事务的场景 决策。
创建交易决策场景
- 在 Scenes 标签页中,添加一个名为 TransactionDecision的新场景。
- 在槽填充下,点击 + 以添加新槽。
- 在选择类型下,选择 actions.type.TransactionDecisionValue作为 广告位类型。
- 在槽名称字段中,将槽命名为 TransactionDecision。
- 选中自定义槽值回写复选框(默认处于启用状态)。
- 在配置槽下,从下拉菜单中选择使用会话参数。
- 在配置槽下,输入用于配置槽的会话参数的名称
将订单存储到文本字段中(即 $session.params.order)。
- 点击保存。  
为了尝试填充 TransactionDecisionValue 槽,Google 助理启动
一种内置体验,您传递的 Order 会直接渲染到
“购物车预览卡片”用户可以说“安排预订”、拒绝交易
或请求更改预留详情。
此时,用户也可以请求更改订单。在这种情况下, 应确保您的履单可以处理 完成购物车组装体验
处理交易决策结果
当 TransactionDecisionValue 槽被填充时,系统会针对
交易决策将存储在一个会话参数中。该值包含
以下:
- ORDER_ACCEPTED、
- ORDER_REJECTED、
- CART_CHANGE_REQUESTED
- USER_CANNOT_TRANSACT。
如需处理事务决策结果,请执行以下操作:
- 从 Scenes 标签页中,选择您新创建的 TransactionDecision场景。
- 在条件下,点击 + 以添加新条件。
- 在文本字段中,输入以下条件语法,以检查 成功条件: - scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
- 将光标悬停在您刚刚添加的条件上,然后点击向上箭头 并将其放置在 - if scene.slots.status == "FINAL"之前。
- 启用 Send prompts,并提供简单的提示让用户知道 预订完成时: - candidates: - first_simple: variants: - speech: >- Transaction completed! Your reservation $session.params.TransactionDecision.order.merchantOrderId is all set!
- 在转换下,选择结束对话以结束对话。  
- 在条件下,点击 + 以添加新条件。 
- 在文本字段中,输入以下条件语法,以检查 失败的情况: - scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_REJECTED"
- 将光标悬停在您刚刚添加的条件上,然后点击向上箭头 并将其放置在 - if scene.slots.status == "FINAL"之前。
- 启用 Send prompts,并提供一条简单提示让用户知道 订单已被拒绝: - candidates: - first_simple: variants: - speech: Looks like you don't want to set up a reservation. Goodbye.
- 在转换下,选择结束对话以结束对话。 
- 选择条件 - else if scene.slots.status == "FINAL"。
- 启用 Send prompts,并提供简单的提示让用户知道 他们无法进行交易: - candidates: - first_simple: variants: - speech: >- Transaction failed with status $session.params.TransactionDecision.transactionDecision
- 在转换下,选择结束对话以结束对话 如果用户无法进行交易。  
完成预订并发送收据
当 TransactionDecisionValue 槽返回 ORDER_ACCEPTED 的结果时,
您必须立即执行安排
(例如将其保留在您自己的数据库中)。
发送简单的回复,让对话继续下去。用户会收到 “收起的收据卡片”连同您的回复一起显示
要发送初始订单更新,请执行以下操作:
- 从 Scenes 标签页中,选择您的 TransactionDecision场景。
- 在条件下,选择用于检查成功结果的条件。 - ORDER_ACCEPTED:- scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
- 对于此条件,请启用 Call your webhook, 并提供 intent 处理程序名称,例如 - update_order。 
- 在网络钩子代码中,添加一个用于发送初始订单更新的 intent 处理程序: - app.handle('update_order', conv => { const currentTime = new Date().toISOString(); let order = conv.session.params.TransactionDecision.order; conv.add(new OrderUpdate({ 'updateMask': { 'paths': [ 'reservation.status', 'reservation.user_visible_status_label', 'reservation.confirmation_code' ] }, 'order': { 'merchantOrderId': order.merchantOrderId, 'lastUpdateTime': currentTime, 'reservation': { 'status': 'CONFIRMED', 'userVisibleStatusLabel': 'Reservation confirmed', 'confirmationCode': '123ABCDEFGXYZ', }, }, 'reason': 'Reason string' })); });
发送订单更新
预留状态在其整个生命周期内不断变化。向用户发送 通过发送到 Orders API 的 HTTP PATCH 请求更新预留订单,包括 订单状态和详情
设置向 Orders API 发出的异步请求
对 Orders API 的订单更新请求已获得访问权限授权
令牌。如需 PATCH 对 Orders API 的订单更新,请下载 JSON
与您的 Actions 控制台项目关联的服务账号密钥,然后交换
不记名令牌的服务账号密钥,该令牌可以传递到
Authorization 标头。
如需检索您的服务账号密钥,请执行以下步骤:
- 在 Google Cloud 控制台中,执行以下操作: 转到菜单 ☰ >API 和服务 >凭据 >创建凭据 >服务账号密钥。
- 在服务账号下,选择新的服务账号。
- 将服务账号设置为 service-account。
- 将角色设置为项目 >所有者。
- 将密钥类型设置为 JSON。
- 选择创建。
- 系统会将一个专用 JSON 服务账号密钥下载到您的本地机器。
在订单更新代码中,使用服务密钥换取不记名令牌 使用 Google API 客户端库 "https://www.googleapis.com/auth/actions.order.developer" 作用域。您可以 有关 API 客户端库的安装步骤和示例 GitHub 页面。
在我们的 Node.js 示例中引用 order-update.js
获取密钥交换示例。
发送订单更新
在用您的服务账号密钥交换 OAuth 不记名令牌之后, 订单更新,作为对 Orders API 的授权 PATCH 请求。
Orders API 网址:
PATCH https://actions.googleapis.com/v3/orders/${orderId}
在请求中提供以下标头:
- 将 "Authorization: Bearer token"替换为 OAuth 不记名令牌 您的服务账号密钥。
- "Content-Type: application/json"。
PATCH 请求应采用以下格式的 JSON 正文:
{ "orderUpdate": OrderUpdate }OrderUpdate
对象包含以下顶级字段:
- updateMask- 要更新的订单的字段。要更新 预订状态 将值设置为- reservation.status, reservation.userVisibleStatusLabel。
- order- 更新的内容。如果您要更新 预留的内容,将该值设置为更新后的- Order对象。 如果您只想更新预留的状态(例如,- "PENDING"到- "FULFILLED"),该对象包含 以下字段:- merchantOrderId- 您在- Order对象中设置的 ID。
- lastUpdateTime- 此更新的时间戳。
- purchase- 包含以下内容的对象: <ph type="x-smartling-placeholder">- </ph>
- status- 订单的状态,显示为- ReservationStatus。 例如“- CONFIRMED”或“- CANCELLED”。
- userVisibleStatusLabel- 面向用户的标签,用于提供 订单状态,例如“您的预订已确认”。
 
 
- userNotification(选填)-- userNotification对象。注意事项 添加此对象并不能保证 用户的设备
以下示例代码显示了一个示例 OrderUpdate,它会更新
FULFILLED:
// 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 the ID of the order to update.
const orderId = '<UNIQUE_MERCHANT_ORDER_ID>';
// Declare order update
const orderUpdate = new OrderUpdate({
   updateMask: {
     paths: [
       'contents.lineItems.reservation.status',
       'contents.lineItems.reservation.userVisibleStatusLabel'
     ]
   },
   order: {
     merchantOrderId: orderId, // Specify the ID of the order to update
     lastUpdateTime: new Date().toISOString(),
     contents: {
       lineItems: [
         {
           reservation: {
             status: 'FULFILLED',
             userVisibleStatusLabel: 'Reservation fulfilled',
           },
         }
       ]
     },
   },
   reason: 'Reservation status was updated to fulfilled.',
});
// 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}`);
}
设置预留状态
订单更新的 ReservationStatus
必须说明订单的当前状态。在您的更新的order.ReservationStatus中
字段中,请使用以下某个值:
- PENDING- 预留“已创建”被您的 Action 触发,但需要 进行额外的处理
- CONFIRMED- 此预订已在时间安排后端中确认。
- CANCELLED- 用户取消了预订。
- FULFILLED- 服务完成用户的预订。
- CHANGE_REQUESTED- 用户请求更改预订,则更改 处理中。
- REJECTED- 如果无法处理或其他情况 确认预留。
发送与您商家相关的每个状态的订单更新
预留。例如,如果您的预订需要手动处理
在收到预订后确认预订,发送 PENDING 订单更新,直到
系统会完成额外的处理并非每个预留都需要每个状态值。
测试您的项目
测试项目时,你可以在 Actions 控制台中启用沙盒模式 在不向付款方式收取任何费用的情况下测试您的 Action。 如需启用沙盒模式,请按以下步骤操作:
- 在 Actions 控制台中,点击导航栏中的 Test。
- 点击设置。
- 启用 Development Sandbox 选项。
对于实际交易,您还可以将字段 isInSandbox 设置为 true(位于
您的样本。此操作等同于在
Actions 控制台。如需查看使用 isInSandbox 的代码段,请参阅
发送订单更新部分。
问题排查
如果您在测试期间遇到任何问题,请参阅我们的问题排查步骤 。
