Panduan ini akan memandu Anda melalui proses pengembangan project Action yang menggunakan Orders API untuk melakukan reservasi.
Alur transaksi
Ketika project Action Anda menangani reservasi, menggunakan alur berikut:
- Validasi persyaratan transaksi (opsional) - Gunakan helper persyaratan transaksi di awal percakapan untuk memastikan bahwa pengguna mampu melakukan transaksi.
- Buat pesanan - Pandu pengguna untuk "perakitan keranjang" di mana mereka membuat detail pemesanan mereka.
- Usulkan pesanan - Setelah "keranjang" selesai, usulkan "pesanan" reservasi dapat pengguna, sehingga mereka dapat mengkonfirmasi bahwa itu benar. Jika reservasi telah dikonfirmasi, Anda akan menerima respons dengan detail reservasi.
- Menyelesaikan pesanan dan mengirimkan tanda terima - Setelah pesanan dikonfirmasi, perbarui sistem reservasi Anda dan mengirimkan tanda terima kepada pengguna.
- Kirim pembaruan pesanan - Selama masa aktif reservasi, memberikan 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 Actions dengan transaksi, jadi pertimbangkan waktu tersebut saat merencanakan jadwal rilis Anda. Untuk memudahkan proses peninjauan, pastikan Anda mematuhi kebijakan dan panduan transaksi sebelum mengirimkan Action untuk ditinjau.
Anda hanya dapat men-deploy Actions yang menggunakan Orders API di negara berikut:
Australia Brasil Kanada Indonesia |
Jepang Meksiko Qatar Rusia |
Singapura Swiss Thailand Turkiye Inggris Raya Amerika Serikat |
Mem-build project Anda
Untuk contoh lengkap percakapan transaksional, lihat contoh transaksi kami di Node.js dan Java.
Penyiapan project
Ketika membuat Action, Anda harus menentukan bahwa Anda ingin melakukan transaksi di Konsol Actions. Juga, jika Anda menggunakan library klien Node.JS, siapkan fulfillment Anda untuk menggunakan versi Orders API.
Untuk menyiapkan project dan fulfillment Anda, lakukan hal berikut:
- Buat project baru atau impor project yang sudah ada.
- Buka Deploy > Informasi direktori.
Di bagian Informasi tambahan > Transaksi > centang kotak yang bertuliskan "Lakukan Tindakan Anda menggunakan Transactions API untuk melakukan transaksi barang fisik?".
Jika Anda menggunakan library klien Node.JS untuk membangun fulfillment Action Anda, buka kode fulfillment Anda dan perbarui delkarasi aplikasi Anda untuk menyetel
ordersv3
untuktrue
. Cuplikan kode berikut menunjukkan aplikasi contoh 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 menyatakan ingin menyiapkan reservasi, sebaiknya picu
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
untuk memastikan dia dapat
melakukan reservasi. Misalnya, saat dipanggil, Action Anda mungkin menanyakan,
"Anda ingin memesan tempat duduk?" Jika pengguna mengatakan
"yes", Anda harus segera meminta intent ini. Hal ini akan memastikan
agar mereka dapat melanjutkan dan memberi mereka
kesempatan untuk memperbaiki setelan
mencegah mereka melanjutkan transaksi.
Meminta transaksi pemeriksaan intent menghasilkan salah satu hasil berikut:
- Jika persyaratan terpenuhi, fulfillment Anda akan menerima intent dengan berhasil dan Anda dapat melanjutkan dengan membuat pesanan pengguna.
Jika satu atau beberapa persyaratan tidak terpenuhi, pemenuhan pesanan Anda akan menerima intent dengan kondisi kegagalan. Dalam hal ini, akhiri percakapan atau untuk beralih dari alur reservasi.
Jika error dapat diperbaiki, pengguna akan otomatis diminta untuk menyelesaikan masalah tersebut di perangkat mereka. Jika percakapan berlangsung di platform khusus suara seperti {i>smart speaker<i}, perangkat itu diserahkan ke ponsel pengguna.
Pemenuhan pesanan
Untuk memastikan bahwa
pengguna memenuhi
persyaratan transaksi, pemenuhan permintaan
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
dengan intent
Objek TransactionRequirementsCheckSpec.
Memeriksa persyaratan
Periksa 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();
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan respons webhook.
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } } } }
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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 Anda
dengan intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK
dengan hasil
dari pemeriksaan.
Untuk menangani permintaan ini dengan benar, deklarasikan intent Dialogflow yang dipicu oleh
peristiwa actions_intent_TRANSACTION_REQUIREMENTS_CHECK
. Saat dipicu,
menangani 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();
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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": "" }
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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 memiliki informasi pengguna yang Anda butuhkan, buat "keranjang perakitan" pengalaman yang memandu pengguna untuk membuat reservasi mereka. Setiap Action akan memiliki alur perakitan keranjang yang sedikit berbeda yang sesuai dengan layanan.
Dalam pengalaman perakitan keranjang dasar, pengguna memilih opsi dari daftar untuk ditambahkan ke reservasi mereka, meskipun Anda dapat merancang percakapan untuk menyederhanakan {i>user experience<i}. Misalnya, bangun pengalaman perakitan keranjang yang memungkinkan untuk menjadwalkan reservasi bulanan dengan pertanyaan ya atau tidak. Anda juga dapat menampilkan carousel atau kartu daftar "direkomendasikan" kepada pengguna beberapa pemesanan.
Sebaiknya gunakan rich respons untuk menampilkan opsi pengguna secara visual, tetapi juga merancang percakapan sehingga pengguna dapat membangun keranjang hanya menggunakan suara mereka. Untuk beberapa praktik terbaik dan contoh pengalaman perakitan keranjang, lihat Panduan Desain Transaksi.
Pemenuhan pesanan
Sepanjang percakapan Anda, kumpulkan detail reservasi yang diinginkan pengguna
dibeli lalu membuat objek Order
.
Order
Anda minimal harus berisi hal-hal berikut:
buyerInfo
- Informasi tentang pengguna yang menjadwalkan reservasi.transactionMerchant
- Informasi tentang penjual yang memfasilitasi melakukan reservasi.contents
- Detail sebenarnya dari reservasi yang tercantum sebagailineItems
.
Lihat dokumentasi respons Order
untuk menyusun keranjang. Perhatikan bahwa Anda mungkin perlu menyertakan kolom yang berbeda
tergantung reservasi.
Kode contoh di bawah menunjukkan pesanan reservasi yang 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; }
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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. Ajukan pesanan
Tunjukkan pesanan reservasi Anda kepada pengguna agar mereka dapat mengonfirmasi atau
tolak. Minta actions.intent.TRANSACTION_DECISION
dan menyediakan Order
yang telah Anda bangun.
Pengalaman Pengguna
Saat Anda meminta intent actions.intent.TRANSACTION_DECISION
, Asisten
memulai pengalaman bawaan saat Order
dirender langsung ke "kartu pratinjau keranjang". Pengguna dapat mengucapkan "jadwalkan reservasi",
menolak transaksi, atau meminta
perubahan detail reservasi.
Pengguna juga dapat meminta perubahan pada pesanan pada tahap ini. Dalam kasus ini, Anda harus memastikan pemenuhan pesanan Anda dapat menangani permintaan perubahan pesanan setelah menyelesaikan pengalaman perakitan keranjang.
Pemenuhan pesanan
Jika Anda meminta
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();
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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" } } } } } }
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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, pemenuhan Anda akan menerima
Intent actions_intent_TRANSACTION_DECISION
dengan argumen yang berisi
TransactionDecisionValue
. Nilai ini akan berisi hal berikut:
transactionDecision
- Keputusan pengguna terkait proposal pesanan. Nilai yang mungkin 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
pemenuhan pesanan 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")); }
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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": "" }
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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. Menyelesaikan reservasi dan mengirimkan tanda terima
Saat intent actions.intent.TRANSACTION_DECISION
ditampilkan dengan
transactionDecision
dari ORDER_ACCEPTED
, lakukan apa pun
diperlukan untuk menjadwalkan reservasi (seperti mempertahankannya
database Anda sendiri).
Kirim respons sederhana untuk menjaga percakapan terus mengalir. Pengguna menerima "kartu tanda terima diciutkan" beserta jawaban Anda.
Pemenuhan pesanan
// 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();
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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" } } } } ] } } } }
Perlu diperhatikan bahwa JSON di bawah mendeskripsikan 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 berubah selama masa pakainya. Mengirim pembaruan pesanan reservasi pengguna dengan HTTP Permintaan PATCH ke Orders API, yang berisi status dan detail pesanan.
Menyiapkan permintaan asinkron ke Orders API
Permintaan pembaruan pesanan ke Orders API diotorisasi oleh akses
sebelumnya yang benar. Untuk melakukan PATCH pembaruan pesanan ke Orders API, download JSON
kunci akun layanan yang terkait dengan project Konsol Actions Anda, lalu tukar
kunci akun layanan untuk token pemilik yang dapat diteruskan ke
Header Authorization
dari permintaan HTTP.
Untuk mengambil kunci akun layanan Anda, lakukan langkah-langkah berikut:
- Di Konsol Google Cloud, buka Menu Unduh > API & Layanan > Kredensial > Buat kredensial > Kunci akun layanan.
- Di bagian Akun Layanan, pilih Akun Layanan Baru.
- Setel akun layanan ke
service-account
. - Tetapkan Role ke Project > Pemilik.
- Tetapkan jenis kunci ke JSON.
- Pilih Create.
- Kunci akun layanan JSON pribadi akan didownload ke komputer lokal Anda.
Dalam kode pembaruan pesanan, 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 instalasi dan contoh di halaman GitHub library klien API.
Referensikan order-update.js
di contoh Node.js dan Java untuk
contoh pertukaran kunci.
Kirim pembaruan pesanan
Setelah Anda menukar kunci akun layanan dengan token pemilik OAuth, kirim pembaruan pesanan sebagai permintaan PATCH yang diotorisasi ke Orders API.
URL API Pesanan:
PATCH https://actions.googleapis.com/v3/orders/${orderId}
Berikan header berikut dalam permintaan Anda:
"Authorization: Bearer token"
dengan token pemilik OAuth yang Anda tukarkan dengan kunci akun layanan Anda."Content-Type: application/json"
.
Permintaan PATCH harus menggunakan isi JSON dengan format berikut:
{ "orderUpdate": OrderUpdate }
OrderUpdate
terdiri dari kolom level teratas berikut ini:
updateMask
- Kolom pesanan yang sedang Anda perbarui. Untuk memperbarui status reservasi, tetapkan nilai kereservation.status, reservation.userVisibleStatusLabel
.order
- Konten update. Jika Anda memperbarui isi reservasi, tetapkan nilai ke objekOrder
yang diperbarui. Jika Anda baru saja memperbarui status reservasi (misalnya, dari"PENDING"
hingga"FULFILLED"
), objek berisi kolom berikut:merchantOrderId
- ID yang sama dengan yang Anda tetapkan di 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
(opsional) - AuserNotification
yang dapat ditampilkan di perangkat pengguna saat pembaruan ini dikirimkan. Catatan bahwa menyertakan objek ini tidak menjamin bahwa 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 mendeskripsikan status pesanan saat ini. Dalam order.ReservationStatus
update Anda
gunakan salah satu nilai berikut:
PENDING
- Reservasi telah "dibuat" oleh Action Anda, tetapi memerlukan pemrosesan tambahan di backend Anda.CONFIRMED
- Pemesanan dikonfirmasi di back-end penjadwalan Anda.CANCELLED
- Pengguna membatalkan reservasi.FULFILLED
- Pemesanan pengguna telah dipenuhi oleh layanan.CHANGE_REQUESTED
- Pengguna meminta perubahan pada reservasi, dan perubahan tersebut sedang diproses.REJECTED
- Jika Anda tidak dapat memproses atau cara lainnya mengonfirmasi reservasi.
Kirim pembaruan pesanan untuk setiap status yang relevan dengan
pemesanan tambahan. Misalnya, jika reservasi Anda memerlukan pemrosesan manual untuk
konfirmasi reservasi setelah diminta, kirimkan pembaruan pesanan sebesar PENDING
hingga
bahwa pemrosesan tambahan itu selesai. Tidak semua reservasi memerlukan setiap nilai status.
Pemecahan masalah
Jika Anda mengalami masalah selama pengujian, baca langkah pemecahan masalah kami untuk transaksi.