ساخت رزرو (Dialogflow)

این راهنما شما را در فرآیند توسعه یک پروژه Actions راهنمایی می کند که از Orders API برای رزرو کردن استفاده می کند.

جریان تراکنش

وقتی پروژه Actions شما رزروها را مدیریت می کند، از جریان زیر استفاده می کند:

  1. اعتبارسنجی الزامات تراکنش (اختیاری) - از کمک کننده الزامات تراکنش ها در شروع مکالمه استفاده کنید تا مطمئن شوید کاربر قادر به انجام تراکنش است.
  2. سفارش را بسازید - کاربر را از طریق "مجموعه سبد خرید" که در آن جزئیات رزرو خود را ایجاد می کند، راهنمایی کنید.
  3. پیشنهاد سفارش - پس از تکمیل "سبد"، "سفارش" رزرو را به کاربر پیشنهاد دهید تا بتواند صحت آن را تایید کند. اگر رزرو تایید شود، پاسخی با جزئیات رزرو دریافت خواهید کرد.
  4. نهایی کردن سفارش و ارسال رسید - با تایید سفارش، سیستم رزرو خود را به روز کنید و رسید را برای کاربر ارسال کنید.
  5. ارسال به‌روزرسانی‌های سفارش - در طول عمر رزرو، با ارسال درخواست‌های PATCH به Orders API به‌روزرسانی‌های وضعیت رزرو را به کاربر ارائه دهید.

محدودیت ها و دستورالعمل های بازبینی

به خاطر داشته باشید که خط‌مشی‌های اضافی برای اقداماتی اعمال می‌شود که از تراکنش‌ها و API سفارش‌ها استفاده می‌کنند. بررسی Actions با تراکنش‌ها می‌تواند تا شش هفته طول بکشد، بنابراین هنگام برنامه‌ریزی زمان‌بندی انتشار، آن زمان را در نظر بگیرید. برای تسهیل روند بازبینی، قبل از ارسال Action برای بررسی، مطمئن شوید که از خط‌مشی‌ها و دستورالعمل‌های تراکنش‌ها پیروی می‌کنید.

فقط می‌توانید اقداماتی را که از Orders API استفاده می‌کنند در کشورهای زیر مستقر کنید:

استرالیا
برزیل
کانادا
اندونزی
ژاپن
مکزیک
قطر
روسیه
سنگاپور
سوئیس
تایلند
بوقلمون
انگلستان
ایالات متحده

پروژه خود را بسازید

برای مثال‌های گسترده از مکالمات تراکنشی، نمونه‌های تراکنش‌های ما را در Node.js و جاوا مشاهده کنید.

راه اندازی پروژه

هنگام ایجاد Action خود، باید مشخص کنید که می‌خواهید تراکنش‌ها را در کنسول Actions انجام دهید. همچنین، اگر از کتابخانه مشتری Node.JS استفاده می‌کنید، اجرای خود را برای استفاده از آخرین نسخه Orders API تنظیم کنید.

برای تنظیم پروژه و اجرای خود، موارد زیر را انجام دهید:

  1. یک پروژه جدید ایجاد کنید یا یک پروژه موجود را وارد کنید.
  2. به Deploy > Directory information بروید.
  3. در قسمت اطلاعات اضافی > تراکنش‌ها > کادری را علامت بزنید که می‌گوید «آیا اقدامات شما از API تراکنش‌ها برای انجام تراکنش‌های کالاهای فیزیکی استفاده می‌کند؟».

  4. اگر از کتابخانه سرویس گیرنده Node.JS برای ساختن اجرای Action خود استفاده می کنید، کد تکمیل خود را باز کنید و نمایه برنامه خود را به روز کنید تا flag 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 کنید.

الزامات را بررسی کنید

بررسی کنید که آیا کاربر الزامات رزرو با کتابخانه مشتری را برآورده می کند یا خیر:

Node.js
conv.ask(new TransactionRequirements());
جاوا
return getResponseBuilder(request)
    .add("Placeholder for transaction requirements text")
    .add(new TransactionRequirements())
    .build();
Dialogflow JSON

توجه داشته باشید که JSON زیر یک پاسخ وب هوک را توضیح می دهد.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
        }
      }
    }
  }
}
Actions SDK JSON

توجه داشته باشید که 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 ایجاد شده است. وقتی فعال شد، این هدف را در تحقق خود مدیریت کنید:

Node.js
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();
Dialogflow JSON

توجه داشته باشید که 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": ""
}
Actions SDK JSON

توجه داشته باشید که 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 مراجعه کنید. توجه داشته باشید که بسته به رزرو ممکن است لازم باشد فیلدهای مختلفی را وارد کنید.

کد نمونه زیر یک سفارش رزرو کامل شامل فیلدهای اختیاری را نشان می دهد:

Node.js
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

توجه داشته باشید که 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 را برای یک سفارش نشان می دهد:

Node.js
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();
Dialogflow JSON

توجه داشته باشید که 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"
          }
        }
      }
    }
  }
}
Actions SDK JSON

توجه داشته باشید که 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 ایجاد شده است. این هدف را در تحقق خود مدیریت کنید:

Node.js
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"));
}
Dialogflow JSON

توجه داشته باشید که 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": ""
}
Actions SDK JSON

توجه داشته باشید که 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 برمی گردد، هر پردازشی را که برای زمان بندی رزرو لازم است انجام دهید (مانند حفظ آن در پایگاه داده خود).

برای ادامه مکالمه یک پاسخ ساده ارسال کنید. کاربر یک "کارت رسید جمع شده" را همراه با پاسخ شما دریافت می کند.

تحقق

Node.js
// 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();
Dialogflow JSON

توجه داشته باشید که 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"
                }
              }
            }
          }
        ]
      }
    }
  }
}
Actions SDK JSON

توجه داشته باشید که 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 منتقل شود، مبادله کنید.

برای بازیابی کلید حساب سرویس خود، مراحل زیر را انجام دهید:

  1. در کنسول Google Cloud ، به منو ☰ > APIs & Services > Credentials > Create credentials > Service key account بروید.
  2. در قسمت Service Account ، New Service Account را انتخاب کنید.
  3. حساب سرویس را روی service-account تنظیم کنید.
  4. Role را روی Project > Owner تنظیم کنید.
  5. نوع کلید را روی JSON تنظیم کنید.
  6. ایجاد را انتخاب کنید.
  7. یک کلید حساب سرویس 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 به روز می کند:

Node.js
// 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 ارسال کنید. هر رزروی به هر مقدار وضعیت نیاز ندارد.

عیب یابی

اگر در طول آزمایش با مشکلی مواجه شدید، مراحل عیب‌یابی تراکنش‌ها را بخوانید.