使用 Google Pay 建立实体交易

本指南将逐步介绍如何开发 Actions 项目 包含实体商品交易并使用 Google Pay 进行付款。

交易流程

当您的 Actions 项目使用商家管理的付款功能处理实际交易时, 采用以下流程:

  1. 收集信息(可选)- 根据您网站的性质, 您可能需要在一开始就向用户收集以下信息 对话内容: <ph type="x-smartling-placeholder">
      </ph>
    1. 验证交易要求 - 在对话开始时, 验证用户是否满足进行交易的要求,例如 之前已正确配置和提供付款信息 构建购物车
    2. 请求配送地址 - 如果交易要求配送 向用户收集一个地址
  2. 建立订单 - 引导用户完成 "购物车组装"在这里,用户选择想要购买的商品
  3. 提议订单 - 购物车完成后,向 用户,以便他们确认其正确无误。订单得到确认后,您可以 收到包含订单详情和付款令牌的响应。
  4. 敲定订单并发送收据 - 订单已确认后,更新 库存跟踪或其他履单服务,然后发送收据 。
  5. 发送订单更新 - 在履单的整个有效期内, 通过向订单发送 PATCH 请求,向用户提供订单更新 API。

限制和查看指南

请注意,其他政策适用于涉及交易的操作。它 我们最多可能需要 6 周时间来审核涉及交易的操作数,因此 然后再安排发布时间表为了简化审核流程 请务必遵守 交易政策和准则 然后再提交 Action 以供审核。

您只能在以下国家/地区部署销售实体商品的 Action:

澳大利亚
巴西
加拿大
印度尼西亚
日本
墨西哥
俄罗斯
新加坡
泰国
土耳其
英国
美国

构建您的项目

如需查看事务性对话的详尽示例,请参阅 Node.js 事务 示例

设置

创建 Action 时,你必须指定要执行交易 在 Actions 控制台中操作。

如需设置项目和执行方式,请执行以下操作:

  1. 创建新项目或导入现有项目。
  2. 导航到部署 >目录信息
  3. 其他信息 >交易 >选中 使用 Transaction API 执行实体商品的交易?”。

1. 收集信息(可选)

1a. 验证交易要求(可选)

用户一表明想购买就行了 您应检查以确保他们能够执行交易。 例如,调用该 Action 后,你的 Action 可能会询问“你想要订购鞋子吗? 或查看您的账号余额?”如果用户说“订购鞋子”,您应确保他们 可以继续操作,并让他们有机会修正导致其无法运行的设置 继续交易为此,您应该改用 用于执行事务要求检查的场景。

创建交易要求检查场景
  1. 在“Scenes”(场景)标签页中,添加一个名为 TransactionRequirementsCheck 的新场景。
  2. 槽填充下,点击 + 以添加新槽。
  3. 选择类型下,选择 actions.type.TransactionRequirementsCheckResult 作为广告位类型
  4. 在槽名称字段中,将槽命名为 TransactionRequirementsCheck
  5. 选中自定义槽值回写复选框(默认处于启用状态)。
  6. 点击保存

事务要求检查会产生以下结果之一:

  • 如果满足这些要求,系统就会成功设置会话参数 您可以继续构建用户订单。
  • 如果无法满足一项或多项要求,系统就会设置会话参数 并带有失败条件在这种情况下, 或结束对话。
    • 如果用户可以更正导致失败状态的任何错误, 系统会提示他们在设备上解决这些问题。如果 对话是在纯语音平台上进行, 。

处理交易要求检查结果

  1. Scenes 标签页中,选择您新创建的场景 TransactionRequirementsCheck 个场景。
  2. 条件下,点击 + 以添加新条件。
  3. 在文本字段中,输入以下条件语法,以检查 成功条件:

    scene.slots.status == "FINAL" && session.params.TransactionRequirementsCheck.resultType == "CAN_TRANSACT"
    
  4. 将光标悬停在您刚刚添加的条件上,然后点击向上箭头 并将其放置在 if scene.slots.status == "FINAL" 之前。

  5. 启用 Send prompts,并提供简单的提示让用户知道 他们已准备好进行交易:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                You are ready to purchase physical goods.
    
  6. 过渡下选择其他场景,以便用户继续 并继续进行交易。

  7. 选择条件 else if scene.slots.status == "FINAL"

  8. 启用 Send prompts,并提供简单的提示让用户知道 他们无法进行交易:

    candidates:
      - first_simple:
          variants:
            - speech: Transaction requirements check failed.
    
  9. Transition(转换)下,选择结束对话以结束对话 用户无法进行交易。

申请配送地址

如果您的交易需要用户的送货地址,您应发出请求 。这项信息可能有助于确定总价 送货/自提位置,或用于确保用户在您的服务区域内。 为此,您应该过渡到一个提示用户做出回答的场景 送货地址。

创建配送地址场景

  1. Scenes 标签页中,添加一个名为 DeliveryAddress 的新场景。
  2. 槽填充下,点击 + 以添加新槽。
  3. 选择类型下,选择 actions.type.DeliveryAddressValue 作为槽类型。
  4. 在槽名称字段中,将槽命名为 TransactionDeliveryAddress
  5. 选中自定义槽值回写复选框(默认处于启用状态)。
  6. 点击保存

在配置槽时,您可以提供一个 reason,以便执行以下操作: 用于获取带有字符串的地址。默认 原因字符串是“知道将订单发送到哪里”。因此,Google 助理 系统可能会询问用户:“我需要先知道你的送货地址,才能知道把订单发送到哪里”。

  • 在带有屏幕的界面上,用户需要选择要使用的地址 。如果他们之前没有提供地址 以便输入新地址
  • 在纯语音界面上,Google 助理会请求用户授予以下权限: 分享交易的默认地址。如果他们之前未 您给出一个地址后,系统就会将相应对话转交给手机以供他人进入。

如需处理配送地址结果,请按以下步骤操作:

  1. Scenes 标签页中,选择您新创建的 DeliveryAddress 场景。
  2. 条件下,点击 + 以添加新条件。
  3. 在文本字段中,输入以下条件语法,以检查 成功条件:

    scene.slots.status == "FINAL" && session.params.TransactionDeliveryAddress.userDecision == "ACCEPTED"
    
  4. 将光标悬停在您刚刚添加的条件上,然后点击向上箭头 并将其放置在 if scene.slots.status == "FINAL" 之前。

  5. 启用 Send prompts,并提供一条简单提示让用户 知道您收到了他们的地址:

    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. 过渡下,选择其他场景,以便用户继续操作 对话。

  7. 选择条件 else if scene.slots.status == "FINAL"

  8. 启用 Send prompts,并提供简单的提示让用户知道 他们无法进行交易:

    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 对象将包含标记化参数,这些参数将 根据您计划使用的 Google Pay 处理方而发生变化 (例如 Stripe、Braintree 和 ACI 等)。

const paymentParamenters = {
      'googlePaymentOption': {
        // facilitationSpec is expected to be a serialized JSON string
        'facilitationSpec': JSON.stringify({
          'apiVersion': 2,
          'apiVersionMinor': 0,
          'merchantInfo': {
            'merchantName': 'Example Merchant',
          },
          'allowedPaymentMethods': [
            {
              'type': 'CARD',
              'parameters': {
                'allowedAuthMethods': ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
                'allowedCardNetworks': [
                  'AMEX', 'DISCOVER', 'JCB', 'MASTERCARD', 'VISA'],
              },
              'tokenizationSpecification': {
                'type': 'PAYMENT_GATEWAY',
                'parameters': {
                  'gateway': 'example',
                  'gatewayMerchantId': 'exampleGatewayMerchantId',
                },
              },
            },
          ],
          'transactionInfo': {
            'totalPriceStatus': 'FINAL',
            'totalPrice': '15.77',
            'currencyCode': 'USD',
          },
        }),
      },
    };

tokenizationSpecification 对象的内容各不相同 支付网关。下表显示了每个网关使用的参数:

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
示例
"parameters": {
  "gateway": "example",
  "gatewayMerchantId": "exampleGatewayMerchantId"
}
ACI
"parameters": {
  "gateway": "aciworldwide",
  "gatewayMerchantId": "YOUR_ENTITY_ID"
}
ADYEN
"parameters": {
  "gateway": "adyen",
  "gatewayMerchantId": "YOUR_MERCHANT_ACCOUNT_NAME"
}
ALFA-BANK
"parameters": {
  "gateway": "alfabank",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
BLUE_MEDIA
"parameters": {
  "gateway": "bluemedia",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
BLUESNAP
"parameters": {
  "gateway": "bluesnap",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
BRAINTREE
"parameters": {
  "gateway": "braintree",
  "braintree:apiVersion": "v1",
  "braintree:sdkVersion": braintree.client.VERSION,
  "braintree:merchantId": "YOUR_BRAINTREE_MERCHANT_ID",
  "braintree:clientKey": "YOUR_BRAINTREE_TOKENIZATION_KEY"
}
CHASE_PAYMENTECH
"parameters": {
  "gateway": "chase",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ACCOUNT_NUMBER"
}
结账
"parameters": {
  "gateway": "checkoutltd",
  "gatewayMerchantId": "YOUR_PUBLIC_KEY"
}
CLOUDPAYMENTS
"parameters": {
  "gateway": "cloudpayments",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
网络来源
"parameters": {
  "gateway": "cybersource",
  "gatewayMerchantId": "YOUR_MERCHANT_ID"
}
DataTRANS
"parameters": {
  "gateway": "datatrans",
  "gatewayMerchantId": "YOUR_MERCHANT_ID"
}
EBANX
"parameters": {
  "gateway": "ebanx",
  "gatewayMerchantId": "YOUR_PUBLIC_INTEGRATION_KEY"
}
FIRST_DATA
"parameters": {
  "gateway": "firstdata",
  "gatewayMerchantId": "YOUR_MERCHANT_ID"
}
GLOBAL_PAYMENTS
"parameters": {
  "gateway": "globalpayments",
  "gatewayMerchantId": "YOUR_MERCHANT_ID"
}
GOPAY
"parameters": {
  "gateway": "gopay",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
命中
"parameters": {
  "gateway": "hitrustpay",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
解题方法
"parameters": {
  "gateway": "imsolutions",
  "gatewayMerchantId": "YOUR_MERCHANT_ID"
}
LYRA
"parameters": {
  "gateway": "lyra",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
MPGS
"parameters": {
  "gateway": "mpgs",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
MONEY_MAIL_RU
"parameters": {
  "gateway": "moneymailru",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
NEWEBPAY
"parameters": {
  "gateway": "newebpay",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
NEXI
"parameters": {
  "gateway": "nexi",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
NMI
"parameters": {
  "gateway": "creditcall",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
PAYSAFE
"parameters": {
  "gateway": "paysafe",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
收益
"parameters": {
  "gateway": "payture",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
付费用户 (PAYU)
"parameters": {
  "gateway": "payu",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
PRZELEWY24
"parameters": {
  "gateway": "przelewy24",
  "gatewayMerchantId": "YOUR_MERCHANT_ID"
}
RBKMONEY
"parameters": {
  "gateway": "rbkmoney",
  "gatewayMerchantId": "YOUR_MERCHANT_ID"
}
SBERBANK
"parameters": {
  "gateway": "sberbank",
  "gatewayMerchantId": "YOUR_ORGANIZATION_NAME"
}
Square
"parameters": {
  "gateway": "square",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
条纹
"parameters": {
  "gateway": "stripe",
  "stripe:version": "2018-10-31",
  "stripe:publishableKey": "YOUR_PUBLIC_STRIPE_KEY"
}
TAPPAY
"parameters": {
  "gateway": "tappay",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
TINKOFF
"parameters": {
  "gateway": "tinkoff",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
UNITELLER
"parameters": {
  "gateway": "uniteller",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
VANTIV
"parameters": {
  "gateway": "vantiv",
  "vantiv:merchantPayPageId": "YOUR_PAY_PAGE_ID",
  "vantiv:merchantOrderId": "YOUR_ORDER_ID",
  "vantiv:merchantTransactionId": "YOUR_TRANSACTION_ID",
  "vantiv:merchantReportGroup": "*web"
}
WORLDPAY
"parameters": {
  "gateway": "worldpay",
  "gatewayMerchantId": "YOUR_WORLDPAY_MERCHANT_ID"
}
YANDEX
"parameters": {
  "gateway": "yandexcheckout",
  "gatewayMerchantId": "YOUR_SHOP_ID"
}

在会话参数中保存订单数据

在 fulfillment 中,将订单数据保存到会话参数中。顺序 对象将用于同一会话的各个场景。

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

提议订单

创建订单后,您必须将其呈现给用户以确认或拒绝。 为此,您应该过渡到执行交易决策的场景。

创建交易决策场景

  1. Scenes 标签页中,添加一个名为 TransactionDecision 的新场景。
  2. 槽填充下,点击 + 以添加新槽。
  3. 选择类型下,选择 actions.type.TransactionDecisionValue 作为 广告位类型。
  4. 在槽名称字段中,将槽命名为 TransactionDecision
  5. 选中自定义槽值回写复选框(默认处于启用状态)。
  6. 配置槽下,从下拉菜单中选择使用会话参数
  7. 配置槽下,输入所用会话参数的名称 将订单存储到文本字段中(即 $session.params.order)。
  8. 点击保存

为了尝试填充 TransactionDecisionValue 槽,Google 助理启动 一种内置体验,您传递的 Order 会直接渲染到 “购物车预览卡片”用户可以说“下单”、拒绝交易 更改付款选项(如信用卡或地址),或申请 订单的内容

此时,用户也可以请求更改订单。在这种情况下, 应确保您的履单可以处理 完成购物车组装体验

处理交易决策结果

TransactionDecisionValue 槽被填充时,系统会针对 交易决策将存储在一个会话参数中。该值包含 以下:

  • ORDER_ACCEPTED
  • ORDER_REJECTED
  • DELIVERY_ADDRESS_UPDATED
  • CART_CHANGE_REQUESTED
  • USER_CANNOT_TRANSACT

如需处理事务决策结果,请执行以下操作:

  1. Scenes 标签页中,选择您新创建的 TransactionDecision 场景。
  2. 条件下,点击 + 以添加新条件。
  3. 在文本字段中,输入以下条件语法以检查成功条件:

    scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  4. 将光标悬停在您刚刚添加的条件上,然后点击向上箭头 并将其放置在 if scene.slots.status == "FINAL" 之前。

  5. 启用 Send prompts,并提供简单的提示让用户知道 订单已完成:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction completed! Your order
                $session.params.TransactionDecision.order.merchantOrderId is all
                set!
    
  6. 转换下,选择结束对话以结束对话。

  7. 条件下,点击 + 以添加新条件。

  8. 在文本字段中,输入以下条件语法,以检查 失败的情况:

      scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_REJECTED"
    
  9. 将光标悬停在您刚刚添加的条件上,然后点击向上箭头 并将其放置在 if scene.slots.status == "FINAL" 之前。

  10. 启用 Send prompts,并提供简单的提示让用户知道 订单遭拒:

    candidates:
      - first_simple:
          variants:
            - speech: Look like you don't want to order anything. Goodbye.
    
  11. 转换下,选择结束对话以结束对话。

  12. 选择条件 else if scene.slots.status == "FINAL"

  13. 启用 Send prompts,并提供一条简单提示让用户 知道自己无法进行交易:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction failed with status
                $session.params.TransactionDecision.transactionDecision
    
  14. 转换下,选择结束对话以结束对话 如果用户无法进行交易。

完成订单并发送收据

TransactionDecisionValue 槽返回 ORDER_ACCEPTED 的结果时, 您必须立即执行任何所需的处理来“确认”该 顺序(例如将其保留在您自己的数据库中并向用户收费)。

您可以使用此回复结束对话,但必须包含一个简单的 让对话继续下去。提供这个初始 orderUpdate,用户将看到“收起收据卡片”以及其余的 。此卡片将反映用户在其 订单历史记录。

在订单确认期间,您的订单对象可包含 userVisibleOrderId、 即用户看到的订单的 ID您可以重复使用 此字段的 merchantOrderId

OrderUpdate 对象的一部分将需要包含一个后续操作对象, 订单详情底部的网址按钮 可在其 Google 助理订单记录中找到

  • 您必须至少提供 VIEW_DETAILS 针对每笔订单采取后续行动。其中应包含指向 表示您的移动应用或网站上的订单。
  • 此外,您还必须通过电子邮件发送符合所有法律法规的正式收据, 除收据卡外,对进行交易所需满足的要求 。

要发送初始订单更新,请执行以下操作:

  1. Scenes 标签页中,选择您的 TransactionDecision 场景。
  2. 条件下,选择用于检查成功结果的条件。 ORDER_ACCEPTED:

      scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  3. 对于此条件,请启用 Call your webhook, 并提供 intent 处理程序名称,例如 update_order

  4. 在网络钩子代码中,添加一个用于发送初始订单的 intent 处理程序 更新:

    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 来发送用户订单更新 向 Orders API 发出的 PATCH 请求,其中包含订单状态和详情。

设置向 Orders API 发出的异步请求

对 Orders API 的订单更新请求已获得访问权限授权 令牌。如需 PATCH 对 Orders API 的订单更新,请下载 JSON 与您的 Actions 控制台项目关联的服务账号密钥,然后交换 不记名令牌的服务账号密钥,该令牌可以传递到 Authorization 标头。

如需检索您的服务账号密钥,请执行以下步骤:

  1. Google Cloud 控制台中,执行以下操作: 转到菜单 ☰ >API 和服务 >凭据 >创建凭据 >服务账号密钥
  2. 服务账号下,选择新的服务账号
  3. 将服务账号设置为 service-account
  4. 角色设置为项目 >所有者
  5. 将密钥类型设置为 JSON
  6. 选择创建
  7. 系统会将一个专用 JSON 服务账号密钥下载到您的本地机器。

在订单更新代码中,您可以将服务密钥换成不记名令牌 使用 Google API 客户端库 &quot;https://www.googleapis.com/auth/actions.order.developer&quot; 作用域。您可以 有关 API 客户端库的安装步骤和示例 GitHub 页面

您还可以在我们的order-update.js Node.js 示例 获取密钥交换示例。

发送订单更新

在用您的服务账号密钥交换 OAuth 不记名令牌之后, 可以将订单更新作为已获授权的 PATCH 请求发送到 Orders API。

Orders API 网址 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 - 包含以下内容的对象: <ph type="x-smartling-placeholder">
        </ph>
      • status - 订单的状态,显示为 PurchaseStatus。 例如“SHIPPED”或“DELIVERED”。
      • userVisibleStatusLabel - 面向用户的标签,用于提供 订单状态,如“您的订单已发货,且处于 方式”。
  • userNotification(选填)- userNotification 对象。注意事项 添加此对象并不能保证 用户的设备

以下示例代码显示了一个示例 OrderUpdate,它会更新 DELIVERED 的订单状态:

// 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 - 订单中的一件或多件商品缺货。
  • CHANGE_REQUESTED - 用户请求更改订单,但更改已 处理中。
  • RETURNED - 商品送达后,用户已发生退货。
  • REJECTED - 如果您无法处理、扣款或其他操作 “启用”订单。
  • CANCELLED - 用户取消了订单。

对于与您的 Google 广告相关的每种状态, 交易。例如,如果您的交易需要人工处理 记录订单,发送 CREATED 订单更新,直到 系统会完成额外的处理并非每个订单都需要每个状态值。

测试您的项目

测试项目时,你可以在 Actions 控制台中启用沙盒模式 在不向付款方式收取任何费用的情况下测试您的 Action。 如需启用沙盒模式,请按以下步骤操作:

  1. 在 Actions 控制台中,点击导航栏中的 Test
  2. 点击设置
  3. 启用 Development Sandbox 选项。

对于实际交易,您还可以将字段 isInSandbox 设置为 true(位于 您的样本。此操作等同于在 Actions 控制台。如需查看使用 isInSandbox 的代码段,请参阅 发送订单更新部分。

问题排查

如果您在测试期间遇到任何问题,请参阅我们的问题排查步骤