คู่มือนี้จะแนะนำให้คุณรู้จักกับกระบวนการพัฒนาโปรเจ็กต์ Actions ที่ใช้ Orders API ในการจอง
ขั้นตอนการทำธุรกรรม
เมื่อโปรเจ็กต์ Actions จัดการการจอง ใช้ขั้นตอนต่อไปนี้
- ตรวจสอบข้อกำหนดของธุรกรรม (ไม่บังคับ) - ใช้เครื่องมือช่วยข้อกำหนดด้านธุรกรรม ในช่วงเริ่มต้นการสนทนา เพื่อให้แน่ใจว่าผู้ใช้ ขณะทำธุรกรรม
- สร้างคำสั่งซื้อ - แนะนำผู้ใช้เกี่ยวกับ "การประกอบรถเข็น" เพื่อสร้างรายละเอียดการจอง
- เสนอคำสั่งซื้อ - เมื่อ "รถเข็น" เสร็จแล้ว ให้เสนอการจอง "คำสั่งซื้อ" ถึง เพื่อให้ผู้ใช้ยืนยันได้ว่าข้อมูลถูกต้อง หากการจองได้รับการยืนยัน คุณจะ ได้รับการตอบกลับพร้อมรายละเอียดการจอง
- สรุปคำสั่งซื้อและส่งใบเสร็จ - อัปเดตคำสั่งซื้อเมื่อยืนยันคำสั่งซื้อแล้ว ระบบการจองของคุณและส่งใบเสร็จ แก่ผู้ใช้ได้
- ส่งการอัปเดตคำสั่งซื้อ - ตลอดอายุของการจอง อัปเดตสถานะการจองของผู้ใช้โดยส่งคำขอ PATCH ไปยัง Orders API
ข้อจำกัดและหลักเกณฑ์การตรวจสอบ
โปรดทราบว่านโยบายเพิ่มเติมจะมีผลกับการดำเนินการที่ใช้ Transaction และ Orders API ด้วย เราอาจใช้เวลาถึง 6 สัปดาห์ในการตรวจสอบการดำเนินการที่มีธุรกรรม ดังนั้นให้คำนึงถึงเวลาเมื่อวางแผนกำหนดการเผยแพร่ โปรดตรวจสอบว่าคุณปฏิบัติตามนโยบายและหลักเกณฑ์สำหรับธุรกรรมก่อนที่จะส่งการดำเนินการเข้ารับการตรวจสอบ เพื่อช่วยให้กระบวนการตรวจสอบง่ายขึ้น
คุณจะติดตั้งใช้งานการดำเนินการที่ใช้ Orders API ได้ในประเทศต่อไปนี้เท่านั้น
ออสเตรเลีย บราซิล แคนาดา อินโดนีเซีย |
ญี่ปุ่น เม็กซิโก กาตาร์ รัสเซีย |
สิงคโปร์ สวิตเซอร์แลนด์ ไทย ตุรกี สหราชอาณาจักร สหรัฐอเมริกา |
สร้างโปรเจ็กต์
สำหรับตัวอย่างการสนทนาที่เกี่ยวกับธุรกรรม ให้ดูตัวอย่างธุรกรรมใน Node.js และ Java
การตั้งค่าโปรเจ็กต์
เมื่อสร้างการดำเนินการ คุณต้องระบุว่าคุณต้องการทำธุรกรรม ในคอนโซล Actions นอกจากนี้ หากคุณ โดยใช้ไลบรารีของไคลเอ็นต์ Node.JS ให้ตั้งค่า Fulfillment ล่าสุดเพื่อใช้เวอร์ชันล่าสุด Orders API ได้
ในการตั้งค่าโปรเจ็กต์และการดำเนินการเพื่อดำเนินการตามคำสั่งซื้อ ให้ทำตามขั้นตอนต่อไปนี้
- สร้างโปรเจ็กต์ใหม่หรือนำเข้าโปรเจ็กต์ที่มีอยู่
- ไปที่ทำให้ใช้งานได้ > ข้อมูลไดเรกทอรี
ใน ข้อมูลเพิ่มเติม > ธุรกรรม > เลือกช่องที่เขียนว่า "การดำเนินการของคุณ ใช้ Transaction API เพื่อทำธุรกรรมสินค้าที่จับต้องได้หรือไม่"
หากคุณใช้ไลบรารีของไคลเอ็นต์ Node.JS เพื่อสร้างการดำเนินการ Fulfillment ของการดำเนินการ เปิดรหัสการดำเนินการตามคำสั่งซื้อแล้วอัปเดตการแชร์แอปเพื่อตั้งค่า
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
ความตั้งใจที่จะช่วยให้มั่นใจว่า
ขอให้จอง ตัวอย่างเช่น เมื่อเรียกใช้ การดำเนินการของคุณอาจถามว่า
"จองที่ให้หน่อยนะ" หากผู้ใช้พูดว่า
"ใช่" คุณควรขอ Intent นี้ทันที วิธีนี้จะช่วย
ดำเนินการต่อและให้โอกาสเขาแก้ไขการตั้งค่า
และป้องกันไม่ให้ทำธุรกรรมต่อ
การขอทำธุรกรรม การตรวจสอบข้อกำหนดจะส่งผลให้เกิดผลลัพธ์อย่างใดอย่างหนึ่งต่อไปนี้
- หากเป็นไปตามข้อกำหนด การดำเนินการตามคำสั่งซื้อจะได้รับความตั้งใจที่มี สถานะความสำเร็จ คุณจึงดำเนินการ สร้างคำสั่งซื้อของผู้ใช้ต่อได้
หากไม่เป็นไปตามข้อกำหนดอย่างน้อย 1 ข้อ การดำเนินการตามคำสั่งซื้อจะได้รับ ที่มีเงื่อนไขความล้มเหลว ในกรณีนี้ ให้สิ้นสุดการสนทนาหรือ สลับออกจากขั้นตอนการจอง
หากผู้ใช้แก้ไขข้อผิดพลาดได้ ระบบจะแจ้งให้แก้ไขปัญหาเหล่านั้นโดยอัตโนมัติ บนอุปกรณ์ของตน หากการสนทนาเกิดขึ้นบนแพลตฟอร์มที่มีเฉพาะเสียง เหมือนลำโพงอัจฉริยะ หมายเลขนั้นจึงได้รับมอบไปยังโทรศัพท์ของผู้ใช้
การดำเนินการตามคำสั่งซื้อ
เพื่อให้แน่ใจว่าผู้ใช้
ข้อกำหนดในการดำเนินธุรกรรม ขอให้ดำเนินการตาม
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
Intent ที่มี
ออบเจ็กต์ TransactionRequirementsCheckSpec
ตรวจสอบข้อกำหนด
ตรวจสอบว่าผู้ใช้มีคุณสมบัติตรงตามข้อกำหนดการจองกับไลบรารีของไคลเอ็นต์หรือไม่ ดังนี้
conv.ask(new TransactionRequirements());
return getResponseBuilder(request) .add("Placeholder for transaction requirements text") .add(new TransactionRequirements()) .build();
โปรดทราบว่า JSON ด้านล่างจะอธิบายการตอบสนองของเว็บฮุค
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } } } }
โปรดทราบว่า JSON ด้านล่างจะอธิบายการตอบสนองของเว็บฮุค
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } ] } ] }
รับผลการตรวจสอบข้อกำหนด
หลังจากที่ Assistant ทำตามความตั้งใจแล้ว ระบบจะส่งคำขอให้คุณดำเนินการ
ด้วย Intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK
ที่มีผลลัพธ์
ของเช็ค
ให้ประกาศ Intent ของ Dialogflow ที่ทริกเกอร์เพื่อจัดการคำขอนี้ได้อย่างเหมาะสม
เหตุการณ์ 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 ด้านล่างอธิบายถึงคำขอเว็บฮุค
{ "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 ด้านล่างอธิบายถึงคำขอเว็บฮุค
{ "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. สร้างคำสั่งซื้อ
ประสบการณ์ของผู้ใช้
เมื่อคุณมีข้อมูลผู้ใช้ที่ต้องการแล้ว ให้สร้าง "รถเข็น" การประกอบ" ที่เป็นแนวทางให้ผู้ใช้สร้างการจอง ทุก การดำเนินการจะมีขั้นตอนการประกอบรถเข็นที่แตกต่างกันเล็กน้อยตามความเหมาะสม service.
ในการประกอบรถเข็นแบบพื้นฐาน ผู้ใช้เลือกตัวเลือกจากรายการเพื่อเพิ่ม กับการจองของพวกเขา แต่คุณสามารถออกแบบบทสนทนาเพื่อให้ ประสบการณ์ของผู้ใช้ ตัวอย่างเช่น สร้างประสบการณ์การประกอบรถเข็นที่เปิดใช้ ผู้ใช้สามารถกำหนดเวลาจองรายเดือนด้วยคำถามง่ายๆ ว่าใช่หรือไม่ใช่ คุณยังแสดงการ์ดภาพสไลด์หรือการ์ดรายการที่ "แนะนำ" ให้แก่ผู้ใช้ได้ด้วย การจองล่วงหน้า
เราขอแนะนำให้ใช้ rich คำตอบเพื่อนำเสนอตัวเลือกของผู้ใช้ ทางสายตา แต่ยังออกแบบบทสนทนาเพื่อให้ผู้ใช้สามารถสร้าง โดยใช้แค่เสียงของพวกเขาเอง หากต้องการดูแนวทางปฏิบัติที่ดีที่สุดและตัวอย่างของ ประสบการณ์การประกอบรถเข็น โปรดดูหลักเกณฑ์การออกแบบธุรกรรม
การดำเนินการตามคำสั่งซื้อ
รวบรวมรายละเอียดการจองที่ผู้ใช้ต้องการตลอดการสนทนา
ในการซื้อ แล้วสร้างออบเจ็กต์ 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 ด้านล่างจะอธิบายการตอบสนองของเว็บฮุค
{ "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
Intent และระบุ Order
ที่คุณสร้างขึ้น
ประสบการณ์ของผู้ใช้
เมื่อคุณขอ Intent ของ actions.intent.TRANSACTION_DECISION
แล้ว Assistant
เริ่มประสบการณ์ในตัวซึ่ง Order
ที่แสดงใน "การ์ดแสดงตัวอย่างรถเข็น" โดยตรง ผู้ใช้อาจพูดว่า "กำหนดเวลาจอง"
ปฏิเสธธุรกรรมหรือขอเปลี่ยนรายละเอียดการจอง
ในตอนนี้ ผู้ใช้ยังขอเปลี่ยนแปลงคำสั่งซื้อได้ด้วย ในกรณีนี้ คุณควรตรวจสอบว่าการดำเนินการตามคำสั่งซื้อสามารถจัดการคำขอเปลี่ยนแปลงคำสั่งซื้อได้หลังจาก การประกอบรถเข็นให้เสร็จ
การดำเนินการตามคำสั่งซื้อ
เมื่อคุณส่งคำขอ
actions.intent.TRANSACTION_DECISION
Intent ให้สร้าง
TransactionDecision
ที่มี Order
และ 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 ด้านล่างจะอธิบายการตอบสนองของเว็บฮุค
{ "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 ด้านล่างจะอธิบายการตอบสนองของเว็บฮุค
{ "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
Intent ที่มีอาร์กิวเมนต์ที่มี
TransactionDecisionValue
ค่านี้จะประกอบด้วยข้อมูลต่อไปนี้
transactionDecision
- การตัดสินใจของผู้ใช้เกี่ยวกับข้อเสนอ คำสั่งซื้อ ค่าที่เป็นไปได้คือORDER_ACCEPTED
,ORDER_REJECTED
,CART_CHANGE_REQUESTED
และUSER_CANNOT_TRANSACT
หากต้องการจัดการคำขอนี้ ให้ประกาศ Intent ของ Dialogflow ที่ทริกเกอร์โดย
เหตุการณ์ 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 ด้านล่างอธิบายถึงคำขอเว็บฮุค
{ "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 ด้านล่างอธิบายถึงคำขอเว็บฮุค
{ "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. ดำเนินการจองให้เสร็จสิ้นและส่งใบเสร็จ
เมื่อ Intent actions.intent.TRANSACTION_DECISION
แสดงผลพร้อม
วันที่ transactionDecision
ของ ORDER_ACCEPTED
ให้ดำเนินการใดก็ได้
ต้องมีการประมวลผลเพื่อกำหนดเวลาการจอง (เช่น ยืนยันใน
ฐานข้อมูลของคุณเอง)
ส่งการตอบกลับง่ายๆ เพื่อให้การสนทนาดำเนินไปได้อย่างต่อเนื่อง ผู้ใช้ได้รับ "การ์ดใบเสร็จที่ยุบอยู่" และคำตอบของคุณ
การดำเนินการตามคำสั่งซื้อ
// 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 ด้านล่างจะอธิบายการตอบสนองของเว็บฮุค
{ "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 ด้านล่างจะอธิบายการตอบสนองของเว็บฮุค
{ "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 Patch ส่งคำขอไปยัง Orders API โดยมีสถานะและรายละเอียดการสั่งซื้อ
ตั้งค่าคำขอแบบไม่พร้อมกันไปยัง Orders API
คำขออัปเดตคำสั่งซื้อไปยัง Orders API ได้รับอนุญาตแล้ว
โทเค็น หากต้องการแพตช์การอัปเดตคำสั่งซื้อใน Orders API ให้ดาวน์โหลด JSON
คีย์บัญชีบริการที่เชื่อมโยงกับโปรเจ็กต์คอนโซล Actions จากนั้นแลกเปลี่ยน
คีย์บัญชีบริการสำหรับโทเค็นสำหรับผู้ถือที่ส่งไปยัง
ส่วนหัว Authorization
ของคำขอ HTTP
หากต้องการเรียกข้อมูลคีย์บัญชีบริการ ให้ทำตามขั้นตอนต่อไปนี้
- ในคอนโซล Google Cloud ไปที่ เมนู ☰ > API และ บริการ > ข้อมูลเข้าสู่ระบบ > สร้างข้อมูลเข้าสู่ระบบ > คีย์บัญชีบริการ
- ในส่วนบัญชีบริการ ให้เลือกบัญชีบริการใหม่
- ตั้งค่าบัญชีบริการเป็น
service-account
- กำหนดบทบาทเป็นโปรเจ็กต์ > เจ้าของ
- ตั้งค่าประเภทคีย์เป็น JSON
- เลือกสร้าง
- ระบบจะดาวน์โหลดคีย์บัญชีบริการ JSON ส่วนตัวไปยังเครื่องภายในของคุณ
ในรหัสการอัปเดตคำสั่งซื้อ ให้แลกเปลี่ยนคีย์บริการเป็นโทเค็นสำหรับผู้ถือ โดยใช้ไลบรารีของไคลเอ็นต์ Google APIs และขอบเขต "https://www.googleapis.com/auth/actions.order.developer" คุณสามารถดูขั้นตอนการติดตั้งและ ตัวอย่างในหน้า GitHub ในไลบรารีของไคลเอ็นต์ API
อ้างอิง order-update.js
ในตัวอย่าง Node.js และ Java ของเราสำหรับ
การแลกเปลี่ยนคีย์ตัวอย่าง
ส่งการอัปเดตคำสั่งซื้อ
เมื่อคุณแลกเปลี่ยนคีย์บัญชีบริการกับโทเค็นสำหรับผู้ถือ OAuth แล้ว ให้ส่ง อัปเดตคำสั่งซื้อเป็นคำขอ Patch ที่ได้รับอนุญาตไปยัง Orders API
URL ของ 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
lastUpdateTime
- การประทับเวลาของการอัปเดตนี้purchase
- ออบเจ็กต์ที่มีข้อมูลต่อไปนี้status
- สถานะของคำสั่งซื้อเป็นReservationStatus
เช่น "CONFIRMED
" หรือ "CANCELLED
"userVisibleStatusLabel
- ป้ายกำกับที่ผู้ใช้เห็นและให้รายละเอียดเกี่ยวกับ สถานะการสั่งซื้อ เช่น "การจองได้รับการยืนยันแล้ว"
userNotification
(ไม่บังคับ) - AuserNotification
ที่สามารถแสดงในอุปกรณ์ของผู้ใช้เมื่อส่งการอัปเดตนี้ หมายเหตุ ว่าการใส่ออบเจ็กต์นี้ไม่ได้รับประกันว่าการแจ้งเตือนจะปรากฏใน อุปกรณ์ของผู้ใช้
โค้ดตัวอย่างต่อไปนี้แสดงตัวอย่าง 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
จนถึง
การประมวลผลเพิ่มเติมจะเสร็จสมบูรณ์ การจองบางรายการไม่ได้กำหนดให้ใช้ค่าสถานะบางรายการ
การแก้ปัญหา
หากพบปัญหาระหว่างการทดสอบ โปรดอ่านขั้นตอนการแก้ปัญหา สำหรับธุรกรรม