透過商家管理的付款功能建立實體交易

本指南將逐步說明如何開發動作專案,該專案包含透過網站管理的付款方式交易實體商品的交易。

交易流程

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

  1. 連結使用者帳戶 - 如要讓使用者使用儲存在服務中的付款方式,請使用帳戶連結,以便將他們的 Google 服務與您服務的帳戶建立關聯。
  2. 收集資訊 (選填) - 視交易的性質而定,建議您及早在對話中收集下列資訊:
    1. 驗證交易規定 - 在對話的交易部分,驗證使用者是否符合交易的規定,例如在建立購物車之前設定正確的付款資訊並可以使用。
    2. 要求寄送地址 - 如果交易需要運送地址,請向使用者收集地址。
  3. 建構訂單 - 透過「購物車裝設」引導使用者挑選想要購買的商品。
  4. 提議訂單 - 購物車完成後,請向使用者顯示訂單,讓使用者確認訂單正確無誤。如果訂單已確認,您會收到回應,並附上訂單詳細資料和付款權杖。
  5. 完成訂單並傳送收據:確認訂單後,請更新庫存追蹤或其他出貨服務,然後將收據傳送給使用者。
  6. 傳送訂單更新 - 在訂單執行期間的生命週期內,將 PATCH 要求傳送至 Orders API 讓使用者更新訂單。

限制和審查規範

請注意,「交易相關動作」須遵守其他政策。交易相關操作最多可能需要 6 週才能完成,因此規劃發布時程時,請考量這一點。為簡化審查流程,請務必先遵循交易的政策與規範,再將動作提交審查。

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

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

建構您的專案

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

專案設定

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

如要設定專案和執行要求,請執行下列步驟:

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

如果您使用自己的付款方式向使用者收費,建議將他們的 Google 帳戶連結至自己的服務帳戶,以便擷取、呈現付款方式,並處理儲存在該帳戶中的付款方式。

設計驗證流程的語音使用者介面

檢查使用者是否已通過驗證,並開始帳戶連結流程

  1. Actions Console 中開啟 Actions Builder 專案。
  2. 建立新的場景,開始在動作中連結帳戶:
    1. 按一下「情境」
    2. 按一下「新增」圖示來新增場景。
  3. 在新建立的情境中,按一下「Conditions」(條件) 圖示。
  4. 新增條件,檢查與對話相關聯的使用者是否為已驗證使用者。如果檢查失敗,則動作無法在對話期間連結帳戶,並且應重新提供不需要連結帳戶的功能。
    1. 在「Condition」(條件) 下方的 Enter new expression 欄位中,輸入下列邏輯: user.verificationStatus != "VERIFIED"
    2. 在「轉換」下方,選取不需要帳戶連結的場景,或只能進入訪客模式的進入點。

  1. 按一下「條件」的「新增」圖示
  2. 新增條件,如果使用者沒有相關聯的身分,請觸發帳戶連結流程。
    1. 在「Condition」(條件) 下方的 Enter new expression 欄位中,輸入下列邏輯: user.verificationStatus == "VERIFIED"
    2. 在「轉換」下方選取「帳戶連結」系統情境。
    3. 按一下「儲存」

儲存後,系統會將名為 <SceneName>_AccountLinking 的新帳戶連結系統專案新增至專案。

自訂帳戶連結情境

  1. 在「情境」下方,選取帳戶連結系統情境。
  2. 按一下「傳送提示」,並新增簡短的說明,向使用者說明動作必須存取其身分的原因 (例如「如要儲存偏好設定」)。
  3. 按一下「儲存」

  1. 在「條件」下方,按一下「如果使用者成功完成帳戶連結作業」
  2. 設定當使用者同意連結帳戶時,流程要繼續的方式。例如,呼叫 Webhook 以處理任何必要的自訂商業邏輯,然後切換回來源情境。
  3. 按一下「儲存」

  1. 在「條件」下方,按一下「使用者取消或關閉帳戶連結」
  2. 設定當使用者不同意連結帳戶時,流程應繼續。例如,傳送確認訊息,並重新導向至提供不需要帳戶連結功能的場景。
  3. 按一下「儲存」

  1. 在「條件」下方,按一下「如果發生系統或網路錯誤」
  2. 設定是否因系統或網路錯誤而無法完成帳戶連結流程。例如,傳送確認訊息,並重新導向至提供不需要帳戶連結功能的場景。
  3. 按一下「儲存」

收集資訊 (選填)

驗證交易規定 (選填)

使用者表示願意購買商品後,請檢查並確認使用者是否能進行交易。舉例來說,叫用時,您的操作可能會詢問「您要訂購鞋款,還是查看帳戶餘額?」使用者說出「訂購鞋」後,必須確保他們可以繼續操作,並有機會修正任何無法繼續交易的設定。如要執行此操作,請轉換為執行交易需求檢查的場景。

建立交易規定檢查情境
  1. 在「場景」分頁中,新增名為 TransactionRequirementsCheck 的場景。
  2. 在「運算單元填充」下方,按一下「+」新增版位。
  3. 在「Select type」(選取類型) 下方,選取 actions.type.TransactionRequirementsCheckResult 做為運算單元類型。
  4. 在運算單元名稱欄位中,將運算單元命名為 TransactionRequirementsCheck
  5. 勾選「Customize slot value Copyback」核取方塊 (預設為啟用)。
  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. 勾選「Customize slot value Copyback」核取方塊 (預設為啟用)。
  6. 按一下「儲存」

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

  • 在有螢幕的畫面上,使用者可以選擇用於交易的地址。如果他們之前尚未提供地址,則可輸入新地址。
  • 在僅限語音的介面上,Google 助理會要求使用者提供分享交易的預設地址。如果之前未曾提供地址,則對話會交給手機進行輸入。

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

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

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

  5. 啟用「傳送提示」,並簡單提示使用者確認已收到他們的地址:

    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 物件包含 merchantPaymentOption 欄位,其中說明使用者訂單的付款方式。以下是使用 Visa 信用卡使用付款參數的範例:

const paymentParamenters = {
      'merchantPaymentOption': {
        'defaultMerchantPaymentMethodId': '12345678',
        'managePaymentMethodUrl': 'https://example.com/managePayment',
        'merchantPaymentMethod': [{
          'paymentMethodDisplayInfo': {
            'paymentMethodDisplayName': 'VISA **** 1234',
            'paymentType': 'PAYMENT_CARD'
          },
          'paymentMethodGroup': 'Payment method group',
          'paymentMethodId': '12345678',
          'paymentMethodStatus': {
            'status': 'STATUS_OK',
            'statusMessage': 'Status message'
          }
        }]
      }
    };

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

在執行要求中,將訂單資料儲存至 session 參數。 對於同一個工作階段,系統會在不同場景使用訂單物件。

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. 勾選「Customize slot value Copyback」核取方塊 (預設為啟用)。
  6. 在「設定運算單元」下方的下拉式選單中,選取「使用工作階段參數」
  7. 在「Configure slot」(設定運算單元) 下方,輸入用於儲存訂單的工作階段參數名稱 (即 $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. 啟用「傳送提示」,並張貼簡單的提示,讓使用者知道訂單已完成:

    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. 啟用「傳送提示」,並接收簡單的提示,讓使用者瞭解訂單遭拒:

    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」下方,選取「EndConversation」即可結束對話:如果使用者無法完成交易,請結束對話。

完成訂單並傳送收據

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. 針對這項條件,請啟用「呼叫您的 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 更新訂單,請下載與 Actions Console 專案相關聯的 JSON 服務帳戶金鑰,然後交換服務帳戶金鑰 (該金鑰可傳遞至 HTTP 要求的 Authorization 標頭)。

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

  1. Google Cloud 控制台中,依序前往「選單」圖示 ☰ >「API 和服務」>「憑證」>「建立憑證」>「服務帳戶金鑰」
  2. 在「服務帳戶」下方,選取「新增服務帳戶」
  3. 將服務帳戶設為 service-account
  4. 將「角色」設為「專案」>「擁有者」
  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 - 包含以下項目的物件:
      • statusPurchaseStatus 中的訂單狀態,例如「SHIPPED」或「DELIVERED」。
      • userVisibleStatusLabel:使用者看見的標籤,提供訂單狀態的詳細資料,例如「您的訂單已出貨,已寄出」
  • userNotification (選用) - 傳送更新時,使用者裝置顯示的 userNotification 物件。請注意,加入這個物件並不保證通知會顯示在使用者的裝置上。

下列程式碼範例示範如何將訂單狀態更新為 DELIVEREDOrderUpdate

// 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 訂單更新,直到其他處理作業完成為止。並非所有訂單都需要所有狀態值。

測試專案

測試專案時,您可以在 Actions 主控台啟用沙箱模式來測試動作,無須透過付款方式付費。如要啟用沙箱模式,請按照下列步驟操作:

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

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

疑難排解

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