In diesem Leitfaden wird Schritt für Schritt erklärt, wie Sie ein Actions-Projekt entwickeln, bei dem die Orders API für Reservierungen verwendet wird.
Transaktionsablauf
Wenn Ihr Actions-Projekt Reservierungen verarbeitet, wird der folgende Ablauf verwendet:
- Transaktionsanforderungen validieren (optional) – Verwenden Sie zu Beginn der Unterhaltung die Hilfe für Transaktionsanforderungen, um zu prüfen, ob der Nutzer in der Lage ist, eine Transaktion durchzuführen.
- Bestellung erstellen: Gehe mit dem Nutzer durch eine „Wagenmontage“, in der er die Details seiner Reservierung zusammenstellt.
- Bestellung vorschlagen: Sobald der Einkaufswagen fertig ist, schlagen Sie dem Nutzer die Reservierung „Bestellung“ vor, damit er bestätigen kann, dass sie korrekt ist. Nach Bestätigung der Reservierung erhalten Sie eine Antwort mit den Reservierungsdetails.
- Bestellung abschließen und Beleg senden: Aktualisieren Sie nach Bestätigung der Bestellung Ihr Reservierungssystem und senden Sie eine Quittung an den Nutzer.
- Bestellaktualisierungen senden: Aktualisiere den Reservierungsstatus der Nutzer während der Laufzeit der Reservierung, indem du PATCH-Anfragen an die Orders API sendest.
Einschränkungen und Richtlinien für Überprüfungen
Für Aktionen, die die Transaktionen und die Orders API verwenden, gelten zusätzliche Richtlinien. Die Überprüfung von Aktionen mit Transaktionen kann bis zu sechs Wochen dauern. Berücksichtigen Sie diese Zeit bei der Planung Ihres Veröffentlichungszeitplans. Achte darauf, dass du die Richtlinien für Transaktionen einhältst, bevor du deine Aktion zur Überprüfung einreichst, um den Überprüfungsprozess zu erleichtern.
Sie können Aktionen, die die Orders API verwenden, nur in den folgenden Ländern bereitstellen:
Australien Brasilien Kanada Indonesien |
Japan Mexiko Katar Russland |
Singapur Schweiz Thailand Türkei Vereinigtes Königreich USA |
Ihr Projekt erstellen
Ausführliche Beispiele für transaktionale Unterhaltungen finden Sie in unseren Transaktionsbeispielen in Node.js und Java.
Projekt einrichten
Beim Erstellen einer Aktion musst du in der Actions Console angeben, dass du Transaktionen ausführen möchtest. Wenn Sie die Node.JS-Clientbibliothek verwenden, richten Sie außerdem die Auftragsausführung so ein, dass die neueste Version der Orders API verwendet wird.
So richten Sie Ihr Projekt und die Auftragsausführung ein:
- Erstellen Sie ein neues Projekt oder importieren Sie ein vorhandenes Projekt.
- Gehen Sie zu Bereitstellen > Verzeichnisinformationen.
Klicke unter Zusätzliche Informationen > Transaktionen auf das Kästchen neben "Verwenden deine Aktionen die Transactions API, um Transaktionen mit physischen Waren durchzuführen?".
Wenn Sie die Node.JS-Clientbibliothek zum Erstellen der Auftragsausführung Ihrer Aktion verwenden, öffnen Sie den Auftragsausführungscode und aktualisieren Sie die App-Bereitstellung, um das Flag
ordersv3
auftrue
zu setzen. Das folgende Code-Snippet zeigt eine Beispiel-App-Deklaration für Orders Version 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. Transaktionsanforderungen validieren (optional)
Nutzererfahrung
Sobald der Nutzer angegeben hat, dass er eine Reservierung einrichten möchte, empfiehlt es sich, den Intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK
auszulösen, damit er eine Reservierung anfordern kann. Wenn deine Aktion beispielsweise aufgerufen wird, könnte sie fragen:
"Möchten Sie einen Platz reservieren?" Wenn der Nutzer „Ja“ sagt, sollten Sie diesen Intent sofort anfordern. So kann er fortfahren und alle Einstellungen ändern, die die Transaktion verhindern.
Wenn Sie die Transaktionsanforderungen anfordern, führt dies zu einem der folgenden Ergebnisse:
- Wenn die Anforderungen erfüllt sind, erhält die Auftragsausführung einen Intent mit einer Erfolgsbedingung und Sie können mit dem Erstellen des Auftrags des Nutzers fortfahren.
Wenn eine oder mehrere Anforderungen nicht erfüllt sind, empfängt die Auftragsausführung den Intent mit einer Fehlerbedingung. Beenden Sie in diesem Fall die Unterhaltung oder ändern Sie den Reservierungsablauf.
Wenn der Nutzer den Fehler beheben kann, wird er automatisch aufgefordert, die Probleme auf seinem Gerät zu beheben. Wenn das Gespräch auf einer sprachgesteuerten Oberfläche wie einem intelligenten Lautsprecher stattfindet, wird es an das Smartphone des Nutzers übergeben.
Auftragsausführung
Damit ein Nutzer die Transaktionsanforderungen erfüllt, fordern Sie die Ausführung des Intents actions.intent.TRANSACTION_REQUIREMENTS_CHECK
mit einem Objekt TransactionRequirementsCheckSpec an.
Anforderungen prüfen
Prüfen Sie, ob ein Nutzer die Reservierungsanforderungen mit der Clientbibliothek erfüllt:
conv.ask(new TransactionRequirements());
return getResponseBuilder(request) .add("Placeholder for transaction requirements text") .add(new TransactionRequirements()) .build();
Beachten Sie, dass der folgende JSON-Code eine Webhook-Antwort beschreibt.
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } } } }
Beachten Sie, dass der folgende JSON-Code eine Webhook-Antwort beschreibt.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } ] } ] }
Das Ergebnis einer Anforderungsprüfung erhalten
Nachdem Assistant den Intent erfüllt hat, sendet er eine Anfrage mit dem Intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK
zusammen mit dem Ergebnis der Prüfung an die Auftragsausführung.
Damit diese Anfrage ordnungsgemäß verarbeitet werden kann, müssen Sie einen Dialogflow-Intent deklarieren, der durch das Ereignis actions_intent_TRANSACTION_REQUIREMENTS_CHECK
ausgelöst wird. Wenn er ausgelöst wird, verarbeiten Sie diesen Intent in der Auftragsausführung:
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();
Der folgende JSON-Code beschreibt eine Webhook-Anfrage.
{ "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": "" }
Der folgende JSON-Code beschreibt eine Webhook-Anfrage.
{ "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. Auftrag erstellen
Nutzererfahrung
Sobald Sie die benötigten Nutzerinformationen haben, erstellen Sie eine „Einkaufswagenmontage“, die den Nutzer beim Erstellen der Reservierung anleitet. Jede Aktion hat je nach Dienst einen etwas anderen Montageablauf für den Warenkorb.
Bei der einfachen Zusammensetzung eines Einkaufswagens wählt ein Nutzer Optionen aus einer Liste aus, die er zu seiner Reservierung hinzufügen möchte. Sie können die Unterhaltung jedoch so gestalten, dass die User Experience vereinfacht wird. Erstellen Sie beispielsweise einen Warenkorbbau, der es dem Nutzer ermöglicht, mit einer einfachen Ja- oder Nein-Frage eine monatliche Reservierung zu vereinbaren. Sie können dem Nutzer auch ein Karussell oder eine Listenkarte mit „empfohlenen“ Reservierungen präsentieren.
Wir empfehlen, aussagekräftige Antworten zu verwenden, um die Optionen des Nutzers visuell darzustellen, aber auch die Unterhaltung so zu gestalten, dass der Nutzer seinen Warenkorb nur mit seiner Stimme erstellen kann. Einige Best Practices und Beispiele für den Zusammenbau von Einkaufswagen finden Sie in den Richtlinien für das Transaktionsdesign.
Auftragsausführung
Erfassen Sie während der Unterhaltung die Reservierungsdetails, die ein Nutzer kaufen möchte, und erstellen Sie dann ein Order
-Objekt.
Ihre Order
muss mindestens Folgendes enthalten:
buyerInfo
– Informationen über den Nutzer, der die Reservierung plant.transactionMerchant
: Informationen zum Händler, der die Reservierung durchführt.contents
: Die tatsächlichen Details der Reservierung, die alslineItems
aufgeführt sind.
Informationen zum Erstellen des Einkaufswagens findest du in der Dokumentation zur Order
-Antwort. Je nach Reservierung müssen Sie möglicherweise unterschiedliche Felder einfügen.
Der folgende Beispielcode zeigt einen vollständigen Reservierungsauftrag mit optionalen Feldern:
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; }
Beachten Sie, dass der folgende JSON-Code eine Webhook-Antwort beschreibt.
{ "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. Auftrag vorschlagen
Zeigen Sie dem Nutzer Ihren Reservierungsauftrag, damit er ihn bestätigen oder ablehnen kann. Fordern Sie den Intent actions.intent.TRANSACTION_DECISION
an und geben Sie das von Ihnen erstellte Order
an.
Benutzerfreundlichkeit
Wenn Sie den Intent actions.intent.TRANSACTION_DECISION
anfordern, initiiert Assistant eine integrierte Funktion, bei der das Order
direkt auf einer „Warenkorbvorschaukarte“ gerendert wird. Der Nutzer kann „Termin vereinbaren“ sagen, die Transaktion ablehnen oder eine Änderung der Reservierungsdetails anfordern.
An dieser Stelle kann der Nutzer auch Änderungen an der Bestellung anfordern. In diesem Fall sollten Sie dafür sorgen, dass die Auftragsausführung nach Abschluss der Warenkorbmontage Anfragen zu Bestelländerungen bearbeiten kann.
Auftragsausführung
Wenn Sie den Intent actions.intent.TRANSACTION_DECISION
anfordern, erstellen Sie ein TransactionDecision
, das die Order
und orderOptions
enthält.
Der folgende Code zeigt ein TransactionsDecision
-Beispiel für eine Bestellung:
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();
Beachten Sie, dass der folgende JSON-Code eine Webhook-Antwort beschreibt.
{ "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" } } } } } }
Beachten Sie, dass der folgende JSON-Code eine Webhook-Antwort beschreibt.
{ "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" } } } ] } ] }
Entscheidungen des Nutzers verarbeiten
Nachdem der Nutzer auf die vorgeschlagene Bestellung geantwortet hat, empfängt die Auftragsausführung den Intent actions_intent_TRANSACTION_DECISION
mit einem Argument, das TransactionDecisionValue
enthält. Dieser Wert enthält Folgendes:
transactionDecision
: Die Entscheidung des Nutzers bezüglich der vorgeschlagenen Bestellung. Mögliche Werte sindORDER_ACCEPTED
,ORDER_REJECTED
,CART_CHANGE_REQUESTED
undUSER_CANNOT_TRANSACT
.
Deklarieren Sie einen Dialogflow-Intent, der durch das Ereignis actions_intent_TRANSACTION_DECISION
ausgelöst wird, um diese Anfrage zu verarbeiten. Verarbeiten Sie diesen Intent in der Auftragsausführung:
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")); }
Der folgende JSON-Code beschreibt eine Webhook-Anfrage.
{ "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": "" }
Der folgende JSON-Code beschreibt eine Webhook-Anfrage.
{ "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. Reservierung abschließen und Beleg senden
Wenn der Intent actions.intent.TRANSACTION_DECISION
mit einem transactionDecision
von ORDER_ACCEPTED
zurückgegeben wird, führen Sie die Verarbeitung durch, die zum Planen der Reservierung erforderlich ist. Speichern Sie sie z. B. in Ihrer eigenen Datenbank.
Senden Sie eine einfache Antwort, um die Unterhaltung am Laufen zu halten. Der Nutzer erhält zusammen mit Ihrer Antwort eine minimierte Belegkarte.
Auftragsausführung
// 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();
Beachten Sie, dass der folgende JSON-Code eine Webhook-Antwort beschreibt.
{ "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" } } } } ] } } } }
Beachten Sie, dass der folgende JSON-Code eine Webhook-Antwort beschreibt.
{ "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. Bestellaktualisierungen senden
Der Reservierungsstatus ändert sich im Laufe der Lebensdauer. Senden Sie die Aktualisierungen der Nutzerreservierungsbestellung mit HTTP-PATCH-Anfragen an die Orders API, die den Bestellstatus und die Details enthält.
Asynchrone Anfragen an die Orders API einrichten
Anfragen zur Bestellaktualisierung an die Orders API werden durch ein Zugriffstoken autorisiert. Wenn du eine Bestellaktualisierung mit PATCH für die Orders API durchführen möchtest, lade einen JSON-Dienstkontoschlüssel herunter, der mit deinem Actions Console-Projekt verknüpft ist, und tauschen Sie den Dienstkontoschlüssel gegen ein Inhabertoken aus, das an den Authorization
-Header der HTTP-Anfrage übergeben werden kann.
Führen Sie die folgenden Schritte aus, um Ihren Dienstkontoschlüssel abzurufen:
- Gehen Sie in der Google Cloud Console zu Menü ⋮ > APIs und Dienste > Anmeldedaten > Anmeldedaten erstellen > Dienstkontoschlüssel.
- Wählen Sie unter Dienstkonto die Option Neues Dienstkonto aus.
- Legen Sie das Dienstkonto auf
service-account
fest. - Stellen Sie die Rolle auf Projekt > Inhaber ein.
- Legen Sie den Schlüsseltyp auf JSON fest.
- Wählen Sie Erstellen aus.
- Ein privater JSON-Dienstkontoschlüssel wird auf Ihren lokalen Computer heruntergeladen.
Tauschen Sie im Code für die Bestellaktualisierung mithilfe der Clientbibliothek der Google APIs und des Bereichs "https://www.googleapis.com/auth/actions.order.developer" gegen ein Inhabertoken aus. Installationsschritte und Beispiele finden Sie auf der GitHub-Seite der API-Clientbibliothek.
Ein Beispiel für einen Schlüsselaustausch finden Sie unter order-update.js
in unseren Node.js- und Java-Beispielen.
Bestellaktualisierungen senden
Nachdem Sie Ihren Dienstkontoschlüssel gegen ein OAuth-Inhabertoken ausgetauscht haben, senden Sie Bestellaktualisierungen als autorisierte PATCH-Anfragen an die Orders API.
URL der Orders API:
PATCH https://actions.googleapis.com/v3/orders/${orderId}
Geben Sie in Ihrer Anfrage die folgenden Header an:
"Authorization: Bearer token"
durch das OAuth-Inhabertoken, gegen das Sie Ihren Dienstkontoschlüssel ausgetauscht haben."Content-Type: application/json"
.
Die PATCH-Anfrage sollte einen JSON-Text im folgenden Format haben:
{ "orderUpdate": OrderUpdate }
Das Objekt OrderUpdate
besteht aus den folgenden Feldern der obersten Ebene:
updateMask
: die Felder des Auftrags, den Sie aktualisieren Legen Sie den Wert aufreservation.status, reservation.userVisibleStatusLabel
fest, um den Reservierungsstatus zu aktualisieren.order
: Der Inhalt des Updates. Wenn Sie den Inhalt der Reservierung aktualisieren, legen Sie den Wert auf das aktualisierteOrder
-Objekt fest. Wenn Sie nur den Status der Reservierung aktualisieren (z. B. von"PENDING"
zu"FULFILLED"
), enthält das Objekt die folgenden Felder:merchantOrderId
: Dies ist die ID, die Sie imOrder
-Objekt festgelegt haben.lastUpdateTime
: Der Zeitstempel dieser Aktualisierung.purchase
: ein Objekt, das Folgendes enthält:status
: Der Status der Bestellung alsReservationStatus
, z. B. „CONFIRMED
“ oder „CANCELLED
“.userVisibleStatusLabel
: ein für den Nutzer sichtbares Label mit Details zum Bestellstatus, z. B. „Ihre Reservierung ist bestätigt“.
userNotification
(optional) – EinuserNotification
-Objekt, das auf dem Gerät des Nutzers angezeigt werden kann, wenn dieses Update gesendet wird. Das Hinzufügen dieses Objekts garantiert jedoch nicht, dass eine Benachrichtigung auf dem Gerät des Nutzers erscheint.
Der folgende Beispielcode zeigt ein OrderUpdate
-Beispiel, das den Status der Reservierungsreihenfolge in FULFILLED
aktualisiert:
// 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);
Reservierungsstatus festlegen
Die ReservationStatus
einer Bestellaktualisierung muss eine Beschreibung des aktuellen Status der Bestellung enthalten. Verwenden Sie im Feld order.ReservationStatus
des Updates einen der folgenden Werte:
PENDING
: Die Reservierung wurde von deiner Aktion "erstellt", erfordert jedoch eine zusätzliche Verarbeitung in deinem Back-End.CONFIRMED
: Die Reservierung wurde im Back-End Ihrer Terminplanung bestätigt.CANCELLED
: Der Nutzer hat seine Reservierung storniert.FULFILLED
: Die Reservierung des Nutzers wurde über den Dienst erfüllt.CHANGE_REQUESTED
: Der Nutzer hat eine Änderung an der Reservierung angefordert und die Änderung wird verarbeitet.REJECTED
: Wenn Sie die Reservierung nicht verarbeiten oder anderweitig bestätigen konnten.
Senden Sie Bestellaktualisierungen für jeden für Ihre Reservierung relevanten Status. Wenn für Ihre Reservierung beispielsweise eine manuelle Verarbeitung erforderlich ist, um die Reservierung nach ihrer Anfrage zu bestätigen, senden Sie eine PENDING
-Bestellaktualisierung, bis die zusätzliche Verarbeitung abgeschlossen ist. Nicht für jede Reservierung ist jeder Statuswert erforderlich.
Fehlerbehebung
Falls während des Tests Probleme auftreten, lesen Sie unsere Schritte zur Fehlerbehebung für Transaktionen.