本指南將逐步引導您完成 Actions 專案的開發程序 這個 API 會使用 Orders API 預訂項目。
交易流程
當您的 Actions 專案處理預留項目時, 使用下列流程:
- 驗證交易需求條件 (選用):使用交易需求條件輔助程式 開始對話,確保使用者能夠 以執行交易
- 建立訂單:引導使用者逐步完成 「購物車組件」以便建立預訂詳細資料
- 提出訂單:按下「購物車」後已完成,提出預訂「order」到 使用者以便確認資訊正確無誤。如果預訂成功 接收包含預訂詳細資料的回應。
- 完成訂單並傳送收據:訂單確認後,請更新 向預訂系統傳送收據 以便傳達給使用者
- 傳送訂單最新進度:在預訂的效期內, 傳送 PATCH 要求給 Orders API)。
限制和評論規範
請注意,其他政策適用於使用交易和 Orders API 的動作。我們最多需要六週的處理時間,才能審查含有交易的動作,因此在規劃發布時間表時,請務必考量這點。為加快審查程序,將動作送審前,請務必遵守交易相關政策與規範。
您只能在下列國家/地區部署使用 Orders API 的動作:
澳洲 巴西 加拿大 印尼 |
日本 墨西哥 卡達 俄羅斯 |
新加坡 瑞士 泰國 土耳其 英國 美國 |
建構您的專案
如需完整的交易對話範例,請參閱 Node.js 和 Java 的交易範例。
專案設定
建立動作時,您必須指定要執行交易 動作控制台。此外,如果您 方法是使用 Node.JS 用戶端程式庫,將執行要求設定為使用 Orders API 版本。
如要設定專案和執行要求,請按照下列步驟操作:
- 建立新專案或匯入現有專案。
- 瀏覽至「部署」>「部署」目錄資訊:
在「其他資訊」部分查看交易 >勾選「執行動作」方塊 交易 API 來執行實體商品交易?」
如果您使用 Node.JS 用戶端程式庫建構動作的執行要求, 開啟執行要求程式碼,並更新應用程式差異,來設定
ordersv3
標記至true
。以下程式碼片段為範例應用程式 訂單第 3 版宣告。
Node.js
const {dialogflow} = require('actions-on-google'); let app = dialogflow({ clientId, // If using account linking debug: true, ordersv3: true, });
Node.js
const {actionssdk} = require('actions-on-google'); let app = actionssdk({ clientId, // If using account linking debug: true, ordersv3: true, });
1. 驗證交易需求條件 (選用)
使用者體驗
使用者指出想設定預留項目後,建議您立即觸發
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
意圖,確保使用者能
要求訂位例如,在叫用時,您的動作可能會詢問:
「想保留席位嗎?」如果使用者回答:
「是」,您應該立即要求這項意圖。這能確保
他們可以繼續操作,並有機會自行修正任何設定
以防止他們繼續交易
要求交易 結果檢查意圖會產生以下結果:
- 如果符合規定,您的執行要求會收到含有 成功條件,您就能繼續建立使用者的訂單。
如果有一或多項規定不符合條件,出貨作業就會收到 包含失敗條件的意圖在此情況下,請結束對話或 而離開預訂流程
如果使用者能修正錯誤,系統會自動提示他們解決這些問題 在裝置上。正在透過語音操作的介面進行對話 例如智慧型揚聲器
Fulfillment
確保使用者符合
交易規定
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
意圖,其中包含
TransactionRequirementsCheckSpec 物件。
查看規定
查看使用者是否透過用戶端程式庫滿足預訂需求:
conv.ask(new TransactionRequirements());
return getResponseBuilder(request) .add("Placeholder for transaction requirements text") .add(new TransactionRequirements()) .build();
請注意,下列 JSON 會說明 Webhook 回應。
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } } } }
請注意,下列 JSON 會說明 Webhook 回應。
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } ] } ] }
接收規定檢查的結果
Google 助理履行意圖後,會向您的執行要求傳送要求
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
意圖,有結果
。
如要正確處理這項要求,請宣告由
actions_intent_TRANSACTION_REQUIREMENTS_CHECK
事件。觸發這項功能時
在執行要求中處理這項意圖:
const arg = conv.arguments.get('TRANSACTION_REQUIREMENTS_CHECK_RESULT'); if (arg && arg.resultType === 'CAN_TRANSACT') { // Normally take the user through cart building flow conv.ask(`Looks like you're good to go!`); } else { conv.close('Transaction failed.'); }
Argument transactionCheckResult = request .getArgument("TRANSACTION_REQUIREMENTS_CHECK_RESULT"); boolean result = false; if (transactionCheckResult != null) { Map<String, Object> map = transactionCheckResult.getExtension(); if (map != null) { String resultType = (String) map.get("resultType"); result = resultType != null && resultType.equals("CAN_TRANSACT"); } } ResponseBuilder responseBuilder = getResponseBuilder(request); if (result) { responseBuilder.add("Looks like you're good to go! Now say 'confirm transaction'"); } else { responseBuilder.add("Transaction failed"); } return responseBuilder.build();
請注意,以下 JSON 描述的是 Webhook 要求。
{ "responseId": "", "queryResult": { "queryText": "", "action": "", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentText": "", "fulfillmentMessages": [], "outputContexts": [], "intent": { "name": "reservation_transaction_check_complete_df", "displayName": "reservation_transaction_check_complete_df" }, "intentDetectionConfidence": 1, "diagnosticInfo": {}, "languageCode": "" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "isInSandbox": true, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "inputs": [ { "rawInputs": [], "intent": "", "arguments": [ { "extension": { "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult", "resultType": "CAN_TRANSACT" }, "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT" } ] } ], "user": {}, "conversation": {}, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] } }, "session": "" }
請注意,以下 JSON 描述的是 Webhook 要求。
{ "user": {}, "device": {}, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "conversation": {}, "inputs": [ { "rawInputs": [], "intent": "reservation_transaction_check_complete_asdk", "arguments": [ { "extension": { "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult", "resultType": "CAN_TRANSACT" }, "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT" } ] } ], "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] }
2. 建立訂單
使用者體驗
取得需要的使用者資訊後,請建立「購物車」 組合引導使用者完成訂位。每次 動作的購物車組件流程會視其情況而定 課程中也會快速介紹 Memorystore 這是 Google Cloud 的全代管 Redis 服務
採用基本的購物車組件流程時,使用者可從清單中選擇要新增的選項 設計對話內容來簡化 使用者體驗舉例來說,您可以打造購物車組件體驗, 使用者可透過簡單的是非題,排定每月預約。 您也可以向使用者展示「建議」的輪轉介面或清單資訊卡 和預留項目
我們建議您使用 rich 回應,顯示使用者的選項 還要設計對話,讓使用者可以自行建立 進而輕鬆分享生活點滴如需 購物車組裝體驗,請參閱交易設計指南。
Fulfillment
在對話中,收集使用者想要的預訂詳細資料
然後建構 Order
物件
您的 Order
至少必須包含下列項目:
buyerInfo
- 使用者安排預訂作業的相關資訊。transactionMerchant
- 提供服務的商家相關資訊 或預訂連結contents
:預訂項目實際詳細資料,顯示為lineItems
。
請參閱 Order
回應說明文件
建立購物車請注意,您可能需要填寫不同欄位
視預留項目而定
以下程式碼範例顯示完整的預訂訂單,包含選填欄位:
app.intent('build_reservation_df', (conv) => { const now = new Date().toISOString(); const order = { createTime: now, lastUpdateTime: now, merchantOrderId: 'UNIQUE_ORDER_ID', userVisibleOrderId: 'USER_VISIBLE_ORDER_ID', transactionMerchant: { id: 'https://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: 'https://example.com', }, }, { type: 'CALL', title: 'Call us', openUrlAction: { url: 'tel:+16501112222', }, }, { type: 'EMAIL', title: 'Email us', openUrlAction: { url: 'mailto:person@example.com', }, }, ], termsOfServiceUrl: 'https://www.example.com', };
private static OrderV3 createOrder() { // Transaction Merchant MerchantV3 transactionMerchant = new MerchantV3() .setId("http://www.example.com") .setName("Example Merchant"); // Line Item // Reservation Item Extension ReservationItemExtension reservationItemExtension = new ReservationItemExtension() .setStatus("PENDING") .setUserVisibleStatusLabel("Reservation pending.") .setType("RESTAURANT") .setReservationTime(new TimeV3() .setTimeIso8601("2020-01-16T01:30:15.01Z")) .setUserAcceptableTimeRange(new TimeV3() .setTimeIso8601("2020-01-15/2020-01-17")) .setPartySize(6) .setStaffFacilitators(Collections.singletonList(new StaffFacilitator() .setName("John Smith"))) .setLocation(new Location() .setZipCode("94086") .setCity("Sunnyvale") .setPostalAddress(new PostalAddress() .setRegionCode("US") .setPostalCode("94086") .setAdministrativeArea("CA") .setLocality("Sunnyvale") .setAddressLines( Collections.singletonList("222, Some other Street")))); LineItemV3 lineItem = new LineItemV3() .setId("LINE_ITEM_ID") .setName("Dinner reservation") .setDescription("A world of flavors all in one destination.") .setReservation(reservationItemExtension); // Order Contents OrderContents contents = new OrderContents() .setLineItems(Collections.singletonList(lineItem)); // User Info UserInfo buyerInfo = new UserInfo() .setEmail("janedoe@gmail.com") .setFirstName("Jane") .setLastName("Doe") .setDisplayName("Jane Doe"); // Follow up actions Action viewDetails = new Action() .setType("VIEW_DETAILS") .setTitle("View details") .setOpenUrlAction(new OpenUrlAction() .setUrl("https://example.com")); Action call = new Action() .setType("CALL") .setTitle("Call us") .setOpenUrlAction(new OpenUrlAction() .setUrl("tel:+16501112222")); Action email = new Action() .setType("EMAIL") .setTitle("Email us") .setOpenUrlAction(new OpenUrlAction() .setUrl("mailto:person@example.com")); // Terms of service and order note String termsOfServiceUrl = "https://example.com"; String now = Instant.now().toString(); OrderV3 order = new OrderV3() .setCreateTime(now) .setLastUpdateTime(now) .setMerchantOrderId("UNIQUE_ORDER_ID") .setUserVisibleOrderId("UNIQUE_USER_VISIBLE_ORDER_ID") .setTransactionMerchant(transactionMerchant) .setContents(contents) .setBuyerInfo(buyerInfo) .setFollowUpActions(Arrays.asList( viewDetails, call, email )) .setTermsOfServiceUrl(termsOfServiceUrl); return order; }
請注意,下列 JSON 會說明 Webhook 回應。
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_DECISION", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "order": { "createTime": "2019-07-17T18:25:30.182Z", "lastUpdateTime": "2019-07-17T18:25:30.182Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://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": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" }, "orderOptions": { "requestDeliveryAddress": false, "userInfoOptions": { "userInfoProperties": [ "EMAIL" ] } }, "presentationOptions": { "actionDisplayName": "RESERVE" } } } } } }
3. 提出訂單
向使用者顯示您的預訂訂單,讓他們確認:
拒絕。要求 actions.intent.TRANSACTION_DECISION
意圖,並提供您建構的 Order
。
使用者體驗
當您要求 actions.intent.TRANSACTION_DECISION
意圖時,Google 助理
會啟動內建體驗,此操作會啟動 Order
直接顯示在「購物車預覽資訊卡」上使用者可以說「schedule 訂位」
拒絕交易,或是要求變更預訂詳細資料
此時使用者也可以要求變更訂單。在本例中 請確保您的執行要求可以在 完成購物車組裝體驗
Fulfillment
當您要求
actions.intent.TRANSACTION_DECISION
意圖,建立
包含 Order
的 TransactionDecision
和orderOptions
以下程式碼為訂單的 TransactionsDecision
範例:
conv.ask(new TransactionDecision({ orderOptions: { requestDeliveryAddress: 'false', }, presentationOptions: { actionDisplayName: 'RESERVE', }, order: order, }));
// Create order options OrderOptionsV3 orderOptions = new OrderOptionsV3() .setRequestDeliveryAddress(false) .setUserInfoOptions(new UserInfoOptions() .setUserInfoProperties(Collections.singletonList("EMAIL"))); // Create presentation options PresentationOptionsV3 presentationOptions = new PresentationOptionsV3() .setActionDisplayName("RESERVE"); // Ask for transaction decision return getResponseBuilder(request) .add("Placeholder for transaction decision text") .add(new TransactionDecision() .setOrder(order) .setOrderOptions(orderOptions) .setPresentationOptions(presentationOptions) ) .build();
請注意,下列 JSON 會說明 Webhook 回應。
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_DECISION", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "orderOptions": { "requestDeliveryAddress": "false" }, "presentationOptions": { "actionDisplayName": "RESERVE" }, "order": { "createTime": "2019-07-17T18:25:30.184Z", "lastUpdateTime": "2019-07-17T18:25:30.184Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://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": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" } } } } } }
請注意,下列 JSON 會說明 Webhook 回應。
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_DECISION", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "orderOptions": { "requestDeliveryAddress": "false" }, "presentationOptions": { "actionDisplayName": "RESERVE" }, "order": { "createTime": "2019-07-17T18:25:30.057Z", "lastUpdateTime": "2019-07-17T18:25:30.057Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://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": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" } } } ] } ] }
處理使用者的決定
使用者回覆提議的訂單後,您的執行要求就會收到
actions_intent_TRANSACTION_DECISION
意圖,其引數包含
TransactionDecisionValue
。這個值包含下列項目:
transactionDecision
- 使用者對提議提案的決定 順序。可能的值為ORDER_ACCEPTED
、ORDER_REJECTED
、CART_CHANGE_REQUESTED
和USER_CANNOT_TRANSACT
。
如要處理這項要求,請宣告由
actions_intent_TRANSACTION_DECISION
事件。在以下位置處理這項意圖:
您的執行要求:
const arg = conv.arguments.get('TRANSACTION_DECISION_VALUE'); if (arg && arg.transactionDecision === 'ORDER_ACCEPTED') { console.log('order accepted'); const order = arg.order; }
Argument transactionDecisionValue = request .getArgument("TRANSACTION_DECISION_VALUE"); Map<String, Object> extension = null; if (transactionDecisionValue != null) { extension = transactionDecisionValue.getExtension(); } String transactionDecision = null; if (extension != null) { transactionDecision = (String) extension.get("transactionDecision"); } if ((transactionDecision != null && transactionDecision.equals("ORDER_ACCEPTED"))) { OrderV3 order = ((OrderV3) extension.get("order")); }
請注意,以下 JSON 描述的是 Webhook 要求。
{ "responseId": "", "queryResult": { "queryText": "", "action": "", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentText": "", "fulfillmentMessages": [], "outputContexts": [], "intent": { "name": "reservation_get_transaction_decision_df", "displayName": "reservation_get_transaction_decision_df" }, "intentDetectionConfidence": 1, "diagnosticInfo": {}, "languageCode": "" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "isInSandbox": true, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "inputs": [ { "rawInputs": [], "intent": "", "arguments": [] } ], "user": {}, "conversation": {}, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] } }, "session": "" }
請注意,以下 JSON 描述的是 Webhook 要求。
{ "user": {}, "device": {}, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "conversation": {}, "inputs": [ { "rawInputs": [], "intent": "reservation_get_transaction_decision_asdk", "arguments": [] } ], "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] }
4. 完成預訂並傳送收據
actions.intent.TRANSACTION_DECISION
意圖傳回含有
transactionDecision
ORDER_ACCEPTED
,執行任何
處理時間才能排定預留時間 (例如將預留資源保存在
自己的資料庫)。
傳送簡單回應 延續對話使用者收到「收合的收據卡」 以及回應
Fulfillment
// Set lastUpdateTime and update status of reservation order.lastUpdateTime = new Date().toISOString(); order.reservation.status = 'CONFIRMED'; order.reservation.userVisibleStatusLabel = 'Reservation confirmed'; order.reservation.confirmationCode = '123ABCDEFGXYZ'; // Send synchronous order update conv.ask(`Transaction completed! You're all set!`); conv.ask(new OrderUpdate({ type: 'SNAPSHOT', reason: 'Reason string', order: order, }));
ResponseBuilder responseBuilder = getResponseBuilder(request); order.setLastUpdateTime(Instant.now().toString()); // Set reservation status to confirmed and provide confirmation code LineItemV3 lineItem = order.getContents().getLineItems().get(0); ReservationItemExtension reservationItemExtension = lineItem.getReservation(); reservationItemExtension.setStatus("CONFIRMED"); reservationItemExtension.setUserVisibleStatusLabel("Reservation confirmed."); reservationItemExtension.setConfirmationCode("123ABCDEFGXYZ"); lineItem.setReservation(reservationItemExtension); order.getContents().getLineItems().set(0, lineItem); // Order update OrderUpdateV3 orderUpdate = new OrderUpdateV3() .setType("SNAPSHOT") .setReason("Reason string") .setOrder(order); responseBuilder .add("Transaction completed! You're all set! Would you like to do anything else?") .add(new StructuredResponse().setOrderUpdateV3(orderUpdate)); return responseBuilder.build();
請注意,下列 JSON 會說明 Webhook 回應。
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Transaction completed! You're all set!" } }, { "structuredResponse": { "orderUpdateV3": { "type": "SNAPSHOT", "reason": "Reason string", "order": { "merchantOrderId": "UNIQUE_ORDER_ID", "reservation": { "status": "CONFIRMED", "userVisibleStatusLabel": "Reservation confirmed", "confirmationCode": "123ABCDEFGXYZ" }, "lastUpdateTime": "2019-07-17T18:25:30.187Z" } } } } ] } } } }
請注意,下列 JSON 會說明 Webhook 回應。
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Transaction completed! You're all set!" } }, { "structuredResponse": { "orderUpdateV3": { "type": "SNAPSHOT", "reason": "Reason string", "order": { "merchantOrderId": "UNIQUE_ORDER_ID", "reservation": { "status": "CONFIRMED", "userVisibleStatusLabel": "Reservation confirmed", "confirmationCode": "123ABCDEFGXYZ" }, "lastUpdateTime": "2019-07-17T18:25:30.059Z" } } } } ] } } } ] }
5. 傳送訂單最新資訊
預訂狀態會在 使用至今透過 HTTP 傳送使用者預訂訂單的最新狀態 傳送至 Orders API 的 PATCH 要求,內含訂單狀態和詳細資料。
設定對 Orders API 的非同步要求
系統會透過存取權授權給 Orders API 的訂單更新要求
產生下一個符記如要 PATCH 訂單更新並更新至 Orders API,請下載 JSON
與 Actions Console 專案相關聯的服務帳戶金鑰,然後交換
不記名權杖的服務帳戶金鑰,可傳遞至
HTTP 要求的 Authorization
標頭。
如要擷取服務帳戶金鑰,請執行下列步驟:
- 前往 Google Cloud 控制台, 依序輕觸「選單」圖示 ⋮ >。API 與服務 >憑證 >建立憑證 >服務帳戶金鑰。
- 在「服務帳戶」下方,選取「新增服務帳戶」。
- 將服務帳戶設為
service-account
。 - 將角色設定為 專案 >擁有者。
- 將金鑰類型設為「JSON」JSON。
- 選取「建立」。
- 系統會將私人 JSON 服務帳戶金鑰下載至本機電腦。
在訂單中更新代碼,請將服務金鑰換成不記名權杖 使用 Google API 用戶端程式庫和 "https://www.googleapis.com/auth/actions.order.developer" 範圍。您可在此找到安裝步驟 API 用戶端程式庫 GitHub 頁面上的範例。
在 Node.js 和 Java 範例中參照 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
- 包含以下內容的物件:status
- 訂單狀態,格式為ReservationStatus
, 例如「CONFIRMED
」或「CANCELLED
」。userVisibleStatusLabel
- 面向使用者的標籤,提供詳細資料 訂單狀態,例如「您的預訂已確認」。
userNotification
(選用) -userNotification
物件。注意事項 包含此物件並不保證會顯示於 使用者的裝置。
下列程式碼範例顯示會更新 OrderUpdate
預訂訂單向 FULFILLED
的狀態:
// Import the 'googleapis' module for authorizing the request. const {google} = require('googleapis'); // Import the 'request' module for sending an HTTP POST request. const request = require('request'); // Import the OrderUpdate class from the Actions on Google client library. const {OrderUpdate} = require('actions-on-google'); // Import the service account key used to authorize the request. Replace the string path with a path to your service account key. const key = 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( key.client_email, null, key.private_key, ['https://www.googleapis.com/auth/actions.order.developer'], null ); // Authorize the client asynchronously, passing in a callback to run upon authorization. jwtClient.authorize((err, tokens) => { if (err) { console.log(err); return; } // Declare the ID of the order to update. const orderId = '<UNIQUE_MERCHANT_ORDER_ID>'; const orderUpdateJson = new OrderUpdate({ updateMask: [ 'lastUpdateTime', 'contents.lineItems.reservation.status', 'contents.lineItems.reservation.userVisibleStatusLabel', ].join(','), order: { merchantOrderId: orderId, 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. const bearer = 'Bearer ' + tokens.access_token; const options = { method: 'PATCH', url: `https://actions.googleapis.com/v3/orders/${orderId}`, headers: { 'Authorization': bearer, }, body: { header: { 'isInSandbox': true, }, orderUpdate: orderUpdateJson, }, json: true, }; // Send the PATCH request to the Orders API. request.patch(options, (err, httpResponse, body) => { if (err) { console.log('There was an error...'); console.log(err); return; } }); });
// Create order update FieldMask fieldMask = FieldMask.newBuilder().addAllPaths(Arrays.asList( "lastUpdateTime", "contents.lineItems.reservation.status", "contents.lineItems.reservation.userVisibleStatusLabel")) .build(); OrderUpdateV3 orderUpdate = new OrderUpdateV3() .setOrder(new OrderV3() .setMerchantOrderId(orderId) .setLastUpdateTime(Instant.now().toString()) .setContents(new OrderContents() .setLineItems(Collections.singletonList(new LineItemV3() .setReservation(new ReservationItemExtension() .setStatus("FULFILLED") .setUserVisibleStatusLabel("Reservation fulfilled.")))))) .setUpdateMask(FieldMaskUtil.toString(fieldMask)) .setReason("Reservation status was updated to fulfilled."); // Setup JSON body containing order update JsonParser parser = new JsonParser(); JsonObject orderUpdateJson = parser.parse(new Gson().toJson(orderUpdate)).getAsJsonObject(); JsonObject body = new JsonObject(); body.add("orderUpdate", orderUpdateJson); JsonObject header = new JsonObject(); header.addProperty("isInSandbox", true); body.add("header", header); StringEntity entity = new StringEntity(body.toString()); entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); request.setEntity(entity); // Make request HttpClient httpClient = HttpClientBuilder.create().build(); HttpResponse response = httpClient.execute(request);
設定預留項目狀態
訂單更新的 ReservationStatus
必須能說明訂單目前的狀態。更新應用程式的「order.ReservationStatus
」中
欄位,請使用下列其中一個值:
PENDING
- 預留項目已建立採取行動,但需要 需要額外處理作業CONFIRMED
- 預訂已在您的排程後端確認。CANCELLED
- 使用者已取消預訂。FULFILLED
- 服務已完成使用者的預訂。CHANGE_REQUESTED
- 使用者要求變更預訂,然後 或圖片。REJECTED
- 如果無法處理或其他原因 確認預訂
針對與您商家相關的各個狀態,傳送最新的訂單狀態
舉例來說,如果預留項目需要手動處理
要求預訂後進行確認,並傳送 PENDING
訂單更新資訊至
完成額外處理程序後不一定每個預留項目都需要所有狀態值。
疑難排解
如果您在測試期間遇到任何問題,請參閱疑難排解步驟 交易類型