對話動作將於 2023 年 6 月 13 日淘汰。詳情請參閱對話動作停用

使用 Google Pay 建立實體交易

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

本指南將逐步引導您完成動作專案,該程序包含實體商品的交易,並使用 Google Pay 付款。

交易流程

當動作專案使用商家管理的付款處理實體交易時,會使用以下流程:

  1. 收集資訊 (選填) - 視交易性質而定,您可能會想在對話開始時向使用者收集下列資訊:
    1. 驗證交易需求:在對話開始時,驗證使用者是否符合交易處理條件,例如在設定購物車前正確設定付款資訊及提供使用。
    2. 要求寄送地址 - 如果交易需要一個寄送地址,請向使用者收集這個地址。
  2. 建構訂單:引導使用者完成「購物車組件」,在當中選擇要購買的商品。
  3. 建議訂單 - 完成購物車後,請向使用者建議訂單,以便確認訂單是否正確。確認訂單後,您會收到內含訂單詳細資料和付款權杖的回應。
  4. 完成訂單並傳送收據:確認訂單後,請更新庫存追蹤或其他出貨服務,然後將收據傳送給使用者。
  5. 傳送訂單更新 - 在訂單履行的效期內,將 PATCH 要求傳送至 Orders API,以提供使用者訂單更新。

限制和審查規範

請注意,包含交易的其他政策均適用。我們最多需要六週的時間來檢視含有交易的動作,因此在規劃發布時間表時,請將這段時間納入考量。為了簡化審查程序,請先確認您遵守交易政策和規範,再將動作送交審查。

您只能在下列國家/地區中部署販售實體商品的動作:

澳洲
巴西
加拿大
印尼
日本
墨西哥
俄羅斯
新加坡
泰國
土耳其
英國
美國

建置您的專案

如需交易對話的完整範例,請參閱 Node.js 交易範例

設定

建立動作時,您必須在動作主控台中指定您要執行交易。

設定專案和執行要求的方式如下:

  1. 建立新專案或匯入現有專案。
  2. 前往 [部署] > [目錄資訊]。
  3. 在「其他資訊 > 交易」下方,勾選「您的動作是否使用交易 API 執行實體商品的交易?」方塊。

1. 收集資訊 (選填)

1a. 驗證交易要求 (選填)

使用者表示有意購買時,請進行檢查以確保使用者能夠進行交易。例如,進行動作時,您的動作可能會詢問:「您要訂購鞋子,還是查看帳戶餘額?」如果使用者說出「訂購鞋款」,您必須確保他們能夠繼續並提供可修正任何設定,以免他們繼續完成交易。如要這麼做,請轉換至執行交易需求檢查的場景。

建立交易規定檢查情境
  1. 在「場景」分頁中,新增名為 TransactionRequirementsCheck 的場景。
  2. 在「運算單元填充」下方,按一下 [+] 來新增運算單元。
  3. 在「Select type」(選取類型) 下方,選取 actions.type.TransactionRequirementsCheckResult 做為運算單元類型。
  4. 在運算單元名稱欄位中,為運算單元命名 TransactionRequirementsCheck
  5. 啟用「Customize slot value writeback」(自訂運算單元值寫入) 核取方塊 (預設為啟用)。
  6. 按一下「儲存」

交易條件檢查結果會產生下列其中一種結果:

  • 如果符合條件,則工作階段參數會設定成功條件,而您可以繼續建立使用者訂單。
  • 如果無法滿足一或多項條件,則工作階段參數會設為失敗時。在這種情況下,您應該將對話轉離交易體驗,或是結束對話。
    • 如果造成故障狀態的錯誤可以由使用者修正,系統會提示他們在裝置上解決這些問題。如果在僅限語音的表面上進行對話,系統會啟動使用者的手機。

處理交易需求檢查結果

  1. 在「Scenes」(場景) 分頁中,選取新建立的 TransactionRequirementsCheck 場景。
  2. 在「條件」下方按一下「+」來新增條件。
  3. 在文字欄位中輸入下列條件語法,檢查是否成功:

    scene.slots.status == "FINAL" && session.params.TransactionRequirementsCheck.resultType == "CAN_TRANSACT"
    
  4. 將遊標懸停在您剛剛新增的條件上,然後按一下向上箭頭,將其放在 if scene.slots.status == "FINAL" 之前。

  5. 啟用 [Send 提示] 並提供簡單的提示,告訴使用者他們已準備好進行交易:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                You are ready to purchase physical goods.
    
  6. 在「Transition」底下,選取另一個情境,讓使用者繼續進行對話並繼續交易。

  7. 選取條件 else if scene.slots.status == "FINAL"

  8. 啟用「Send 提示」並提供簡單的提示,讓使用者知道無法進行交易:

    candidates:
      - first_simple:
          variants:
            - speech: Transaction requirements check failed.
    
  9. 在「Transition」(轉換) 下方,選取 [End 對話] 以結束使用者無法進行交易的對話。

索取寄送地址

如果交易需要使用者的寄送地址,您應向使用者要求。這有助於判斷總價、運送/取貨地點,或確保使用者在您的服務範圍內。如要這麼做,請轉換至提示使用者提供地址的場景。

建立寄送地址場景

  1. 在「場景」分頁中,新增名為 DeliveryAddress 的新場景。
  2. 在「運算單元填充」下方,按一下 [+] 來新增運算單元。
  3. 在「Select type」(選取類型) 下方,選取 actions.type.DeliveryAddressValue 做為運算單元類型。
  4. 在運算單元名稱欄位中,為運算單元命名 TransactionDeliveryAddress
  5. 勾選 [自訂版位值寫入] 核取方塊 (預設為啟用)。
  6. 按一下「Save」

設定運算單元時,您可以提供 reason,以在 Google 助理提出要求之前,透過字串取得地址。預設原因字串為「知道要傳送訂單的位置」。因此,Google 助理可能會詢問使用者:「如要瞭解訂單的傳送地點,我需要取得您的寄送地址」。

  • 使用螢幕上的介面時,使用者會選擇想要用於交易的地址。如果他們先前沒有提供地址, 可以輸入新地址。
  • 在僅限語音的平台上,Google 助理會要求使用者授予分享交易預設地址的權限。如果他們先前沒有提供地址,則對話會轉給手機輸入。

如要處理寄送地址結果,請依照下列步驟操作:

  1. 在「場景」分頁中,選取新建立的 DeliveryAddress 場景。
  2. 在「條件」下方按一下「+」來新增條件。
  3. 在文字欄位中輸入下列條件語法,檢查是否成功:

    scene.slots.status == "FINAL" && session.params.TransactionDeliveryAddress.userDecision == "ACCEPTED"
    
  4. 將遊標懸停在您剛剛新增的條件上,然後按一下向上箭頭,將其放在 if scene.slots.status == "FINAL" 之前。

  5. 啟用 [Send 提示] 並提供簡單的提示,讓使用者知道您已經收到他們的地址:

    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. 在「Transition」底下,選取其他情境,讓使用者繼續進行對話。

  7. 選取條件 else if scene.slots.status == "FINAL"

  8. 啟用「Send 提示」並提供簡單的提示,讓使用者知道無法進行交易:

    candidates:
      - first_simple:
          variants:
            - speech: I failed to get your delivery address.
    
  9. 在「Transition」(轉換) 下方,選取 [End 對話] 以結束使用者無法進行交易的對話。

建立訂單

取得所需資訊後,您將建構「購物車組」體驗,引導使用者建立訂單。每個動作的購物車組件會略有不同,適合其產品或服務使用。

最基本的購物車組合功能可讓使用者從清單中挑選要新增至訂單的項目,不過您可以設計對話來簡化使用者體驗。您可以建立購物車組合體驗,讓使用者只需透過一個簡單或沒問題的問題,就能訂購最近購買的品項。您也可以將熱門「精選」或「推薦」項目的輪轉介面或清單資訊卡提供給使用者。

我們建議使用豐富回應,以視覺化方式呈現使用者的選項,同時設計對話,讓使用者可以使用自己的語音建構購物車。如需瞭解高品質購物車組裝的最佳做法與範例,請參閱設計規範

建立一個訂單

在整個對話中,您需要收集使用者想要購買的項目,然後建構 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 物件內容都不同。下表列出各閘道使用的參數:

範例
"parameters": {
  "gateway": "example",
  "gatewayMerchantId": "exampleGatewayMerchantId"
}
ACI
"parameters": {
  "gateway": "aciworldwide",
  "gatewayMerchantId": "YOUR_ENTITY_ID"
}
ADYEN
"parameters": {
  "gateway": "adyen",
  "gatewayMerchantId": "YOUR_MERCHANT_ACCOUNT_NAME"
}
ALFA 銀行
"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"
}
入門
"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"
}
HITRUST
"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_MMS_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"
}
PayTURE
"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"
}
正方形
"parameters": {
  "gateway": "square",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
STRIPE
"parameters": {
  "gateway": "stripe",
  "stripe:version": "2018-10-31",
  "stripe:publishableKey": "YOUR_PUBLIC_STRIPE_KEY"
}
TAPPAY
"parameters": {
  "gateway": "tappay",
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"
}
TunKOFF
"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"
}

在工作階段參數中儲存訂單資料

根據您的出貨要求,將訂單資料儲存至工作階段參數。這個順序物件將用於同一工作階段的情境。

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

建議訂單

建立訂單之後,你必須向使用者顯示該訂單,才能確認或拒絕訂單。 如要這麼做,您必須轉換至執行交易決策的場景。

建立交易決策場景

  1. 在「場景」分頁中,新增名為 TransactionDecision 的新場景。
  2. 在「運算單元填充」下方,按一下 [+] 來新增運算單元。
  3. 在「Select type」(選取類型) 下方,選取 actions.type.TransactionDecisionValue 做為運算單元類型。
  4. 在運算單元名稱欄位中,為運算單元命名 TransactionDecision
  5. 勾選 [自訂版位值寫入] 核取方塊 (預設為啟用)。
  6. 在「Configure slot」(設定版位) 下方的下拉式選單中,選取 [使用工作階段參數]
  7. 在「Configure slot」(設定版位) 下方,在文字欄位中,輸入用於儲存訂單的工作階段參數名稱 (即 $session.params.order)。
  8. 按一下「Save」

為了嘗試填入 TransactionDecisionValue 位置,Google 助理會啟動內建體驗,您傳遞的 Order 會直接顯示在「購物車預覽卡」上。使用者可以說出「下單」、拒絕交易、變更信用卡或地址等付款方式,或要求變更訂單的內容。

此時,使用者也可以要求變更訂單。在這種情況下,您應確保在完成購物車組合體驗後,您的出貨要求可以處理訂單變更要求。

處理交易決策結果

填入 TransactionDecisionValue 運算單元時,使用者對交易決策的答案會儲存在工作階段參數中。這個值包含下列項目:

  • ORDER_ACCEPTED
  • ORDER_REJECTED
  • DELIVERY_ADDRESS_UPDATED
  • CART_CHANGE_REQUESTED
  • USER_CANNOT_TRANSACT

如何處理交易決策結果:

  1. 在「場景」分頁中,選取新建立的 TransactionDecision 場景。
  2. 在「條件」下方按一下「+」來新增條件。
  3. 在文字欄位中輸入下列條件語法,檢查是否成功。

    scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  4. 將遊標懸停在您剛剛新增的條件上,然後按一下向上箭頭,將其放在 if scene.slots.status == "FINAL" 之前。

  5. 啟用「Send 提示」並提供簡單的提示,讓使用者知道訂單已完成:

    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 提示] 並提供簡單的提示,讓使用者知道訂單遭拒:

    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 提示] 並提供簡單的提示,讓使用者知道無法進行交易:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction failed with status
                $session.params.TransactionDecision.transactionDecision
    
  14. 在「Transition」(轉換) 下方,選取 [End 對話] 以結束使用者無法進行交易的對話。

完成訂單並傳送收據

TransactionDecisionValue 運算單元傳回 ORDER_ACCEPTED 的結果時,您必須立即執行確認「確認」訂單所需的任何處理作業 (例如在自己的資料庫中保留該順序並向使用者收費)。

您可以透過此回應結束對話,但是您必須加入簡單的回應,才能讓對話繼續進行。當您提供這個初始 orderUpdate 時,使用者會看到「已收合的收據卡片」以及其他回應。這張資訊卡會反映使用者在訂單記錄中找到的收據。

在訂單確認期間,訂單物件可包含 userVisibleOrderId,也就是使用者看到訂單的 ID。您可以針對這個欄位重複使用 merchantOrderId

部分 OrderUpdate 物件需要包含後續操作物件,該物件會以網址按鈕的形式顯示在使用者 Google 助理訂單記錄中的訂單詳細資料底部。

  • 您至少必須為每筆訂單提供 VIEW_DETAILS 後續動作。當中應包含深層連結,可在您的行動應用程式或網站上顯示訂單。
  • 除了動作對話中的收據卡外,您也必須透過電子郵件傳送正式的收據,並符合所有交易相關法律要求。

如何傳送初始訂單更新:

  1. 在「Scenes」(場景) 分頁中選取您的 TransactionDecision 場景。
  2. 在「Condition」(條件) 之下,選取檢查成功結果的條件 ORDER_ACCEPTED

      scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  3. 啟用 Call Webhook 並提供意圖處理常式名稱,例如 update_order

  4. 在 Webhook 程式碼中,新增可傳送初始訂單更新的意圖處理常式:

    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 PATCH 要求傳送至 Orders API (內含訂單狀態和詳細資料),以傳送使用者訂單更新。

設定向 Orders API 發出的非同步要求

向 Orders API 發出的訂單更新要求將獲得存取權杖的授權。若要向 Orders API 提交訂單更新,請下載與您的 Actions 主控台專案相關聯的 JSON 服務帳戶金鑰,然後為服務帳戶權杖交換可於 HTTP 要求 Authorization 標頭中持有的不記名憑證。

如要擷取您的服務帳戶金鑰,請執行下列步驟:

  1. Google Cloud 控制台中,依序前往 [Menu] 選單 > [API 和服務] > [憑證] > [建立憑證] > [服務帳戶金鑰]。
  2. 在「Service Account」(服務帳戶) 之下選取 [New Service Account] (新增服務帳戶)
  3. 將服務帳戶設為 service-account
  4. 將「Role」(角色) 設為「Project」>「Owner」(擁有者)
  5. 將金鑰類型設為「JSON」
  6. 選取「建立」
  7. 私密 JSON 服務帳戶金鑰會下載到您的本機電腦上。

在訂單更新程式碼中,您可以使用 Google API 用戶端程式庫和 "https://www.googleapis.com/auth/actions.order.developer" 範圍,將服務金鑰交換給不記名憑證。您可以在 API 用戶端程式庫的 GitHub 頁面中找到安裝步驟和範例。

您也可以參考 Node.js 範例中的 order-update.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 - 包含以下項目的物件:
      • 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 - 使用者已取消訂單。

針對與交易相關的每個狀態,您應傳送訂單更新資訊。例如,如果您的交易需要手動處理,以便在下單後記錄訂單,請傳送 CREATED 訂單更新,直到完成額外的處理作業為止。並非所有訂單都需要每個狀態值。

測試專案

測試專案時,您可以在動作主控台中啟用沙箱模式,以便測試動作而不收費。如要啟用沙箱模式,請按照下列步驟操作:

  1. 在動作控制台中,按一下導覽中的 [測試]
  2. 按一下「設定」。
  3. 啟用 [Development Sandbox] 選項。

對於實體交易,您也可以在範例中將 isInSandbox 欄位設定為 true。這個動作相當於在「動作」控制台中啟用沙箱模式設定。如要查看使用 isInSandbox 的程式碼片段,請參閱傳送訂單更新一節。

疑難排解

如果您在測試期間遇到任何問題,請參閱交易的疑難排解步驟