إنشاء حجوزات (Dialogflow)

سيرشدك هذا الدليل خلال عملية تطوير مشروع المهام. يستخدم Orders API لإجراء الحجوزات.

تدفق المعاملة

عندما يتعامل مشروع الإجراءات مع الحجوزات، التدفق التالي:

  1. التحقّق من صحة متطلبات المعاملات (اختياري) - استخدِم "مساعد متطلبات المعاملات" في بداية المحادثة للتأكد من أن المستخدم قادر على على إجراء معاملة.
  2. إنشاء الطلب - وجِّه المستخدم نحو "تجميع عربة التسوق" حيث يقوم بإنشاء تفاصيل حجزه.
  3. اقتراح الطلب: بعد اختيار "سلّة التسوّق" اكتمل، اقترح "الطلب" إلى المستخدم، حتى يتمكن من تأكيد صحته. إذا تم تأكيد الحجز، فستحتاج تلقي رد مع تفاصيل الحجز.
  4. إنهاء الطلب وإرسال إيصال: بعد تأكيد الطلب، يمكنك تعديل نظام الحجز الخاص بك وإرسال إيصال للمستخدم.
  5. إرسال تحديثات الطلب - على مدار فترة الحجز، تعديل حالة حجز المستخدم من خلال إرسال طلبات التصحيح إلى واجهة برمجة التطبيقات Orders API.

إرشادات المراجعة والقيود

يُرجى العلم أنّ سياسات إضافية تنطبق على "المهام" التي تستخدم المعاملات وواجهة برمجة التطبيقات Orders API. قد تستغرق مراجعة الإجراءات التي تتضمن معاملات ما يصل إلى ستة أسابيع، لذا يجب أخذ هذا الوقت في الاعتبار عند التخطيط للجدول الزمني للإصدار. لتسهيل عملية المراجعة، تأكَّد من الالتزام بالسياسات والإرشادات الخاصة بالمعاملات قبل إرسال الإجراء للمراجعة.

لا يمكنك نشر الإجراءات التي تستخدم Orders API إلا في البلدان التالية:

أستراليا
البرازيل
كندا
إندونيسيا
اليابان
المكسيك
قطر
روسيا
سنغافورة
سويسرا
تايلاند
تركيا
المملكة المتحدة
الولايات المتحدة

إنشاء مشروعك

للحصول على أمثلة شاملة على المحادثات المتعلقة بالمعاملات، يمكنك الاطّلاع على نماذج المعاملات في Node.js وJava.

إعداد المشروع

عند إنشاء الإجراء الخاص بك، يجب تحديد أنّك تريد إجراء المعاملات. في وحدة تحكّم الإجراءات. أيضًا، إذا كنت باستخدام مكتبة برامج Node.JS، يمكنك إعداد التنفيذ لاستخدام أحدث إصدار من Orders API.

لإعداد مشروعك وتنفيذك، قم بما يلي:

  1. أنشِئ مشروعًا جديدًا أو استورِد مشروعًا حاليًا.
  2. انتقل إلى نشر > معلومات الدليل:
  3. ضمن معلومات إضافية > المعاملات > حدد المربع الذي يقول "تنفيذ إجراءاتك استخدام واجهة برمجة التطبيقات للمعاملات لإجراء معاملات السلع المادية؟"

  4. إذا كنت تستخدم مكتبة برامج Node.JS لإنشاء عملية تنفيذ الإجراء، افتح رمز توصيل الطلب وعدِّل عملية تغيير التطبيق من أجل ضبط إبلاغ "ordersv3" عن "true" يعرض مقتطف الرمز التالي مثالاً على تطبيق لإصدار الطلبات 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 التأكد من إمكانية طلب إجراء حجز. على سبيل المثال، عند استدعاء الإجراء، قد يسأل الإجراء التالي: "هل تريد حجز مقعد؟" إذا قال المستخدم "نعم"، يجب طلب هذا الغرض على الفور. سيضمن ذلك يمكنه المتابعة ومنحه فرصة لتعديل أي إعدادات تمنعه من مواصلة المعاملة.

طلب المعاملات تحقق من المتطلبات الرغبة في التحقق من النية في إحدى النتائج التالية:

  • في حال استيفاء المتطلبات، يكون الهدف من توصيل الطلب هو نجاحك ويمكنك متابعة إنشاء طلب المستخدم.
  • في حال عدم استيفاء شرط واحد أو أكثر من المتطلبات، ستتلقى عملية استيفاء الطلب. الغرض من ذلك هو شرط الفشل. في هذه الحالة، قم بإنهاء المحادثة أو بعيدًا عن تدفق الحجز.

    إذا كان بإمكان المستخدم إصلاح الخطأ، سيُطلَب منه تلقائيًا حل هذه المشاكل. على أجهزتهم. إذا كانت المحادثة جارية على سطح صوتي فقط مثل مكبّر صوت ذكي، يتم تسليمه إلى هاتف المستخدم.

توصيل الطلبات

لضمان تلبية المستخدم متطلبات المعاملات، تطلب تنفيذ actions.intent.TRANSACTION_REQUIREMENTS_CHECK هدفًا بضمان العنصر TransactionRequirementsCheckSpec.

الاطّلاع على المتطلبات

تحقق لمعرفة ما إذا كان المستخدم يلبي متطلبات الحجز من خلال مكتبة العملاء:

Node.js
conv.ask(new TransactionRequirements());
Java
return getResponseBuilder(request)
    .add("Placeholder for transaction requirements text")
    .add(new TransactionRequirements())
    .build();
ملف JSON لـ Dialogflow

تجدر الإشارة إلى أن ملف JSON أدناه يصف استجابة ردّ تلقائي على الويب.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
        }
      }
    }
  }
}
ملف JSON لحزمة تطوير البرامج (SDK) الخاصة بالإجراءات

تجدر الإشارة إلى أن ملف JSON أدناه يصف استجابة ردّ تلقائي على الويب.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
          }
        }
      ]
    }
  ]
}
استلام نتيجة فحص المتطلبات

بعد أن ينفِّذ "مساعد Google" الغرض، يرسل طلبًا لتنفيذ المهمة. بهدف 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.');
}
Java
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 لـ Dialogflow

تجدر الإشارة إلى أن ملف JSON أدناه يصف طلب ردّ تلقائي على الويب.

{
  "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 لحزمة تطوير البرامج (SDK) الخاصة بالإجراءات

تجدر الإشارة إلى أن ملف JSON أدناه يصف طلب ردّ تلقائي على الويب.

{
  "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. لإنشاء عربة التسوق الخاصة بك. تجدر الإشارة إلى أنّك قد تحتاج إلى تضمين حقول مختلفة. اعتمادًا على الحجز.

يوضح الرمز النموذجي أدناه طلب حجز كامل، بما في ذلك الحقول الاختيارية:

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',
  };
Java
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 الذي أنشأته.

انطباع المستخدم

عند طلب intent لـ actions.intent.TRANSACTION_DECISION، يستخدم "مساعد Google" تشغيل تجربة مدمجة يتم فيها عرض Order مباشرةً في "بطاقة معاينة سلة التسوق". يمكن للمستخدم قول "تحديد موعد الحجز"، أو رفض المعاملة أو طلب تغيير تفاصيل الحجز.

يمكن للمستخدم أيضًا طلب إجراء تغييرات على الطلب في هذه المرحلة. وفي هذه الحالة، يجب أن تتأكّد من أنّ خدمة توصيل الطلبات قادرة على التعامل مع طلبات تغيير الطلب بعد الانتهاء من تجربة تجميع عربة التسوق.

توصيل الطلبات

عند طلب actions.intent.TRANSACTION_DECISION intent، أنشئ TransactionDecision الذي يحتوي على Order وorderOptions

يعرض الرمز التالي مثالاً على TransactionsDecision لأحد الطلبات:

Node.js
conv.ask(new TransactionDecision({
  orderOptions: {
    requestDeliveryAddress: 'false',
  },
  presentationOptions: {
    actionDisplayName: 'RESERVE',
  },
  order: order,
}));
Java
// 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 لـ Dialogflow

تجدر الإشارة إلى أن ملف 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 لحزمة تطوير البرامج (SDK) الخاصة بالإجراءات

تجدر الإشارة إلى أن ملف 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;
}
Java
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 لـ Dialogflow

تجدر الإشارة إلى أن ملف JSON أدناه يصف طلب ردّ تلقائي على الويب.

{
  "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 لحزمة تطوير البرامج (SDK) الخاصة بالإجراءات

تجدر الإشارة إلى أن ملف JSON أدناه يصف طلب ردّ تلقائي على الويب.

{
  "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,
}));
Java
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 لـ Dialogflow

تجدر الإشارة إلى أن ملف 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 لحزمة تطوير البرامج (SDK) الخاصة بالإجراءات

تجدر الإشارة إلى أن ملف 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 تصحيح الطلبات إلى واجهة برمجة التطبيقات Orders API التي تحتوي على حالة الطلب وتفاصيله

إعداد الطلبات غير المتزامنة في Orders API

يتم السماح بطلبات تعديل الطلبات المرسَلة إلى Orders API من خلال إذن وصول الرمز المميز. لتصحيح تعديل الطلب في واجهة برمجة التطبيقات Orders API، يجب تنزيل ملف JSON. مفتاح حساب الخدمة المرتبط بمشروع "وحدة تحكّم المهام"، ثم استبدال مفتاح حساب الخدمة لرمز الحامل المميز الذي يمكن تمريره إلى عنوان Authorization لطلب HTTP.

لاسترداد مفتاح حساب الخدمة، عليك اتّباع الخطوات التالية:

  1. في وحدة تحكُّم Google Cloud، الانتقال إلى رمز القائمة ⋮ > واجهات برمجة التطبيقات الخدمات > بيانات الاعتماد > إنشاء بيانات الاعتماد > مفتاح حساب الخدمة.
  2. ضمن حساب الخدمة، اختَر حساب خدمة جديد.
  3. اضبط حساب الخدمة على service-account.
  4. ضبط الدور على مشروع > المالك:
  5. اضبط نوع المفتاح على JSON.
  6. اختَر إنشاء.
  7. سيتم تنزيل مفتاح حساب خدمة JSON خاص إلى جهازك المحلي.

في رمز تعديلات الطلب، يمكنك استبدال مفتاح الخدمة برمز الحامل المميّز. باستخدام مكتبة برامج Google APIs والنطاق &quot;https://www.googleapis.com/auth/actions.order.developer&quot;. يمكنك العثور على خطوات التثبيت الأمثلة على صفحة GitHub في مكتبة برامج واجهة برمجة التطبيقات.

يمكنك الرجوع إلى order-update.js في نموذجي Node.js وJava كمثال لتبادل المفاتيح.

إرسال آخر أخبار الطلبات

بعد استبدال مفتاح حساب الخدمة برمز حامل بروتوكول OAuth، أرسِل الطلبات باعتبارها طلبات تصحيح معتمدة إلى Orders API.

عنوان URL لواجهة برمجة التطبيقات Orders API: PATCH https://actions.googleapis.com/v3/orders/${orderId}

قدِّم العناوين التالية في طلبك:

  • "Authorization: Bearer token" يتضمن الرمز المميز لحامل OAuth الذي استبدلت مفتاح حساب الخدمة من أجله.
  • "Content-Type: application/json".

يجب أن يأخذ طلب التصحيح نص 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;
        }
    });
});
Java
// 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 حتى إتمام المعالجة الإضافية. لا تتطلّب كل عملية حجز كلّ قيمة حالة.

تحديد المشاكل وحلّها

في حال مواجهة أي مشاكل أثناء الاختبار، يُرجى الاطّلاع على خطوات تحديد المشاكل وحلّها. للمعاملات