این راهنما شما را در فرآیند توسعه یک پروژه Actions راهنمایی می کند که از Orders API برای رزرو کردن استفاده می کند.
جریان تراکنش
وقتی پروژه Actions شما رزروها را مدیریت می کند، از جریان زیر استفاده می کند:
- اعتبارسنجی الزامات تراکنش (اختیاری) - از کمک کننده الزامات تراکنش ها در شروع مکالمه استفاده کنید تا مطمئن شوید کاربر قادر به انجام تراکنش است.
- سفارش را بسازید - کاربر را از طریق "مجموعه سبد خرید" که در آن جزئیات رزرو خود را ایجاد می کند، راهنمایی کنید.
- پیشنهاد سفارش - پس از تکمیل "سبد"، "سفارش" رزرو را به کاربر پیشنهاد دهید تا بتواند صحت آن را تایید کند. اگر رزرو تایید شود، پاسخی با جزئیات رزرو دریافت خواهید کرد.
- نهایی کردن سفارش و ارسال رسید - با تایید سفارش، سیستم رزرو خود را به روز کنید و رسید را برای کاربر ارسال کنید.
- ارسال بهروزرسانیهای سفارش - در طول عمر رزرو، با ارسال درخواستهای PATCH به Orders API بهروزرسانیهای وضعیت رزرو را به کاربر ارائه دهید.
محدودیت ها و دستورالعمل های بازبینی
به خاطر داشته باشید که خطمشیهای اضافی برای اقداماتی اعمال میشود که از تراکنشها و API سفارشها استفاده میکنند. بررسی Actions با تراکنشها میتواند تا شش هفته طول بکشد، بنابراین هنگام برنامهریزی زمانبندی انتشار، آن زمان را در نظر بگیرید. برای تسهیل روند بازبینی، قبل از ارسال Action برای بررسی، مطمئن شوید که از خطمشیها و دستورالعملهای تراکنشها پیروی میکنید.
فقط میتوانید اقداماتی را که از Orders API استفاده میکنند در کشورهای زیر مستقر کنید:
استرالیا برزیل کانادا اندونزی | ژاپن مکزیک قطر روسیه | سنگاپور سوئیس تایلند ترکیه انگلستان ایالات متحده |
پروژه خود را بسازید
برای مثالهای گسترده از مکالمات تراکنشی، نمونههای تراکنشهای ما را در Node.js و جاوا مشاهده کنید.
راه اندازی پروژه
هنگام ایجاد Action خود، باید مشخص کنید که میخواهید تراکنشها را در کنسول Actions انجام دهید. همچنین، اگر از کتابخانه مشتری Node.JS استفاده میکنید، اجرای خود را برای استفاده از آخرین نسخه Orders API تنظیم کنید.
برای تنظیم پروژه و اجرای خود، موارد زیر را انجام دهید:
- یک پروژه جدید ایجاد کنید یا یک پروژه موجود را وارد کنید.
- به Deploy > Directory information بروید.
در قسمت اطلاعات اضافی > تراکنشها > کادری را علامت بزنید که میگوید «آیا اقدامات شما از API تراکنشها برای انجام تراکنشهای کالاهای فیزیکی استفاده میکند؟».
اگر از کتابخانه سرویس گیرنده Node.JS برای ساختن اجرای Action خود استفاده می کنید، کد تکمیل خود را باز کنید و نمایه برنامه خود را به روز کنید تا پرچم
ordersv3
را رویtrue
تنظیم کنید. قطعه کد زیر نمونه ای از اعلان برنامه را برای Orders نسخه 3 نشان می دهد.
Node.js
const {dialogflow} = require('actions-on-google'); let app = dialogflow({ clientId, // If using account linking debug: true, ordersv3: true, });
Node.js
const {actionssdk} = require('actions-on-google'); let app = actionssdk({ clientId, // If using account linking debug: true, ordersv3: true, });
1. اعتبارسنجی الزامات تراکنش (اختیاری)
تجربه کاربری
به محض اینکه کاربر اعلام کرد که میخواهد یک رزرو تنظیم کند، توصیه میکنیم برای اطمینان از اینکه میتواند درخواست رزرو کند، قصد actions.intent.TRANSACTION_REQUIREMENTS_CHECK
را فعال کنید. برای مثال، هنگام فراخوانی، Action شما ممکن است بپرسد: "آیا میخواهید یک صندلی رزرو کنید؟" اگر کاربر «بله» گفت، باید فوراً این هدف را درخواست کنید. این تضمین می کند که آنها می توانند ادامه دهند و به آنها فرصتی می دهد تا تنظیماتی را که مانع از ادامه تراکنش می شوند، اصلاح کنند.
درخواست بررسی الزامات تراکنشها منجر به یکی از نتایج زیر میشود:
- در صورت برآورده شدن شرایط، تحقق شما یک قصد با شرط موفقیت دریافت می کند و می توانید به ساخت سفارش کاربر ادامه دهید.
اگر یک یا چند مورد از الزامات وجود نداشته باشد، تحقق شما هدف را با یک شرط شکست دریافت می کند. در این مورد، مکالمه را پایان دهید یا از جریان رزرو دور شوید.
اگر کاربر بتواند خطا را برطرف کند، به طور خودکار از او خواسته میشود این مشکلات را در دستگاه خود حل کند. اگر مکالمه روی یک سطح فقط صدا مانند بلندگوی هوشمند انجام شود، به تلفن کاربر منتقل می شود.
تحقق
برای اطمینان از اینکه کاربر الزامات تراکنش را برآورده می کند، با یک شی TransactionRequirementsCheckSpec ، درخواست انجام intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK
کنید.
الزامات را بررسی کنید
بررسی کنید که آیا کاربر الزامات رزرو با کتابخانه مشتری را برآورده می کند یا خیر:
conv.ask(new TransactionRequirements());
return getResponseBuilder(request) .add("Placeholder for transaction requirements text") .add(new TransactionRequirements()) .build();
توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } } } }
توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec" } } ] } ] }
نتیجه بررسی الزامات را دریافت کنید
پس از اینکه «دستیار» هدف را برآورده کرد، با نتیجه بررسی، درخواستی را با هدف 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. نظم را بسازید
تجربه کاربری
هنگامی که اطلاعات کاربری مورد نیاز خود را به دست آوردید، یک تجربه "مونتاژ سبد خرید" بسازید که کاربر را برای رزرو خود راهنمایی می کند. هر Action یک جریان مونتاژ سبد خرید متناسب با خدمات خود کمی متفاوت خواهد داشت.
در یک تجربه مونتاژ اولیه سبد خرید، کاربر گزینههایی را از فهرست انتخاب میکند تا به رزرو خود اضافه کند، اگرچه میتوانید مکالمه را برای سادهسازی تجربه کاربر طراحی کنید. به عنوان مثال، یک تجربه مونتاژ سبد خرید بسازید که کاربر را قادر میسازد تا با یک سوال بله یا خیر، یک رزرو ماهانه را برنامهریزی کند. همچنین می توانید یک چرخ فلک یا کارت لیست رزروهای "توصیه شده" را به کاربر ارائه دهید.
توصیه می کنیم از پاسخ های غنی برای ارائه گزینه های کاربر به صورت بصری استفاده کنید، اما مکالمه را نیز طوری طراحی کنید که کاربر بتواند تنها با استفاده از صدای خود سبد خرید خود را بسازد. برای برخی از بهترین شیوهها و نمونههایی از تجربیات مونتاژ سبد خرید، به دستورالعملهای طراحی معاملات مراجعه کنید.
تحقق
در طول مکالمه خود، جزئیات رزروی را که کاربر میخواهد خریداری کند، جمعآوری کنید و سپس یک شیء Order
بسازید.
Order
شما باید حداقل شامل موارد زیر باشد:
-
buyerInfo
- اطلاعات در مورد کاربر که رزرو را برنامه ریزی می کند. -
transactionMerchant
- اطلاعاتی درباره تاجری که رزرو را تسهیل می کند. -
contents
- جزئیات واقعی رزرو به عنوانlineItems
فهرست شده است.
برای ساخت سبد خرید خود به مستندات پاسخ Order
مراجعه کنید. توجه داشته باشید که بسته به رزرو ممکن است لازم باشد فیلدهای مختلفی را وارد کنید.
کد نمونه زیر یک سفارش رزرو کامل شامل فیلدهای اختیاری را نشان می دهد:
app.intent('build_reservation_df', (conv) => { const now = new Date().toISOString(); const order = { createTime: now, lastUpdateTime: now, merchantOrderId: 'UNIQUE_ORDER_ID', userVisibleOrderId: 'USER_VISIBLE_ORDER_ID', transactionMerchant: { id: 'https://www.example.com', name: 'Example Merchant', }, contents: { lineItems: [ { id: 'LINE_ITEM_ID', name: 'Dinner reservation', description: 'A world of flavors all in one destination.', reservation: { status: 'PENDING', userVisibleStatusLabel: 'Reservation is pending.', type: 'RESTAURANT', reservationTime: { timeIso8601: '2020-01-16T01:30:15.01Z', }, userAcceptableTimeRange: { timeIso8601: '2020-01-15/2020-01-17', }, partySize: 6, staffFacilitators: [ { name: 'John Smith', }, ], location: { zipCode: '94086', city: 'Sunnyvale', postalAddress: { regionCode: 'US', postalCode: '94086', administrativeArea: 'CA', locality: 'Sunnyvale', addressLines: [ '222, Some other Street', ], }, }, }, }, ], }, buyerInfo: { email: 'janedoe@gmail.com', firstName: 'Jane', lastName: 'Doe', displayName: 'Jane Doe', }, followUpActions: [ { type: 'VIEW_DETAILS', title: 'View details', openUrlAction: { url: 'https://example.com', }, }, { type: 'CALL', title: 'Call us', openUrlAction: { url: 'tel:+16501112222', }, }, { type: 'EMAIL', title: 'Email us', openUrlAction: { url: 'mailto:person@example.com', }, }, ], termsOfServiceUrl: 'https://www.example.com', };
private static OrderV3 createOrder() { // Transaction Merchant MerchantV3 transactionMerchant = new MerchantV3() .setId("http://www.example.com") .setName("Example Merchant"); // Line Item // Reservation Item Extension ReservationItemExtension reservationItemExtension = new ReservationItemExtension() .setStatus("PENDING") .setUserVisibleStatusLabel("Reservation pending.") .setType("RESTAURANT") .setReservationTime(new TimeV3() .setTimeIso8601("2020-01-16T01:30:15.01Z")) .setUserAcceptableTimeRange(new TimeV3() .setTimeIso8601("2020-01-15/2020-01-17")) .setPartySize(6) .setStaffFacilitators(Collections.singletonList(new StaffFacilitator() .setName("John Smith"))) .setLocation(new Location() .setZipCode("94086") .setCity("Sunnyvale") .setPostalAddress(new PostalAddress() .setRegionCode("US") .setPostalCode("94086") .setAdministrativeArea("CA") .setLocality("Sunnyvale") .setAddressLines( Collections.singletonList("222, Some other Street")))); LineItemV3 lineItem = new LineItemV3() .setId("LINE_ITEM_ID") .setName("Dinner reservation") .setDescription("A world of flavors all in one destination.") .setReservation(reservationItemExtension); // Order Contents OrderContents contents = new OrderContents() .setLineItems(Collections.singletonList(lineItem)); // User Info UserInfo buyerInfo = new UserInfo() .setEmail("janedoe@gmail.com") .setFirstName("Jane") .setLastName("Doe") .setDisplayName("Jane Doe"); // Follow up actions Action viewDetails = new Action() .setType("VIEW_DETAILS") .setTitle("View details") .setOpenUrlAction(new OpenUrlAction() .setUrl("https://example.com")); Action call = new Action() .setType("CALL") .setTitle("Call us") .setOpenUrlAction(new OpenUrlAction() .setUrl("tel:+16501112222")); Action email = new Action() .setType("EMAIL") .setTitle("Email us") .setOpenUrlAction(new OpenUrlAction() .setUrl("mailto:person@example.com")); // Terms of service and order note String termsOfServiceUrl = "https://example.com"; String now = Instant.now().toString(); OrderV3 order = new OrderV3() .setCreateTime(now) .setLastUpdateTime(now) .setMerchantOrderId("UNIQUE_ORDER_ID") .setUserVisibleOrderId("UNIQUE_USER_VISIBLE_ORDER_ID") .setTransactionMerchant(transactionMerchant) .setContents(contents) .setBuyerInfo(buyerInfo) .setFollowUpActions(Arrays.asList( viewDetails, call, email )) .setTermsOfServiceUrl(termsOfServiceUrl); return order; }
توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_DECISION", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "order": { "createTime": "2019-07-17T18:25:30.182Z", "lastUpdateTime": "2019-07-17T18:25:30.182Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://www.example.com", "name": "Example Merchant" }, "contents": { "lineItems": [ { "id": "LINE_ITEM_ID", "name": "Dinner reservation", "description": "A world of flavors all in one destination.", "reservation": { "status": "PENDING", "userVisibleStatusLabel": "Reservation is pending.", "type": "RESTAURANT", "reservationTime": { "timeIso8601": "2020-01-16T01:30:15.01Z" }, "userAcceptableTimeRange": { "timeIso8601": "2020-01-15/2020-01-17" }, "partySize": 6, "staffFacilitators": [ { "name": "John Smith" } ], "location": { "zipCode": "94086", "city": "Sunnyvale", "postalAddress": { "regionCode": "US", "postalCode": "94086", "administrativeArea": "CA", "locality": "Sunnyvale", "addressLines": [ "222, Some other Street" ] } } } } ] }, "buyerInfo": { "email": "janedoe@gmail.com", "firstName": "Jane", "lastName": "Doe", "displayName": "Jane Doe" }, "followUpActions": [ { "type": "VIEW_DETAILS", "title": "View details", "openUrlAction": { "url": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" }, "orderOptions": { "requestDeliveryAddress": false, "userInfoOptions": { "userInfoProperties": [ "EMAIL" ] } }, "presentationOptions": { "actionDisplayName": "RESERVE" } } } } } }
3. دستور را پیشنهاد دهید
سفارش رزرو خود را به کاربر ارائه دهید تا تایید یا رد شود. قصد actions.intent.TRANSACTION_DECISION
را درخواست کنید و Order
را که ساخته اید ارائه دهید.
تجربه کاربری
وقتی قصد actions.intent.TRANSACTION_DECISION
را درخواست میکنید، دستیار یک تجربه داخلی را آغاز میکند که در آن Order
مستقیماً روی یک «کارت پیشنمایش سبد خرید» ارائه میشود. کاربر میتواند بگوید «رزرو برنامهریزی کن»، تراکنش را رد کند یا درخواست تغییر جزئیات رزرو کند.
کاربر همچنین ممکن است در این مرحله درخواست تغییر در سفارش را داشته باشد. در این مورد، باید مطمئن شوید که انجام شما میتواند درخواستهای تغییر سفارش را پس از اتمام تجربه مونتاژ سبد خرید انجام دهد.
تحقق
وقتی قصد actions.intent.TRANSACTION_DECISION
را درخواست میکنید، یک TransactionDecision
ایجاد کنید که حاوی Order
و orderOptions
باشد.
کد زیر نمونه ای از TransactionsDecision
را برای یک سفارش نشان می دهد:
conv.ask(new TransactionDecision({ orderOptions: { requestDeliveryAddress: 'false', }, presentationOptions: { actionDisplayName: 'RESERVE', }, order: order, }));
// Create order options OrderOptionsV3 orderOptions = new OrderOptionsV3() .setRequestDeliveryAddress(false) .setUserInfoOptions(new UserInfoOptions() .setUserInfoProperties(Collections.singletonList("EMAIL"))); // Create presentation options PresentationOptionsV3 presentationOptions = new PresentationOptionsV3() .setActionDisplayName("RESERVE"); // Ask for transaction decision return getResponseBuilder(request) .add("Placeholder for transaction decision text") .add(new TransactionDecision() .setOrder(order) .setOrderOptions(orderOptions) .setPresentationOptions(presentationOptions) ) .build();
توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.
{ "payload": { "google": { "expectUserResponse": true, "systemIntent": { "intent": "actions.intent.TRANSACTION_DECISION", "data": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "orderOptions": { "requestDeliveryAddress": "false" }, "presentationOptions": { "actionDisplayName": "RESERVE" }, "order": { "createTime": "2019-07-17T18:25:30.184Z", "lastUpdateTime": "2019-07-17T18:25:30.184Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://www.example.com", "name": "Example Merchant" }, "contents": { "lineItems": [ { "id": "LINE_ITEM_ID", "name": "Dinner reservation", "description": "A world of flavors all in one destination.", "reservation": { "status": "PENDING", "userVisibleStatusLabel": "Reservation is pending.", "type": "RESTAURANT", "reservationTime": { "timeIso8601": "2020-01-16T01:30:15.01Z" }, "userAcceptableTimeRange": { "timeIso8601": "2020-01-15/2020-01-17" }, "partySize": 6, "staffFacilitators": [ { "name": "John Smith" } ], "location": { "zipCode": "94086", "city": "Sunnyvale", "postalAddress": { "regionCode": "US", "postalCode": "94086", "administrativeArea": "CA", "locality": "Sunnyvale", "addressLines": [ "222, Some other Street" ] } } } } ] }, "buyerInfo": { "email": "janedoe@gmail.com", "firstName": "Jane", "lastName": "Doe", "displayName": "Jane Doe" }, "followUpActions": [ { "type": "VIEW_DETAILS", "title": "View details", "openUrlAction": { "url": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" } } } } } }
توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TRANSACTION_DECISION", "inputValueData": { "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec", "orderOptions": { "requestDeliveryAddress": "false" }, "presentationOptions": { "actionDisplayName": "RESERVE" }, "order": { "createTime": "2019-07-17T18:25:30.057Z", "lastUpdateTime": "2019-07-17T18:25:30.057Z", "merchantOrderId": "UNIQUE_ORDER_ID", "userVisibleOrderId": "USER_VISIBLE_ORDER_ID", "transactionMerchant": { "id": "https://www.example.com", "name": "Example Merchant" }, "contents": { "lineItems": [ { "id": "LINE_ITEM_ID", "name": "Dinner reservation", "description": "A world of flavors all in one destination.", "reservation": { "status": "PENDING", "userVisibleStatusLabel": "Reservation is pending.", "type": "RESTAURANT", "reservationTime": { "timeIso8601": "2020-01-16T01:30:15.01Z" }, "userAcceptableTimeRange": { "timeIso8601": "2020-01-15/2020-01-17" }, "partySize": 6, "staffFacilitators": [ { "name": "John Smith" } ], "location": { "zipCode": "94086", "city": "Sunnyvale", "postalAddress": { "regionCode": "US", "postalCode": "94086", "administrativeArea": "CA", "locality": "Sunnyvale", "addressLines": [ "222, Some other Street" ] } } } } ] }, "buyerInfo": { "email": "janedoe@gmail.com", "firstName": "Jane", "lastName": "Doe", "displayName": "Jane Doe" }, "followUpActions": [ { "type": "VIEW_DETAILS", "title": "View details", "openUrlAction": { "url": "https://example.com" } }, { "type": "CALL", "title": "Call us", "openUrlAction": { "url": "tel:+16501112222" } }, { "type": "EMAIL", "title": "Email us", "openUrlAction": { "url": "mailto:person@example.com" } } ], "termsOfServiceUrl": "https://www.example.com" } } } ] } ] }
تصمیم کاربر را مدیریت کنید
پس از اینکه کاربر به سفارش پیشنهادی پاسخ داد، انجام شما هدف actions_intent_TRANSACTION_DECISION
را با آرگومان حاوی 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
برمی گردد، هر پردازشی را که برای زمان بندی رزرو لازم است انجام دهید (مانند حفظ آن در پایگاه داده خود).
برای ادامه مکالمه یک پاسخ ساده ارسال کنید. کاربر یک "کارت رسید جمع شده" را همراه با پاسخ شما دریافت می کند.
تحقق
// Set lastUpdateTime and update status of reservation order.lastUpdateTime = new Date().toISOString(); order.reservation.status = 'CONFIRMED'; order.reservation.userVisibleStatusLabel = 'Reservation confirmed'; order.reservation.confirmationCode = '123ABCDEFGXYZ'; // Send synchronous order update conv.ask(`Transaction completed! You're all set!`); conv.ask(new OrderUpdate({ type: 'SNAPSHOT', reason: 'Reason string', order: order, }));
ResponseBuilder responseBuilder = getResponseBuilder(request); order.setLastUpdateTime(Instant.now().toString()); // Set reservation status to confirmed and provide confirmation code LineItemV3 lineItem = order.getContents().getLineItems().get(0); ReservationItemExtension reservationItemExtension = lineItem.getReservation(); reservationItemExtension.setStatus("CONFIRMED"); reservationItemExtension.setUserVisibleStatusLabel("Reservation confirmed."); reservationItemExtension.setConfirmationCode("123ABCDEFGXYZ"); lineItem.setReservation(reservationItemExtension); order.getContents().getLineItems().set(0, lineItem); // Order update OrderUpdateV3 orderUpdate = new OrderUpdateV3() .setType("SNAPSHOT") .setReason("Reason string") .setOrder(order); responseBuilder .add("Transaction completed! You're all set! Would you like to do anything else?") .add(new StructuredResponse().setOrderUpdateV3(orderUpdate)); return responseBuilder.build();
توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Transaction completed! You're all set!" } }, { "structuredResponse": { "orderUpdateV3": { "type": "SNAPSHOT", "reason": "Reason string", "order": { "merchantOrderId": "UNIQUE_ORDER_ID", "reservation": { "status": "CONFIRMED", "userVisibleStatusLabel": "Reservation confirmed", "confirmationCode": "123ABCDEFGXYZ" }, "lastUpdateTime": "2019-07-17T18:25:30.187Z" } } } } ] } } } }
توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Transaction completed! You're all set!" } }, { "structuredResponse": { "orderUpdateV3": { "type": "SNAPSHOT", "reason": "Reason string", "order": { "merchantOrderId": "UNIQUE_ORDER_ID", "reservation": { "status": "CONFIRMED", "userVisibleStatusLabel": "Reservation confirmed", "confirmationCode": "123ABCDEFGXYZ" }, "lastUpdateTime": "2019-07-17T18:25:30.059Z" } } } } ] } } } ] }
5. ارسال به روز رسانی سفارش
وضعیت رزرو در طول عمر آن تغییر می کند. بهروزرسانیهای سفارش رزرو کاربر را با درخواستهای HTTP PATCH به Orders API ارسال کنید که شامل وضعیت سفارش و جزئیات است.
درخواست های ناهمزمان را در Orders API تنظیم کنید
درخواستهای بهروزرسانی سفارش به Orders API توسط یک نشانه دسترسی مجاز است. برای وصله بهروزرسانی سفارش در Orders API، یک کلید حساب سرویس JSON مرتبط با پروژه Actions Console خود را دانلود کنید، سپس کلید حساب سرویس را با یک توکن حامل که میتواند به سرصفحه Authorization
درخواست HTTP منتقل شود، مبادله کنید.
برای بازیابی کلید حساب سرویس خود، مراحل زیر را انجام دهید:
- در کنسول Google Cloud ، به منو ☰ > APIs & Services > Credentials > Create credentials > Service key account بروید.
- در قسمت Service Account ، New Service Account را انتخاب کنید.
- حساب سرویس را روی
service-account
تنظیم کنید. - Role را روی Project > Owner تنظیم کنید.
- نوع کلید را روی JSON تنظیم کنید.
- ایجاد را انتخاب کنید.
- یک کلید حساب سرویس JSON خصوصی در دستگاه محلی شما دانلود می شود.
در کد بهروزرسانیهای سفارش، کلید خدمات خود را با یک توکن حامل با استفاده از کتابخانه سرویس گیرنده Google APIs و محدوده «https://www.googleapis.com/auth/actions.order.developer» تعویض کنید. میتوانید مراحل و نمونههای نصب را در صفحه GitHub کتابخانه سرویس گیرنده API پیدا کنید.
order-update.js
در نمونه های Node.js و جاوا ما برای تبادل کلید مثال مراجعه کنید.
ارسال به روز رسانی سفارش
هنگامی که کلید حساب سرویس خود را با یک توکن حامل OAuth مبادله کردید، بهروزرسانیهای سفارش را به عنوان درخواستهای PATCH مجاز به Orders API ارسال کنید.
URL API سفارشات: PATCH https://actions.googleapis.com/v3/orders/${orderId}
سرفصل های زیر را در درخواست خود وارد کنید:
-
"Authorization: Bearer token"
با نماد حامل OAuth که کلید حساب سرویس خود را با آن مبادله کرده اید. -
"Content-Type: application/json"
.
درخواست PATCH باید بدنه JSON با فرمت زیر داشته باشد:
{ "orderUpdate": OrderUpdate }
شی OrderUpdate
از فیلدهای سطح بالای زیر تشکیل شده است:
-
updateMask
- فیلدهای سفارشی که در حال به روز رسانی هستید. برای بهروزرسانی وضعیت رزرو، مقدار را رویreservation.status, reservation.userVisibleStatusLabel
تنظیم کنید. order
- محتویات به روز رسانی. اگر محتوای رزرو را بهروزرسانی میکنید، مقدار را روی شی بهروزرسانی شدهOrder
تنظیم کنید. اگر فقط وضعیت رزرو را بهروزرسانی میکنید (مثلاً از"PENDING"
به"FULFILLED"
)، شی حاوی فیلدهای زیر است:-
merchantOrderId
- همان شناسه ای که در شیءOrder
خود تنظیم کرده اید. -
lastUpdateTime
- مهر زمانی این به روز رسانی. -
purchase
- یک شی حاوی موارد زیر:-
status
- وضعیت سفارش به عنوانReservationStatus
، مانند "CONFIRMED
" یا "CANCELLED
". -
userVisibleStatusLabel
- یک برچسب رو به روی کاربر که جزئیات وضعیت سفارش را ارائه می دهد، مانند "رزرو شما تایید شد".
-
-
userNotification
(اختیاری) - یک شیuserNotification
که می تواند هنگام ارسال این به روز رسانی در دستگاه کاربر نمایش داده شود. توجه داشته باشید که گنجاندن این شیء تضمین نمی کند که یک اعلان در دستگاه کاربر ظاهر شود.
کد نمونه زیر نمونه ای از 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
- رزرو توسط Action شما "ایجاد" شده است، اما نیاز به پردازش اضافی در پشتیبان شما دارد. -
CONFIRMED
- رزرو در برنامه ریزی شما تایید شد. -
CANCELLED
- کاربر رزرو خود را لغو کرد. -
FULFILLED
- رزرو کاربر توسط سرویس انجام شد. -
CHANGE_REQUESTED
- کاربر درخواست تغییر در رزرو کرده است و تغییر در حال پردازش است. -
REJECTED
- اگر نتوانستید رزرو را پردازش یا تأیید کنید.
بهروزرسانیهای سفارش را برای هر وضعیتی که مربوط به رزرو شما است ارسال کنید. به عنوان مثال، اگر رزرو شما نیاز به پردازش دستی برای تأیید رزرو پس از درخواست دارد، تا زمانی که پردازش اضافی انجام شود، یک بهروزرسانی سفارش PENDING
ارسال کنید. هر رزروی به هر مقدار وضعیت نیاز ندارد.
عیب یابی
اگر در طول آزمایش با مشکلی مواجه شدید، مراحل عیبیابی تراکنشها را بخوانید.