Panduan ini akan memandu Anda menjalani proses pengembangan project Action yang menggunakan Orders API untuk melakukan reservasi.
Alur transaksi
Saat project Action Anda menangani reservasi, project tersebut menggunakan alur berikut:
- Validasi persyaratan transaksi (opsional) - Gunakan helper persyaratan transaksi di awal percakapan untuk memastikan pengguna dapat melakukan transaksi.
- Membuat pesanan - Pandu pengguna untuk melakukan "perakitan keranjang" tempat mereka membuat detail reservasi.
- Mengusulkan pesanan - Setelah "keranjang" selesai, ajukan "pesanan" reservasi kepada pengguna, agar mereka dapat mengonfirmasi bahwa pesanan sudah benar. Jika reservasi dikonfirmasi, Anda akan menerima respons dengan detail reservasi.
- Menyelesaikan pesanan dan mengirim tanda terima - Setelah pesanan dikonfirmasi, update sistem reservasi Anda dan kirim tanda terima kepada pengguna.
- Mengirim pembaruan pesanan - Selama masa aktif reservasi, berikan pembaruan status reservasi pengguna dengan mengirimkan permintaan PATCH ke Orders API.
Pembatasan dan panduan peninjauan
Perlu diingat bahwa kebijakan tambahan berlaku untuk Action yang menggunakan transaksi dan Orders API. Kami membutuhkan waktu hingga enam minggu untuk meninjau Action dengan transaksi, jadi pertimbangkan waktu tersebut saat merencanakan jadwal rilis Anda. Untuk memudahkan proses peninjauan, pastikan Anda mematuhi kebijakan dan panduan untuk transaksi sebelum mengirimkan Action untuk ditinjau.
Anda hanya dapat men-deploy Action yang menggunakan Orders API di negara berikut:
Australia Brasil Kanada Indonesia |
Jepang Meksiko Qatar Rusia |
Singapura Swiss Thailand Turki Inggris Raya Amerika Serikat |
Mem-build project Anda
Untuk contoh lengkap percakapan transaksional, lihat contoh transaksi kami di Node.js dan Java.
Penyiapan project
Saat membuat Action, Anda harus menentukan bahwa Anda ingin melakukan transaksi di Konsol Actions. Selain itu, jika Anda menggunakan library klien Node.JS, siapkan fulfillment Anda untuk menggunakan Orders API versi terbaru.
Untuk menyiapkan project dan fulfillment Anda, lakukan hal berikut:
- Buat project baru atau impor project yang ada.
- Buka Deploy > Directory information.
Di bagian Additional information > Transactions > centang kotak yang bertuliskan "Apakah Actions Anda menggunakan Transactions API untuk melakukan transaksi barang fisik?".
Jika Anda menggunakan library klien Node.JS untuk mem-build fulfillment Action, buka kode fulfillment Anda dan update delkarasi aplikasi untuk menetapkan tanda
ordersv3
ketrue
. Cuplikan kode berikut menunjukkan contoh deklarasi aplikasi untuk Pesanan versi 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. Memvalidasi persyaratan transaksi (opsional)
Pengalaman pengguna
Segera setelah pengguna menunjukkan bahwa mereka ingin menyiapkan reservasi, sebaiknya picu intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK
untuk memastikan mereka dapat meminta reservasi. Misalnya, saat dipanggil, Action Anda mungkin bertanya,
"apakah Anda ingin memesan tempat?" Jika pengguna mengatakan
"yes", Anda harus segera meminta intent ini. Tindakan ini akan memastikan
pengguna dapat melanjutkan dan memberi mereka kesempatan untuk memperbaiki setelan
yang mencegah mereka melanjutkan transaksi.
Meminta intent pemeriksaan persyaratan transaksi akan menghasilkan salah satu hasil berikut:
- Jika persyaratannya terpenuhi, fulfillment Anda akan menerima intent dengan kondisi berhasil dan Anda dapat melanjutkan pembuatan pesanan pengguna.
Jika satu atau beberapa persyaratan tidak, fulfillment Anda akan menerima intent dengan kondisi gagal. Dalam hal ini, akhiri percakapan atau beralih dari alur reservasi.
Jika dapat memperbaiki error, pengguna akan otomatis diminta untuk menyelesaikan masalah tersebut di perangkat. Jika percakapan berlangsung di permukaan khusus suara seperti smart speaker, percakapan tersebut diteruskan ke ponsel pengguna.
Pemenuhan pemesanan
Untuk memastikan pengguna memenuhi
persyaratan transaksi, minta fulfillment intent
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
dengan objek
TransactionRequirementsCheckSpec.
Memeriksa persyaratan
Periksa untuk melihat apakah pengguna memenuhi persyaratan reservasi dengan library klien:
conv.ask(new TransactionRequirements());
return getResponseBuilder(request) .add("Placeholder for transaction requirements text") .add(new TransactionRequirements()) .build();
Perhatikan bahwa JSON di bawah menjelaskan respons webhook.
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } } } }
Perhatikan bahwa JSON di bawah menjelaskan respons webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } ] } ] }
Menerima hasil pemeriksaan persyaratan
Setelah memenuhi intent, Asisten akan mengirimkan permintaan fulfillment
dengan intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK
dengan hasil
pemeriksaan.
Untuk menangani permintaan ini dengan benar, deklarasikan intent Dialogflow yang dipicu oleh
peristiwa actions_intent_TRANSACTION_REQUIREMENTS_CHECK
. Saat dipicu,
tangani intent ini dalam fulfillment Anda:
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();
Perhatikan bahwa JSON di bawah menjelaskan permintaan 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": "" }
Perhatikan bahwa JSON di bawah menjelaskan permintaan 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. Membuat pesanan
Pengalaman pengguna
Setelah Anda memiliki informasi pengguna yang dibutuhkan, buat pengalaman "keranjang keranjang" yang memandu pengguna untuk melakukan reservasi. Setiap Action akan memiliki alur perakitan keranjang yang sedikit berbeda yang sesuai untuk layanannya.
Dalam pengalaman penggabungan keranjang dasar, pengguna memilih opsi dari daftar untuk ditambahkan ke reservasi mereka, meskipun Anda dapat mendesain percakapan untuk menyederhanakan pengalaman pengguna. Misalnya, buat pengalaman perakitan keranjang yang memungkinkan pengguna menjadwalkan reservasi bulanan dengan pertanyaan ya atau tidak yang sederhana. Anda juga dapat menampilkan carousel atau kartu daftar reservasi "direkomendasikan" kepada pengguna.
Sebaiknya gunakan respons lengkap untuk menampilkan opsi pengguna secara visual, sekaligus desain percakapan agar pengguna dapat membuat keranjang hanya menggunakan suara. Untuk beberapa praktik terbaik dan contoh pengalaman perakitan keranjang, lihat Panduan Desain Transaksi.
Pemenuhan pemesanan
Selama percakapan Anda, kumpulkan detail reservasi yang ingin dibeli pengguna, lalu buat objek Order
.
Order
Anda setidaknya harus berisi hal berikut:
buyerInfo
- Informasi tentang pengguna yang menjadwalkan reservasi.transactionMerchant
- Informasi tentang penjual yang memfasilitasi reservasi.contents
- Detail reservasi sebenarnya yang tercantum sebagailineItems
.
Lihat dokumentasi respons Order
untuk membuat keranjang. Perhatikan bahwa Anda mungkin perlu menyertakan kolom yang berbeda, bergantung pada reservasi.
Kode contoh di bawah menunjukkan pesanan reservasi lengkap, termasuk kolom opsional:
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; }
Perhatikan bahwa JSON di bawah menjelaskan respons 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. Mengusulkan pesanan
Tunjukkan pesanan reservasi Anda kepada pengguna agar mereka dapat mengonfirmasi atau menolak. Minta intent actions.intent.TRANSACTION_DECISION
dan berikan Order
yang Anda build.
Pengalaman Pengguna
Saat Anda meminta intent actions.intent.TRANSACTION_DECISION
, Asisten
akan memulai pengalaman bawaan tempat Order
dirender langsung ke "kartu pratinjau keranjang". Pengguna bisa mengatakan "jadwalkan reservasi", menolak transaksi, atau meminta untuk mengubah detail reservasi.
Pada tahap ini, pengguna juga dapat meminta perubahan pesanan. Dalam hal ini, Anda harus memastikan fulfillment dapat menangani permintaan perubahan pesanan setelah menyelesaikan pengalaman perakitan keranjang.
Pemenuhan pemesanan
Saat Anda meminta
intent actions.intent.TRANSACTION_DECISION
, buat
TransactionDecision
yang berisi Order
dan orderOptions
Kode berikut menunjukkan contoh TransactionsDecision
untuk pesanan:
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();
Perhatikan bahwa JSON di bawah menjelaskan respons 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" } } } } } }
Perhatikan bahwa JSON di bawah menjelaskan respons 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" } } } ] } ] }
Menangani keputusan pengguna
Setelah pengguna merespons pesanan yang diusulkan, fulfillment Anda akan menerima
intent actions_intent_TRANSACTION_DECISION
dengan argumen yang berisi
TransactionDecisionValue
. Nilai ini akan berisi hal berikut:
transactionDecision
- Keputusan pengguna terkait pesanan yang diusulkan. Kemungkinan nilainya adalahORDER_ACCEPTED
,ORDER_REJECTED
,CART_CHANGE_REQUESTED
, danUSER_CANNOT_TRANSACT
.
Untuk menangani permintaan ini, deklarasikan intent Dialogflow yang dipicu oleh
peristiwa actions_intent_TRANSACTION_DECISION
. Tangani intent ini dalam
fulfillment Anda:
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")); }
Perhatikan bahwa JSON di bawah menjelaskan permintaan 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": "" }
Perhatikan bahwa JSON di bawah menjelaskan permintaan 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. Selesaikan reservasi dan kirim tanda terima
Saat intent actions.intent.TRANSACTION_DECISION
ditampilkan dengan
transactionDecision
dari ORDER_ACCEPTED
, lakukan pemrosesan apa pun
yang diperlukan untuk menjadwalkan reservasi (seperti mempertahankannya di
database Anda sendiri).
Kirim respons sederhana untuk menjaga percakapan tetap berjalan. Pengguna akan menerima "kartu tanda terima yang diciutkan" beserta respons Anda.
Pemenuhan pemesanan
// 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();
Perhatikan bahwa JSON di bawah menjelaskan respons 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" } } } } ] } } } }
Perhatikan bahwa JSON di bawah menjelaskan respons 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. Kirim pembaruan pesanan
Status reservasi akan berubah selama masa aktifnya. Mengirim pembaruan pesanan reservasi pengguna dengan permintaan PATCH HTTP ke Orders API, yang berisi status dan detail pesanan.
Menyiapkan permintaan asinkron ke Orders API
Permintaan pembaruan pesanan ke Orders API diotorisasi oleh token akses. Untuk mem-PATCH pembaruan pesanan ke Orders API, download kunci akun layanan
JSON yang terkait dengan project Konsol Actions Anda, lalu tukar
kunci akun layanan dengan token pemilik yang dapat diteruskan ke
header Authorization
permintaan HTTP.
Untuk mengambil kunci akun layanan, lakukan langkah-langkah berikut:
- Di Konsol Google Cloud, buka Menu Changes > API & Layanan > Kredensial > Buat kredensial > Kunci akun layanan.
- Pada Akun Layanan, pilih Akun Layanan Baru.
- Tetapkan akun layanan ke
service-account
. - Tetapkan Role ke Project > Owner.
- Tetapkan jenis kunci ke JSON.
- Pilih Create.
- Kunci akun layanan JSON pribadi akan didownload ke komputer lokal Anda.
Dalam kode pembaruan pesanan Anda, tukar kunci layanan dengan token pemilik menggunakan library klien Google API dan cakupan "https://www.googleapis.com/auth/actions.order.developer". Anda dapat menemukan langkah-langkah penginstalan dan contoh di halaman GitHub library klien API.
Referensikan order-update.js
dalam contoh Node.js dan Java kami untuk pertukaran kunci contoh.
Kirim pembaruan pesanan
Setelah menukar kunci akun layanan dengan token pemilik OAuth, kirim pembaruan pesanan sebagai permintaan PATCH yang diotorisasi ke Orders API.
URL Orders API:
PATCH https://actions.googleapis.com/v3/orders/${orderId}
Masukkan header berikut dalam permintaan Anda:
"Authorization: Bearer token"
dengan token pemilik OAuth yang Anda tukarkan kunci akun layanannya."Content-Type: application/json"
.
Permintaan PATCH harus mengambil isi JSON dari format berikut:
{ "orderUpdate": OrderUpdate }
Objek OrderUpdate
terdiri dari kolom level teratas berikut:
updateMask
- Kolom pesanan yang Anda perbarui. Untuk memperbarui status reservasi, tetapkan nilai kereservation.status, reservation.userVisibleStatusLabel
.order
- Konten update. Jika Anda memperbarui konten reservasi, tetapkan nilai ke objekOrder
yang diperbarui. Jika Anda hanya memperbarui status reservasi (misalnya, dari"PENDING"
menjadi"FULFILLED"
), objek akan berisi kolom berikut:merchantOrderId
- ID yang sama dengan yang Anda tetapkan dalam objekOrder
.lastUpdateTime
- Stempel waktu update ini.purchase
- Objek yang berisi hal berikut:status
- Status pesanan sebagaiReservationStatus
, seperti "CONFIRMED
" atau "CANCELLED
".userVisibleStatusLabel
- Label yang ditampilkan kepada pengguna yang memberikan detail tentang status pesanan, seperti "Reservasi Anda telah dikonfirmasi".
userNotification
yang dapat ditampilkan di perangkat pengguna saat update ini dikirim. Perhatikan bahwa menyertakan objek ini tidak menjamin notifikasi muncul di perangkat pengguna.
Kode contoh berikut menunjukkan contoh OrderUpdate
yang memperbarui
status pesanan reservasi menjadi 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);
Menetapkan status reservasi
ReservationStatus
pembaruan pesanan
harus deskriptif tentang status pesanan saat ini. Di kolom order.ReservationStatus
update Anda, gunakan salah satu nilai berikut:
PENDING
- Reservasi telah "dibuat" oleh Action Anda, tetapi memerlukan pemrosesan tambahan pada backend Anda.CONFIRMED
- Reservasi telah dikonfirmasi di back-end penjadwalan Anda.CANCELLED
- Pengguna membatalkan reservasinya.FULFILLED
- Reservasi pengguna dipenuhi oleh layanan.CHANGE_REQUESTED
- Pengguna meminta perubahan pada reservasi, dan perubahan sedang diproses.REJECTED
- Jika Anda tidak dapat memproses atau mengonfirmasi reservasi.
Mengirim pembaruan pesanan untuk setiap status yang relevan dengan reservasi Anda. Misalnya, jika reservasi Anda memerlukan pemrosesan manual untuk mengonfirmasi reservasi setelah diminta, kirim pembaruan pesanan PENDING
hingga pemrosesan tambahan selesai. Tidak semua reservasi memerlukan setiap nilai status.
Pemecahan masalah
Jika Anda mengalami masalah selama pengujian, baca langkah pemecahan masalah untuk transaksi.