Derleme rezervasyonları (Dialogflow)

Bu rehber, rezervasyon yapmak için Siparişler API'sini kullanan bir Actions projesi geliştirme sürecinde size yol gösterecektir.

İşlem akışı

Actions projeniz rezervasyonları işlerken aşağıdaki akışı kullanır:

  1. İşlem gereksinimlerini doğrulayın (isteğe bağlı) - Kullanıcının bir işlemi gerçekleştirebildiğinden emin olmak için görüşmenin başında işlem gereksinimleri yardımcısını kullanın.
  2. Siparişi oluşturun: Kullanıcıyı rezervasyon ayrıntılarını oluşturduğu "alışveriş sepeti düzenlemesi" için yönlendirin.
  3. Siparişi önerin - "Alışveriş sepeti" tamamlandığında, doğru olduğunu onaylayabilmesi için kullanıcıya rezervasyon "siparişi"ni önerin. Rezervasyon onaylanırsa rezervasyon ayrıntılarını içeren bir yanıt alırsınız.
  4. Siparişi kesinleştirin ve makbuz gönderin - Sipariş onaylandıktan sonra rezervasyon sisteminizi güncelleyin ve kullanıcıya makbuz gönderin.
  5. Sipariş güncellemeleri gönderme - Rezervasyonun kullanım süresi boyunca, Orders API'ye PATCH istekleri göndererek kullanıcıya rezervasyon durumu güncellemeleri bildirin.

Kısıtlamalar ve inceleme kuralları

İşlemler ve Siparişler API'sini kullanan işlemler için ek politikaların geçerli olduğunu unutmayın. İşlem içeren işlemleri incelememiz altı haftayı bulabileceğinden, yayın planınızı planlarken bu süreyi de hesaba katın. İnceleme sürecini kolaylaştırmak için İşleminizi incelemeye göndermeden önce işlemlerle ilgili politikalara ve kurallara uyduğunuzdan emin olun.

Yalnızca aşağıdaki ülkelerde Siparişler API'sini kullanan İşlemleri dağıtabilirsiniz:

Avustralya
Brezilya
Kanada
Endonezya
Japonya
Meksika
Katar
Rusya
Singapur
İsviçre
Tayland
Türkiye
Birleşik Krallık
Amerika Birleşik Devletleri

Projenizi oluşturun

İşlem sohbetlerinin kapsamlı örnekleri için Node.js ve Java'daki işlem örneklerimizi inceleyin.

Proje ayarlama

İşleminizi oluştururken Actions console'da işlem gerçekleştirmek istediğinizi belirtmeniz gerekir. Ayrıca, Node.JS istemci kitaplığını kullanıyorsanız sipariş karşılama sisteminizi Orders API'nin en son sürümünü kullanacak şekilde ayarlayın.

Projenizi ve sipariş karşılamanızı ayarlamak için aşağıdakileri yapın:

  1. Yeni proje oluşturun veya mevcut bir projeyi içe aktarın.
  2. Dağıtma > Dizin bilgileri'ne gidin.
  3. Ek bilgiler > İşlemler bölümünün altında "İşlemleriniz fiziksel ürünlerle ilgili işlemler yapmak için Transaction API'yi kullanıyor mu?" yazan kutuyu işaretleyin.

  4. İşleminizin karşılanmasını derlemek için Node.JS istemci kitaplığını kullanıyorsanız istek karşılama kodunuzu açın ve uygulama kaldırma işleminizi güncelleyerek ordersv3 işaretini true olarak ayarlayın. Aşağıdaki kod snippet'inde, Siparişler sürüm 3 için örnek bir uygulama beyanı gösterilmektedir.

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. İşlem şartlarını doğrulayın (isteğe bağlı)

Kullanıcı deneyimi

Kullanıcı rezervasyon oluşturmak istediğini belirttiğinde, rezervasyon isteğinde bulunabildiğinden emin olmak için actions.intent.TRANSACTION_REQUIREMENTS_CHECK amacını tetiklemenizi öneririz. Örneğin, çağrıldığında İşleminiz " yer ayırtmak ister misiniz?" diye sorabilir. Kullanıcı "evet" derse bu niyeti hemen istemelisiniz. Bu sayede, işleme devam edebilmelerini sağlar ve işleme devam etmesini engelleyen ayarları düzeltme fırsatına sahip olurlar.

İşlem gereksinimlerini istemek, amacın kontrol edilmesini sağlamak için aşağıdaki sonuçlardan biriyle sonuçlanır:

  • Şartlar karşılanırsa, istek karşılama işleminiz başarılı bir amaç doğrultusunda gerçekleşir ve kullanıcının siparişini oluşturma işlemine devam edebilirsiniz.
  • Koşullardan biri veya daha fazlası eşleşmiyorsa amacınız, istek karşılamayı başarısız olduğu için alır. Bu durumda görüşmeyi bitirin veya rezervasyon akışından ayrılın.

    Hatayı düzeltebilen kullanıcılardan otomatik olarak, cihazlarında bu sorunları çözmeleri istenir. Konuşma, akıllı hoparlör gibi yalnızca sesli bir yüzeyde gerçekleşiyorsa kullanıcının telefonuna iletilir.

Sipariş karşılama

Kullanıcının işlem gereksinimlerini karşıladığından emin olmak için bir TransactionRequirementsCheckSpec nesnesiyle actions.intent.TRANSACTION_REQUIREMENTS_CHECK amacının yerine getirilmesini isteyin.

Gereksinimleri kontrol edin

İstemci kitaplığıyla kullanıcının rezervasyon gereksinimlerini karşılayıp karşılamadığını kontrol edin:

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

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

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

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
          }
        }
      ]
    }
  ]
}
Bir gereksinim kontrolünün sonucunu alma

Asistan, amacı yerine getirdikten sonra kontrolün sonucunu actions.intent.TRANSACTION_REQUIREMENTS_CHECK niyetiyle birlikte yerine getirmenize yönelik bir istek gönderir.

Bu isteği düzgün bir şekilde işlemek için actions_intent_TRANSACTION_REQUIREMENTS_CHECK etkinliği tarafından tetiklenen bir Dialogflow niyeti tanımlayın. Tetiklendiğinde, istek karşılamada şu amacı ele alın:

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

Aşağıdaki JSON'un bir webhook isteğini açıkladığını unutmayın.

{
  "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

Aşağıdaki JSON'un bir webhook isteğini açıkladığını unutmayın.

{
  "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. Siparişi oluşturmak

Kullanıcı deneyimi

İhtiyacınız olan kullanıcı bilgilerini edindikten sonra, kullanıcıyı rezervasyonunu oluşturması için yönlendiren bir "alışveriş sepeti montajı" deneyimi oluşturun. Her İşlemin sunduğu hizmete uygun alışveriş sepeti montaj akışı biraz farklı olacaktır.

Temel bir alışveriş sepeti montaj deneyiminde kullanıcı, listeden rezervasyonuna eklemek için seçenekler belirler. Ancak siz konuşmayı kullanıcı deneyimini kolaylaştıracak şekilde tasarlayabilirsiniz. Örneğin, kullanıcının basit bir evet-hayır sorusuyla aylık rezervasyon planlaması yapmasını sağlayan bir alışveriş sepeti montaj deneyimi oluşturun. Ayrıca kullanıcıya "önerilen" rezervasyonlardan oluşan bir bant veya liste kartı sunabilirsiniz.

Kullanıcıya seçeneklerini görsel olarak sunmak için zengin yanıtlar kullanmanızı öneririz. Ancak aynı zamanda konuşmayı, kullanıcının yalnızca sesini kullanarak alışveriş sepetini oluşturabileceği şekilde tasarlamanızı öneririz. Bazı en iyi uygulamalar ve alışveriş sepeti derleme deneyimleriyle ilgili örnekler için İşlem Tasarım Yönergeleri'ne bakın.

Sipariş karşılama

Görüşmeniz boyunca, kullanıcının satın almak istediği rezervasyon ayrıntılarını toplayın ve ardından bir Order nesnesi oluşturun.

Order size en az şunları içermelidir:

  • buyerInfo - Rezervasyonu programlayan kullanıcı hakkında bilgiler.
  • transactionMerchant - Rezervasyonu kolaylaştıran satıcıyla ilgili bilgiler.
  • contents - lineItems olarak listelenen rezervasyonun gerçek ayrıntıları.

Alışveriş sepetinizi oluşturmak için Order yanıt belgelerini inceleyin. Rezervasyona bağlı olarak farklı alanlar eklemeniz gerekebileceğini unutmayın.

Aşağıdaki örnek kod, isteğe bağlı alanlar da dahil olmak üzere eksiksiz bir rezervasyon siparişini göstermektedir:

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

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "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. Siparişi öner

Onaylaması veya reddetmesi için rezervasyon siparişinizi kullanıcıya gösterin. actions.intent.TRANSACTION_DECISION amacını isteyin ve derlediğiniz Order öğesini sağlayın.

Kullanıcı Deneyimi

actions.intent.TRANSACTION_DECISION amacını istediğinizde Asistan, Order öğesinin doğrudan "alışveriş sepeti önizleme kartı" üzerinde oluşturulduğu yerleşik bir deneyim başlatır. Kullanıcı, "rezervasyon yap" diyebilir, işlemi reddedebilir veya rezervasyon ayrıntılarını değiştirme isteğinde bulunabilir.

Kullanıcı bu noktada sipariş için değişiklik isteğinde de bulunabilir. Bu durumda, alışveriş sepeti montajı deneyimini tamamladıktan sonra sipariş karşılama işleminizin sipariş değişikliği isteklerini karşılayabileceğinden emin olmanız gerekir.

Sipariş karşılama

actions.intent.TRANSACTION_DECISION amacını istediğinizde Order ve orderOptions öğelerini içeren bir TransactionDecision oluşturun

Aşağıdaki kodda sipariş için örnek TransactionsDecision gösterilmektedir:

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

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "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

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "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"
            }
          }
        }
      ]
    }
  ]
}
Kullanıcının kararını işleme

Kullanıcı önerilen siparişe yanıt verdikten sonra, istek karşılama mantığınız TransactionDecisionValue içeren bir bağımsız değişkenle actions_intent_TRANSACTION_DECISION amacını alır. Bu değer şunları içerir:

  • transactionDecision - Kullanıcının önerilen siparişle ilgili kararı. Olası değerler ORDER_ACCEPTED, ORDER_REJECTED, CART_CHANGE_REQUESTED ve USER_CANNOT_TRANSACT'dir.

Bu isteği işlemek için actions_intent_TRANSACTION_DECISION etkinliği tarafından tetiklenen bir Dialogflow niyeti tanımlayın. İstek karşılamada bu amacı ele alın:

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

Aşağıdaki JSON'un bir webhook isteğini açıkladığını unutmayın.

{
  "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

Aşağıdaki JSON'un bir webhook isteğini açıkladığını unutmayın.

{
  "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. Rezervasyonu tamamlama ve makbuz gönderme

actions.intent.TRANSACTION_DECISION niyeti, transactionDecision değerindeki ORDER_ACCEPTED değeri ile geri döndüğünde rezervasyonu planlamak için gerekli olan işlemleri gerçekleştirin (bunu kendi veritabanınızda tutmak gibi).

Görüşmenin devam etmesini sağlamak için basit bir yanıt gönderin. Kullanıcı, yanıtınızla birlikte bir "daraltılmış makbuz kartı" alır.

Sipariş karşılama

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

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "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

Aşağıdaki JSON'un bir webhook yanıtını açıkladığını unutmayın.

{
  "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. Sipariş güncellemeleri gönder

Rezervasyon durumu, kullanım ömrü boyunca değişir. Kullanıcıyı, HTTP PATCH istekleri içeren rezervasyon siparişi güncellemelerini, sipariş durumunu ve ayrıntılarını içeren Orders API'ye gönderin.

Orders API'ye eşzamansız istekler oluşturma

Orders API'ye gönderilen sipariş güncelleme istekleri, erişim jetonuyla yetkilendirilir. Siparişler API'ye YAMA YAYAMAK için Actions Console projenizle ilişkili bir JSON hizmet hesabı anahtarı indirin, ardından hizmet hesabı anahtarını, HTTP isteğinin Authorization başlığına iletilebilecek bir hamiline ait jetonla değiştirin.

Hizmet hesabı anahtarınızı almak için aşağıdaki adımları uygulayın:

  1. Google Cloud konsolunda, Menü değişikliği > API'ler ve Hizmetler > Kimlik bilgileri > Kimlik bilgisi oluştur > Hizmet hesabı anahtarı'na gidin.
  2. Service Account (Hizmet Hesabı) bölümünde New Service Account (Yeni Hizmet Hesabı) seçeneğini belirleyin.
  3. Hizmet hesabını service-account olarak ayarlayın.
  4. RolProje > Sahip olarak ayarlayın.
  5. Anahtar türünü JSON olarak ayarlayın.
  6. Oluştur'u seçin.
  7. Özel bir JSON hizmet hesabı anahtarı yerel makinenize indirilir.

Sipariş güncelleme kodunuzda, Google API'leri istemci kitaplığını ve "https://www.googleapis.com/auth/actions.order.developer" kapsamını kullanarak hizmet anahtarınızı hamiline ait jetonla değiştirin. Kurulum adımlarını ve örnekleri API istemci kitaplığı GitHub sayfasında bulabilirsiniz.

Örnek anahtar değişimi için Node.js ve Java örneklerimizde order-update.js referansına bakın.

Sipariş güncellemeleri gönder

Hizmet hesabı anahtarınızı OAuth hamiline ait jetonla değiştirdikten sonra, sipariş güncellemelerini Siparişler API'sine yetkili PATCH istekleri olarak gönderin.

Siparişler API URL'si: PATCH https://actions.googleapis.com/v3/orders/${orderId}

İsteğinizde aşağıdaki başlıkları sağlayın:

  • Hizmet hesabı anahtarınızı değiştirdiğiniz OAuth hamiline ait jetonla "Authorization: Bearer token".
  • "Content-Type: application/json".

YAMA isteği, aşağıdaki biçimde bir JSON gövdesi almalıdır:

{ "orderUpdate": OrderUpdate }

OrderUpdate nesnesi, aşağıdaki üst düzey alanlardan oluşur:

  • updateMask - Güncellediğiniz siparişin alanları. Rezervasyon durumunu güncellemek için değeri reservation.status, reservation.userVisibleStatusLabel olarak ayarlayın.
  • order - Güncellemenin içeriği. Rezervasyonun içeriğini güncelliyorsanız değeri, güncellenen Order nesnesine ayarlayın. Sadece rezervasyonun durumunu güncelliyorsanız (örneğin, "PENDING" değerinden "FULFILLED" değerine) nesne aşağıdaki alanları içerir:

    • merchantOrderId: Order nesnenizde ayarladığınız kimlik.
    • lastUpdateTime - Bu güncellemenin zaman damgası.
    • purchase - Aşağıdakileri içeren bir nesne:
      • status - Siparişin ReservationStatus olarak durumu (ör. "CONFIRMED" veya "CANCELLED").
      • userVisibleStatusLabel: Sipariş durumuyla ilgili ayrıntıları (ör. "Rezervasyonunuz onaylandı") sağlayan, kullanıcıya gösterilen etiket.
  • userNotification nesnesi. Bu nesnenin dahil edilmesinin, kullanıcının cihazında bir bildirimin görüneceğini garanti etmediğini unutmayın.

Aşağıdaki örnek kod, rezervasyon siparişinin durumunu FULFILLED olarak güncelleyen bir OrderUpdate örneğini gösterir:

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);
Rezervasyon durumunu ayarlama

Sipariş güncellemesinin ReservationStatus değeri, siparişin mevcut durumunu açıklayıcı olmalıdır. Güncellemenizin order.ReservationStatus alanında aşağıdaki değerlerden birini kullanın:

  • PENDING - Rezervasyon İşleminiz tarafından "oluşturulmuş" ancak arka uçunuzda ek işlem yapılması gerekiyor.
  • CONFIRMED - Rezervasyon, planlama arka uçunuzda onaylanmıştır.
  • CANCELLED - Kullanıcı rezervasyonunu iptal etti.
  • FULFILLED - Kullanıcının rezervasyonu hizmet tarafından yerine getirildi.
  • CHANGE_REQUESTED - Kullanıcı, rezervasyonda değişiklik isteğinde bulundu ve değişiklik işleniyor.
  • REJECTED - Rezervasyonu işleyemediyseniz veya başka bir şekilde onaylayamadıysanız.

Rezervasyonunuzla ilgili her durum için sipariş güncellemeleri gönderin. Örneğin, rezervasyonunuz istendiğinde rezervasyonu onaylamak için manuel işlem gerektiriyorsa ek işlem tamamlanana kadar PENDING sipariş güncellemesi gönderin. Her rezervasyon için her durum değeri gerekli değildir.

Sorun giderme

Test sırasında herhangi bir sorunla karşılaşırsanız işlemlerle ilgili sorun giderme adımlarımızı okuyun.