Tạo khoảng trống đặt trước (Dialogflow)

Hướng dẫn này sẽ trình bày quy trình phát triển một dự án Hành động có sử dụng API đơn đặt hàng để đặt trước.

Luồng giao dịch

Khi dự án Actions của bạn xử lý các mục đặt trước, dự án đó sẽ sử dụng quy trình sau:

  1. Xác thực các yêu cầu về giao dịch (không bắt buộc) – Sử dụng trình trợ giúp đáp ứng yêu cầu về giao dịch khi bắt đầu cuộc trò chuyện để đảm bảo người dùng có thể thực hiện một giao dịch.
  2. Tạo đơn đặt hàng – Hướng dẫn người dùng thực hiện quy trình "tập hợp giỏ hàng" để họ tạo thông tin chi tiết cho giao dịch đặt trước.
  3. Đề xuất đơn đặt hàng – Sau khi "giỏ hàng" hoàn tất, hãy đề xuất "đơn đặt hàng" đặt trước cho người dùng để họ có thể xác nhận đặt hàng là chính xác. Nếu yêu cầu đặt trước được xác nhận, bạn sẽ nhận được phản hồi kèm theo thông tin đặt trước.
  4. Hoàn tất đơn đặt hàng và gửi biên nhận – Sau khi xác nhận đơn đặt hàng, hãy cập nhật hệ thống đặt chỗ của bạn và gửi biên nhận cho người dùng.
  5. Gửi thông tin cập nhật về đơn đặt hàng – Trong suốt thời gian hoạt động của yêu cầu đặt trước, hãy cung cấp thông tin cập nhật về trạng thái đặt trước của người dùng bằng cách gửi yêu cầu PATCH tới API đơn đặt hàng.

Các quy định hạn chế và nguyên tắc về bài đánh giá

Xin lưu ý rằng các chính sách bổ sung áp dụng cho những Hành động sử dụng API giao dịch và đơn đặt hàng. Có thể mất đến 6 tuần để chúng tôi xem xét Hành động có giao dịch, vì vậy, hãy tính thời gian đó khi lên kế hoạch cho lịch phát hành. Để quá trình xem xét diễn ra dễ dàng hơn, hãy đảm bảo bạn tuân thủ các chính sách và nguyên tắc về giao dịch trước khi gửi Hành động đi xem xét.

Bạn chỉ có thể triển khai Hành động sử dụng API Đơn đặt hàng ở những quốc gia sau đây:

Úc
Brazil
Canada
Indonesia
Nhật Bản
Mexico
Qatar
Nga
Singapore
Thuỵ Sĩ
Thái Lan
Thổ Nhĩ Kỳ
Vương quốc Anh
Hoa Kỳ

Xây dựng dự án của bạn

Để biết ví dụ bao quát về các cuộc trò chuyện giao dịch, hãy xem mẫu giao dịch của chúng tôi trong Node.jsJava.

Thiết lập dự án

Khi tạo Hành động, bạn phải chỉ định rằng bạn muốn thực hiện giao dịch trong Bảng điều khiển Actions. Ngoài ra, nếu bạn đang sử dụng thư viện ứng dụng Node.JS, hãy thiết lập phương thức thực hiện để sử dụng phiên bản mới nhất của API Đơn đặt hàng.

Để thiết lập dự án và phương thức thực hiện, hãy làm như sau:

  1. Tạo dự án mới hoặc nhập dự án hiện có.
  2. Chuyển đến phần Triển khai > Thông tin thư mục.
  3. Trong phần Thông tin bổ sung > Giao dịch >, hãy đánh dấu hộp có nội dung "Hành động của bạn có sử dụng API Giao dịch để thực hiện các giao dịch đối với hàng hoá thực không?".

  4. Nếu bạn đang dùng thư viện ứng dụng Node.JS để tạo phương thức thực hiện cho Hành động, hãy mở mã phương thức thực hiện và cập nhật lệnh phân tách ứng dụng để đặt cờ ordersv3 thành true. Đoạn mã sau đây minh hoạ nội dung khai báo ứng dụng mẫu cho Đơn đặt hàng phiên bản 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. Xác thực các yêu cầu về giao dịch (không bắt buộc)

Trải nghiệm người dùng

Ngay khi người dùng cho biết họ muốn thiết lập yêu cầu đặt trước, bạn nên kích hoạt ý định actions.intent.TRANSACTION_REQUIREMENTS_CHECK để đảm bảo họ có thể yêu cầu đặt trước. Ví dụ: khi được gọi, Hành động của bạn có thể hỏi "bạn có muốn đặt chỗ ngồi không?" Nếu người dùng trả lời "có", bạn nên yêu cầu ý định này ngay lập tức. Điều này sẽ đảm bảo rằng họ có thể tiếp tục và tạo cơ hội để họ khắc phục mọi chế độ cài đặt khiến họ không thể tiếp tục giao dịch.

Việc yêu cầu ý định kiểm tra các yêu cầu về giao dịch sẽ dẫn đến một trong các kết quả sau:

  • Nếu đáp ứng các yêu cầu, phương thức thực hiện của bạn sẽ nhận được một ý định với điều kiện thành công và bạn có thể tiếp tục tạo đơn đặt hàng của người dùng.
  • Nếu một hoặc nhiều yêu cầu không có, thì phương thức thực hiện của bạn sẽ nhận được ý định kèm theo điều kiện lỗi. Trong trường hợp này, hãy kết thúc cuộc trò chuyện hoặc chuyển hướng khỏi quy trình đặt trước.

    Nếu người dùng có thể khắc phục lỗi, họ sẽ tự động nhận được lời nhắc giải quyết những vấn đề đó trên thiết bị. Nếu cuộc trò chuyện diễn ra trên nền tảng chỉ có giọng nói, chẳng hạn như loa thông minh, thì cuộc trò chuyện sẽ được chuyển đến điện thoại của người dùng.

Quy trình thực hiện đơn hàng

Để đảm bảo người dùng đáp ứng các yêu cầu của giao dịch, hãy yêu cầu thực hiện ý định actions.intent.TRANSACTION_REQUIREMENTS_CHECK bằng đối tượng TransactionRequirementsCheckSpec.

Kiểm tra các yêu cầu

Kiểm tra xem người dùng có đáp ứng các yêu cầu đặt trước với thư viện ứng dụng hay không:

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

Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.

{
  "payload": {
    "google": {
      "expectUserResponse": true,
      "systemIntent": {
        "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
        "data": {
          "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
        }
      }
    }
  }
}
Định dạng JSON cho SDK Hành động

Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckSpec"
          }
        }
      ]
    }
  ]
}
Nhận kết quả kiểm tra các yêu cầu

Sau khi thực hiện ý định, Trợ lý sẽ gửi yêu cầu thực hiện bằng ý định actions.intent.TRANSACTION_REQUIREMENTS_CHECK kèm theo kết quả kiểm tra.

Để xử lý yêu cầu này đúng cách, hãy khai báo một ý định Dialogflow được sự kiện actions_intent_TRANSACTION_REQUIREMENTS_CHECK kích hoạt. Khi được kích hoạt, hãy xử lý ý định này trong phương thức thực hiện của bạ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

Xin lưu ý rằng JSON ở bên dưới mô tả một yêu cầu 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": ""
}
Định dạng JSON cho SDK Hành động

Xin lưu ý rằng JSON ở bên dưới mô tả một yêu cầu 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. Tạo đơn đặt hàng

Trải nghiệm người dùng

Sau khi bạn có thông tin người dùng cần thiết, hãy tạo trải nghiệm "tập hợp giỏ hàng" để hướng dẫn người dùng tạo mục hàng đặt trước. Mỗi Hành động sẽ có quy trình tập hợp giỏ hàng hơi khác một chút, phù hợp với dịch vụ của chúng.

Trong trải nghiệm tập hợp giỏ hàng cơ bản, người dùng sẽ chọn các tuỳ chọn trong một danh sách để thêm vào mục đặt trước của mình, mặc dù bạn có thể thiết kế cuộc trò chuyện để đơn giản hoá trải nghiệm người dùng. Ví dụ: tạo trải nghiệm tập hợp giỏ hàng cho phép người dùng lên lịch đặt trước hằng tháng chỉ với câu hỏi đơn giản có hoặc không. Bạn cũng có thể hiển thị cho người dùng băng chuyền hoặc thẻ danh sách các mục đặt trước "nên dùng".

Bạn nên sử dụng phản hồi đa dạng thức để trình bày trực quan các lựa chọn của người dùng, đồng thời thiết kế cuộc trò chuyện để người dùng có thể tạo giỏ hàng chỉ bằng giọng nói. Để biết một số phương pháp hay nhất và ví dụ về trải nghiệm tập hợp giỏ hàng, hãy xem Nguyên tắc thiết kế giao dịch.

Quy trình thực hiện đơn hàng

Trong suốt cuộc trò chuyện, hãy thu thập thông tin đặt trước mà người dùng muốn mua, sau đó tạo đối tượng Order.

Order của bạn ít nhất phải chứa:

  • buyerInfo – Thông tin về người dùng lên lịch đặt chỗ.
  • transactionMerchant – Thông tin về người bán đang hỗ trợ đặt trước.
  • contents – Thông tin thực tế về yêu cầu đặt chỗ được liệt kê là lineItems.

Tham khảo tài liệu về phản hồi Order để tạo giỏ hàng. Xin lưu ý rằng bạn có thể cần phải bao gồm nhiều trường khác nhau tuỳ thuộc vào yêu cầu đặt trước.

Mã mẫu dưới đây cho thấy một đơn đặt hàng đặt trước hoàn chỉnh, bao gồm cả các trường không bắt buộc:

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

Xin lưu ý rằng JSON dưới đây mô tả phản hồi 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. Đề xuất đơn đặt hàng

Hiển thị đơn đặt hàng đặt trước của bạn cho người dùng để họ xác nhận hoặc từ chối. Yêu cầu ý định actions.intent.TRANSACTION_DECISION và cung cấp Order mà bạn đã tạo.

Trải nghiệm Người dùng

Khi bạn yêu cầu ý định actions.intent.TRANSACTION_DECISION, Trợ lý sẽ bắt đầu một trải nghiệm tích hợp, trong đó Order được hiển thị trực tiếp vào "thẻ xem trước giỏ hàng". Người dùng có thể nói "lên lịch đặt chỗ", từ chối giao dịch hoặc yêu cầu thay đổi thông tin đặt trước.

Người dùng cũng có thể yêu cầu thay đổi đơn đặt hàng tại thời điểm này. Trong trường hợp này, bạn nên đảm bảo phương thức thực hiện của mình có thể xử lý các yêu cầu thay đổi đơn đặt hàng sau khi hoàn tất trải nghiệm lắp ráp giỏ hàng.

Quy trình thực hiện đơn hàng

Khi bạn yêu cầu ý định actions.intent.TRANSACTION_DECISION, hãy tạo một TransactionDecision chứa OrderorderOptions

Mã sau đây minh hoạ TransactionsDecision mẫu cho một đơn đặt hàng:

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

Xin lưu ý rằng JSON dưới đây mô tả phản hồi 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"
          }
        }
      }
    }
  }
}
Định dạng JSON cho SDK Hành động

Xin lưu ý rằng JSON dưới đây mô tả phản hồi 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"
            }
          }
        }
      ]
    }
  ]
}
Xử lý quyết định của người dùng

Sau khi người dùng phản hồi đơn đặt hàng đề xuất, phương thức thực hiện của bạn sẽ nhận được ý định actions_intent_TRANSACTION_DECISION với một đối số chứa TransactionDecisionValue. Giá trị này sẽ chứa:

  • transactionDecision – Quyết định của người dùng liên quan đến đơn đặt hàng được đề xuất. Các giá trị có thể là ORDER_ACCEPTED, ORDER_REJECTED, CART_CHANGE_REQUESTEDUSER_CANNOT_TRANSACT.

Để xử lý yêu cầu này, hãy khai báo một ý định Dialogflow được sự kiện actions_intent_TRANSACTION_DECISION kích hoạt. Xử lý ý định này trong quá trình thực hiện của bạ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

Xin lưu ý rằng JSON ở bên dưới mô tả một yêu cầu 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": ""
}
Định dạng JSON cho SDK Hành động

Xin lưu ý rằng JSON ở bên dưới mô tả một yêu cầu 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. Hoàn tất yêu cầu đặt chỗ và gửi biên nhận

Khi ý định actions.intent.TRANSACTION_DECISION trả về với transactionDecisionORDER_ACCEPTED, hãy thực hiện mọi hoạt động xử lý cần thiết để lên lịch đặt trước (chẳng hạn như lưu giữ ý định đó trong cơ sở dữ liệu của riêng bạn).

Gửi một câu trả lời đơn giản để duy trì cuộc trò chuyện. Người dùng sẽ nhận được một "thẻ biên nhận đã thu gọn" cùng với phản hồi của bạn.

Quy trình thực hiện đơn hàng

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

Xin lưu ý rằng JSON dưới đây mô tả phản hồi 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"
                }
              }
            }
          }
        ]
      }
    }
  }
}
Định dạng JSON cho SDK Hành động

Xin lưu ý rằng JSON dưới đây mô tả phản hồi 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. Gửi thông tin cập nhật về đơn đặt hàng

Trạng thái đặt trước sẽ thay đổi trong suốt thời gian hoạt động. Gửi thông tin cập nhật về đơn đặt hàng đặt trước của người dùng bằng yêu cầu PATCH HTTP tới API đơn đặt hàng, trong đó chứa trạng thái và thông tin chi tiết về đơn đặt hàng.

Thiết lập các yêu cầu không đồng bộ cho API đơn đặt hàng

Các yêu cầu cập nhật đơn đặt hàng đối với API Đơn đặt hàng được uỷ quyền bằng một mã truy cập. Để PATCH cập nhật đơn đặt hàng lên API đơn đặt hàng, hãy tải khoá tài khoản dịch vụ JSON liên kết với dự án Actions Console của bạn, sau đó đổi khoá tài khoản dịch vụ lấy mã thông báo truy cập có thể được truyền vào tiêu đề Authorization của yêu cầu HTTP.

Để truy xuất khoá tài khoản dịch vụ của bạn, hãy thực hiện các bước sau:

  1. Trong Google Cloud Console, hãy chuyển đến Trình đơn STDEV > API và Dịch vụ > Thông tin xác thực > Tạo thông tin xác thực > Khoá tài khoản dịch vụ.
  2. Trong phần Tài khoản dịch vụ, hãy chọn Tài khoản dịch vụ mới.
  3. Đặt tài khoản dịch vụ thành service-account.
  4. Đặt Role thành Project > Owner (Dự án > Chủ sở hữu).
  5. Đặt loại khoá thành JSON.
  6. Chọn Tạo.
  7. Khoá tài khoản dịch vụ JSON riêng tư sẽ được tải xuống máy cục bộ của bạn.

Trong mã cập nhật đơn đặt hàng của bạn, hãy đổi khoá dịch vụ lấy mã thông báo truy cập bằng cách sử dụng thư viện ứng dụng API của Google và phạm vi "https://www.googleapis.com/auth/actions.order.developer". Bạn có thể tìm thấy các bước cài đặt và ví dụ trên trang GitHub của thư viện ứng dụng API.

Hãy tham khảo order-update.js trong các mẫu Node.jsJava của chúng tôi để xem một ví dụ về trao đổi khoá.

Gửi thông tin cập nhật về đơn đặt hàng

Sau khi bạn đã đổi khoá tài khoản dịch vụ của mình lấy mã thông báo truy cập OAuth, hãy gửi thông tin cập nhật đơn đặt hàng dưới dạng yêu cầu PATCH được uỷ quyền tới API đơn đặt hàng.

URL của API Đơn đặt hàng: PATCH https://actions.googleapis.com/v3/orders/${orderId}

Cung cấp các tiêu đề sau trong yêu cầu của bạn:

  • "Authorization: Bearer token" bằng mã thông báo truy cập OAuth mà bạn đã đổi khoá tài khoản dịch vụ của mình.
  • "Content-Type: application/json".

Yêu cầu PATCH phải có nội dung JSON có định dạng sau:

{ "orderUpdate": OrderUpdate }

Đối tượng OrderUpdate bao gồm các trường cấp cao nhất sau đây:

  • updateMask – Các trường của đơn đặt hàng bạn đang cập nhật. Để cập nhật trạng thái đặt trước, hãy đặt giá trị thành reservation.status, reservation.userVisibleStatusLabel.
  • order – Nội dung của bản cập nhật. Nếu bạn đang cập nhật nội dung của phần đặt trước, hãy đặt giá trị thành đối tượng Order cập nhật. Nếu bạn chỉ cập nhật trạng thái của yêu cầu đặt trước (ví dụ: từ "PENDING" thành "FULFILLED"), thì đối tượng này sẽ chứa các trường sau:

    • merchantOrderId – Mã nhận dạng mà bạn đã đặt cho đối tượng Order.
    • lastUpdateTime – Dấu thời gian của lần cập nhật này.
    • purchase – Đối tượng chứa:
      • status – Trạng thái của đơn đặt hàng dưới dạng ReservationStatus, chẳng hạn như "CONFIRMED" hoặc "CANCELLED".
      • userVisibleStatusLabel – Một nhãn dành cho người dùng, cung cấp thông tin chi tiết về trạng thái đơn đặt hàng, chẳng hạn như "Yêu cầu đặt chỗ của bạn đã được xác nhận".
  • userNotification có thể hiển thị trên thiết bị của người dùng khi bản cập nhật này được gửi. Xin lưu ý rằng việc thêm đối tượng này không đảm bảo rằng thông báo sẽ xuất hiện trên thiết bị của người dùng.

Mã mẫu sau đây minh hoạ một OrderUpdate mẫu cập nhật trạng thái của đơn đặt hàng trước thành 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);
Đặt trạng thái đặt chỗ

ReservationStatus của bản cập nhật đơn đặt hàng phải mô tả trạng thái hiện tại của đơn đặt hàng. Trong trường order.ReservationStatus của bản cập nhật, hãy dùng một trong những giá trị sau:

  • PENDING – Hành động của bạn đã "tạo" yêu cầu đặt chỗ nhưng cần xử lý thêm trên máy chủ phụ trợ.
  • CONFIRMED – Yêu cầu đặt chỗ đã được xác nhận trong phần phụ trợ lập lịch biểu của bạn.
  • CANCELLED – Người dùng đã huỷ yêu cầu đặt chỗ.
  • FULFILLED – Yêu cầu đặt chỗ của người dùng đã được dịch vụ thực hiện.
  • CHANGE_REQUESTED – Người dùng đã yêu cầu thay đổi thông tin đặt trước và thay đổi đó đang được xử lý.
  • REJECTED – Nếu bạn không thể xử lý hoặc xác nhận yêu cầu đặt phòng.

Gửi thông tin cập nhật về đơn đặt hàng cho từng trạng thái liên quan đến yêu cầu đặt trước của bạn. Ví dụ: nếu yêu cầu đặt trước của bạn yêu cầu xử lý thủ công để xác nhận việc đặt trước sau khi được yêu cầu, hãy gửi thông tin cập nhật về đơn đặt hàng PENDING cho đến khi quá trình xử lý bổ sung đó hoàn tất. Không phải lượt đặt trước nào cũng yêu cầu tất cả giá trị trạng thái.

Khắc phục sự cố

Nếu bạn gặp vấn đề nào trong quá trình kiểm thử, hãy đọc các bước khắc phục sự cố của chúng tôi để biết thông tin về các giao dịch.