Reservasi build (Dialogflow)

Panduan ini akan memandu Anda menjalani proses pengembangan project Action yang menggunakan Orders API untuk melakukan reservasi.

Alur transaksi

Saat project Action Anda menangani reservasi, project tersebut menggunakan alur berikut:

  1. Validasi persyaratan transaksi (opsional) - Gunakan helper persyaratan transaksi di awal percakapan untuk memastikan pengguna dapat melakukan transaksi.
  2. Membuat pesanan - Pandu pengguna untuk melakukan "perakitan keranjang" tempat mereka membuat detail reservasi.
  3. Mengusulkan pesanan - Setelah "keranjang" selesai, ajukan "pesanan" reservasi kepada pengguna, agar mereka dapat mengonfirmasi bahwa pesanan sudah benar. Jika reservasi dikonfirmasi, Anda akan menerima respons dengan detail reservasi.
  4. Menyelesaikan pesanan dan mengirim tanda terima - Setelah pesanan dikonfirmasi, update sistem reservasi Anda dan kirim tanda terima kepada pengguna.
  5. Mengirim pembaruan pesanan - Selama masa aktif reservasi, berikan pembaruan status reservasi pengguna dengan mengirimkan permintaan PATCH ke Orders API.

Pembatasan dan panduan peninjauan

Perlu diingat bahwa kebijakan tambahan berlaku untuk Action yang menggunakan transaksi dan Orders API. Kami membutuhkan waktu hingga enam minggu untuk meninjau Action dengan transaksi, jadi pertimbangkan waktu tersebut saat merencanakan jadwal rilis Anda. Untuk memudahkan proses peninjauan, pastikan Anda mematuhi kebijakan dan panduan untuk transaksi sebelum mengirimkan Action untuk ditinjau.

Anda hanya dapat men-deploy Action yang menggunakan Orders API di negara berikut:

Australia
Brasil
Kanada
Indonesia
Jepang
Meksiko
Qatar
Rusia
Singapura
Swiss
Thailand
Turki
Inggris Raya
Amerika Serikat

Mem-build project Anda

Untuk contoh lengkap percakapan transaksional, lihat contoh transaksi kami di Node.js dan Java.

Penyiapan project

Saat membuat Action, Anda harus menentukan bahwa Anda ingin melakukan transaksi di Konsol Actions. Selain itu, jika Anda menggunakan library klien Node.JS, siapkan fulfillment Anda untuk menggunakan Orders API versi terbaru.

Untuk menyiapkan project dan fulfillment Anda, lakukan hal berikut:

  1. Buat project baru atau impor project yang ada.
  2. Buka Deploy > Directory information.
  3. Di bagian Additional information > Transactions > centang kotak yang bertuliskan "Apakah Actions Anda menggunakan Transactions API untuk melakukan transaksi barang fisik?".

  4. Jika Anda menggunakan library klien Node.JS untuk mem-build fulfillment Action, buka kode fulfillment Anda dan update delkarasi aplikasi untuk menetapkan tanda ordersv3 ke true. Cuplikan kode berikut menunjukkan contoh deklarasi aplikasi untuk Pesanan versi 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. Memvalidasi persyaratan transaksi (opsional)

Pengalaman pengguna

Segera setelah pengguna menunjukkan bahwa mereka ingin menyiapkan reservasi, sebaiknya picu intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK untuk memastikan mereka dapat meminta reservasi. Misalnya, saat dipanggil, Action Anda mungkin bertanya, "apakah Anda ingin memesan tempat?" Jika pengguna mengatakan "yes", Anda harus segera meminta intent ini. Tindakan ini akan memastikan pengguna dapat melanjutkan dan memberi mereka kesempatan untuk memperbaiki setelan yang mencegah mereka melanjutkan transaksi.

Meminta intent pemeriksaan persyaratan transaksi akan menghasilkan salah satu hasil berikut:

  • Jika persyaratannya terpenuhi, fulfillment Anda akan menerima intent dengan kondisi berhasil dan Anda dapat melanjutkan pembuatan pesanan pengguna.
  • Jika satu atau beberapa persyaratan tidak, fulfillment Anda akan menerima intent dengan kondisi gagal. Dalam hal ini, akhiri percakapan atau beralih dari alur reservasi.

    Jika dapat memperbaiki error, pengguna akan otomatis diminta untuk menyelesaikan masalah tersebut di perangkat. Jika percakapan berlangsung di permukaan khusus suara seperti smart speaker, percakapan tersebut diteruskan ke ponsel pengguna.

Pemenuhan pemesanan

Untuk memastikan pengguna memenuhi persyaratan transaksi, minta fulfillment intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK dengan objek TransactionRequirementsCheckSpec.

Memeriksa persyaratan

Periksa untuk melihat apakah pengguna memenuhi persyaratan reservasi dengan library klien:

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

Perhatikan bahwa JSON di bawah menjelaskan respons webhook.

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

Perhatikan bahwa JSON di bawah menjelaskan respons webhook.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
          }
        }
      ]
    }
  ]
}
Menerima hasil pemeriksaan persyaratan

Setelah memenuhi intent, Asisten akan mengirimkan permintaan fulfillment dengan intent actions.intent.TRANSACTION_REQUIREMENTS_CHECK dengan hasil pemeriksaan.

Untuk menangani permintaan ini dengan benar, deklarasikan intent Dialogflow yang dipicu oleh peristiwa actions_intent_TRANSACTION_REQUIREMENTS_CHECK. Saat dipicu, tangani intent ini dalam fulfillment Anda:

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

Perhatikan bahwa JSON di bawah menjelaskan permintaan webhook.

{
  "responseId": "",
  "queryResult": {
    "queryText": "",
    "action": "",
    "parameters": {},
    "allRequiredParamsPresent": true,
    "fulfillmentText": "",
    "fulfillmentMessages": [],
    "outputContexts": [],
    "intent": {
      "name": "reservation_transaction_check_complete_df",
      "displayName": "reservation_transaction_check_complete_df"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": ""
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          }
        ]
      },
      "inputs": [
        {
          "rawInputs": [],
          "intent": "",
          "arguments": [
            {
              "extension": {
                "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult",
                "resultType": "CAN_TRANSACT"
              },
              "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT"
            }
          ]
        }
      ],
      "user": {},
      "conversation": {},
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "session": ""
}
JSON SDK Tindakan

Perhatikan bahwa JSON di bawah menjelaskan permintaan webhook.

{
  "user": {},
  "device": {},
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      }
    ]
  },
  "conversation": {},
  "inputs": [
    {
      "rawInputs": [],
      "intent": "reservation_transaction_check_complete_asdk",
      "arguments": [
        {
          "extension": {
            "@type": "type.googleapis.com/google.transactions.v3.TransactionRequirementsCheckResult",
            "resultType": "CAN_TRANSACT"
          },
          "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT"
        }
      ]
    }
  ],
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

2. Membuat pesanan

Pengalaman pengguna

Setelah Anda memiliki informasi pengguna yang dibutuhkan, buat pengalaman "keranjang keranjang" yang memandu pengguna untuk melakukan reservasi. Setiap Action akan memiliki alur perakitan keranjang yang sedikit berbeda yang sesuai untuk layanannya.

Dalam pengalaman penggabungan keranjang dasar, pengguna memilih opsi dari daftar untuk ditambahkan ke reservasi mereka, meskipun Anda dapat mendesain percakapan untuk menyederhanakan pengalaman pengguna. Misalnya, buat pengalaman perakitan keranjang yang memungkinkan pengguna menjadwalkan reservasi bulanan dengan pertanyaan ya atau tidak yang sederhana. Anda juga dapat menampilkan carousel atau kartu daftar reservasi "direkomendasikan" kepada pengguna.

Sebaiknya gunakan respons lengkap untuk menampilkan opsi pengguna secara visual, sekaligus desain percakapan agar pengguna dapat membuat keranjang hanya menggunakan suara. Untuk beberapa praktik terbaik dan contoh pengalaman perakitan keranjang, lihat Panduan Desain Transaksi.

Pemenuhan pemesanan

Selama percakapan Anda, kumpulkan detail reservasi yang ingin dibeli pengguna, lalu buat objek Order.

Order Anda setidaknya harus berisi hal berikut:

  • buyerInfo - Informasi tentang pengguna yang menjadwalkan reservasi.
  • transactionMerchant - Informasi tentang penjual yang memfasilitasi reservasi.
  • contents - Detail reservasi sebenarnya yang tercantum sebagai lineItems.

Lihat dokumentasi respons Order untuk membuat keranjang. Perhatikan bahwa Anda mungkin perlu menyertakan kolom yang berbeda, bergantung pada reservasi.

Kode contoh di bawah menunjukkan pesanan reservasi lengkap, termasuk kolom opsional:

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

Perhatikan bahwa JSON di bawah menjelaskan respons webhook.

{
  "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. Mengusulkan pesanan

Tunjukkan pesanan reservasi Anda kepada pengguna agar mereka dapat mengonfirmasi atau menolak. Minta intent actions.intent.TRANSACTION_DECISION dan berikan Order yang Anda build.

Pengalaman Pengguna

Saat Anda meminta intent actions.intent.TRANSACTION_DECISION, Asisten akan memulai pengalaman bawaan tempat Order dirender langsung ke "kartu pratinjau keranjang". Pengguna bisa mengatakan "jadwalkan reservasi", menolak transaksi, atau meminta untuk mengubah detail reservasi.

Pada tahap ini, pengguna juga dapat meminta perubahan pesanan. Dalam hal ini, Anda harus memastikan fulfillment dapat menangani permintaan perubahan pesanan setelah menyelesaikan pengalaman perakitan keranjang.

Pemenuhan pemesanan

Saat Anda meminta intent actions.intent.TRANSACTION_DECISION, buat TransactionDecision yang berisi Order dan orderOptions

Kode berikut menunjukkan contoh TransactionsDecision untuk pesanan:

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

Perhatikan bahwa JSON di bawah menjelaskan respons webhook.

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

Perhatikan bahwa JSON di bawah menjelaskan respons webhook.

{
  "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"
            }
          }
        }
      ]
    }
  ]
}
Menangani keputusan pengguna

Setelah pengguna merespons pesanan yang diusulkan, fulfillment Anda akan menerima intent actions_intent_TRANSACTION_DECISION dengan argumen yang berisi TransactionDecisionValue. Nilai ini akan berisi hal berikut:

  • transactionDecision - Keputusan pengguna terkait pesanan yang diusulkan. Kemungkinan nilainya adalah ORDER_ACCEPTED, ORDER_REJECTED, CART_CHANGE_REQUESTED, dan USER_CANNOT_TRANSACT.

Untuk menangani permintaan ini, deklarasikan intent Dialogflow yang dipicu oleh peristiwa actions_intent_TRANSACTION_DECISION. Tangani intent ini dalam fulfillment Anda:

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

Perhatikan bahwa JSON di bawah menjelaskan permintaan webhook.

{
  "responseId": "",
  "queryResult": {
    "queryText": "",
    "action": "",
    "parameters": {},
    "allRequiredParamsPresent": true,
    "fulfillmentText": "",
    "fulfillmentMessages": [],
    "outputContexts": [],
    "intent": {
      "name": "reservation_get_transaction_decision_df",
      "displayName": "reservation_get_transaction_decision_df"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {},
    "languageCode": ""
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          }
        ]
      },
      "inputs": [
        {
          "rawInputs": [],
          "intent": "",
          "arguments": []
        }
      ],
      "user": {},
      "conversation": {},
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "session": ""
}
JSON SDK Tindakan

Perhatikan bahwa JSON di bawah menjelaskan permintaan webhook.

{
  "user": {},
  "device": {},
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      }
    ]
  },
  "conversation": {},
  "inputs": [
    {
      "rawInputs": [],
      "intent": "reservation_get_transaction_decision_asdk",
      "arguments": []
    }
  ],
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

4. Selesaikan reservasi dan kirim tanda terima

Saat intent actions.intent.TRANSACTION_DECISION ditampilkan dengan transactionDecision dari ORDER_ACCEPTED, lakukan pemrosesan apa pun yang diperlukan untuk menjadwalkan reservasi (seperti mempertahankannya di database Anda sendiri).

Kirim respons sederhana untuk menjaga percakapan tetap berjalan. Pengguna akan menerima "kartu tanda terima yang diciutkan" beserta respons Anda.

Pemenuhan pemesanan

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

Perhatikan bahwa JSON di bawah menjelaskan respons webhook.

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

Perhatikan bahwa JSON di bawah menjelaskan respons webhook.

{
  "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. Kirim pembaruan pesanan

Status reservasi akan berubah selama masa aktifnya. Mengirim pembaruan pesanan reservasi pengguna dengan permintaan PATCH HTTP ke Orders API, yang berisi status dan detail pesanan.

Menyiapkan permintaan asinkron ke Orders API

Permintaan pembaruan pesanan ke Orders API diotorisasi oleh token akses. Untuk mem-PATCH pembaruan pesanan ke Orders API, download kunci akun layanan JSON yang terkait dengan project Konsol Actions Anda, lalu tukar kunci akun layanan dengan token pemilik yang dapat diteruskan ke header Authorization permintaan HTTP.

Untuk mengambil kunci akun layanan, lakukan langkah-langkah berikut:

  1. Di Konsol Google Cloud, buka Menu Changes > API & Layanan > Kredensial > Buat kredensial > Kunci akun layanan.
  2. Pada Akun Layanan, pilih Akun Layanan Baru.
  3. Tetapkan akun layanan ke service-account.
  4. Tetapkan Role ke Project > Owner.
  5. Tetapkan jenis kunci ke JSON.
  6. Pilih Create.
  7. Kunci akun layanan JSON pribadi akan didownload ke komputer lokal Anda.

Dalam kode pembaruan pesanan Anda, tukar kunci layanan dengan token pemilik menggunakan library klien Google API dan cakupan "https://www.googleapis.com/auth/actions.order.developer". Anda dapat menemukan langkah-langkah penginstalan dan contoh di halaman GitHub library klien API.

Referensikan order-update.js dalam contoh Node.js dan Java kami untuk pertukaran kunci contoh.

Kirim pembaruan pesanan

Setelah menukar kunci akun layanan dengan token pemilik OAuth, kirim pembaruan pesanan sebagai permintaan PATCH yang diotorisasi ke Orders API.

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

Masukkan header berikut dalam permintaan Anda:

  • "Authorization: Bearer token" dengan token pemilik OAuth yang Anda tukarkan kunci akun layanannya.
  • "Content-Type: application/json".

Permintaan PATCH harus mengambil isi JSON dari format berikut:

{ "orderUpdate": OrderUpdate }

Objek OrderUpdate terdiri dari kolom level teratas berikut:

  • updateMask - Kolom pesanan yang Anda perbarui. Untuk memperbarui status reservasi, tetapkan nilai ke reservation.status, reservation.userVisibleStatusLabel.
  • order - Konten update. Jika Anda memperbarui konten reservasi, tetapkan nilai ke objek Order yang diperbarui. Jika Anda hanya memperbarui status reservasi (misalnya, dari "PENDING" menjadi "FULFILLED"), objek akan berisi kolom berikut:

    • merchantOrderId - ID yang sama dengan yang Anda tetapkan dalam objek Order.
    • lastUpdateTime - Stempel waktu update ini.
    • purchase - Objek yang berisi hal berikut:
      • status - Status pesanan sebagai ReservationStatus, seperti "CONFIRMED" atau "CANCELLED".
      • userVisibleStatusLabel - Label yang ditampilkan kepada pengguna yang memberikan detail tentang status pesanan, seperti "Reservasi Anda telah dikonfirmasi".
  • userNotification yang dapat ditampilkan di perangkat pengguna saat update ini dikirim. Perhatikan bahwa menyertakan objek ini tidak menjamin notifikasi muncul di perangkat pengguna.

Kode contoh berikut menunjukkan contoh OrderUpdate yang memperbarui status pesanan reservasi menjadi 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);
Menetapkan status reservasi

ReservationStatus pembaruan pesanan harus deskriptif tentang status pesanan saat ini. Di kolom order.ReservationStatus update Anda, gunakan salah satu nilai berikut:

  • PENDING - Reservasi telah "dibuat" oleh Action Anda, tetapi memerlukan pemrosesan tambahan pada backend Anda.
  • CONFIRMED - Reservasi telah dikonfirmasi di back-end penjadwalan Anda.
  • CANCELLED - Pengguna membatalkan reservasinya.
  • FULFILLED - Reservasi pengguna dipenuhi oleh layanan.
  • CHANGE_REQUESTED - Pengguna meminta perubahan pada reservasi, dan perubahan sedang diproses.
  • REJECTED - Jika Anda tidak dapat memproses atau mengonfirmasi reservasi.

Mengirim pembaruan pesanan untuk setiap status yang relevan dengan reservasi Anda. Misalnya, jika reservasi Anda memerlukan pemrosesan manual untuk mengonfirmasi reservasi setelah diminta, kirim pembaruan pesanan PENDING hingga pemrosesan tambahan selesai. Tidak semua reservasi memerlukan setiap nilai status.

Pemecahan masalah

Jika Anda mengalami masalah selama pengujian, baca langkah pemecahan masalah untuk transaksi.