Tworzenie rezerwacji (Dialogflow)

Z tego przewodnika dowiesz się, jak tworzyć projekt w Actions. który do składania rezerwacji używa interfejsu Orders API.

Przepływ transakcji

Gdy projekt w Actions obsługuje rezerwacje, korzysta z takiego procesu:

  1. Wymagania dotyczące weryfikacji transakcji (opcjonalnie) – użyj asystenta wymagań dotyczących transakcji na początku rozmowy, aby upewnić się, że użytkownik może realizowania transakcji.
  2. Ustal kolejność – pokaż użytkownikowi „skład koszyka” gdzie podają szczegóły rezerwacji.
  3. Zaproponuj zamówienie – gdy „koszyk” zakończono, zaproponuj „zamówienie” rezerwacji do użytkownika, aby mógł potwierdzić, że jest poprawny. Jeśli rezerwacja zostanie potwierdzona, otrzyma odpowiedź ze szczegółami rezerwacji.
  4. Sfinalizuj zamówienie i wyślij potwierdzenie – po potwierdzeniu zamówienia zaktualizuj do systemu rezerwacji i wysłać rachunek po stronie użytkownika.
  5. Wysyłaj aktualne informacje o zamówieniu – w trakcie okresu ważności rezerwacji aktualizować stan rezerwacji użytkownika, wysyłając żądania PATCH do Orders API.

Ograniczenia i wytyczne dotyczące sprawdzania

Pamiętaj, że w przypadku akcji, które korzystają z transakcji i interfejsu Orders API, obowiązują dodatkowe zasady. Sprawdzanie działań z transakcjami może zająć do 6 tygodni, więc uwzględnij ten czas w planowaniu harmonogramu publikacji. Aby uprościć proces weryfikacji, przed przesłaniem akcji do sprawdzenia upewnij się, że przestrzegasz zasad i wytycznych dotyczących transakcji.

Działania używające interfejsu Orders API możesz wdrażać tylko w tych krajach:

Australia
Brazylia
Kanada
Indonezja,
Japonia
Meksyk
Katar
Rosja
Singapur
Szwajcaria
Tajlandia
Turcja
Wielka Brytania
Stany Zjednoczone

Kompilowanie projektu

Obszerne przykłady rozmów transakcyjnych znajdziesz w przykładach transakcji w środowiskach Node.js i Java.

Konfigurowanie projektu

Tworząc akcję, musisz określić, że chcesz dokonywać transakcji. w Konsoli działań. Poza tym, jeśli za pomocą biblioteki klienta Node.JS, skonfiguruj realizację tak, aby wykorzystywała korzystając z interfejsu Orders API.

Aby skonfigurować projekt i realizację:

  1. Utwórz nowy projekt lub zaimportuj istniejący.
  2. Przejdź do Wdróż > Informacje o katalogu.
  3. W sekcji Dodatkowe informacje > Transakcje > zaznacz pole z napisem „Wykonuj działania”. używać interfejsu Transaction API do przeprowadzania transakcji na towary fizyczne?”.

  4. Jeśli do tworzenia realizacji akcji używasz biblioteki klienta Node.JS, otwórz kod realizacji i zaktualizuj przekazywanie danych aplikacji, aby ustawić flaga ordersv3 do: true. Ten fragment kodu pokazuje przykładową aplikację deklaracja dotycząca wersji 3 usługi Orders.

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. Wymagania dotyczące weryfikacji transakcji (opcjonalne)

Interfejs użytkownika

Gdy tylko użytkownik wskaże, że chce utworzyć rezerwację, zalecamy aktywowanie reguły actions.intent.TRANSACTION_REQUIREMENTS_CHECK chce zapewnić tę możliwość poprosić o rezerwację. Akcja może na przykład zapytać: „Czy chcesz zarezerwować miejsce?” Jeśli użytkownik mówi „tak”, zgłoś tę intencję jak najszybciej. Dzięki temu że można kontynuować i dać mu szansę na poprawienie ustawień, co uniemożliwia kontynuowanie transakcji.

Wysyłanie próśb o transakcje wymaga sprawdzenia, aby intencje były zgodne z jednym z tych wyników:

  • Jeśli wymagania są spełnione, realizacja otrzymuje intencję z atrybutem możesz kontynuować tworzenie zamówienia użytkownika.
  • Jeśli co najmniej jedno z wymagań nie spełnia tego wymogu, intencję z warunkiem błędu. W takim przypadku zakończ rozmowę lub odejść od procesu rezerwacji.

    Jeśli użytkownik może naprawić błąd, zostanie automatycznie poproszony o rozwiązanie problemu. na swoim urządzeniu. czy rozmowa odbywa się na platformie z włączonym głosem; jak inteligentny głośnik – przekaz jest przekazywany na telefon użytkownika.

Realizacja

Aby użytkownicy spełniali wymagania dotyczące transakcji, żądanie spełnienia Intencja actions.intent.TRANSACTION_REQUIREMENTS_CHECK ze obiektu TransactionRequirementsCheckSpec.

Sprawdź wymagania

Sprawdź, czy użytkownik spełnia wymagania dotyczące rezerwacji w bibliotece klienta:

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

Pamiętaj, że poniższy kod JSON opisuje odpowiedź webhooka.

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

Pamiętaj, że poniższy kod JSON opisuje odpowiedź webhooka.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
          }
        }
      ]
    }
  ]
}
Otrzymaj wynik kontroli wymagań

Gdy Asystent spełni intencję, wysyła żądanie dotyczące jej realizacji. z intencją actions.intent.TRANSACTION_REQUIREMENTS_CHECK i wynikiem weryfikacji.

Aby prawidłowo obsługiwać to żądanie, zadeklaruj intencję Dialogflow aktywowaną przez zdarzenie actions_intent_TRANSACTION_REQUIREMENTS_CHECK. Po uruchomieniu obsługuj tę intencję w swojej realizacji:

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

Zwróć uwagę, że poniższy kod JSON opisuje żądanie webhooka.

{
  "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": ""
}
Plik JSON z pakietu SDK Actions

Zwróć uwagę, że poniższy kod JSON opisuje żądanie webhooka.

{
  "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. Tworzenie zamówienia

Interfejs użytkownika

Po zgromadzeniu potrzebnych informacji o użytkowniku utwórz „koszyk”, montaż” która pomaga użytkownikowi zrobić rezerwację. Co Procedura składania koszyka będzie wyglądał trochę inaczej, zależnie od potrzeb posprzedażna.

W podstawowym procesie składania koszyka użytkownik wybiera z listy opcje, które chce dodać do rezerwacji, chociaż możesz tak zaplanować rozmowę, aby uprościć użytkowników. Stwórz na przykład środowisko składania koszyków, które umożliwia zarezerwowanie miesięcznej rezerwacji, odpowiadając na pytanie typu „tak” lub „nie”. Możesz też pokazać użytkownikowi kartę karuzeli lub z listą „Polecane” rezerwacji.

Zalecamy użycie formatu multimedialnego odpowiedzi, aby przedstawić opcje użytkownika, również wizualnie, ale też zaprojektować rozmowę w taki sposób, aby użytkownik tylko za pomocą głosu. Kilka sprawdzonych metod i przykładów procesu składania koszyków, zapoznaj się ze wskazówkami dotyczącymi projektowania transakcji.

Realizacja

Podczas rozmowy zbieraj szczegóły rezerwacji potrzebne użytkownikowi. kupić ją, a potem utworzyć obiekt Order.

Order musi zawierać przynajmniej:

  • buyerInfo – informacje o użytkowniku planującym rezerwację.
  • transactionMerchant – informacje o sprzedawcy, który ułatwia korzystanie z usługi. rezerwacji.
  • contents – rzeczywiste szczegóły rezerwacji wymienione jako lineItems.
.

Zapoznaj się z dokumentacją odpowiedzi Order. aby utworzyć koszyk. Pamiętaj, że może być konieczne uwzględnienie innych pól w zależności od rezerwacji.

Przykładowy kod poniżej przedstawia kompletne zamówienie rezerwacji, w tym pola opcjonalne:

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

Pamiętaj, że poniższy kod JSON opisuje odpowiedź webhooka.

{
  "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. Zaproponuj zamówienie

Przedstaw użytkownikowi zamówienie rezerwacji, aby mógł je potwierdzić lub odrzuć. Poproś o actions.intent.TRANSACTION_DECISION i udostępnij stworzony przez siebie zasób Order.

Wygoda użytkowników

Gdy poprosisz o intencję actions.intent.TRANSACTION_DECISION, Asystent uruchamia wbudowane środowisko, w którym Order jest renderowanych bezpośrednio na „karcie podglądu koszyka”. Użytkownik może powiedzieć „zaplanuj rezerwację”, odrzucić transakcję lub poprosić o zmianę szczegółów rezerwacji.

Na tym etapie użytkownik może również poprosić o zmianę zamówienia. W tym przypadku musisz się upewnić, że Twoja realizacja będzie mogła obsługiwać prośby o zmianę zamówienia po i kończę składanie koszyka.

Realizacja

Gdy poprosisz o Intencja actions.intent.TRANSACTION_DECISION, utwórz TransactionDecision, która zawiera Order i orderOptions

Poniżej znajduje się przykładowy TransactionsDecision dla zamówienia:

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

Pamiętaj, że poniższy kod JSON opisuje odpowiedź webhooka.

{
  "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"
          }
        }
      }
    }
  }
}
Plik JSON z pakietu SDK Actions

Pamiętaj, że poniższy kod JSON opisuje odpowiedź webhooka.

{
  "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"
            }
          }
        }
      ]
    }
  ]
}
Podejmowanie decyzji użytkownika

Gdy użytkownik odpowie na proponowane zamówienie, Twoja realizacja otrzyma Intencja actions_intent_TRANSACTION_DECISION z argumentem zawierającym TransactionDecisionValue Ta wartość będzie zawierać:

  • transactionDecision – decyzja użytkownika w sprawie proponowanej zamówienie. Możliwe wartości to ORDER_ACCEPTED, ORDER_REJECTED, CART_CHANGE_REQUESTED i USER_CANNOT_TRANSACT.

Aby obsłużyć to żądanie, zadeklaruj intencję Dialogflow, która jest aktywowana przez zdarzenie actions_intent_TRANSACTION_DECISION. Obsługuj tę intencję w realizację:

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

Zwróć uwagę, że poniższy kod JSON opisuje żądanie webhooka.

{
  "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": ""
}
Plik JSON z pakietu SDK Actions

Zwróć uwagę, że poniższy kod JSON opisuje żądanie webhooka.

{
  "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. Dokończ rezerwację i wyślij rachunek

Gdy intencja actions.intent.TRANSACTION_DECISION zwraca się z parametrem transactionDecision z ORDER_ACCEPTED, wykonaj dowolną do zaplanowania rezerwacji jest wymagane przetwarzanie (np. przechowywanie dzięki własnej bazie danych).

Wyślij prostą odpowiedź aby podtrzymywać kontakt z widzami. Użytkownik otrzymuje „zwinięta kartę z potwierdzeniem zakupu” wraz z Twoją odpowiedzią.

Realizacja

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

Pamiętaj, że poniższy kod JSON opisuje odpowiedź webhooka.

{
  "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"
                }
              }
            }
          }
        ]
      }
    }
  }
}
Plik JSON z pakietu SDK Actions

Pamiętaj, że poniższy kod JSON opisuje odpowiedź webhooka.

{
  "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. Wysyłaj aktualne informacje o zamówieniu

Stan rezerwacji zmienia się w ciągu od początku jego istnienia. Wysyłaj aktualizacje dotyczące zamówień z rezerwacją użytkownika przez HTTP Żądania PATCH wysyłane do interfejsu Orders API zawierające stan i szczegóły zamówienia.

Konfigurowanie żądań asynchronicznych do interfejsu Orders API

Żądania aktualizacji zamówień do interfejsu Orders API są autoryzowane przez dostęp token. Aby uzupełnić aktualizację zamówienia do interfejsu Orders API, pobierz plik JSON klucz konta usługi powiązany z projektem w Konsoli Actions, a następnie klucz konta usługi dla tokena okaziciela, który można przekazać do Nagłówek Authorization żądania HTTP.

Aby pobrać klucz konta usługi, wykonaj te czynności:

  1. W konsoli Google Cloud: przejdź do Menu &#9776 > Interfejsy API Usługi > Dane logowania > Utwórz dane logowania > Klucz konta usługi.
  2. W sekcji Konto usługi wybierz Nowe konto usługi.
  3. Ustaw konto usługi na service-account.
  4. Ustaw Rola na Projekt > Właściciel.
  5. Ustaw typ klucza na JSON.
  6. Kliknij Utwórz.
  7. Prywatny klucz konta usługi JSON zostanie pobrany na Twój komputer lokalny.

W kodzie aktualizacji zamówienia wymień klucz usługi na token okaziciela za pomocą biblioteki klienta interfejsów API Google i zakresu &quot;https://www.googleapis.com/auth/actions.order.developer&quot;. Instrukcje instalacji i opis znajdziesz znajdziesz na stronie GitHub biblioteki klienta interfejsów API.

Odwołaj się do order-update.js w naszych przykładach Node.js i Java dla przykładową wymianę kluczy.

Wysyłaj aktualne informacje o zamówieniu

Po wymianie klucza konta usługi na token okaziciela OAuth wyślij aktualizacje zamówień jako autoryzowane żądania PATCH wysyłane do interfejsu Orders API.

Adres URL interfejsu Orders API: PATCH https://actions.googleapis.com/v3/orders/${orderId}

Umieść w żądaniu te nagłówki:

  • "Authorization: Bearer token" z tokenem okaziciela OAuth dla którego wymieniono klucz konta usługi.
  • "Content-Type: application/json".

Żądanie PATCH powinno przyjąć treść JSON w tym formacie:

{ "orderUpdate": OrderUpdate }

OrderUpdate obiekt składa się z następujących pól najwyższego poziomu:

  • updateMask – pola aktualizowanego zamówienia. Aby zaktualizować stan rezerwacji, ustaw wartość na reservation.status, reservation.userVisibleStatusLabel.
  • order – zawartość aktualizacji. Jeśli aktualizujesz treści rezerwacji, ustaw wartość na zaktualizowany obiekt Order. Jeśli tylko aktualizujesz stan rezerwacji (na przykład z od "PENDING" do "FULFILLED"), obiekt zawiera tych pól:

    • merchantOrderId – identyfikator, który został ustawiony w obiekcie Order.
    • lastUpdateTime – sygnatura czasowa aktualizacji.
    • purchase – obiekt zawierający:
      • status – stan zamówienia (ReservationStatus), na przykład „CONFIRMED” lub „CANCELLED”.
      • userVisibleStatusLabel – etykieta dla użytkownika zawierająca szczegółowe informacje stan zamówienia, np. „Rezerwacja została potwierdzona”.
  • userNotification (opcjonalnie) – A userNotification do wyświetlenia na urządzeniu użytkownika po wysłaniu tej aktualizacji. Notatka że uwzględnienie tego obiektu nie gwarantuje, że powiadomienie na urządzeniu użytkownika.

Poniżej znajduje się przykładowy kod OrderUpdate, który aktualizuje stan zamówienia rezerwacji na 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);
Ustawianie stanu rezerwacji

Identyfikator ReservationStatus aktualizacji zamówienia musi opisywać bieżący stan zamówienia. W grupie order.ReservationStatus aktualizacji użyj jednej z tych wartości:

  • PENDING – rezerwacja została „utworzona” przez akcję, ale wymaga dodatkowe przetwarzanie w Twoim zapleczu.
  • CONFIRMED – rezerwacja została potwierdzona w backendzie do planowania.
  • CANCELLED – użytkownik anulował rezerwację.
  • FULFILLED – rezerwacja użytkownika została zrealizowana przez usługę.
  • CHANGE_REQUESTED – użytkownik poprosił o zmianę rezerwacji, która została wprowadzona. w trakcie przetwarzania danych.
  • REJECTED – jeśli nie udało się przetworzyć lub masz inne problemy potwierdzić rezerwację.

Wysyłaj aktualne informacje o zamówieniach o każdym stanie powiązanym z rezerwacji. Jeśli na przykład Twoja rezerwacja wymaga ręcznego przetwarzania, aby potwierdź rezerwację po przesłaniu prośby, wyślij aktualizację dotyczącą zamówienia u sprzedawcy PENDING do że jest wykonywane dodatkowe przetwarzanie. Nie każda rezerwacja wymaga każdej wartości stanu.

Rozwiązywanie problemów

Jeśli podczas testowania wystąpią jakiekolwiek problemy, przeczytaj artykuł o rozwiązywaniu problemów. transakcji.