このガイドでは、Actions プロジェクトの開発プロセスについて説明します。 注文を処理する方法を紹介します
取引の流れ
Actions プロジェクトで予約を処理する際、 次のフローを使用します。
- 取引要件を検証する(省略可) - 取引要件ヘルパーを使用します。 会話の冒頭で、ユーザーが以下の操作ができることを確かめます。 トランザクションの実行などです
- 注文を作成する - お客様に 「カート アセンブリ」予約の詳細を作成します
- 注文を提案する - カート予約「order」を提案しますから 正しいことを確認します。予約が確定すると、 予約の詳細を含むレスポンスが返されます。
- 注文を確定して領収書を送信する - 注文を確定したら、更新します。 領収書を送信します 提供します。
- 注文の最新情報を送信する - 予約の存続期間中、 ユーザーの予約状況を更新するには、PATCH リクエストを Orders API です。
制限と審査のガイドライン
Transaction API と Orders API を使用するアクションには追加のポリシーが適用されることに注意してください。取引を含むアクションのレビューには最大で 6 週間ほどかかります。リリース スケジュールを計画する際は、この点を考慮してください。レビュー プロセスがスムーズに進むよう、レビューにアクションを提出する前に、取引に関するポリシーとガイドラインに準拠していることを確認してください。
Orders API を使用するアクションは、次の国でのみデプロイできます。
オーストラリア ブラジル カナダ インドネシア |
日本 メキシコ カタール ロシア |
シンガポール スイス タイ トルコ 英国 米国 |
プロジェクトのビルド
取引に関連する会話の例については、Node.js と Java の取引のサンプルをご覧ください。
プロジェクトの設定
アクションを作成するときは、取引を実行することを指定する必要があります。 Actions Console を使用します。また 最新のものを使用するようにフルフィルメントを設定します Orders API の新しいバージョンです
プロジェクトとフルフィルメントを設定する手順は次のとおりです。
- 新しいプロジェクトを作成するか、既存のプロジェクトをインポートします。
- [デプロイ] > [ディレクトリ情報] の順に移動します。
[その他の情報] >トランザクション >[Do your Actions] というチェックボックスをオンにして 「トランザクション API を使用して物理的な商品の取引を実行する」という質問です。
Node.JS クライアント ライブラリを使用してアクションのフルフィルメントを作成する場合は、 フルフィルメント コードを開き、アプリの宣言を更新して
ordersv3
フラグをtrue
に設定します。次のコード スニペットは、サンプルアプリを示しています。 宣言する必要があります。
Node.js
const {dialogflow} = require('actions-on-google'); let app = dialogflow({ clientId, // If using account linking debug: true, ordersv3: true, });
Node.js
const {actionssdk} = require('actions-on-google'); let app = actionssdk({ clientId, // If using account linking debug: true, ordersv3: true, });
1. 取引要件を確認する(省略可)
ユーザー エクスペリエンス
ユーザーが予約を設定することを示したら、すぐに
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
インテントを使用して、ユーザーが以下を行えるようにします。
予約をリクエストできます。たとえば、呼び出されたときに、アクションは
「お席を予約していただけますか?」お客様の声
「yes」の場合、このインテントを直ちにリクエストする必要があります。これにより、先に進むだけでなく、取引の続行を妨げる設定を修正する機会を用意できます。
トランザクションのリクエスト 要件チェックのインテントの結果は、次のいずれかになります。
- 要件を満たしている場合、フルフィルメントは ユーザーの注文の作成に進むことができます。
1 つ以上の要件が満たされない場合、フルフィルメントは 自動的に渡されます。この場合は、会話を終了するか、 予約フローから離れます
ユーザーがエラーを解決できる場合は、問題を解決するように促すメッセージが自動的に表示されます。 確認できます。会話が音声のみのサーフェスで行われている場合 ユーザーのスマートフォンに引き継がれます
フルフィルメント
ユーザーが次の要件を満たしていることを確認するには、
取引要件、取引要件、取引要件、
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
インテントを
TransactionRequirementsCheckSpec オブジェクト。
要件を確認する
クライアント ライブラリを使用して、ユーザーが予約要件を満たしているかどうかを確認します。
<ph type="x-smartling-placeholder">conv.ask(new TransactionRequirements());
return getResponseBuilder(request) .add("Placeholder for transaction requirements text") .add(new TransactionRequirements()) .build();
下記の JSON は Webhook レスポンスを示します。
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } } } }
下記の JSON は Webhook レスポンスを示します。
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } ] } ] }
要件確認の結果を受け取る
アシスタントはインテントを実行した後、フルフィルメントにリクエストを送信します
actions.intent.TRANSACTION_REQUIREMENTS_CHECK
インテントを含む
表示されます。
このリクエストを適切に処理するには、リクエストによってトリガーされる Dialogflow インテントを宣言します。
actions_intent_TRANSACTION_REQUIREMENTS_CHECK
イベント。トリガーされると
フルフィルメントでこのインテントを処理します。
const arg = conv.arguments.get('TRANSACTION_REQUIREMENTS_CHECK_RESULT'); if (arg && arg.resultType === 'CAN_TRANSACT') { // Normally take the user through cart building flow conv.ask(`Looks like you're good to go!`); } else { conv.close('Transaction failed.'); }
Argument transactionCheckResult = request .getArgument("TRANSACTION_REQUIREMENTS_CHECK_RESULT"); boolean result = false; if (transactionCheckResult != null) { Map<String, Object> map = transactionCheckResult.getExtension(); if (map != null) { String resultType = (String) map.get("resultType"); result = resultType != null && resultType.equals("CAN_TRANSACT"); } } ResponseBuilder responseBuilder = getResponseBuilder(request); if (result) { responseBuilder.add("Looks like you're good to go! Now say 'confirm transaction'"); } else { responseBuilder.add("Transaction failed"); } return responseBuilder.build();
下記の JSON は Webhook リクエストを示します。
{ "responseId": "", "queryResult": { "queryText": "", "action": "", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentText": "", "fulfillmentMessages": [], "outputContexts": [], "intent": { "name": "reservation_transaction_check_complete_df", "displayName": "reservation_transaction_check_complete_df" }, "intentDetectionConfidence": 1, "diagnosticInfo": {}, "languageCode": "" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "isInSandbox": true, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "inputs": [ { "rawInputs": [], "intent": "", "arguments": [ { "extension": { "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult", "resultType": "CAN_TRANSACT" }, "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT" } ] } ], "user": {}, "conversation": {}, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] } }, "session": "" }
下記の JSON は Webhook リクエストを示します。
{ "user": {}, "device": {}, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "conversation": {}, "inputs": [ { "rawInputs": [], "intent": "reservation_transaction_check_complete_asdk", "arguments": [ { "extension": { "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult", "resultType": "CAN_TRANSACT" }, "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT" } ] } ], "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] }
2. 注文を作成する
ユーザー エクスペリエンス
必要なユーザー情報を入手したら、カートを作成します。 組み立てます」ユーザーが予約を構築するためのガイドになります。毎 アクションのカート アセンブリ フローは、ユーザーのニーズに応じて若干異なります。 あります。
基本的なカート アセンブリのエクスペリエンスでは、ユーザーがリストからオプションを選択して追加する 会話を設計することもできますが、 向上させることができますたとえば、カート アセンブリのエクスペリエンスを作成し、 「はい」か「いいえ」で答える簡単な質問で、毎月の予約を申し込むことができます。 ユーザーに「おすすめ」のカルーセルまたはリストカードを表示することもできます。 できます。
「リッチコンテンツ ユーザーの選択肢を提示する ユーザーが会話をデザインできるようにして 音声だけで操作できますベスト プラクティスと例については、 カート アセンブリのエクスペリエンスについては、取引の設計ガイドラインをご覧ください。
フルフィルメント
会話を通じて、ユーザーが求めている予約の詳細を収集する
購入し、Order
オブジェクトを作成します。
Order
には、少なくとも次のものが含まれている必要があります。
buyerInfo
- 予約をスケジュール設定したユーザーに関する情報。transactionMerchant
- 斡旋している販売者に関する情報 表示されます。contents
-lineItems
として表示される予約の実際の詳細。
Order
レスポンスのドキュメントをご覧ください。
カートを作成します異なるフィールドを含める必要がある場合があります。
予約に応じて異なります。
次のサンプルコードは、省略可能なフィールドを含む完全な予約注文を示しています。
<ph type="x-smartling-placeholder">app.intent('build_reservation_df', (conv) => { const now = new Date().toISOString(); const order = { createTime: now, lastUpdateTime: now, merchantOrderId: 'UNIQUE_ORDER_ID', userVisibleOrderId: 'USER_VISIBLE_ORDER_ID', transactionMerchant: { id: 'https://www.example.com', name: 'Example Merchant', }, contents: { lineItems: [ { id: 'LINE_ITEM_ID', name: 'Dinner reservation', description: 'A world of flavors all in one destination.', reservation: { status: 'PENDING', userVisibleStatusLabel: 'Reservation is pending.', type: 'RESTAURANT', reservationTime: { timeIso8601: '2020-01-16T01:30:15.01Z', }, userAcceptableTimeRange: { timeIso8601: '2020-01-15/2020-01-17', }, partySize: 6, staffFacilitators: [ { name: 'John Smith', }, ], location: { zipCode: '94086', city: 'Sunnyvale', postalAddress: { regionCode: 'US', postalCode: '94086', administrativeArea: 'CA', locality: 'Sunnyvale', addressLines: [ '222, Some other Street', ], }, }, }, }, ], }, buyerInfo: { email: 'janedoe@gmail.com', firstName: 'Jane', lastName: 'Doe', displayName: 'Jane Doe', }, followUpActions: [ { type: 'VIEW_DETAILS', title: 'View details', openUrlAction: { url: 'https://example.com', }, }, { type: 'CALL', title: 'Call us', openUrlAction: { url: 'tel:+16501112222', }, }, { type: 'EMAIL', title: 'Email us', openUrlAction: { url: 'mailto:person@example.com', }, }, ], termsOfServiceUrl: 'https://www.example.com', };
private static OrderV3 createOrder() { // Transaction Merchant MerchantV3 transactionMerchant = new MerchantV3() .setId("http://www.example.com") .setName("Example Merchant"); // Line Item // Reservation Item Extension ReservationItemExtension reservationItemExtension = new ReservationItemExtension() .setStatus("PENDING") .setUserVisibleStatusLabel("Reservation pending.") .setType("RESTAURANT") .setReservationTime(new TimeV3() .setTimeIso8601("2020-01-16T01:30:15.01Z")) .setUserAcceptableTimeRange(new TimeV3() .setTimeIso8601("2020-01-15/2020-01-17")) .setPartySize(6) .setStaffFacilitators(Collections.singletonList(new StaffFacilitator() .setName("John Smith"))) .setLocation(new Location() .setZipCode("94086") .setCity("Sunnyvale") .setPostalAddress(new PostalAddress() .setRegionCode("US") .setPostalCode("94086") .setAdministrativeArea("CA") .setLocality("Sunnyvale") .setAddressLines( Collections.singletonList("222, Some other Street")))); LineItemV3 lineItem = new LineItemV3() .setId("LINE_ITEM_ID") .setName("Dinner reservation") .setDescription("A world of flavors all in one destination.") .setReservation(reservationItemExtension); // Order Contents OrderContents contents = new OrderContents() .setLineItems(Collections.singletonList(lineItem)); // User Info UserInfo buyerInfo = new UserInfo() .setEmail("janedoe@gmail.com") .setFirstName("Jane") .setLastName("Doe") .setDisplayName("Jane Doe"); // Follow up actions Action viewDetails = new Action() .setType("VIEW_DETAILS") .setTitle("View details") .setOpenUrlAction(new OpenUrlAction() .setUrl("https://example.com")); Action call = new Action() .setType("CALL") .setTitle("Call us") .setOpenUrlAction(new OpenUrlAction() .setUrl("tel:+16501112222")); Action email = new Action() .setType("EMAIL") .setTitle("Email us") .setOpenUrlAction(new OpenUrlAction() .setUrl("mailto:person@example.com")); // Terms of service and order note String termsOfServiceUrl = "https://example.com"; String now = Instant.now().toString(); OrderV3 order = new OrderV3() .setCreateTime(now) .setLastUpdateTime(now) .setMerchantOrderId("UNIQUE_ORDER_ID") .setUserVisibleOrderId("UNIQUE_USER_VISIBLE_ORDER_ID") .setTransactionMerchant(transactionMerchant) .setContents(contents) .setBuyerInfo(buyerInfo) .setFollowUpActions(Arrays.asList( viewDetails, call, email )) .setTermsOfServiceUrl(termsOfServiceUrl); return order; }
下記の JSON は Webhook レスポンスを示します。
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_DECISION", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "order": { "createTime": "2019-07-17T18:25:30.182Z", "lastUpdateTime": "2019-07-17T18:25:30.182Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://www.example.com", "name": "Example Merchant" }, "contents": { "lineItems": [ { "id": "LINE_ITEM_ID", "name": "Dinner reservation", "description": "A world of flavors all in one destination.", "reservation": { "status": "PENDING", "userVisibleStatusLabel": "Reservation is pending.", "type": "RESTAURANT", "reservationTime": { "timeIso8601": "2020-01-16T01:30:15.01Z" }, "userAcceptableTimeRange": { "timeIso8601": "2020-01-15/2020-01-17" }, "partySize": 6, "staffFacilitators": [ { "name": "John Smith" } ], "location": { "zipCode": "94086", "city": "Sunnyvale", "postalAddress": { "regionCode": "US", "postalCode": "94086", "administrativeArea": "CA", "locality": "Sunnyvale", "addressLines": [ "222, Some other Street" ] } } } } ] }, "buyerInfo": { "email": "janedoe@gmail.com", "firstName": "Jane", "lastName": "Doe", "displayName": "Jane Doe" }, "followUpActions": [ { "type": "VIEW_DETAILS", "title": "View details", "openUrlAction": { "url": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" }, "orderOptions": { "requestDeliveryAddress": false, "userInfoOptions": { "userInfoProperties": [ "EMAIL" ] } }, "presentationOptions": { "actionDisplayName": "RESERVE" } } } } } }
3. 注文内容を表示する
ユーザーが確認または確認できるよう、予約の注文を表示します。
拒否されます。actions.intent.TRANSACTION_DECISION
をリクエストする
インテントを作成し、作成した Order
を提供します。
ユーザー エクスペリエンス
actions.intent.TRANSACTION_DECISION
インテントをリクエストすると、アシスタントは
Order
が組み込まれた組み込みエクスペリエンスを開始します。
「カートのプレビュー カード」に直接レンダリングされます。ユーザーは“予約する”と言うと
取引を拒否するか、予約の詳細の変更をリクエストします。
ユーザーはこの時点で注文内容の変更をリクエストできます。この例では 変更後は、フルフィルメントが注文変更リクエストを処理できることを確認してください。 カートの組み立て作業を完了します
フルフィルメント
actions.intent.TRANSACTION_DECISION
インテントをリクエストしてから、
Order
を含む TransactionDecision
およびorderOptions
次のコードは、注文の TransactionsDecision
の例を示しています。
conv.ask(new TransactionDecision({ orderOptions: { requestDeliveryAddress: 'false', }, presentationOptions: { actionDisplayName: 'RESERVE', }, order: order, }));
// Create order options OrderOptionsV3 orderOptions = new OrderOptionsV3() .setRequestDeliveryAddress(false) .setUserInfoOptions(new UserInfoOptions() .setUserInfoProperties(Collections.singletonList("EMAIL"))); // Create presentation options PresentationOptionsV3 presentationOptions = new PresentationOptionsV3() .setActionDisplayName("RESERVE"); // Ask for transaction decision return getResponseBuilder(request) .add("Placeholder for transaction decision text") .add(new TransactionDecision() .setOrder(order) .setOrderOptions(orderOptions) .setPresentationOptions(presentationOptions) ) .build();
下記の JSON は Webhook レスポンスを示します。
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_DECISION", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "orderOptions": { "requestDeliveryAddress": "false" }, "presentationOptions": { "actionDisplayName": "RESERVE" }, "order": { "createTime": "2019-07-17T18:25:30.184Z", "lastUpdateTime": "2019-07-17T18:25:30.184Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://www.example.com", "name": "Example Merchant" }, "contents": { "lineItems": [ { "id": "LINE_ITEM_ID", "name": "Dinner reservation", "description": "A world of flavors all in one destination.", "reservation": { "status": "PENDING", "userVisibleStatusLabel": "Reservation is pending.", "type": "RESTAURANT", "reservationTime": { "timeIso8601": "2020-01-16T01:30:15.01Z" }, "userAcceptableTimeRange": { "timeIso8601": "2020-01-15/2020-01-17" }, "partySize": 6, "staffFacilitators": [ { "name": "John Smith" } ], "location": { "zipCode": "94086", "city": "Sunnyvale", "postalAddress": { "regionCode": "US", "postalCode": "94086", "administrativeArea": "CA", "locality": "Sunnyvale", "addressLines": [ "222, Some other Street" ] } } } } ] }, "buyerInfo": { "email": "janedoe@gmail.com", "firstName": "Jane", "lastName": "Doe", "displayName": "Jane Doe" }, "followUpActions": [ { "type": "VIEW_DETAILS", "title": "View details", "openUrlAction": { "url": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" } } } } } }
下記の JSON は Webhook レスポンスを示します。
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_DECISION", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "orderOptions": { "requestDeliveryAddress": "false" }, "presentationOptions": { "actionDisplayName": "RESERVE" }, "order": { "createTime": "2019-07-17T18:25:30.057Z", "lastUpdateTime": "2019-07-17T18:25:30.057Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://www.example.com", "name": "Example Merchant" }, "contents": { "lineItems": [ { "id": "LINE_ITEM_ID", "name": "Dinner reservation", "description": "A world of flavors all in one destination.", "reservation": { "status": "PENDING", "userVisibleStatusLabel": "Reservation is pending.", "type": "RESTAURANT", "reservationTime": { "timeIso8601": "2020-01-16T01:30:15.01Z" }, "userAcceptableTimeRange": { "timeIso8601": "2020-01-15/2020-01-17" }, "partySize": 6, "staffFacilitators": [ { "name": "John Smith" } ], "location": { "zipCode": "94086", "city": "Sunnyvale", "postalAddress": { "regionCode": "US", "postalCode": "94086", "administrativeArea": "CA", "locality": "Sunnyvale", "addressLines": [ "222, Some other Street" ] } } } } ] }, "buyerInfo": { "email": "janedoe@gmail.com", "firstName": "Jane", "lastName": "Doe", "displayName": "Jane Doe" }, "followUpActions": [ { "type": "VIEW_DETAILS", "title": "View details", "openUrlAction": { "url": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" } } } ] } ] }
ユーザーの判断に対応する
提案された注文にユーザーが応答すると、フルフィルメントは
actions_intent_TRANSACTION_DECISION
インテントの引数を引数に指定し、
TransactionDecisionValue
。この値には次のものが含まれます。
transactionDecision
- 提案された内容に関するユーザーの判断 できます。指定できる値はORDER_ACCEPTED
、ORDER_REJECTED
、CART_CHANGE_REQUESTED
、USER_CANNOT_TRANSACT
。
このリクエストを処理するには、次によってトリガーされる Dialogflow インテントを宣言します。
actions_intent_TRANSACTION_DECISION
イベント。このインテントを
:
const arg = conv.arguments.get('TRANSACTION_DECISION_VALUE'); if (arg && arg.transactionDecision === 'ORDER_ACCEPTED') { console.log('order accepted'); const order = arg.order; }
Argument transactionDecisionValue = request .getArgument("TRANSACTION_DECISION_VALUE"); Map<String, Object> extension = null; if (transactionDecisionValue != null) { extension = transactionDecisionValue.getExtension(); } String transactionDecision = null; if (extension != null) { transactionDecision = (String) extension.get("transactionDecision"); } if ((transactionDecision != null && transactionDecision.equals("ORDER_ACCEPTED"))) { OrderV3 order = ((OrderV3) extension.get("order")); }
下記の JSON は Webhook リクエストを示します。
{ "responseId": "", "queryResult": { "queryText": "", "action": "", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentText": "", "fulfillmentMessages": [], "outputContexts": [], "intent": { "name": "reservation_get_transaction_decision_df", "displayName": "reservation_get_transaction_decision_df" }, "intentDetectionConfidence": 1, "diagnosticInfo": {}, "languageCode": "" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "isInSandbox": true, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "inputs": [ { "rawInputs": [], "intent": "", "arguments": [] } ], "user": {}, "conversation": {}, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] } }, "session": "" }
下記の JSON は Webhook リクエストを示します。
{ "user": {}, "device": {}, "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] }, "conversation": {}, "inputs": [ { "rawInputs": [], "intent": "reservation_get_transaction_decision_asdk", "arguments": [] } ], "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] }
4. 予約を確定して領収書を送る
actions.intent.TRANSACTION_DECISION
インテントが「
transactionDecision
ORDER_ACCEPTED
のすべての要素を含む場合は、
予約をスケジューリングするための処理が必要となります(予約を永続化したり、
使用する場合もあります。
シンプルなレスポンスを送信する 会話が進みます折りたたまれた状態の領収書がユーザーに表示されます 回答が表示されます
フルフィルメント
<ph type="x-smartling-placeholder">// Set lastUpdateTime and update status of reservation order.lastUpdateTime = new Date().toISOString(); order.reservation.status = 'CONFIRMED'; order.reservation.userVisibleStatusLabel = 'Reservation confirmed'; order.reservation.confirmationCode = '123ABCDEFGXYZ'; // Send synchronous order update conv.ask(`Transaction completed! You're all set!`); conv.ask(new OrderUpdate({ type: 'SNAPSHOT', reason: 'Reason string', order: order, }));
ResponseBuilder responseBuilder = getResponseBuilder(request); order.setLastUpdateTime(Instant.now().toString()); // Set reservation status to confirmed and provide confirmation code LineItemV3 lineItem = order.getContents().getLineItems().get(0); ReservationItemExtension reservationItemExtension = lineItem.getReservation(); reservationItemExtension.setStatus("CONFIRMED"); reservationItemExtension.setUserVisibleStatusLabel("Reservation confirmed."); reservationItemExtension.setConfirmationCode("123ABCDEFGXYZ"); lineItem.setReservation(reservationItemExtension); order.getContents().getLineItems().set(0, lineItem); // Order update OrderUpdateV3 orderUpdate = new OrderUpdateV3() .setType("SNAPSHOT") .setReason("Reason string") .setOrder(order); responseBuilder .add("Transaction completed! You're all set! Would you like to do anything else?") .add(new StructuredResponse().setOrderUpdateV3(orderUpdate)); return responseBuilder.build();
下記の JSON は Webhook レスポンスを示します。
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Transaction completed! You're all set!" } }, { "structuredResponse": { "orderUpdateV3": { "type": "SNAPSHOT", "reason": "Reason string", "order": { "merchantOrderId": "UNIQUE_ORDER_ID", "reservation": { "status": "CONFIRMED", "userVisibleStatusLabel": "Reservation confirmed", "confirmationCode": "123ABCDEFGXYZ" }, "lastUpdateTime": "2019-07-17T18:25:30.187Z" } } } } ] } } } }
下記の JSON は Webhook レスポンスを示します。
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Transaction completed! You're all set!" } }, { "structuredResponse": { "orderUpdateV3": { "type": "SNAPSHOT", "reason": "Reason string", "order": { "merchantOrderId": "UNIQUE_ORDER_ID", "reservation": { "status": "CONFIRMED", "userVisibleStatusLabel": "Reservation confirmed", "confirmationCode": "123ABCDEFGXYZ" }, "lastUpdateTime": "2019-07-17T18:25:30.059Z" } } } } ] } } } ] }
5. 注文の更新情報を送信する
予約のステータスは、時間の経過とともに あります。HTTP でユーザー予約注文の更新を送信する Orders API に送信される PATCH リクエスト。注文のステータスと詳細が含まれます。
Orders API に非同期リクエストを設定する
Orders API への注文更新リクエストはアクセス権によって承認される
あります。Orders API で注文の更新を PATCH するには、JSON をダウンロードしてください。
サービス アカウント キーを使用して ID を交換し、
サービス アカウント キーに、署名なしトークンの
HTTP リクエストの Authorization
ヘッダー。
サービス アカウント キーを取得するには、次の手順に従います。
- Google Cloud コンソールで次の操作を行います。 メニュー 💻? > に移動API とサービス >クルデンシャル >認証情報を作成 >サービス アカウント キー。
- [サービス アカウント] で [新しいサービス アカウント] を選択します。
- サービス アカウントを
service-account
に設定します。 - [役割] を [プロジェクト] > [オーナー] に設定します。
- キータイプを [JSON] に設定します。
- [作成] を選択します。
- 非公開の JSON サービス アカウント キーがローカルマシンにダウンロードされます。
注文更新コードでサービスキーを署名なしトークンと交換します Google API クライアント ライブラリと "https://www.googleapis.com/auth/actions.order.developer" スコープを使用します。インストール手順と API クライアント ライブラリの GitHub ページの例。
Node.js と Java サンプルで order-update.js
を参照してください。
鍵交換の例を見てみましょう。
注文の更新情報を送信する
サービス アカウント キーを OAuth 署名なしトークンと交換したら、 承認済みの PATCH リクエストとして Orders API に送ります。
Orders API の URL:
PATCH https://actions.googleapis.com/v3/orders/${orderId}
リクエストに次のヘッダーを指定します。
"Authorization: Bearer token"
は、OAuth 署名なしトークンに置き換えます サービス アカウント キーを交換した場所。"Content-Type: application/json"
。
PATCH リクエストは、次の形式の JSON 本文を使用します。
{ "orderUpdate": OrderUpdate }
OrderUpdate
オブジェクトは、次のトップレベル フィールドで構成されています。
updateMask
- 更新する注文のフィールド。更新するには、 予約ステータス、 値をreservation.status, reservation.userVisibleStatusLabel
に設定します。order
- 更新の内容。Deployment を更新する場合は、 予約の内容を確認するには、値を更新後のOrder
オブジェクトに設定します。 予約のステータスを更新するだけの場合(たとえば、"PENDING"
から"FULFILLED"
など)、オブジェクトには 次のフィールドがあります。merchantOrderId
-Order
オブジェクトで設定したのと同じ ID。lastUpdateTime
- この更新のタイムスタンプ。purchase
- 以下を含むオブジェクト。 <ph type="x-smartling-placeholder">- </ph>
status
-ReservationStatus
としての注文のステータス。 例: 「CONFIRMED
」または「CANCELLED
」。userVisibleStatusLabel
- 詳細情報を提供するユーザー向けのラベル 注文ステータス(「予約が確定しました」など)
userNotification
(省略可) - AuserNotification
この更新の送信時にユーザーのデバイスに表示できるオブジェクトです。備考 このオブジェクトを含めても、通知が アクセスします。
次のサンプルコードは、バージョンを更新する OrderUpdate
の例を示しています。
予約注文のステータスを FULFILLED
に送信します。
// Import the 'googleapis' module for authorizing the request. const {google} = require('googleapis'); // Import the 'request' module for sending an HTTP POST request. const request = require('request'); // Import the OrderUpdate class from the Actions on Google client library. const {OrderUpdate} = require('actions-on-google'); // Import the service account key used to authorize the request. Replace the string path with a path to your service account key. const key = require('./service-account.json'); // Create a new JWT client for the Actions API using credentials from the service account key. let jwtClient = new google.auth.JWT( key.client_email, null, key.private_key, ['https://www.googleapis.com/auth/actions.order.developer'], null ); // Authorize the client asynchronously, passing in a callback to run upon authorization. jwtClient.authorize((err, tokens) => { if (err) { console.log(err); return; } // Declare the ID of the order to update. const orderId = '<UNIQUE_MERCHANT_ORDER_ID>'; const orderUpdateJson = new OrderUpdate({ updateMask: [ 'lastUpdateTime', 'contents.lineItems.reservation.status', 'contents.lineItems.reservation.userVisibleStatusLabel', ].join(','), order: { merchantOrderId: orderId, lastUpdateTime: new Date().toISOString(), contents: { lineItems: [ { reservation: { status: 'FULFILLED', userVisibleStatusLabel: 'Reservation fulfilled', }, } ] } }, reason: 'Reservation status was updated to fulfilled.', }); // Set up the PATCH request header and body, including the authorized token // and order update. const bearer = 'Bearer ' + tokens.access_token; const options = { method: 'PATCH', url: `https://actions.googleapis.com/v3/orders/${orderId}`, headers: { 'Authorization': bearer, }, body: { header: { 'isInSandbox': true, }, orderUpdate: orderUpdateJson, }, json: true, }; // Send the PATCH request to the Orders API. request.patch(options, (err, httpResponse, body) => { if (err) { console.log('There was an error...'); console.log(err); return; } }); });
// Create order update FieldMask fieldMask = FieldMask.newBuilder().addAllPaths(Arrays.asList( "lastUpdateTime", "contents.lineItems.reservation.status", "contents.lineItems.reservation.userVisibleStatusLabel")) .build(); OrderUpdateV3 orderUpdate = new OrderUpdateV3() .setOrder(new OrderV3() .setMerchantOrderId(orderId) .setLastUpdateTime(Instant.now().toString()) .setContents(new OrderContents() .setLineItems(Collections.singletonList(new LineItemV3() .setReservation(new ReservationItemExtension() .setStatus("FULFILLED") .setUserVisibleStatusLabel("Reservation fulfilled.")))))) .setUpdateMask(FieldMaskUtil.toString(fieldMask)) .setReason("Reservation status was updated to fulfilled."); // Setup JSON body containing order update JsonParser parser = new JsonParser(); JsonObject orderUpdateJson = parser.parse(new Gson().toJson(orderUpdate)).getAsJsonObject(); JsonObject body = new JsonObject(); body.add("orderUpdate", orderUpdateJson); JsonObject header = new JsonObject(); header.addProperty("isInSandbox", true); body.add("header", header); StringEntity entity = new StringEntity(body.toString()); entity.setContentType(ContentType.APPLICATION_JSON.getMimeType()); request.setEntity(entity); // Make request HttpClient httpClient = HttpClientBuilder.create().build(); HttpResponse response = httpClient.execute(request);
予約ステータスを設定する
注文の更新の ReservationStatus
注文の現在の状態を示す必要がありますアップデートの order.ReservationStatus
次のいずれかの値を使用します。
PENDING
- 予約は作成されました指定することもできますが、 バックエンドで追加の処理を行えますCONFIRMED
- 予約がスケジューリング バックエンドで確認されました。CANCELLED
- ユーザーが予約をキャンセルしました。FULFILLED
- ユーザーの予約がサービスによって履行されました。CHANGE_REQUESTED
- ユーザーが予約の変更をリクエストし、変更が あります。REJECTED
- 処理できなかった場合 予約を確認します。
お客様に関連するステータスごとに
できます。たとえば、予約で手動処理が必要な場合に、
リクエスト後に予約を確定したら、PENDING
の注文更新情報を送信します。期限:
追加の処理が行われます。すべての予約でステータス値が必要になるとは限りません。
トラブルシューティング
テスト中に問題が発生した場合は、トラブルシューティングの手順をご覧ください。 提供しています