建構保留項目

本指南將逐步引導您開發使用 Orders API 進行預留項目的 Actions 專案。

交易流程

動作專案處理保留項目時,會使用下列流程:

  1. 驗證交易要求 (選用) - 在對話開始時使用交易需求輔助程式,以確保使用者能夠執行交易。
  2. 建立訂單:逐步引導使用者完成「購物車組合」步驟,以便建立保留項目的詳細資料。
  3. 建議訂單 - 完成「購物車」後,請向使用者提出預訂「訂單」,以確認其正確。如果確認預訂,您會收到含有保留項目詳細資料的回應。
  4. 完成訂單並傳送收據:在訂單確認後,更新預訂系統並傳送收據給使用者。
  5. 傳送訂單更新 - 在預留的效期內,將 PATCH 要求傳送至 Orders API,進而掌握使用者保留項目狀態更新。

限制和查看規範

請注意,其他政策適用於使用交易和 Orders API 的動作。我們最多可能需要六週審查交易相關動作,因此在規劃發布時間表時,請將這段時間納入考量。為簡化審查程序,請確保您遵守交易政策與規範,再將動作送審。

您只能在下列國家/地區部署使用 Orders API 的動作:

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

建構您的專案

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

設定

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

如要設定專案和執行要求,請按照以下步驟操作:

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

驗證交易規定 (選用)

一旦使用者表示想要設定保留項目,您就應檢查他們是否可以要求預留。例如,叫用時,您的動作可能會詢問「Would you like to keep a placet?」如果使用者表示「是」,您應確保他們可以繼續操作,並讓使用者有機會修正所有設定,防止他們繼續進行交易。如要這麼做,您應轉換至執行交易需求檢查的場景。

「建立交易要求」檢查場景

  1. 在「Scenes」分頁中,新增名為 TransactionRequirementsCheck 的新場景。
  2. 在「運算單元填充」下方,按一下「+」來新增版位。
  3. 在「Select type」(選取類型) 下方,選取 actions.type.TransactionRequirementsCheckResult 做為運算單元類型。
  4. 在運算單元名稱欄位中,為版位提供名稱 TransactionRequirementsCheck
  5. 勾選「CustomizeSlot 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: >-
                Looks like you're good to go!.
    
  6. 在「Transition」下方選取另一個場景,以便使用者繼續進行對話並繼續進行交易。

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

  8. 啟用「Send 提示」,並透過簡單提示,讓使用者瞭解他們無法完成交易:

    candidates:
      - first_simple:
          variants:
            - speech: Transaction requirements check failed.
    
  9. 如果使用者無法進行交易,請選取「轉換」下方的「結束對話」結束對話。

建立訂單

取得所需的使用者資訊後,請建構「購物車組合」體驗,引導使用者建立保留項目。每個動作的購物車組合流程可能會因服務而異。

在基本的購物車組合體驗中,使用者可從清單中選取選項,並新增至預訂項目,不過您可以設計對話來簡化使用者體驗。例如,建構購物車組合體驗,讓使用者透過簡單的是非題來排定每月預約時間。您也可以向使用者呈現顯示「推薦」預訂項目的輪轉介面或清單資訊卡。

我們建議使用複合式回應以視覺化方式呈現使用者選項,同時設計對話,讓使用者僅使用語音建立購物車。如需購物車組裝體驗的最佳做法和範例,請參閱設計指南

建立一筆訂單

在對話期間,收集使用者的保留項目詳細資料,然後建構 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'
    };

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

透過執行要求,將訂單資料儲存至工作階段參數。訂單物件會用於同一個工作階段的不同場景。

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

提出訂單

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

建立交易決策情境

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

為了嘗試填入 TransactionDecisionValue 位置,Google 助理會啟動內建體驗,而您傳遞的 Order 會直接轉譯至「購物車預覽資訊卡」。使用者可以說出「安排預約」、「拒絕交易」,或要求變更保留項目詳細資料。

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

處理交易決策結果

填補 TransactionDecisionValue 運算單元後,使用者對交易決策的答案會儲存在工作階段參數中。這個值包含以下內容:

  • ORDER_ACCEPTED,
  • ORDER_REJECTED,
  • 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 提示」,並提供簡單的提示,讓使用者知道預留項目已完成:

    candidates:
      - first_simple:
          variants:
            - speech: >-
                Transaction completed! Your reservation
                $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: Looks like you don't want to set up a reservation. 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 的結果時,您必須立即執行為排定預留作業所需的任何處理工作,例如將預留項目保存在您自己的資料庫中。

傳送簡單的回覆,持續對話。使用者會收到「收合的收據卡」和您的回覆。

如要傳送初始訂單更新,請按照下列指示操作:

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

    scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
    
  3. 對於這個條件,請啟用「Call your 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': [
            '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'
      }));
    });
    

傳送訂單最新狀態

預訂狀態在效期內會全程變更。使用 HTTP PATCH 要求,將使用者預訂訂單更新傳送至 Orders API,其中包含訂單狀態和詳細資料。

設定對 Orders API 的非同步要求

系統會透過存取權杖授權向 Orders API 發出訂單更新要求。如要對 Orders API 更新訂單,請下載與 Actions Console 專案相關聯的 JSON 服務帳戶金鑰,然後交換服務帳戶金鑰,取得可傳遞至 HTTP 要求 Authorization 標頭的不記名憑證。

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

  1. Google Cloud 控制台中,依序前往「選單」圖示 ⋮ >「API 和服務」>「憑證」>「建立憑證」>「服務帳戶金鑰」
  2. 在「服務帳戶」下方,選取「新增服務帳戶」
  3. 將服務帳戶設為 service-account
  4. 將「Role」(角色) 設為 [Project] (專案) > [Owner] (擁有者)
  5. 將金鑰類型設為「JSON」
  6. 選取「Create」(建立)
  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 - 要更新的訂單欄位。如要更新保留項目狀態,請將值設為 reservation.status, reservation.userVisibleStatusLabel
  • order:更新的內容。如果您要更新保留項目的內容,請將值設為更新後的 Order 物件。如果您只是更新保留項目的狀態 (例如從 "PENDING""FULFILLED"),物件包含下列欄位:

    • merchantOrderId:您在 Order 物件中設定的 ID。
    • lastUpdateTime:本次更新的時間戳記。
    • purchase - 包含下列項目的物件:
      • status:訂單狀態,為 ReservationStatus,例如「CONFIRMED」或「CANCELLED」。
      • userVisibleStatusLabel - 向使用者顯示的標籤,提供訂單狀態詳細資料,例如「您的預訂已確認」。
  • 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 - 您的動作已「建立」保留項目,但後端需要進行額外的處理。
  • CONFIRMED - 已在您的排程後端確認預訂。
  • CANCELLED - 使用者已取消預訂。
  • FULFILLED - 服務已完成使用者的預訂。
  • CHANGE_REQUESTED:使用者要求變更保留項目,系統正在處理變更。
  • REJECTED - 如果您無法處理或確認保留項目。

針對每個與預訂相關的狀態傳送訂單最新狀態。例如,如果預留項目在要求後需要以手動處理的方式確認保留項目,請傳送 PENDING 訂單更新,直到該額外處理完成為止。並非所有保留項目都需要所有狀態值。

測試專案

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

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

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

疑難排解

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