Xây dựng giao dịch thực bằng phương thức thanh toán do người bán quản lý (Dialogflow)

Hướng dẫn này sẽ chỉ cho bạn quy trình phát triển một dự án Hành động kết hợp các giao dịch cho hàng hoá thực bằng cách sử dụng các phương thức thanh toán do trang web của bạn quản lý.

Luồng giao dịch

Khi dự án Actions của bạn xử lý các giao dịch thực bằng khoản thanh toán do người bán quản lý, sử dụng quy trình sau:

  1. Thu thập thông tin (không bắt buộc) – Tuỳ thuộc vào tính chất của thông tin giao dịch, bạn có thể muốn thu thập các thông tin sau đây từ người dùng ngay từ đầu của cuộc trò chuyện:
    1. Xác thực các yêu cầu về giao dịch – Sử dụng công cụ trợ giúp về yêu cầu giao dịch ở đầu cuộc trò chuyện để đảm bảo thông tin thanh toán của người dùng được định cấu hình đúng cách và có sẵn trước khi người dùng tạo giỏ hàng.
    2. Yêu cầu địa chỉ giao hàng – Nếu giao dịch của bạn cần phải giao hàng địa chỉ, yêu cầu thực hiện ý định của trình trợ giúp về địa chỉ giao hàng để thu thập dữ liệu từ người dùng.
  2. Tạo đơn đặt hàng – Hướng dẫn người dùng tìm hiểu "lắp ráp giỏ hàng" nơi họ chọn những mặt hàng họ muốn mua.
  3. Thực hiện liên kết tài khoản - Để người dùng sử dụng thanh toán mà họ đã lưu với dịch vụ của bạn, hãy sử dụng tính năng Liên kết tài khoản để liên kết Tài khoản Google của họ với tài khoản của họ trên dịch vụ của bạn.
  4. Đề xuất đơn đặt hàng - Sau khi giỏ hàng hoàn tất, hãy đề xuất đơn đặt hàng cho người dùng để họ có thể xác nhận rằng thông tin đó là chính xác. Nếu đơn đặt hàng được xác nhận, bạn sẽ sẽ nhận được phản hồi kèm theo chi tiết đơn đặt hàng và mã thông báo thanh toán.
  5. Hoàn tất đơn đặt hàng và gửi biên nhận – Sau khi đơn đặt hàng được xác nhận, hãy cập nhật theo dõi kho hàng hoặc các dịch vụ thực hiện đơn hàng khác, rồi gửi biên nhận cho người dùng.
  6. Gửi thông tin cập nhật về đơn đặt hàng – Trong suốt thời gian thực hiện đơn đặt hàng, cập nhật đơn đặt hàng của người dùng bằng cách gửi yêu cầu PATCH đến Đơn đặt hàng API.

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 Hành động có giao dịch. Chúng tôi có thể mất đến 6 tuần để xem xét các 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 suôn sẻ, hãy đảm bảo rằng bạn tuân thủ các chính sách và nguyên tắc đối với 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 bán hàng hoá thực ở các quốc gia sau:

Úc
Braxin
Canada
Indonesia
Nhật Bản
Mexico
Quatar
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 thêm ví dụ về các cuộc trò chuyện giao dịch, hãy xem các 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 nêu rõ 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 bằng cách 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 của bạn để sử dụng phiên bản của Orders API.

Để 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 về thư mục.
  3. Trong Thông tin bổ sung > Giao dịch > chọn hộp có nội dung "Thực hiện hành động của bạn sử dụng API Giao dịch để thực hiện các giao dịch hàng hoá thực tế không?".

  4. Nếu bạn đang dùng thư viện ứng dụng Node.JS để xây dựng phương thức thực hiện cho Hành động, mở mã thực hiện đơn hàng rồi cập nhật quá trình tách biệt ứng dụng để đặt giá trị ordersv3 gắn cờ thành true. Đoạn mã sau đây cho thấy một ứng dụng mẫu khai báo 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,
});

Thiết lập đăng nhập

Khi tính phí người dùng bằng phương thức thanh toán của riêng mình, bạn nên liên kết Tài khoản Google của họ với tài khoản họ có với dịch vụ của riêng bạn để truy xuất, trình bày và tính phí các phương thức thanh toán được lưu trữ trong đó.

Chúng tôi cung cấp tính năng liên kết tài khoản OAuth 2.0 để đáp ứng điều này . Bạn nên bật quy trình Xác nhận OAuth 2.0 vì quy trình này mang lại trải nghiệm người dùng rất đơn giản.

Chúng tôi cung cấp ý định actions.intent.SIGN_IN, cho phép bạn yêu cầu một người dùng liên kết tài khoản giữa cuộc trò chuyện. Bạn phải bật tính năng liên kết tài khoản trong Bảng điều khiển Actions để sử dụng Ý định actions.intent.SIGN_IN.

Bạn nên sử dụng ý định này nếu không thể tìm thấy accessToken trong User đối tượng trong yêu cầu webhook. Điều này có nghĩa là người dùng chưa đã liên kết tài khoản của mình.

Sau khi yêu cầu ý định actions.intent.SIGN_IN, bạn sẽ nhận được một Argument chứa SignInStatus có giá trị là "OK", "CANCELLED" hoặc "ERROR". Nếu trạng thái là "OK", bạn sẽ có thể thấy accessToken trong đối tượng User.

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

Yêu cầu đăng nhập

Node.js

app.intent('Sign In', (conv) => {
  conv.ask(new SignIn('To get your account details'));
});

Node.js

conv.ask(new SignIn('To get your account details'));

Java

@ForIntent("Sign In")
public ActionResponse signIn(ActionRequest request) {
  return getResponseBuilder(request).add(
      new SignIn()
          .setContext("To get your account details"))
      .build();
}

Java

return getResponseBuilder(request).add(
    new SignIn()
        .setContext("To get your account details"))
    .build();

JSON

{
    "payload": {
      "google": {
        "expectUserResponse": true,
        "systemIntent": {
          "intent": "actions.intent.SIGN_IN",
          "data": {
            "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec",
            "optContext": "To get your account details"
          }
        }
      }
    }
  }

JSON

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.SIGN_IN",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec",
            "optContext": "To get your account details"
          }
        }
      ]
    }
  ],
  "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
}
Nhận kết quả đăng nhập

Node.js

app.intent('Sign In Complete', (conv, params, signin) => {
  if (signin.status !== 'OK') {
    conv.ask('You need to sign in before making a transaction.');
  } else {
    const accessToken = conv.user.access.token;
    // possibly do something with access token
    conv.ask('You must meet all the requirements necessary ' +
      'to make a transaction. Try saying ' +
      '"check transaction requirements".');
      conv.ask(new Suggestions(`check requirements`));
  }
});

Node.js

app.intent('actions.intent.SIGN_IN', (conv, params, signin) => {
  if (signin.status !== 'OK') {
    conv.ask('You need to sign in before making a transaction.');
  } else {
    const accessToken = conv.user.access.token;
    // possibly do something with access token
    conv.ask('You must meet all the requirements necessary ' +
      'to make a transaction. Try saying ' +
      '"check transaction requirements".');
      conv.ask(new Suggestions(`check requirements`));
  }
});

Java

@ForIntent("Sign In Complete")
public ActionResponse signInComplete(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.isSignInGranted()) {
    responseBuilder
        .add("You must meet all the requirements necessary to make a " +
            "transaction. Try saying \"check transaction requirements\".")
        .addSuggestions(new String[] {
            "check requirements"
        });
  } else {
    responseBuilder.add("You need to sign in before making a transaction.");
  }
  return responseBuilder.build();
}

Java

@ForIntent("actions.intent.SIGN_IN")
public ActionResponse signInComplete(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.isSignInGranted()) {
    responseBuilder
        .add("You must meet all the requirements necessary to make a " +
            "transaction. Try saying \"check transaction requirements\".")
        .addSuggestions(new String[] {
            "check requirements"
        });
  } else {
    responseBuilder.add("You need to sign in before making a transaction.");
  }
  return responseBuilder.build();
}

JSON

{
    "responseId": "d2123d8d-3f00-466e-b5a9-1a4ed53a7cb7-594de0a7",
    "queryResult": {
      "queryText": "actions_intent_SIGN_IN",
      "parameters": {},
      "allRequiredParamsPresent": true,
      "fulfillmentMessages": [
        {
          "text": {
            "text": [
              ""
            ]
          }
        }
      ],
      "outputContexts": [
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/merchant_payment",
          "lifespanCount": 2
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_web_browser"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_screen_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_account_linking"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_media_response_audio"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_audio_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/google_assistant_input_type_keyboard"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_intent_sign_in",
          "parameters": {
            "SIGN_IN": {
              "@type": "type.googleapis.com/google.actions.v2.SignInValue",
              "status": "OK"
            },
            "text": ""
          }
        }
      ],
      "intent": {
        "name": "projects/df-transactions/agent/intents/105b925b-b186-4f5d-8bde-a9a782a0fa9f",
        "displayName": "Sign In Complete"
      },
      "intentDetectionConfidence": 1,
      "languageCode": "en"
    },
    "originalDetectIntentRequest": {
      "source": "google",
      "version": "2",
      "payload": {
        "user": {
          "locale": "en-US",
          "lastSeen": "2019-09-23T19:49:18Z",
          "userVerificationStatus": "VERIFIED"
        },
        "conversation": {
          "conversationId": "ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy",
          "type": "ACTIVE",
          "conversationToken": "[]"
        },
        "inputs": [
          {
            "intent": "actions.intent.SIGN_IN",
            "rawInputs": [
              {
                "inputType": "KEYBOARD"
              }
            ],
            "arguments": [
              {
                "name": "SIGN_IN",
                "extension": {
                  "@type": "type.googleapis.com/google.actions.v2.SignInValue",
                  "status": "OK"
                }
              },
              {
                "name": "text"
              }
            ]
          }
        ],
        "surface": {
          "capabilities": [
            {
              "name": "actions.capability.WEB_BROWSER"
            },
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.ACCOUNT_LINKING"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            }
          ]
        },
        "availableSurfaces": [
          {
            "capabilities": [
              {
                "name": "actions.capability.WEB_BROWSER"
              },
              {
                "name": "actions.capability.AUDIO_OUTPUT"
              },
              {
                "name": "actions.capability.SCREEN_OUTPUT"
              }
            ]
          }
        ]
      }
    },
    "session": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy"
  }

JSON

{
  "user": {
    "locale": "en-US",
    "lastSeen": "2019-11-11T23:55:52Z",
    "userVerificationStatus": "VERIFIED"
  },
  "conversation": {
    "conversationId": "ABwppHGFwStZlYaQ9YT8rg9t_idVsxZrku1pUDrEbGSJmSUMatVdPwPEEQSCe1IwIBoN4sS4Weyn9pmgetEgbsWgw3JSvQmw",
    "type": "ACTIVE",
    "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.SIGN_IN",
      "rawInputs": [
        {}
      ],
      "arguments": [
        {
          "name": "SIGN_IN",
          "extension": {
            "@type": "type.googleapis.com/google.actions.v2.SignInValue",
            "status": "OK"
          }
        },
        {
          "name": "text"
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.ACCOUNT_LINKING"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      }
    ]
  },
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

1. Thu thập thông tin (không bắt buộc)

1a. 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

Kích hoạt ý định actions.intent.TRANSACTION_REQUIREMENTS_CHECK để nhanh chóng kiểm tra xem người dùng có thể thực hiện giao dịch hay không. Chiến dịch này sẽ đảm bảo người dùng có thể tiếp tục và tạo cơ hội để họ sửa mọi chế độ cài đặt ngăn họ thực hiện giao dịch.

Ví dụ: khi được gọi, Hành động của bạn có thể yêu cầu: "bạn muốn đặt hàng giày hay kiểm tra số dư tài khoản?" Nếu người dùng nói "đặt hàng giày", bạn nên yêu cầu ý định này ngay lập tức để đảm bảo họ có thể tiếp tục và cho họ cơ hội khắc phục bất kỳ chế độ cài đặt nào ngăn họ tiếp tục giao dịch.

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

  • Nếu đáp ứng các yêu cầu, ý định sẽ được gửi lại cho phương thức thực hiện của bạn kèm theo một điều kiện thành công và bạn có thể tiến hành tạo đơn đặt hàng của người dùng.
  • Nếu không thể đáp ứng một hoặc nhiều yêu cầu, ý định sẽ được gửi lại cho phương thức thực hiện có điều kiện lỗi. Trong trường hợp này, bạn nên chuyển hướng tránh xa trải nghiệm giao dịch hoặc kết thúc cuộc trò chuyện.
    • Nếu người dùng có thể khắc phục bất kỳ lỗi nào dẫn đến trạng thái lỗi, con sẽ được nhắc giải quyết những vấn đề đó trên thiết bị. Nếu cuộc trò chuyện đang diễn ra trên nền tảng chỉ có giọng nói, tính năng chuyển giao sẽ được bắt đầu đế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 về giao dịch, thực hiện yêu cầu Ý định actions.intent.TRANSACTION_REQUIREMENTS_CHECK bằng một Đối tượng TransactionRequirementsCheckSpec.

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

Bạn có thể kiểm tra xem người dùng có đáp ứng các yêu cầu giao dịch hay không bằng cách sử dụng thư viện ứng dụng:

Node.js

conv.ask(new TransactionRequirements());

Node.js

conv.ask(new TransactionRequirements());

Java

return getResponseBuilder(request)
    .add(new TransactionRequirements())
    .build();

Java

return getResponseBuilder(request)
    .add(new TransactionRequirements())
    .build();

JSON

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

JSON

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TEXT"
        }
      ],
      "inputPrompt": {
        "richInitialPrompt": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "Looks like you're good to go! Next I'll need your delivery address.Try saying \"get delivery address\"."
              }
            }
          ],
          "suggestions": [
            {
              "title": "get delivery address"
            }
          ]
        }
      }
    }
  ],
  "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
}
Nhận kết quả kiểm tra yêu cầu

Sau khi thực hiện ý định, Trợ lý sẽ gửi cho bạn một yêu cầu thực hiện với ý định actions.intent.TRANSACTION_REQUIREMENTS_CHECK kèm theo kết quả của séc. Để xử lý yêu cầu này đúng cách, hãy khai báo ý định Dialogflow được kích hoạt bởi sự kiện actions_intent_TRANSACTION_REQUIREMENTS_CHECK. Khi được kích hoạt, xử lý trong phương thức thực hiện bằng cách sử dụng thư viện ứng dụng:

Node.js

app.intent('Transaction Check Complete', (conv) => {
  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! ` +
      `Next I'll need your delivery address.` +
      `Try saying "get delivery address".`);
    conv.ask(new Suggestions('get delivery address'));
  } else {
    // Exit conversation
    conv.close('Transaction failed.');
  }
});

Node.js

app.intent('actions.intent.TRANSACTION_REQUIREMENTS_CHECK', (conv) => {
  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! ` +
      `Next I'll need your delivery address.` +
      `Try saying "get delivery address".`);
    conv.ask(new Suggestions('get delivery address'));
  } else {
    // Exit conversation
    conv.close('Transaction failed.');
  }
});

Java

@ForIntent("Transaction Check Complete")
public ActionResponse transactionCheckComplete(ActionRequest request) {
  LOGGER.info("Checking Transaction Requirements Result.");

  // Check result of transaction requirements check
  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) {
    // Normally take the user through cart building flow
    responseBuilder
        .add("Looks like you're good to go! Next " +
            "I'll need your delivery address. Try saying " +
            "\"get delivery address\".")
        .addSuggestions(new String[]{"get delivery address"});
  } else {
    // Exit conversation
    responseBuilder.add("Transaction failed.");
  }
  return responseBuilder.build();
}

Java

@ForIntent("actions.intent.TRANSACTION_REQUIREMENTS_CHECK")
public ActionResponse transactionCheckComplete(ActionRequest request) {
  LOGGER.info("Checking Transaction Requirements Result.");

  // Check result of transaction requirements check
  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) {
    // Normally take the user through cart building flow
    responseBuilder
        .add("Looks like you're good to go! Next " +
            "I'll need your delivery address. Try saying " +
            "\"get delivery address\".")
        .addSuggestions(new String[]{"get delivery address"});
  } else {
    // Exit conversation
    responseBuilder.add("Transaction failed.");
  }
  return responseBuilder.build();
}

JSON

{
    "responseId": "db1a333c-2781-41e3-84b1-cc0cc37643d7-594de0a7",
    "queryResult": {
      "queryText": "actions_intent_TRANSACTION_REQUIREMENTS_CHECK",
      "action": "transaction.check.complete",
      "parameters": {},
      "allRequiredParamsPresent": true,
      "fulfillmentText": "Failed to get transaction check results",
      "fulfillmentMessages": [
        {
          "text": {
            "text": [
              "Failed to get transaction check results"
            ]
          }
        }
      ],
      "outputContexts": [
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_media_response_audio"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_audio_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_account_linking"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_screen_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_web_browser"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/google_assistant_input_type_keyboard"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/merchant_payment",
          "lifespanCount": 1
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_intent_transaction_requirements_check",
          "parameters": {
            "TRANSACTION_REQUIREMENTS_CHECK_RESULT": {
              "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckResult",
              "resultType": "CAN_TRANSACT"
            },
            "text": ""
          }
        }
      ],
      "intent": {
        "name": "projects/df-transactions/agent/intents/fd16d86b-60db-4d19-a683-5b52a22f4795",
        "displayName": "Transaction Check Complete"
      },
      "intentDetectionConfidence": 1,
      "languageCode": "en"
    },
    "originalDetectIntentRequest": {
      "source": "google",
      "version": "2",
      "payload": {
        "user": {
          "locale": "en-US",
          "lastSeen": "2019-09-23T19:49:32Z",
          "userVerificationStatus": "VERIFIED"
        },
        "conversation": {
          "conversationId": "ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy",
          "type": "ACTIVE",
          "conversationToken": "[\"merchant_payment\"]"
        },
        "inputs": [
          {
            "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
            "rawInputs": [
              {
                "inputType": "KEYBOARD"
              }
            ],
            "arguments": [
              {
                "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT",
                "extension": {
                  "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckResult",
                  "resultType": "CAN_TRANSACT"
                }
              },
              {
                "name": "text"
              }
            ]
          }
        ],
        "surface": {
          "capabilities": [
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.ACCOUNT_LINKING"
            },
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        },
        "availableSurfaces": [
          {
            "capabilities": [
              {
                "name": "actions.capability.WEB_BROWSER"
              },
              {
                "name": "actions.capability.AUDIO_OUTPUT"
              },
              {
                "name": "actions.capability.SCREEN_OUTPUT"
              }
            ]
          }
        ]
      }
    },
    "session": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy"
  }

JSON

{
  "user": {
    "locale": "en-US",
    "lastSeen": "2019-11-11T23:56:03Z",
    "userVerificationStatus": "VERIFIED"
  },
  "conversation": {
    "conversationId": "ABwppHGFwStZlYaQ9YT8rg9t_idVsxZrku1pUDrEbGSJmSUMatVdPwPEEQSCe1IwIBoN4sS4Weyn9pmgetEgbsWgw3JSvQmw",
    "type": "ACTIVE",
    "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.TRANSACTION_REQUIREMENTS_CHECK",
      "rawInputs": [
        {}
      ],
      "arguments": [
        {
          "name": "TRANSACTION_REQUIREMENTS_CHECK_RESULT",
          "extension": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionRequirementsCheckResult",
            "resultType": "CAN_TRANSACT"
          }
        },
        {
          "name": "text"
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.ACCOUNT_LINKING"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      }
    ]
  },
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

1b. Yêu cầu địa chỉ giao hàng (không bắt buộc)

Nếu giao dịch của bạn cần có địa chỉ giao hàng của người dùng, bạn có thể yêu cầu phương thức thực hiện ý định actions.intent.DELIVERY_ADDRESS. Có thể là hữu ích cho việc xác định tổng giá, vị trí giao hàng/nhận hàng hoặc đảm bảo người dùng ở trong khu vực kinh doanh của bạn.

Khi yêu cầu thực hiện ý định này, bạn truyền vào một tuỳ chọn reason mà cho phép bạn mở đầu yêu cầu của Trợ lý về việc lấy địa chỉ bằng một chuỗi. Ví dụ: nếu bạn chỉ định "để biết nơi gửi đơn đặt hàng", Trợ lý có thể hỏi người dùng:

"Để biết nơi gửi đơn đặt hàng, tôi cần biết địa chỉ giao hàng của bạn"

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

Trên các nền tảng có màn hình, người dùng sẽ chọn địa chỉ họ muốn sử dụng cho giao dịch. Nếu trước đây chưa cung cấp địa chỉ, họ sẽ có thể nhập địa chỉ mới.

Trên các nền tảng chỉ hỗ trợ giọng nói, Trợ lý sẽ yêu cầu người dùng cấp quyền chia sẻ địa chỉ mặc định của họ cho giao dịch. Nếu trước đó họ chưa cung cấp thì cuộc trò chuyện sẽ được chuyển đến một điện thoại để truy cập.

Yêu cầu địa chỉ

Node.js

app.intent('Delivery Address', (conv) => {
  conv.ask(new DeliveryAddress({
    addressOptions: {
      reason: 'To know where to send the order',
    },
  }));
});

Node.js

conv.ask(new DeliveryAddress({
  addressOptions: {
    reason: 'To know where to send the order',
  },
}));

Java

@ForIntent("Delivery Address")
public ActionResponse deliveryAddress(ActionRequest request) {
  DeliveryAddressValueSpecAddressOptions addressOptions =
      new DeliveryAddressValueSpecAddressOptions()
          .setReason("To know where to send the order");
  return getResponseBuilder(request)
      .add(new DeliveryAddress()
          .setAddressOptions(addressOptions))
      .build();
}

Java

DeliveryAddressValueSpecAddressOptions addressOptions =
    new DeliveryAddressValueSpecAddressOptions()
        .setReason("To know where to send the order");
return getResponseBuilder(request)
    .add(new DeliveryAddress()
        .setAddressOptions(addressOptions))
    .build();

JSON

{
    "payload": {
      "google": {
        "expectUserResponse": true,
        "systemIntent": {
          "intent": "actions.intent.DELIVERY_ADDRESS",
          "data": {
            "@type": "type.googleapis.com/google.actions.v2.DeliveryAddressValueSpec",
            "addressOptions": {
              "reason": "To know where to send the order"
            }
          }
        }
      }
    }
  }

JSON

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.DELIVERY_ADDRESS",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.DeliveryAddressValueSpec",
            "addressOptions": {
              "reason": "To know where to send the order"
            }
          }
        }
      ]
    }
  ],
  "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
}
Nhận địa chỉ

Sau khi thực hiện ý định, Trợ lý sẽ gửi cho bạn một yêu cầu thực hiện với ý định actions.intent.DELIVERY_ADDRESS.

Để xử lý yêu cầu này đúng cách, hãy khai báo ý định Dialogflow được kích hoạt bằng sự kiện actions_intent_DELIVERY_ADDRESS. Khi được kích hoạt, hãy xử lý trong bằng cách sử dụng thư viện ứng dụng:

Node.js

app.intent('Delivery Address Complete', (conv) => {
  const arg = conv.arguments.get('DELIVERY_ADDRESS_VALUE');
  if (arg && arg.userDecision ==='ACCEPTED') {
    conv.data.location = arg.location;
    conv.ask('Great, got your address! Now say "confirm transaction".');
    conv.ask(new Suggestions('confirm transaction'));
  } else {
    conv.close('Transaction failed.');
  }
});

Node.js

app.intent('actions.intent.DELIVERY_ADDRESS', (conv) => {
  const arg = conv.arguments.get('DELIVERY_ADDRESS_VALUE');
  if (arg && arg.userDecision ==='ACCEPTED') {
    conv.data.location = arg.location;
    conv.ask('Great, got your address! Now say "confirm transaction".');
    conv.ask(new Suggestions('confirm transaction'));
  } else {
    conv.close('Transaction failed.');
  }
});

Java

@ForIntent("Delivery Address Complete")
public ActionResponse deliveryAddressComplete(ActionRequest request) {
  Argument deliveryAddressValue = request.getArgument("DELIVERY_ADDRESS_VALUE");
  Location deliveryAddress = null;
  if (deliveryAddressValue != null) {
    Map<String, Object> map = deliveryAddressValue.getExtension();
    if (map != null) {
      String userDecision = (String) map.get("userDecision");
      Location location = (Location) map.get("location");
      deliveryAddress = userDecision != null && userDecision.equals("ACCEPTED") ? location : null;
    }
  }
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (deliveryAddress != null) {
    // Cache delivery address in conversation data for later use
    Map<String, Object> conversationData = request.getConversationData();
    conversationData.put("location",
        GSON_BUILDER.create().toJson(deliveryAddress, Location.class));
    responseBuilder
        .add("Great, got your address! Now say \"confirm transaction\".")
        .addSuggestions(new String[] {
            "confirm transaction"
        });
  } else {
    responseBuilder.add("Transaction failed.").endConversation();
  }
  return responseBuilder.build();
}

Java

@ForIntent("actions.intent.DELIVERY_ADDRESS")
public ActionResponse deliveryAddressComplete(ActionRequest request) {
  Argument deliveryAddressValue = request.getArgument("DELIVERY_ADDRESS_VALUE");
  Location deliveryAddress = null;
  if (deliveryAddressValue != null) {
    Map<String, Object> map = deliveryAddressValue.getExtension();
    if (map != null) {
      String userDecision = (String) map.get("userDecision");
      Location location = (Location) map.get("location");
      deliveryAddress = userDecision != null && userDecision.equals("ACCEPTED") ? location : null;
    }
  }
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (deliveryAddress != null) {
    // Cache delivery address in conversation data for later use
    Map<String, Object> conversationData = request.getConversationData();
    conversationData.put("location",
        GSON_BUILDER.create().toJson(deliveryAddress, Location.class));
    responseBuilder
        .add("Great, got your address! Now say \"confirm transaction\".")
        .addSuggestions(new String[] {
            "confirm transaction"
        });
  } else {
    responseBuilder.add("Transaction failed.").endConversation();
  }
  return responseBuilder.build();
}

JSON

{
    "responseId": "58b0c305-b437-47ac-8593-4fb0122a19e6-594de0a7",
    "queryResult": {
      "queryText": "actions_intent_DELIVERY_ADDRESS",
      "parameters": {},
      "allRequiredParamsPresent": true,
      "fulfillmentMessages": [
        {
          "text": {
            "text": [
              ""
            ]
          }
        }
      ],
      "outputContexts": [
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_media_response_audio"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_audio_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_account_linking"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_screen_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_web_browser"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_intent_delivery_address",
          "parameters": {
            "DELIVERY_ADDRESS_VALUE": {
              "@type": "type.googleapis.com/google.actions.v2.DeliveryAddressValue",
              "userDecision": "ACCEPTED",
              "location": {
                "coordinates": {
                  "latitude": 37.432524,
                  "longitude": -122.098545
                },
                "zipCode": "94043-1351",
                "city": "MOUNTAIN VIEW",
                "postalAddress": {
                  "regionCode": "US",
                  "postalCode": "94043-1351",
                  "administrativeArea": "CA",
                  "locality": "MOUNTAIN VIEW",
                  "addressLines": [
                    "1600 AMPHITHEATRE PKWY"
                  ],
                  "recipients": [
                    "John Doe"
                  ]
                },
                "phoneNumber": "+1 123-456-7890"
              }
            },
            "text": "1600 AMPHITHEATRE PKWY"
          }
        }
      ],
      "intent": {
        "name": "projects/df-transactions/agent/intents/0be5d130-1760-4355-85e9-4dc01da8bf3c",
        "displayName": "Delivery Address Complete"
      },
      "intentDetectionConfidence": 1,
      "languageCode": "en"
    },
    "originalDetectIntentRequest": {
      "source": "google",
      "version": "2",
      "payload": {
        "user": {
          "locale": "en-US",
          "lastSeen": "2019-09-23T19:49:55Z",
          "userVerificationStatus": "VERIFIED"
        },
        "conversation": {
          "conversationId": "ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy",
          "type": "ACTIVE",
          "conversationToken": "[]"
        },
        "inputs": [
          {
            "intent": "actions.intent.DELIVERY_ADDRESS",
            "rawInputs": [
              {
                "query": "1600 AMPHITHEATRE PKWY"
              }
            ],
            "arguments": [
              {
                "name": "DELIVERY_ADDRESS_VALUE",
                "extension": {
                  "@type": "type.googleapis.com/google.actions.v2.DeliveryAddressValue",
                  "userDecision": "ACCEPTED",
                  "location": {
                    "coordinates": {
                      "latitude": 37.432524,
                      "longitude": -122.098545
                    },
                    "zipCode": "94043-1351",
                    "city": "MOUNTAIN VIEW",
                    "postalAddress": {
                      "regionCode": "US",
                      "postalCode": "94043-1351",
                      "administrativeArea": "CA",
                      "locality": "MOUNTAIN VIEW",
                      "addressLines": [
                        "1600 AMPHITHEATRE PKWY"
                      ],
                      "recipients": [
                        "John Doe"
                      ]
                    },
                    "phoneNumber": "+1 123-456-7890"
                  }
                }
              }
            ]
          }
        ],
        "surface": {
          "capabilities": [
            {
              "name": "actions.capability.WEB_BROWSER"
            },
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.ACCOUNT_LINKING"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            }
          ]
        },
        "availableSurfaces": [
          {
            "capabilities": [
              {
                "name": "actions.capability.WEB_BROWSER"
              },
              {
                "name": "actions.capability.AUDIO_OUTPUT"
              },
              {
                "name": "actions.capability.SCREEN_OUTPUT"
              }
            ]
          }
        ]
      }
    },
    "session": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy"
  }

JSON

{
  "user": {
    "locale": "en-US",
    "lastSeen": "2019-11-11T23:57:20Z",
    "userVerificationStatus": "VERIFIED"
  },
  "conversation": {
    "conversationId": "ABwppHGFwStZlYaQ9YT8rg9t_idVsxZrku1pUDrEbGSJmSUMatVdPwPEEQSCe1IwIBoN4sS4Weyn9pmgetEgbsWgw3JSvQmw",
    "type": "ACTIVE",
    "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.DELIVERY_ADDRESS",
      "rawInputs": [
        {
          "inputType": "VOICE",
          "query": "1600 AMPHITHEATRE PKWY"
        }
      ],
      "arguments": [
        {
          "name": "DELIVERY_ADDRESS_VALUE",
          "extension": {
            "@type": "type.googleapis.com/google.actions.v2.DeliveryAddressValue",
            "userDecision": "ACCEPTED",
            "location": {
              "coordinates": {
                "latitude": 37.421578499999995,
                "longitude": -122.0837816
              },
              "zipCode": "94043-1351",
              "city": "MOUNTAIN VIEW",
              "postalAddress": {
                "regionCode": "US",
                "postalCode": "94043-1351",
                "administrativeArea": "CA",
                "locality": "MOUNTAIN VIEW",
                "addressLines": [
                  "1600 AMPHITHEATRE PKWY"
                ],
                "recipients": [
                  "John Doe"
                ]
              },
              "phoneNumber": "+1 123-456-7890"
            }
          }
        },
        {
          "name": "text",
          "rawText": "1600 AMPHITHEATRE PKWY",
          "textValue": "1600 AMPHITHEATRE PKWY"
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.ACCOUNT_LINKING"
      }
    ]
  },
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        },
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        }
      ]
    }
  ]
}

2. Tạo đơn đặt hàng

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

Khi có thông tin người dùng cần thiết, bạn sẽ tạo một "giỏ hàng lắp ráp" để hướng dẫn người dùng tạo đơn đặt hàng. Mọi Hành động sẽ có quy trình lắp ráp giỏ hàng hơi khác một chút để phù hợp với sản phẩm hoặc dịch vụ của bạn.

Trong quy trình lắp ráp giỏ hàng cơ bản nhất, người dùng có thể chọn các mặt hàng trong một danh sách để thêm cho đơn đặt hàng của họ, 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. Bạn có thể xây dựng trải nghiệm lắp ráp giỏ hàng cho phép để đặt hàng lại giao dịch mua hàng gần đây nhất của họ thông qua một câu hỏi có hoặc không đơn giản. Bạn cũng có thể trình bày cho người dùng một băng chuyền hoặc thẻ danh sách chứa "tính năng nổi bật" hàng đầu hoặc "đề xuất" mục.

Bạn nên sử dụng thành phần nhiều để đưa ra lựa chọn của người dùng một cách trực quan, mà còn thiết kế cuộc trò chuyện sao cho người dùng có thể xây dựng giỏ hàng chỉ bằng giọng nói. Để xem một số phương pháp hay nhất và ví dụ về trải nghiệm lắp ráp giỏ hàng chất lượng cao, 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, bạn sẽ cần thu thập những mục mà người dùng muốn để mua rồi tạo đối tượng Order.

Ít nhất, Order của bạn phải có các nội dung sau:

  • buyerInfo – Thông tin về người dùng mua hàng.
  • transactionMerchant – Thông tin về người bán đã hỗ trợ đơn đặt hàng.
  • contents – Nội dung thực tế của đơn đặt hàng được liệt kê là lineItems.
  • priceAttributes – Thông tin chi tiết về giá của đơn đặt hàng, bao gồm cả tổng giá chi phí của đơn đặt hàng cùng với các khoản chiết khấu và thuế.

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

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

Node.js

const order = {
  createTime: '2019-09-24T18:00:00.877Z',
  lastUpdateTime: '2019-09-24T18:00:00.877Z',
  merchantOrderId: orderId, // A unique ID String for the order
  userVisibleOrderId: orderId,
  transactionMerchant: {
    id: 'http://www.example.com',
    name: 'Example Merchant',
  },
  contents: {
    lineItems: [
      {
        id: 'LINE_ITEM_ID',
        name: 'Pizza',
        description: 'A four cheese pizza.',
        priceAttributes: [
          {
            type: 'REGULAR',
            name: 'Item Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 8990000,
            },
            taxIncluded: true,
          },
          {
            type: 'TOTAL',
            name: 'Total Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 9990000,
            },
            taxIncluded: true,
          },
        ],
        notes: [
          'Extra cheese.',
        ],
        purchase: {
          quantity: 1,
          unitMeasure: {
            measure: 1,
            unit: 'POUND',
          },
          itemOptions: [
            {
              id: 'ITEM_OPTION_ID',
              name: 'Pepperoni',
              prices: [
                {
                  type: 'REGULAR',
                  state: 'ACTUAL',
                  name: 'Item Price',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
                {
                  type: 'TOTAL',
                  name: 'Total Price',
                  state: 'ACTUAL',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
              ],
              note: 'Extra pepperoni',
              quantity: 1,
              subOptions: [],
            },
          ],
        },
      },
    ],
  },
  buyerInfo: {
    email: 'janedoe@gmail.com',
    firstName: 'Jane',
    lastName: 'Doe',
    displayName: 'Jane Doe',
  },
  priceAttributes: [
    {
      type: 'SUBTOTAL',
      name: 'Subtotal',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 9990000,
      },
      taxIncluded: true,
    },
    {
      type: 'DELIVERY',
      name: 'Delivery',
      state: 'ACTUAL',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 2000000,
      },
      taxIncluded: true,
    },
    {
      type: 'TAX',
      name: 'Tax',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 3780000,
      },
      taxIncluded: true,
    },
    {
      type: 'TOTAL',
      name: 'Total Price',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 15770000,
      },
      taxIncluded: true,
    },
  ],
  followUpActions: [
    {
      type: 'VIEW_DETAILS',
      title: 'View details',
      openUrlAction: {
        url: 'http://example.com',
      },
    },
    {
      type: 'CALL',
      title: 'Call us',
      openUrlAction: {
        url: 'tel:+16501112222',
      },
    },
    {
      type: 'EMAIL',
      title: 'Email us',
      openUrlAction: {
        url: 'mailto:person@example.com',
      },
    },
  ],
  termsOfServiceUrl: 'http://www.example.com',
  note: 'Sale event',
  promotions: [
    {
      coupon: 'COUPON_CODE',
    },
  ],
  purchase: {
    status: 'CREATED',
    userVisibleStatusLabel: 'CREATED',
    type: 'FOOD',
    returnsInfo: {
      isReturnable: false,
      daysToReturn: 1,
      policyUrl: 'http://www.example.com',
    },
    fulfillmentInfo: {
      id: 'FULFILLMENT_SERVICE_ID',
      fulfillmentType: 'DELIVERY',
      expectedFulfillmentTime: {
        timeIso8601: '2019-09-25T18:00:00.877Z',
      },
      location: location,
      price: {
        type: 'REGULAR',
        name: 'Delivery Price',
        state: 'ACTUAL',
        amount: {
          currencyCode: 'USD',
          amountInMicros: 2000000,
        },
        taxIncluded: true,
      },
      fulfillmentContact: {
        email: 'johnjohnson@gmail.com',
        firstName: 'John',
        lastName: 'Johnson',
        displayName: 'John Johnson',
      },
    },
    purchaseLocationType: 'ONLINE_PURCHASE',
  },
};

Node.js

const order = {
  createTime: '2019-09-24T18:00:00.877Z',
  lastUpdateTime: '2019-09-24T18:00:00.877Z',
  merchantOrderId: orderId, // A unique ID String for the order
  userVisibleOrderId: orderId,
  transactionMerchant: {
    id: 'http://www.example.com',
    name: 'Example Merchant',
  },
  contents: {
    lineItems: [
      {
        id: 'LINE_ITEM_ID',
        name: 'Pizza',
        description: 'A four cheese pizza.',
        priceAttributes: [
          {
            type: 'REGULAR',
            name: 'Item Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 8990000,
            },
            taxIncluded: true,
          },
          {
            type: 'TOTAL',
            name: 'Total Price',
            state: 'ACTUAL',
            amount: {
              currencyCode: 'USD',
              amountInMicros: 9990000,
            },
            taxIncluded: true,
          },
        ],
        notes: [
          'Extra cheese.',
        ],
        purchase: {
          quantity: 1,
          unitMeasure: {
            measure: 1,
            unit: 'POUND',
          },
          itemOptions: [
            {
              id: 'ITEM_OPTION_ID',
              name: 'Pepperoni',
              prices: [
                {
                  type: 'REGULAR',
                  state: 'ACTUAL',
                  name: 'Item Price',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
                {
                  type: 'TOTAL',
                  name: 'Total Price',
                  state: 'ACTUAL',
                  amount: {
                    currencyCode: 'USD',
                    amountInMicros: 1000000,
                  },
                  taxIncluded: true,
                },
              ],
              note: 'Extra pepperoni',
              quantity: 1,
              subOptions: [],
            },
          ],
        },
      },
    ],
  },
  buyerInfo: {
    email: 'janedoe@gmail.com',
    firstName: 'Jane',
    lastName: 'Doe',
    displayName: 'Jane Doe',
  },
  priceAttributes: [
    {
      type: 'SUBTOTAL',
      name: 'Subtotal',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 9990000,
      },
      taxIncluded: true,
    },
    {
      type: 'DELIVERY',
      name: 'Delivery',
      state: 'ACTUAL',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 2000000,
      },
      taxIncluded: true,
    },
    {
      type: 'TAX',
      name: 'Tax',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 3780000,
      },
      taxIncluded: true,
    },
    {
      type: 'TOTAL',
      name: 'Total Price',
      state: 'ESTIMATE',
      amount: {
        currencyCode: 'USD',
        amountInMicros: 15770000,
      },
      taxIncluded: true,
    },
  ],
  followUpActions: [
    {
      type: 'VIEW_DETAILS',
      title: 'View details',
      openUrlAction: {
        url: 'http://example.com',
      },
    },
    {
      type: 'CALL',
      title: 'Call us',
      openUrlAction: {
        url: 'tel:+16501112222',
      },
    },
    {
      type: 'EMAIL',
      title: 'Email us',
      openUrlAction: {
        url: 'mailto:person@example.com',
      },
    },
  ],
  termsOfServiceUrl: 'http://www.example.com',
  note: 'Sale event',
  promotions: [
    {
      coupon: 'COUPON_CODE',
    },
  ],
  purchase: {
    status: 'CREATED',
    userVisibleStatusLabel: 'CREATED',
    type: 'FOOD',
    returnsInfo: {
      isReturnable: false,
      daysToReturn: 1,
      policyUrl: 'http://www.example.com',
    },
    fulfillmentInfo: {
      id: 'FULFILLMENT_SERVICE_ID',
      fulfillmentType: 'DELIVERY',
      expectedFulfillmentTime: {
        timeIso8601: '2019-09-25T18:00:00.877Z',
      },
      location: location,
      price: {
        type: 'REGULAR',
        name: 'Delivery Price',
        state: 'ACTUAL',
        amount: {
          currencyCode: 'USD',
          amountInMicros: 2000000,
        },
        taxIncluded: true,
      },
      fulfillmentContact: {
        email: 'johnjohnson@gmail.com',
        firstName: 'John',
        lastName: 'Johnson',
        displayName: 'John Johnson',
      },
    },
    purchaseLocationType: 'ONLINE_PURCHASE',
  },
};

Java

// Transaction Merchant
MerchantV3 transactionMerchant = new MerchantV3()
    .setId("http://www.example.com")
    .setName("Example Merchant");

// Line Item
PriceAttribute itemPrice = new PriceAttribute()
    .setType("REGULAR")
    .setName("Item Price")
    .setState("ACTUAL")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(8990000L)
    )
    .setTaxIncluded(true);

PriceAttribute totalItemPrice = new PriceAttribute()
    .setType("TOTAL")
    .setName("Total Price")
    .setState("ACTUAL")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(9990000L)
    )
    .setTaxIncluded(true);

// Purchase Item Extension
PurchaseItemExtension purchaseItemExtension = new PurchaseItemExtension()
    .setQuantity(1)
    .setUnitMeasure(new MerchantUnitMeasure()
        .setMeasure(1.0)
        .setUnit("POUND"))
    .setItemOptions(Arrays.asList(new PurchaseItemExtensionItemOption()
        .setId("ITEM_OPTION_ID")
        .setName("Pepperoni")
        .setPrices(Arrays.asList(
            new PriceAttribute()
              .setType("REGULAR")
              .setState("ACTUAL")
              .setName("Item Price")
              .setAmount(new MoneyV3()
                  .setCurrencyCode("USD")
                  .setAmountInMicros(1000000L))
              .setTaxIncluded(true),
            new PriceAttribute()
                .setType("TOTAL")
                .setState("ACTUAL")
                .setName("Total Price")
                .setAmount(new MoneyV3()
                    .setCurrencyCode("USD")
                    .setAmountInMicros(1000000L))
                .setTaxIncluded(true)
            ))
        .setNote("Extra pepperoni")
        .setQuantity(1)));

LineItemV3 lineItem = new LineItemV3()
    .setId("LINE_ITEM_ID")
    .setName("Pizza")
    .setDescription("A four cheese pizza.")
    .setPriceAttributes(Arrays.asList(itemPrice, totalItemPrice))
    .setNotes(Collections.singletonList("Extra cheese."))
    .setPurchase(purchaseItemExtension);

// 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");

// Price Attributes
PriceAttribute subTotal = new PriceAttribute()
    .setType("SUBTOTAL")
    .setName("Subtotal")
    .setState("ESTIMATE")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(9990000L)
    )
    .setTaxIncluded(true);
PriceAttribute deliveryFee = new PriceAttribute()
    .setType("DELIVERY")
    .setName("Delivery")
    .setState("ACTUAL")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(2000000L)
    )
    .setTaxIncluded(true);
PriceAttribute tax = new PriceAttribute()
    .setType("TAX")
    .setName("Tax")
    .setState("ESTIMATE")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(3780000L)
    )
    .setTaxIncluded(true);
PriceAttribute totalPrice = new PriceAttribute()
    .setType("TOTAL")
    .setName("Total Price")
    .setState("ESTIMATE")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(15770000L)
    )
    .setTaxIncluded(true);

// 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 = "http://example.com";
String orderNote = "Sale event";

// Promotions
PromotionV3 promotion = new PromotionV3()
    .setCoupon("COUPON_CODE");

// Purchase Order Extension
Location location = GSON_BUILDER.create().fromJson(
    (String) conversationData.get("location"), Location.class);

PurchaseOrderExtension purchaseOrderExtension = new PurchaseOrderExtension()
    .setStatus("CREATED")
    .setUserVisibleStatusLabel("CREATED")
    .setType("FOOD")
    .setReturnsInfo(new PurchaseReturnsInfo()
        .setIsReturnable(false)
        .setDaysToReturn(1)
        .setPolicyUrl("https://example.com"))
    .setFulfillmentInfo(new PurchaseFulfillmentInfo()
        .setId("FULFILLMENT_SERVICE_ID")
        .setFulfillmentType("DELIVERY")
        .setExpectedFulfillmentTime(new TimeV3()
            .setTimeIso8601("2019-09-25T18:00:00.877Z"))
        .setLocation(location)
        .setPrice(new PriceAttribute()
            .setType("REGULAR")
            .setName("Delivery price")
            .setState("ACTUAL")
            .setAmount(new MoneyV3()
                .setCurrencyCode("USD")
                .setAmountInMicros(2000000L))
            .setTaxIncluded(true))
        .setFulfillmentContact(new UserInfo()
            .setEmail("johnjohnson@gmail.com")
            .setFirstName("John")
            .setLastName("Johnson")
            .setDisplayName("John Johnson")))
    .setPurchaseLocationType("ONLINE_PURCHASE");

OrderV3 order = new OrderV3()
    .setCreateTime("2019-09-24T18:00:00.877Z")
    .setLastUpdateTime("2019-09-24T18:00:00.877Z")
    .setMerchantOrderId(orderId)
    .setUserVisibleOrderId(orderId)
    .setTransactionMerchant(transactionMerchant)
    .setContents(contents)
    .setBuyerInfo(buyerInfo)
    .setPriceAttributes(Arrays.asList(
        subTotal,
        deliveryFee,
        tax,
        totalPrice
    ))
    .setFollowUpActions(Arrays.asList(
        viewDetails,
        call,
        email
    ))
    .setTermsOfServiceUrl(termsOfServiceUrl)
    .setNote(orderNote)
    .setPromotions(Collections.singletonList(promotion))
    .setPurchase(purchaseOrderExtension);

Java

// Transaction Merchant
MerchantV3 transactionMerchant = new MerchantV3()
    .setId("http://www.example.com")
    .setName("Example Merchant");

// Line Item
PriceAttribute itemPrice = new PriceAttribute()
    .setType("REGULAR")
    .setName("Item Price")
    .setState("ACTUAL")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(8990000L)
    )
    .setTaxIncluded(true);

PriceAttribute totalItemPrice = new PriceAttribute()
    .setType("TOTAL")
    .setName("Total Price")
    .setState("ACTUAL")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(9990000L)
    )
    .setTaxIncluded(true);

// Purchase Item Extension
PurchaseItemExtension purchaseItemExtension = new PurchaseItemExtension()
    .setUnitMeasure(new MerchantUnitMeasure()
        .setMeasure(1.0)
        .setUnit("POUND"))
    .setItemOptions(Arrays.asList(new PurchaseItemExtensionItemOption()
        .setId("ITEM_OPTION_ID")
        .setName("Pepperoni")
        .setPrices(Arrays.asList(
            new PriceAttribute()
              .setType("REGULAR")
              .setState("ACTUAL")
              .setName("Item Price")
              .setAmount(new MoneyV3()
                  .setCurrencyCode("USD")
                  .setAmountInMicros(1000000L))
              .setTaxIncluded(true),
            new PriceAttribute()
                .setType("TOTAL")
                .setState("ACTUAL")
                .setName("Total Price")
                .setAmount(new MoneyV3()
                    .setCurrencyCode("USD")
                    .setAmountInMicros(1000000L))
                .setTaxIncluded(true)
            ))
        .setNote("Extra pepperoni")));

LineItemV3 lineItem = new LineItemV3()
    .setId("LINE_ITEM_ID")
    .setName("Pizza")
    .setDescription("A four cheese pizza.")
    .setPriceAttributes(Arrays.asList(itemPrice, totalItemPrice))
    .setNotes(Collections.singletonList("Extra cheese."))
    .setPurchase(purchaseItemExtension);

// 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");

// Price Attributes
PriceAttribute subTotal = new PriceAttribute()
    .setType("SUBTOTAL")
    .setName("Subtotal")
    .setState("ESTIMATE")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(9990000L)
    )
    .setTaxIncluded(true);
PriceAttribute deliveryFee = new PriceAttribute()
    .setType("DELIVERY")
    .setName("Delivery")
    .setState("ACTUAL")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(2000000L)
    )
    .setTaxIncluded(true);
PriceAttribute tax = new PriceAttribute()
    .setType("TAX")
    .setName("Tax")
    .setState("ESTIMATE")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(3780000L)
    )
    .setTaxIncluded(true);
PriceAttribute totalPrice = new PriceAttribute()
    .setType("TOTAL")
    .setName("Total Price")
    .setState("ESTIMATE")
    .setAmount(new MoneyV3()
        .setCurrencyCode("USD")
        .setAmountInMicros(15770000L)
    )
    .setTaxIncluded(true);

// 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 = "http://example.com";
String orderNote = "Sale event";

// Promotions
PromotionV3 promotion = new PromotionV3()
    .setCoupon("COUPON_CODE");

// Purchase Order Extension
Location location = GSON_BUILDER.create().fromJson(
    (String) conversationData.get("location"), Location.class);

PurchaseOrderExtension purchaseOrderExtension = new PurchaseOrderExtension()
    .setStatus("CREATED")
    .setUserVisibleStatusLabel("CREATED")
    .setType("FOOD")
    .setReturnsInfo(new PurchaseReturnsInfo()
        .setIsReturnable(false)
        .setDaysToReturn(1)
        .setPolicyUrl("https://example.com"))
    .setFulfillmentInfo(new PurchaseFulfillmentInfo()
        .setId("FULFILLMENT_SERVICE_ID")
        .setFulfillmentType("DELIVERY")
        .setExpectedFulfillmentTime(new TimeV3()
            .setTimeIso8601("2019-09-25T18:00:00.877Z"))
        .setLocation(location)
        .setPrice(new PriceAttribute()
            .setType("REGULAR")
            .setName("Delivery price")
            .setState("ACTUAL")
            .setAmount(new MoneyV3()
                .setCurrencyCode("USD")
                .setAmountInMicros(2000000L))
            .setTaxIncluded(true))
        .setFulfillmentContact(new UserInfo()
            .setEmail("johnjohnson@gmail.com")
            .setFirstName("John")
            .setLastName("Johnson")
            .setDisplayName("John Johnson")))
    .setPurchaseLocationType("ONLINE_PURCHASE");

OrderV3 order = new OrderV3()
    .setCreateTime("2019-09-24T18:00:00.877Z")
    .setLastUpdateTime("2019-09-24T18:00:00.877Z")
    .setMerchantOrderId(orderId)
    .setUserVisibleOrderId(orderId)
    .setTransactionMerchant(transactionMerchant)
    .setContents(contents)
    .setBuyerInfo(buyerInfo)
    .setPriceAttributes(Arrays.asList(
        subTotal,
        deliveryFee,
        tax,
        totalPrice
    ))
    .setFollowUpActions(Arrays.asList(
        viewDetails,
        call,
        email
    ))
    .setTermsOfServiceUrl(termsOfServiceUrl)
    .setNote(orderNote)
    .setPromotions(Collections.singletonList(promotion))
    .setPurchase(purchaseOrderExtension);

3. Thực hiện liên kết tài khoản

Khi tính phí người dùng bằng phương thức thanh toán của riêng mình, bạn nên liên kết Tài khoản Google của họ với tài khoản họ có với dịch vụ của riêng bạn để truy xuất, trình bày và tính phí các phương thức thanh toán được lưu trữ trong đó.

Chúng tôi cung cấp tính năng liên kết tài khoản OAuth 2.0 để đáp ứng điều này . Bạn nên bật quy trình Xác nhận OAuth 2.0 vì quy trình này mang lại trải nghiệm người dùng rất đơn giản.

Chúng tôi cung cấp ý định actions.intent.SIGN_IN, cho phép bạn yêu cầu một người dùng liên kết tài khoản giữa cuộc trò chuyện. Bạn phải bật tính năng liên kết tài khoản trong Bảng điều khiển Actions để sử dụng Ý định actions.intent.SIGN_IN.

Bạn nên sử dụng ý định này nếu không thể tìm thấy accessToken trong User đối tượng trong yêu cầu webhook. Điều này có nghĩa là người dùng chưa đã liên kết tài khoản của mình.

Sau khi yêu cầu ý định actions.intent.SIGN_IN, bạn sẽ nhận được một Argument chứa SignInStatus có giá trị là "OK", "CANCELLED" hoặc "ERROR". Nếu trạng thái là "OK", bạn sẽ có thể thấy accessToken trong đối tượng User.

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

Yêu cầu đăng nhập

Node.js

app.intent('Sign In', (conv) => {
  conv.ask(new SignIn('To get your account details'));
});

Node.js

conv.ask(new SignIn('To get your account details'));

Java

@ForIntent("Sign In")
public ActionResponse signIn(ActionRequest request) {
  return getResponseBuilder(request).add(
      new SignIn()
          .setContext("To get your account details"))
      .build();
}

Java

return getResponseBuilder(request).add(
    new SignIn()
        .setContext("To get your account details"))
    .build();

JSON

{
    "payload": {
      "google": {
        "expectUserResponse": true,
        "systemIntent": {
          "intent": "actions.intent.SIGN_IN",
          "data": {
            "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec",
            "optContext": "To get your account details"
          }
        }
      }
    }
  }

JSON

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.SIGN_IN",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec",
            "optContext": "To get your account details"
          }
        }
      ]
    }
  ],
  "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
}
Nhận kết quả đăng nhập

Node.js

app.intent('Sign In Complete', (conv, params, signin) => {
  if (signin.status !== 'OK') {
    conv.ask('You need to sign in before making a transaction.');
  } else {
    const accessToken = conv.user.access.token;
    // possibly do something with access token
    conv.ask('You must meet all the requirements necessary ' +
      'to make a transaction. Try saying ' +
      '"check transaction requirements".');
      conv.ask(new Suggestions(`check requirements`));
  }
});

Node.js

app.intent('actions.intent.SIGN_IN', (conv, params, signin) => {
  if (signin.status !== 'OK') {
    conv.ask('You need to sign in before making a transaction.');
  } else {
    const accessToken = conv.user.access.token;
    // possibly do something with access token
    conv.ask('You must meet all the requirements necessary ' +
      'to make a transaction. Try saying ' +
      '"check transaction requirements".');
      conv.ask(new Suggestions(`check requirements`));
  }
});

Java

@ForIntent("Sign In Complete")
public ActionResponse signInComplete(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.isSignInGranted()) {
    responseBuilder
        .add("You must meet all the requirements necessary to make a " +
            "transaction. Try saying \"check transaction requirements\".")
        .addSuggestions(new String[] {
            "check requirements"
        });
  } else {
    responseBuilder.add("You need to sign in before making a transaction.");
  }
  return responseBuilder.build();
}

Java

@ForIntent("actions.intent.SIGN_IN")
public ActionResponse signInComplete(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.isSignInGranted()) {
    responseBuilder
        .add("You must meet all the requirements necessary to make a " +
            "transaction. Try saying \"check transaction requirements\".")
        .addSuggestions(new String[] {
            "check requirements"
        });
  } else {
    responseBuilder.add("You need to sign in before making a transaction.");
  }
  return responseBuilder.build();
}

JSON

{
    "responseId": "d2123d8d-3f00-466e-b5a9-1a4ed53a7cb7-594de0a7",
    "queryResult": {
      "queryText": "actions_intent_SIGN_IN",
      "parameters": {},
      "allRequiredParamsPresent": true,
      "fulfillmentMessages": [
        {
          "text": {
            "text": [
              ""
            ]
          }
        }
      ],
      "outputContexts": [
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/merchant_payment",
          "lifespanCount": 2
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_web_browser"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_screen_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_account_linking"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_media_response_audio"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_audio_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/google_assistant_input_type_keyboard"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_intent_sign_in",
          "parameters": {
            "SIGN_IN": {
              "@type": "type.googleapis.com/google.actions.v2.SignInValue",
              "status": "OK"
            },
            "text": ""
          }
        }
      ],
      "intent": {
        "name": "projects/df-transactions/agent/intents/105b925b-b186-4f5d-8bde-a9a782a0fa9f",
        "displayName": "Sign In Complete"
      },
      "intentDetectionConfidence": 1,
      "languageCode": "en"
    },
    "originalDetectIntentRequest": {
      "source": "google",
      "version": "2",
      "payload": {
        "user": {
          "locale": "en-US",
          "lastSeen": "2019-09-23T19:49:18Z",
          "userVerificationStatus": "VERIFIED"
        },
        "conversation": {
          "conversationId": "ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy",
          "type": "ACTIVE",
          "conversationToken": "[]"
        },
        "inputs": [
          {
            "intent": "actions.intent.SIGN_IN",
            "rawInputs": [
              {
                "inputType": "KEYBOARD"
              }
            ],
            "arguments": [
              {
                "name": "SIGN_IN",
                "extension": {
                  "@type": "type.googleapis.com/google.actions.v2.SignInValue",
                  "status": "OK"
                }
              },
              {
                "name": "text"
              }
            ]
          }
        ],
        "surface": {
          "capabilities": [
            {
              "name": "actions.capability.WEB_BROWSER"
            },
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.ACCOUNT_LINKING"
            },
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            }
          ]
        },
        "availableSurfaces": [
          {
            "capabilities": [
              {
                "name": "actions.capability.WEB_BROWSER"
              },
              {
                "name": "actions.capability.AUDIO_OUTPUT"
              },
              {
                "name": "actions.capability.SCREEN_OUTPUT"
              }
            ]
          }
        ]
      }
    },
    "session": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy"
  }

JSON

{
  "user": {
    "locale": "en-US",
    "lastSeen": "2019-11-11T23:55:52Z",
    "userVerificationStatus": "VERIFIED"
  },
  "conversation": {
    "conversationId": "ABwppHGFwStZlYaQ9YT8rg9t_idVsxZrku1pUDrEbGSJmSUMatVdPwPEEQSCe1IwIBoN4sS4Weyn9pmgetEgbsWgw3JSvQmw",
    "type": "ACTIVE",
    "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\"}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.SIGN_IN",
      "rawInputs": [
        {}
      ],
      "arguments": [
        {
          "name": "SIGN_IN",
          "extension": {
            "@type": "type.googleapis.com/google.actions.v2.SignInValue",
            "status": "OK"
          }
        },
        {
          "name": "text"
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.ACCOUNT_LINKING"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      }
    ]
  },
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        }
      ]
    }
  ]
}

4. Đề xuất đơn đặt hàng

Sau khi tạo đơn đặt hàng, bạn phải cung cấp đơn đặt hàng đó cho người dùng để xác nhận hoặc từ chối. Yêu cầu actions.intent.TRANSACTION_DECISION ý định và cung cấp đơn đặt hàng mà bạn đã tạo bằng khoản thanh toán đã lưu của người dùng của bạn.

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

Khi bạn yêu cầu ý định actions.intent.TRANSACTION_DECISION, Trợ lý bắt đầu trải nghiệm tích hợp trong đó Order mà bạn đã truyền là hiển thị trực tiếp trên "thẻ xem trước giỏ hàng". Người dùng có thể nói "đặt hàng", từ chối giao dịch, thay đổi tuỳ chọn thanh toán như thẻ tín dụng hoặc địa chỉ hoặc yêu cầu thay đổi nội dung của đơn đặt hàng.

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

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

Khi bạn yêu cầu actions.intent.TRANSACTION_DECISION, bạn sẽ tạo một TransactionDecision chứa Order cũng như orderOptionspaymentParameters. paymentParameters của bạn bao gồm một merchantPaymentOption có các trường mô tả thông tin phương thức thanh toán.

Mã sau đây là ví dụ về TransactionsDecision cho một đơn đặt hàng, có tính phí bằng thẻ tín dụng Visa:

Node.js

conv.ask(new TransactionDecision({
  orderOptions: {
    userInfoOptions: {
      userInfoProperties: [
        'EMAIL',
      ],
    },
  },
  paymentParameters: {
    merchantPaymentOption: {
      defaultMerchantPaymentMethodId: '12345678',
      managePaymentMethodUrl: 'https://example.com/managePayment',
      merchantPaymentMethod: [
        {
          paymentMethodDisplayInfo: {
            paymentMethodDisplayName: 'VISA **** 1234',
            paymentType: 'PAYMENT_CARD',
          },
          paymentMethodGroup: 'Payment method group',
          paymentMethodId: '12345678',
          paymentMethodStatus: {
            status: 'STATUS_OK',
            statusMessage: 'Status message',
          },
        },
      ],
    },
  },
  presentationOptions: {
    actionDisplayName: 'PLACE_ORDER',
  },
  order: order,
}));

Node.js

conv.ask(new TransactionDecision({
  orderOptions: {
    userInfoOptions: {
      userInfoProperties: [
        'EMAIL',
      ],
    },
  },
  paymentParameters: {
    merchantPaymentOption: {
      defaultMerchantPaymentMethodId: '12345678',
      managePaymentMethodUrl: 'https://example.com/managePayment',
      merchantPaymentMethod: [
        {
          paymentMethodDisplayInfo: {
            paymentMethodDisplayName: 'VISA **** 1234',
            paymentType: 'PAYMENT_CARD',
          },
          paymentMethodGroup: 'Payment method group',
          paymentMethodId: '12345678',
          paymentMethodStatus: {
            status: 'STATUS_OK',
            statusMessage: 'Status message',
          },
        },
      ],
    },
  },
  presentationOptions: {
    actionDisplayName: 'PLACE_ORDER',
  },
  order: order,
}));

Java

// Create order options
OrderOptionsV3 orderOptions = new OrderOptionsV3()
    .setUserInfoOptions(new UserInfoOptions()
        .setUserInfoProperties(Collections.singletonList("EMAIL")));

// Create presentation options
PresentationOptionsV3 presentationOptions = new PresentationOptionsV3()
    .setActionDisplayName("PLACE_ORDER");

// Create payment parameters
MerchantPaymentMethod merchantPaymentMethod = new MerchantPaymentMethod()
    .setPaymentMethodDisplayInfo(new PaymentMethodDisplayInfo()
        .setPaymentMethodDisplayName("VISA **** 1234")
        .setPaymentType("PAYMENT_CARD"))
    .setPaymentMethodGroup("Payment method group")
    .setPaymentMethodId("12345678")
    .setPaymentMethodStatus(new PaymentMethodStatus()
        .setStatus("STATUS_OK")
        .setStatusMessage("Status message"));

MerchantPaymentOption merchantPaymentOption = new MerchantPaymentOption()
    .setDefaultMerchantPaymentMethodId("12345678")
    .setManagePaymentMethodUrl("https://example.com/managePayment")
    .setMerchantPaymentMethod(Collections.singletonList(merchantPaymentMethod));

paymentParameters.setMerchantPaymentOption(merchantPaymentOption);

return getResponseBuilder(request)
    .add(new TransactionDecision()
        .setOrder(order)
        .setOrderOptions(orderOptions)
        .setPresentationOptions(presentationOptions)
        .setPaymentParameters(paymentParameters)
    )
    .build();

Java

// Create order options
OrderOptionsV3 orderOptions = new OrderOptionsV3()
    .setUserInfoOptions(new UserInfoOptions()
        .setUserInfoProperties(Collections.singletonList("EMAIL")));

// Create presentation options
PresentationOptionsV3 presentationOptions = new PresentationOptionsV3()
    .setActionDisplayName("PLACE_ORDER");

// Create payment parameters
MerchantPaymentMethod merchantPaymentMethod = new MerchantPaymentMethod()
    .setPaymentMethodDisplayInfo(new PaymentMethodDisplayInfo()
        .setPaymentMethodDisplayName("VISA **** 1234")
        .setPaymentType("PAYMENT_CARD"))
    .setPaymentMethodGroup("Payment method group")
    .setPaymentMethodId("12345678")
    .setPaymentMethodStatus(new PaymentMethodStatus()
        .setStatus("STATUS_OK")
        .setStatusMessage("Status message"));

MerchantPaymentOption merchantPaymentOption = new MerchantPaymentOption()
    .setDefaultMerchantPaymentMethodId("12345678")
    .setManagePaymentMethodUrl("https://example.com/managePayment")
    .setMerchantPaymentMethod(Collections.singletonList(merchantPaymentMethod));

paymentParameters.setMerchantPaymentOption(merchantPaymentOption);

return getResponseBuilder(request)
    .add(new TransactionDecision()
        .setOrder(order)
        .setOrderOptions(orderOptions)
        .setPresentationOptions(presentationOptions)
        .setPaymentParameters(paymentParameters)
    )
    .build();

JSON

{
    "payload": {
      "google": {
        "expectUserResponse": true,
        "richResponse": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "Transaction Decision Placeholder."
              }
            }
          ]
        },
        "systemIntent": {
          "intent": "actions.intent.TRANSACTION_DECISION",
          "data": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
            "orderOptions": {
              "userInfoOptions": {
                "userInfoProperties": [
                  "EMAIL"
                ]
              }
            },
            "paymentParameters": {
              "merchantPaymentOption": {
                "defaultMerchantPaymentMethodId": "12345678",
                "managePaymentMethodUrl": "https://example.com/managePayment",
                "merchantPaymentMethod": [
                  {
                    "paymentMethodDisplayInfo": {
                      "paymentMethodDisplayName": "VISA **** 1234",
                      "paymentType": "PAYMENT_CARD"
                    },
                    "paymentMethodGroup": "Payment method group",
                    "paymentMethodId": "12345678",
                    "paymentMethodStatus": {
                      "status": "STATUS_OK",
                      "statusMessage": "Status message"
                    }
                  }
                ]
              }
            },
            "presentationOptions": {
              "actionDisplayName": "PLACE_ORDER"
            },
            "order": {
              "createTime": "2019-09-24T18:00:00.877Z",
              "lastUpdateTime": "2019-09-24T18:00:00.877Z",
              "merchantOrderId": "ORDER_ID",
              "userVisibleOrderId": "ORDER_ID",
              "transactionMerchant": {
                "id": "http://www.example.com",
                "name": "Example Merchant"
              },
              "contents": {
                "lineItems": [
                  {
                    "id": "LINE_ITEM_ID",
                    "name": "Pizza",
                    "description": "A four cheese pizza.",
                    "priceAttributes": [
                      {
                        "type": "REGULAR",
                        "name": "Item Price",
                        "state": "ACTUAL",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 8990000
                        },
                        "taxIncluded": true
                      },
                      {
                        "type": "TOTAL",
                        "name": "Total Price",
                        "state": "ACTUAL",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 9990000
                        },
                        "taxIncluded": true
                      }
                    ],
                    "notes": [
                      "Extra cheese."
                    ],
                    "purchase": {
                      "quantity": 1,
                      "unitMeasure": {
                        "measure": 1,
                        "unit": "POUND"
                      },
                      "itemOptions": [
                        {
                          "id": "ITEM_OPTION_ID",
                          "name": "Pepperoni",
                          "prices": [
                            {
                              "type": "REGULAR",
                              "state": "ACTUAL",
                              "name": "Item Price",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": 1000000
                              },
                              "taxIncluded": true
                            },
                            {
                              "type": "TOTAL",
                              "name": "Total Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": 1000000
                              },
                              "taxIncluded": true
                            }
                          ],
                          "note": "Extra pepperoni",
                          "quantity": 1,
                          "subOptions": []
                        }
                      ]
                    }
                  }
                ]
              },
              "buyerInfo": {
                "email": "janedoe@gmail.com",
                "firstName": "Jane",
                "lastName": "Doe",
                "displayName": "Jane Doe"
              },
              "priceAttributes": [
                {
                  "type": "SUBTOTAL",
                  "name": "Subtotal",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 9990000
                  },
                  "taxIncluded": true
                },
                {
                  "type": "DELIVERY",
                  "name": "Delivery",
                  "state": "ACTUAL",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 2000000
                  },
                  "taxIncluded": true
                },
                {
                  "type": "TAX",
                  "name": "Tax",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 3780000
                  },
                  "taxIncluded": true
                },
                {
                  "type": "TOTAL",
                  "name": "Total Price",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 15770000
                  },
                  "taxIncluded": true
                }
              ],
              "followUpActions": [
                {
                  "type": "VIEW_DETAILS",
                  "title": "View details",
                  "openUrlAction": {
                    "url": "http://example.com"
                  }
                },
                {
                  "type": "CALL",
                  "title": "Call us",
                  "openUrlAction": {
                    "url": "tel:+16501112222"
                  }
                },
                {
                  "type": "EMAIL",
                  "title": "Email us",
                  "openUrlAction": {
                    "url": "mailto:person@example.com"
                  }
                }
              ],
              "termsOfServiceUrl": "http://www.example.com",
              "note": "Sale event",
              "promotions": [
                {
                  "coupon": "COUPON_CODE"
                }
              ],
              "purchase": {
                "status": "CREATED",
                "userVisibleStatusLabel": "CREATED",
                "type": "FOOD",
                "returnsInfo": {
                  "isReturnable": false,
                  "daysToReturn": 1,
                  "policyUrl": "http://www.example.com"
                },
                "fulfillmentInfo": {
                  "id": "FULFILLMENT_SERVICE_ID",
                  "fulfillmentType": "DELIVERY",
                  "expectedFulfillmentTime": {
                    "timeIso8601": "2019-09-25T18:00:00.877Z"
                  },
                  "location": {
                    "city": "MOUNTAIN VIEW",
                    "coordinates": {
                      "latitude": 37.432524,
                      "longitude": -122.098545
                    },
                    "phoneNumber": "+1 123-456-7890",
                    "postalAddress": {
                      "addressLines": [
                        "1600 AMPHITHEATRE PKWY"
                      ],
                      "administrativeArea": "CA",
                      "locality": "MOUNTAIN VIEW",
                      "postalCode": "94043-1351",
                      "recipients": [
                        "John Doe"
                      ],
                      "regionCode": "US"
                    },
                    "zipCode": "94043-1351"
                  },
                  "price": {
                    "type": "REGULAR",
                    "name": "Delivery Price",
                    "state": "ACTUAL",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": 2000000
                    },
                    "taxIncluded": true
                  },
                  "fulfillmentContact": {
                    "email": "johnjohnson@gmail.com",
                    "firstName": "John",
                    "lastName": "Johnson",
                    "displayName": "John Johnson"
                  }
                },
                "purchaseLocationType": "ONLINE_PURCHASE"
              }
            }
          }
        }
      }
    },
    "outputContexts": [
      {
        "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/_actions_on_google",
        "lifespanCount": 99,
        "parameters": {
          "data": "{\"location\":{\"coordinates\":{\"latitude\":37.432524,\"longitude\":-122.098545},\"zipCode\":\"94043-1351\",\"city\":\"MOUNTAIN VIEW\",\"postalAddress\":{\"regionCode\":\"US\",\"postalCode\":\"94043-1351\",\"administrativeArea\":\"CA\",\"locality\":\"MOUNTAIN VIEW\",\"addressLines\":[\"1600 AMPHITHEATRE PKWY\"],\"recipients\":[\"John Doe\"]},\"phoneNumber\":\"+1 123-456-7890\"},\"latestOrderId\":\"ORDER_ID\"}"
        }
      }
    ]
  }

JSON

{
  "expectUserResponse": true,
  "expectedInputs": [
    {
      "possibleIntents": [
        {
          "intent": "actions.intent.TRANSACTION_DECISION",
          "inputValueData": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec",
            "orderOptions": {
              "userInfoOptions": {
                "userInfoProperties": [
                  "EMAIL"
                ]
              }
            },
            "paymentParameters": {
              "merchantPaymentOption": {
                "defaultMerchantPaymentMethodId": "12345678",
                "managePaymentMethodUrl": "https://example.com/managePayment",
                "merchantPaymentMethod": [
                  {
                    "paymentMethodDisplayInfo": {
                      "paymentMethodDisplayName": "VISA **** 1234",
                      "paymentType": "PAYMENT_CARD"
                    },
                    "paymentMethodGroup": "Payment method group",
                    "paymentMethodId": "12345678",
                    "paymentMethodStatus": {
                      "status": "STATUS_OK",
                      "statusMessage": "Status message"
                    }
                  }
                ]
              }
            },
            "presentationOptions": {
              "actionDisplayName": "PLACE_ORDER"
            },
            "order": {
              "createTime": "2019-09-24T18:00:00.877Z",
              "lastUpdateTime": "2019-09-24T18:00:00.877Z",
              "merchantOrderId": "ORDER_ID",
              "userVisibleOrderId": "ORDER_ID",
              "transactionMerchant": {
                "id": "http://www.example.com",
                "name": "Example Merchant"
              },
              "contents": {
                "lineItems": [
                  {
                    "id": "LINE_ITEM_ID",
                    "name": "Pizza",
                    "description": "A four cheese pizza.",
                    "priceAttributes": [
                      {
                        "type": "REGULAR",
                        "name": "Item Price",
                        "state": "ACTUAL",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 8990000
                        },
                        "taxIncluded": true
                      },
                      {
                        "type": "TOTAL",
                        "name": "Total Price",
                        "state": "ACTUAL",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 9990000
                        },
                        "taxIncluded": true
                      }
                    ],
                    "notes": [
                      "Extra cheese."
                    ],
                    "purchase": {
                      "quantity": 1,
                      "unitMeasure": {
                        "measure": 1,
                        "unit": "POUND"
                      },
                      "itemOptions": [
                        {
                          "id": "ITEM_OPTION_ID",
                          "name": "Pepperoni",
                          "prices": [
                            {
                              "type": "REGULAR",
                              "state": "ACTUAL",
                              "name": "Item Price",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": 1000000
                              },
                              "taxIncluded": true
                            },
                            {
                              "type": "TOTAL",
                              "name": "Total Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": 1000000
                              },
                              "taxIncluded": true
                            }
                          ],
                          "note": "Extra pepperoni",
                          "quantity": 1,
                          "subOptions": []
                        }
                      ]
                    }
                  }
                ]
              },
              "buyerInfo": {
                "email": "janedoe@gmail.com",
                "firstName": "Jane",
                "lastName": "Doe",
                "displayName": "Jane Doe"
              },
              "priceAttributes": [
                {
                  "type": "SUBTOTAL",
                  "name": "Subtotal",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 9990000
                  },
                  "taxIncluded": true
                },
                {
                  "type": "DELIVERY",
                  "name": "Delivery",
                  "state": "ACTUAL",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 2000000
                  },
                  "taxIncluded": true
                },
                {
                  "type": "TAX",
                  "name": "Tax",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 3780000
                  },
                  "taxIncluded": true
                },
                {
                  "type": "TOTAL",
                  "name": "Total Price",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": 15770000
                  },
                  "taxIncluded": true
                }
              ],
              "followUpActions": [
                {
                  "type": "VIEW_DETAILS",
                  "title": "View details",
                  "openUrlAction": {
                    "url": "http://example.com"
                  }
                },
                {
                  "type": "CALL",
                  "title": "Call us",
                  "openUrlAction": {
                    "url": "tel:+16501112222"
                  }
                },
                {
                  "type": "EMAIL",
                  "title": "Email us",
                  "openUrlAction": {
                    "url": "mailto:person@example.com"
                  }
                }
              ],
              "termsOfServiceUrl": "http://www.example.com",
              "note": "Sale event",
              "promotions": [
                {
                  "coupon": "COUPON_CODE"
                }
              ],
              "purchase": {
                "status": "CREATED",
                "userVisibleStatusLabel": "CREATED",
                "type": "FOOD",
                "returnsInfo": {
                  "isReturnable": false,
                  "daysToReturn": 1,
                  "policyUrl": "http://www.example.com"
                },
                "fulfillmentInfo": {
                  "id": "FULFILLMENT_SERVICE_ID",
                  "fulfillmentType": "DELIVERY",
                  "expectedFulfillmentTime": {
                    "timeIso8601": "2019-09-25T18:00:00.877Z"
                  },
                  "location": {
                    "coordinates": {
                      "latitude": 37.421578499999995,
                      "longitude": -122.0837816
                    },
                    "zipCode": "94043-1351",
                    "city": "MOUNTAIN VIEW",
                    "postalAddress": {
                      "regionCode": "US",
                      "postalCode": "94043-1351",
                      "administrativeArea": "CA",
                      "locality": "MOUNTAIN VIEW",
                      "addressLines": [
                        "1600 AMPHITHEATRE PKWY"
                      ],
                      "recipients": [
                        "John Doe"
                      ]
                    },
                    "phoneNumber": "+1 123-456-7890"
                  },
                  "price": {
                    "type": "REGULAR",
                    "name": "Delivery Price",
                    "state": "ACTUAL",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": 2000000
                    },
                    "taxIncluded": true
                  },
                  "fulfillmentContact": {
                    "email": "johnjohnson@gmail.com",
                    "firstName": "John",
                    "lastName": "Johnson",
                    "displayName": "John Johnson"
                  }
                },
                "purchaseLocationType": "ONLINE_PURCHASE"
              }
            }
          }
        }
      ],
      "inputPrompt": {
        "richInitialPrompt": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "Transaction Decision Placeholder."
              }
            }
          ]
        }
      }
    }
  ],
  "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\",\"location\":{\"coordinates\":{\"latitude\":37.421578499999995,\"longitude\":-122.0837816},\"zipCode\":\"94043-1351\",\"city\":\"MOUNTAIN VIEW\",\"postalAddress\":{\"regionCode\":\"US\",\"postalCode\":\"94043-1351\",\"administrativeArea\":\"CA\",\"locality\":\"MOUNTAIN VIEW\",\"addressLines\":[\"1600 AMPHITHEATRE PKWY\"],\"recipients\":[\"John Doe\"]},\"phoneNumber\":\"+1 123-456-7890\"},\"latestOrderId\":\"ORDER_ID\"}}"
}

Xử lý quyết định của người dùng

Sau khi thực hiện ý định, Trợ lý sẽ gửi cho bạn một yêu cầu thực hiện với ý định actions_intent_TRANSACTION_DECISION cùng với câu trả lời của người dùng quyết định về giao dịch. Bạn sẽ nhận được một Argument có chứa một giá trị giao dịch. Giá trị này sẽ bao gồm:

  • transactionDecision - Quyết định của người dùng về đề xuất đơn đặt hàng. Các giá trị có thể là ORDER_ACCEPTED, ORDER_REJECTED, DELIVERY_ADDRESS_UPDATED, CART_CHANGE_REQUESTEDUSER_CANNOT_TRANSACT.
  • deliveryAddress - Địa chỉ giao hàng được cập nhật, trong trường hợp người dùng đã thay đổi địa chỉ giao hàng của họ. Trong trường hợp này, giá trị của transactionDecision sẽ DELIVERY_ADDRESS_UPDATED.

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

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

// Check transaction decision value
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");
}
ResponseBuilder responseBuilder = getResponseBuilder(request);
if ((transactionDecision != null && transactionDecision.equals("ORDER_ACCEPTED"))) {
  OrderV3 order = ((OrderV3) extension.get("order"));
}

Java

// Check transaction decision value
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");
}
ResponseBuilder responseBuilder = getResponseBuilder(request);
if ((transactionDecision != null && transactionDecision.equals("ORDER_ACCEPTED"))) {
  OrderV3 order = ((OrderV3) extension.get("order"));
}

JSON

{
    "responseId": "aba44717-4236-4602-af55-e5ae1fc2d97a-594de0a7",
    "queryResult": {
      "queryText": "actions_intent_TRANSACTION_DECISION",
      "action": "transaction.decision.complete",
      "parameters": {},
      "allRequiredParamsPresent": true,
      "fulfillmentText": "Failed to get transaction decision",
      "fulfillmentMessages": [
        {
          "text": {
            "text": [
              "Failed to get transaction decision"
            ]
          }
        }
      ],
      "outputContexts": [
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_media_response_audio"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_audio_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_account_linking"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_screen_output"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_capability_web_browser"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/google_assistant_input_type_voice"
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/_actions_on_google",
          "lifespanCount": 97,
          "parameters": {
            "data": "{\"location\":{\"coordinates\":{\"latitude\":37.432524,\"longitude\":-122.098545},\"zipCode\":\"94043-1351\",\"city\":\"MOUNTAIN VIEW\",\"postalAddress\":{\"regionCode\":\"US\",\"postalCode\":\"94043-1351\",\"administrativeArea\":\"CA\",\"locality\":\"MOUNTAIN VIEW\",\"addressLines\":[\"1600 AMPHITHEATRE PKWY\"],\"recipients\":[\"John Doe\"]},\"phoneNumber\":\"+1 123-456-7890\"}}"
          }
        },
        {
          "name": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy/contexts/actions_intent_transaction_decision",
          "parameters": {
            "TRANSACTION_DECISION_VALUE": {
              "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValue",
              "transactionDecision": "ORDER_ACCEPTED",
              "order": {
                "createTime": "2019-09-24T18:00:00.877Z",
                "lastUpdateTime": "2019-09-24T18:00:00.877Z",
                "merchantOrderId": "ORDER_ID",
                "userVisibleOrderId": "ORDER_ID",
                "transactionMerchant": {
                  "id": "http://www.example.com",
                  "name": "Example Merchant"
                },
                "contents": {
                  "lineItems": [
                    {
                      "id": "LINE_ITEM_ID",
                      "name": "Pizza",
                      "description": "A four cheese pizza.",
                      "priceAttributes": [
                        {
                          "type": "REGULAR",
                          "name": "Line Item Price",
                          "state": "ACTUAL",
                          "amount": {
                            "currencyCode": "USD",
                            "amountInMicros": 8990000
                          },
                          "taxIncluded": true
                        },
                        {
                          "type": "TOTAL",
                          "name": "Total Price",
                          "state": "ACTUAL",
                          "amount": {
                            "currencyCode": "USD",
                            "amountInMicros": 9990000
                          },
                          "taxIncluded": true
                        }
                      ],
                      "notes": [
                        "Extra cheese."
                      ],
                      "purchase": {
                        "quantity": 1,
                        "unitMeasure": {
                          "measure": 1,
                          "unit": "POUND"
                        },
                        "itemOptions": [
                          {
                            "id": "ITEM_OPTION_ID",
                            "name": "Pepperoni",
                            "prices": [
                              {
                                "type": "REGULAR",
                                "state": "ACTUAL",
                                "name": "Item Price",
                                "amount": {
                                  "currencyCode": "USD",
                                  "amountInMicros": 1000000
                                },
                                "taxIncluded": true
                              },
                              {
                                "type": "TOTAL",
                                "name": "Total Price",
                                "state": "ACTUAL",
                                "amount": {
                                  "currencyCode": "USD",
                                  "amountInMicros": 1000000
                                },
                                "taxIncluded": true
                              }
                            ],
                            "note": "Extra pepperoni",
                            "quantity": 1,
                            "subOptions": []
                          }
                        ]
                      }
                    }
                  ]
                },
                "buyerInfo": {
                  "email": "janedoe@gmail.com",
                  "firstName": "Jane",
                  "lastName": "Doe",
                  "displayName": "Jane Doe"
                },
                "priceAttributes": [
                  {
                    "type": "SUBTOTAL",
                    "name": "Subtotal",
                    "state": "ESTIMATE",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": 9990000
                    },
                    "taxIncluded": true
                  },
                  {
                    "type": "DELIVERY",
                    "name": "Delivery",
                    "state": "ACTUAL",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": 2000000
                    },
                    "taxIncluded": true
                  },
                  {
                    "type": "TAX",
                    "name": "Tax",
                    "state": "ESTIMATE",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": 3780000
                    },
                    "taxIncluded": true
                  },
                  {
                    "type": "TOTAL",
                    "name": "Total Price",
                    "state": "ESTIMATE",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": 15770000
                    },
                    "taxIncluded": true
                  }
                ],
                "followUpActions": [
                  {
                    "type": "VIEW_DETAILS",
                    "title": "View details",
                    "openUrlAction": {
                      "url": "http://example.com"
                    }
                  },
                  {
                    "type": "CALL",
                    "title": "Call us",
                    "openUrlAction": {
                      "url": "tel:+16501112222"
                    }
                  },
                  {
                    "type": "EMAIL",
                    "title": "Email us",
                    "openUrlAction": {
                      "url": "mailto:person@example.com"
                    }
                  }
                ],
                "termsOfServiceUrl": "www.example.com",
                "note": "Sale event",
                "promotions": [
                  {
                    "coupon": "COUPON_CODE"
                  }
                ],
                "purchase": {
                  "status": "CREATED",
                  "userVisibleStatusLabel": "CREATED",
                  "type": "FOOD",
                  "returnsInfo": {
                    "isReturnable": false,
                    "daysToReturn": 1,
                    "policyUrl": "http://www.example.com"
                  },
                  "fulfillmentInfo": {
                    "id": "FULFILLMENT_SERVICE_ID",
                    "fulfillmentType": "DELIVERY",
                    "expectedFulfillmentTime": {
                      "timeIso8601": "2019-09-25T18:00:00.877Z"
                    },
                    "location": {},
                    "price": {
                      "type": "REGULAR",
                      "name": "Delivery Price",
                      "state": "ACTUAL",
                      "amount": {
                        "currencyCode": "USD",
                        "amountInMicros": 2000000
                      },
                      "taxIncluded": true
                    },
                    "fulfillmentContact": {
                      "email": "johnjohnson@gmail.com",
                      "firstName": "John",
                      "lastName": "Johnson",
                      "displayName": "John Johnson"
                    }
                  },
                  "purchaseLocationType": "ONLINE_PURCHASE"
                }
              }
            },
            "text": ""
          }
        }
      ],
      "intent": {
        "name": "projects/df-transactions/agent/intents/fd16d86b-60db-4d19-a683-5b52a22f4795",
        "displayName": "Transaction Decision Complete"
      },
      "intentDetectionConfidence": 1,
      "languageCode": "en"
    },
    "originalDetectIntentRequest": {
      "source": "google",
      "version": "2",
      "payload": {
        "user": {
          "locale": "en-US",
          "lastSeen": "2019-09-23T19:49:32Z",
          "userVerificationStatus": "VERIFIED"
        },
        "conversation": {
          "conversationId": "ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy",
          "type": "ACTIVE",
          "conversationToken": "[\"merchant_payment\"]"
        },
        "inputs": [
          {
            "intent": "actions.intent.TRANSACTION_DECISION",
            "rawInputs": [
              {
                "inputType": "KEYBOARD"
              }
            ],
            "arguments": [
              {
                "name": "TRANSACTION_DECISION_VALUE",
                "extension": {
                  "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValue",
                  "transactionDecision": "ORDER_ACCEPTED",
                  "order": {
                    "createTime": "2019-09-24T18:00:00.877Z",
                    "lastUpdateTime": "2019-09-24T19:00:00.877Z",
                    "merchantOrderId": "ORDER_ID",
                    "userVisibleOrderId": "ORDER_ID",
                    "transactionMerchant": {
                      "id": "http://www.example.com",
                      "name": "Example Merchant"
                    },
                    "contents": {
                      "lineItems": [
                        {
                          "id": "LINE_ITEM_ID",
                          "name": "Pizza",
                          "description": "A four cheese pizza.",
                          "priceAttributes": [
                            {
                              "type": "REGULAR",
                              "name": "Line Item Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": 8990000
                              },
                              "taxIncluded": true
                            },
                            {
                              "type": "TOTAL",
                              "name": "Total Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": 9990000
                              },
                              "taxIncluded": true
                            }
                          ],
                          "notes": [
                            "Extra cheese."
                          ],
                          "purchase": {
                            "quantity": 1,
                            "unitMeasure": {
                              "measure": 1,
                              "unit": "POUND"
                            },
                            "itemOptions": [
                              {
                                "id": "ITEM_OPTION_ID",
                                "name": "Pepperoni",
                                "prices": [
                                  {
                                    "type": "REGULAR",
                                    "state": "ACTUAL",
                                    "name": "Item Price",
                                    "amount": {
                                      "currencyCode": "USD",
                                      "amountInMicros": 1000000
                                    },
                                    "taxIncluded": true
                                  },
                                  {
                                    "type": "TOTAL",
                                    "name": "Total Price",
                                    "state": "ACTUAL",
                                    "amount": {
                                      "currencyCode": "USD",
                                      "amountInMicros": 1000000
                                    },
                                    "taxIncluded": true
                                  }
                                ],
                                "note": "Extra pepperoni",
                                "quantity": 1,
                                "subOptions": []
                              }
                            ]
                          }
                        }
                      ]
                    },
                    "buyerInfo": {
                      "email": "janedoe@gmail.com",
                      "firstName": "Jane",
                      "lastName": "Doe",
                      "displayName": "Jane Doe"
                    },
                    "priceAttributes": [
                      {
                        "type": "SUBTOTAL",
                        "name": "Subtotal",
                        "state": "ESTIMATE",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 9990000
                        },
                        "taxIncluded": true
                      },
                      {
                        "type": "DELIVERY",
                        "name": "Delivery",
                        "state": "ACTUAL",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 2000000
                        },
                        "taxIncluded": true
                      },
                      {
                        "type": "TAX",
                        "name": "Tax",
                        "state": "ESTIMATE",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 3780000
                        },
                        "taxIncluded": true
                      },
                      {
                        "type": "TOTAL",
                        "name": "Total Price",
                        "state": "ESTIMATE",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": 15770000
                        },
                        "taxIncluded": true
                      }
                    ],
                    "followUpActions": [
                      {
                        "type": "VIEW_DETAILS",
                        "title": "View details",
                        "openUrlAction": {
                          "url": "http://example.com"
                        }
                      },
                      {
                        "type": "CALL",
                        "title": "Call us",
                        "openUrlAction": {
                          "url": "tel:+16501112222"
                        }
                      },
                      {
                        "type": "EMAIL",
                        "title": "Email us",
                        "openUrlAction": {
                          "url": "mailto:person@example.com"
                        }
                      }
                    ],
                    "termsOfServiceUrl": "www.example.com",
                    "note": "Sale event",
                    "promotions": [
                      {
                        "coupon": "COUPON_CODE"
                      }
                    ],
                    "purchase": {
                      "status": "CREATED",
                      "userVisibleStatusLabel": "CREATED",
                      "type": "FOOD",
                      "returnsInfo": {
                        "isReturnable": false,
                        "daysToReturn": 1,
                        "policyUrl": "http://www.example.com"
                      },
                      "fulfillmentInfo": {
                        "id": "FULFILLMENT_SERVICE_ID",
                        "fulfillmentType": "DELIVERY",
                        "expectedFulfillmentTime": {
                          "timeIso8601": "2019-09-25T18:00:00.877Z"
                        },
                        "location": {},
                        "price": {
                          "type": "REGULAR",
                          "name": "Delivery Price",
                          "state": "ACTUAL",
                          "amount": {
                            "currencyCode": "USD",
                            "amountInMicros": 2000000
                          },
                          "taxIncluded": true
                        },
                        "fulfillmentContact": {
                          "email": "johnjohnson@gmail.com",
                          "firstName": "John",
                          "lastName": "Johnson",
                          "displayName": "John Johnson"
                        }
                      },
                      "purchaseLocationType": "ONLINE_PURCHASE"
                    }
                  }
                }
              },
              {
                "name": "text"
              }
            ]
          }
        ],
        "surface": {
          "capabilities": [
            {
              "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.ACCOUNT_LINKING"
            },
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        },
        "availableSurfaces": [
          {
            "capabilities": [
              {
                "name": "actions.capability.WEB_BROWSER"
              },
              {
                "name": "actions.capability.AUDIO_OUTPUT"
              },
              {
                "name": "actions.capability.SCREEN_OUTPUT"
              }
            ]
          }
        ]
      }
    },
    "session": "projects/df-transactions/agent/sessions/ABwppHGYEP2Fj7tJBxoaKMevL6lZ2rs063lOEWhSW5etZWVOoJe7Dzm_bLejRTYIYXL3D78ER7YvA5aN9Wpy"
  }

JSON

{
  "user": {
    "locale": "en-US",
    "lastSeen": "2019-11-11T23:57:31Z",
    "userVerificationStatus": "VERIFIED"
  },
  "conversation": {
    "conversationId": "ABwppHGFwStZlYaQ9YT8rg9t_idVsxZrku1pUDrEbGSJmSUMatVdPwPEEQSCe1IwIBoN4sS4Weyn9pmgetEgbsWgw3JSvQmw",
    "type": "ACTIVE",
    "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\",\"location\":{\"coordinates\":{\"latitude\":37.421578499999995,\"longitude\":-122.0837816},\"zipCode\":\"94043-1351\",\"city\":\"MOUNTAIN VIEW\",\"postalAddress\":{\"regionCode\":\"US\",\"postalCode\":\"94043-1351\",\"administrativeArea\":\"CA\",\"locality\":\"MOUNTAIN VIEW\",\"addressLines\":[\"1600 AMPHITHEATRE PKWY\"],\"recipients\":[\"John Doe\"]},\"phoneNumber\":\"+1 123-456-7890\"},\"latestOrderId\":\"ORDER_ID\"}}"
  },
  "inputs": [
    {
      "intent": "actions.intent.TRANSACTION_DECISION",
      "rawInputs": [
        {}
      ],
      "arguments": [
        {
          "name": "TRANSACTION_DECISION_VALUE",
          "extension": {
            "@type": "type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValue",
            "transactionDecision": "ORDER_ACCEPTED",
            "order": {
              "googleOrderId": "05528125187071048269",
              "merchantOrderId": "ORDER_ID",
              "userVisibleOrderId": "ORDER_ID",
              "buyerInfo": {
                "email": "janedoe@example.com",
                "firstName": "Jane",
                "lastName": "Doe",
                "displayName": "Jane Doe"
              },
              "createTime": "2019-09-24T18:00:00.877Z",
              "lastUpdateTime": "2019-09-24T18:00:00.877Z",
              "transactionMerchant": {
                "id": "http://www.example.com",
                "name": "Example Merchant"
              },
              "contents": {
                "lineItems": [
                  {
                    "id": "LINE_ITEM_ID",
                    "name": "Pizza",
                    "priceAttributes": [
                      {
                        "type": "REGULAR",
                        "name": "Item Price",
                        "state": "ACTUAL",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": "8990000"
                        },
                        "taxIncluded": true
                      },
                      {
                        "type": "TOTAL",
                        "name": "Total Price",
                        "state": "ACTUAL",
                        "amount": {
                          "currencyCode": "USD",
                          "amountInMicros": "9990000"
                        },
                        "taxIncluded": true
                      }
                    ],
                    "description": "A four cheese pizza.",
                    "notes": [
                      "Extra cheese."
                    ],
                    "purchase": {
                      "quantity": 1,
                      "itemOptions": [
                        {
                          "id": "ITEM_OPTION_ID",
                          "name": "Pepperoni",
                          "prices": [
                            {
                              "type": "REGULAR",
                              "name": "Item Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": "1000000"
                              },
                              "taxIncluded": true
                            },
                            {
                              "type": "TOTAL",
                              "name": "Total Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": "1000000"
                              },
                              "taxIncluded": true
                            }
                          ],
                          "note": "Extra pepperoni",
                          "quantity": 1
                        }
                      ],
                      "unitMeasure": {
                        "measure": 1,
                        "unit": "POUND"
                      }
                    },
                    "vertical": {
                      "@type": "type.googleapis.com/google.actions.orders.v3.verticals.purchase.PurchaseItemExtension",
                      "quantity": 1,
                      "itemOptions": [
                        {
                          "id": "ITEM_OPTION_ID",
                          "name": "Pepperoni",
                          "prices": [
                            {
                              "type": "REGULAR",
                              "name": "Item Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": "1000000"
                              },
                              "taxIncluded": true
                            },
                            {
                              "type": "TOTAL",
                              "name": "Total Price",
                              "state": "ACTUAL",
                              "amount": {
                                "currencyCode": "USD",
                                "amountInMicros": "1000000"
                              },
                              "taxIncluded": true
                            }
                          ],
                          "note": "Extra pepperoni",
                          "quantity": 1
                        }
                      ],
                      "unitMeasure": {
                        "measure": 1,
                        "unit": "POUND"
                      }
                    }
                  }
                ]
              },
              "priceAttributes": [
                {
                  "type": "SUBTOTAL",
                  "name": "Subtotal",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": "9990000"
                  },
                  "taxIncluded": true
                },
                {
                  "type": "DELIVERY",
                  "name": "Delivery",
                  "state": "ACTUAL",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": "2000000"
                  },
                  "taxIncluded": true
                },
                {
                  "type": "TAX",
                  "name": "Tax",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": "3780000"
                  },
                  "taxIncluded": true
                },
                {
                  "type": "TOTAL",
                  "name": "Total Price",
                  "state": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "amountInMicros": "15770000"
                  },
                  "taxIncluded": true
                }
              ],
              "followUpActions": [
                {
                  "type": "VIEW_DETAILS",
                  "title": "View details",
                  "openUrlAction": {
                    "url": "http://example.com"
                  }
                },
                {
                  "type": "CALL",
                  "title": "Call us",
                  "openUrlAction": {
                    "url": "tel:+16501112222"
                  }
                },
                {
                  "type": "EMAIL",
                  "title": "Email us",
                  "openUrlAction": {
                    "url": "mailto:person@example.com"
                  }
                }
              ],
              "termsOfServiceUrl": "http://www.example.com",
              "note": "Sale event",
              "paymentData": {
                "paymentResult": {
                  "merchantPaymentMethodId": "12345678"
                },
                "paymentInfo": {
                  "paymentMethodDisplayInfo": {
                    "paymentType": "PAYMENT_CARD",
                    "paymentMethodDisplayName": "VISA **** 1234"
                  },
                  "paymentMethodProvenance": "PAYMENT_METHOD_PROVENANCE_MERCHANT"
                }
              },
              "promotions": [
                {
                  "coupon": "COUPON_CODE"
                }
              ],
              "purchase": {
                "status": "CREATED",
                "type": "FOOD",
                "returnsInfo": {
                  "daysToReturn": 1,
                  "policyUrl": "http://www.example.com"
                },
                "fulfillmentInfo": {
                  "id": "FULFILLMENT_SERVICE_ID",
                  "fulfillmentType": "DELIVERY",
                  "expectedFulfillmentTime": {
                    "timeIso8601": "2019-09-25T18:00:00.877Z"
                  },
                  "location": {
                    "coordinates": {
                      "latitude": 37.421578499999995,
                      "longitude": -122.0837816
                    },
                    "zipCode": "94043-1351",
                    "city": "MOUNTAIN VIEW",
                    "postalAddress": {
                      "regionCode": "US",
                      "postalCode": "94043-1351",
                      "administrativeArea": "CA",
                      "locality": "MOUNTAIN VIEW",
                      "addressLines": [
                        "1600 AMPHITHEATRE PKWY"
                      ],
                      "recipients": [
                        "John Doe"
                      ]
                    },
                    "phoneNumber": "+1 123-456-7890"
                  },
                  "price": {
                    "type": "REGULAR",
                    "name": "Delivery Price",
                    "state": "ACTUAL",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": "2000000"
                    },
                    "taxIncluded": true
                  },
                  "fulfillmentContact": {
                    "email": "johnjohnson@gmail.com",
                    "firstName": "John",
                    "lastName": "Johnson",
                    "displayName": "John Johnson"
                  }
                },
                "purchaseLocationType": "ONLINE_PURCHASE",
                "userVisibleStatusLabel": "CREATED"
              },
              "vertical": {
                "@type": "type.googleapis.com/google.actions.orders.v3.verticals.purchase.PurchaseOrderExtension",
                "status": "CREATED",
                "type": "FOOD",
                "returnsInfo": {
                  "daysToReturn": 1,
                  "policyUrl": "http://www.example.com"
                },
                "fulfillmentInfo": {
                  "id": "FULFILLMENT_SERVICE_ID",
                  "fulfillmentType": "DELIVERY",
                  "expectedFulfillmentTime": {
                    "timeIso8601": "2019-09-25T18:00:00.877Z"
                  },
                  "location": {
                    "coordinates": {
                      "latitude": 37.421578499999995,
                      "longitude": -122.0837816
                    },
                    "zipCode": "94043-1351",
                    "city": "MOUNTAIN VIEW",
                    "postalAddress": {
                      "regionCode": "US",
                      "postalCode": "94043-1351",
                      "administrativeArea": "CA",
                      "locality": "MOUNTAIN VIEW",
                      "addressLines": [
                        "1600 AMPHITHEATRE PKWY"
                      ],
                      "recipients": [
                        "John Doe"
                      ]
                    },
                    "phoneNumber": "+1 123-456-7890"
                  },
                  "price": {
                    "type": "REGULAR",
                    "name": "Delivery Price",
                    "state": "ACTUAL",
                    "amount": {
                      "currencyCode": "USD",
                      "amountInMicros": "2000000"
                    },
                    "taxIncluded": true
                  },
                  "fulfillmentContact": {
                    "email": "johnjohnson@gmail.com",
                    "firstName": "John",
                    "lastName": "Johnson",
                    "displayName": "John Johnson"
                  }
                },
                "purchaseLocationType": "ONLINE_PURCHASE",
                "userVisibleStatusLabel": "CREATED"
              }
            }
          }
        },
        {
          "name": "text"
        }
      ]
    }
  ],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      },
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.ACCOUNT_LINKING"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      }
    ]
  },
  "availableSurfaces": [
    {
      "capabilities": [
        {
          "name": "actions.capability.SCREEN_OUTPUT"
        },
        {
          "name": "actions.capability.WEB_BROWSER"
        },
        {
          "name": "actions.capability.AUDIO_OUTPUT"
        }
      ]
    }
  ]
}

5. Hoàn tất đơn đặt hàng và gửi biên nhận

Khi ý định actions.intent.TRANSACTION_DECISION trả về với một transactionDecisionORDER_ACCEPTED, bạn phải ngay lập tức thực hiện mọi bắt buộc phải xử lý để "xác nhận" thứ tự (như duy trì nó trong cơ sở dữ liệu của riêng bạn và tính phí người dùng).

Bạn có thể kết thúc cuộc trò chuyện bằng câu trả lời này nhưng bạn phải đưa ra một câu trả lời đơn giản để duy trì cuộc trò chuyện. Khi bạn cung cấp orderUpdate ban đầu này, người dùng sẽ thấy "thẻ biên nhận đã thu gọn" cùng với phần phản hồi còn lại của bạn. Thẻ này sẽ phản ánh biên nhận mà người dùng tìm thấy trong Danh sách đơn đặt hàng.

Trong quá trình xác nhận đơn đặt hàng, đối tượng đơn đặt hàng của bạn có thể bao gồm một userVisibleOrderId là mã nhận dạng mà người dùng nhìn thấy cho đơn đặt hàng. Bạn có thể sử dụng lại merchantOrderId của mình cho trường này.

Một phần của OrderUpdate Đối tượng sẽ cần chứa một hành động tiếp theo Biểu tượng này sẽ được thể hiện dưới dạng các nút URL ở cuối chi tiết đơn đặt hàng mà người dùng có thể tìm thấy trong Danh sách đơn đặt hàng của họ trên Trợ lý.

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

Node.js

// Set lastUpdateTime and update status of order
const order = arg.order;
order.lastUpdateTime = '2019-09-24T19:00:00.877Z';
order.purchase.status = 'CONFIRMED';
order.purchase.userVisibleStatusLabel = 'Order confirmed';

// Send synchronous order update
conv.ask(`Transaction completed! Your order`
+ ` ${conv.data.latestOrderId} is all set!`);
conv.ask(new Suggestions('send order update'));
conv.ask(new OrderUpdate({
  type: 'SNAPSHOT',
  reason: 'Reason string',
  order: order,
}));

Node.js

// Set lastUpdateTime and update status of order
const order = arg.order;
order.lastUpdateTime = '2019-09-24T19:00:00.877Z';
order.purchase.status = 'CONFIRMED';
order.purchase.userVisibleStatusLabel = 'Order confirmed';

// Send synchronous order update
conv.ask(`Transaction completed! Your order `
+ `${conv.data.latestOrderId} is all set!`);
conv.ask(new Suggestions('send order update'));
conv.ask(new OrderUpdate({
  type: 'SNAPSHOT',
  reason: 'Reason string',
  order: order,
}));

Java

OrderV3 order = ((OrderV3) extension.get("order"));
order.setLastUpdateTime("2019-09-24T19:00:00.877Z");

// Update order status
PurchaseOrderExtension purchaseOrderExtension = order.getPurchase();
purchaseOrderExtension.setStatus("CONFIRMED");
purchaseOrderExtension.setUserVisibleStatusLabel("Order confirmed");
order.setPurchase(purchaseOrderExtension);

// Order update
OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setType("SNAPSHOT")
    .setReason("Reason string")
    .setOrder(order);

Map<String, Object> conversationData = request.getConversationData();
String orderId = (String) conversationData.get("latestOrderId");
responseBuilder
    .add("Transaction completed! Your order " + orderId + " is all set!")
    .addSuggestions(new String[] {"send order update"})
    .add(new StructuredResponse().setOrderUpdateV3(orderUpdate));

Java

OrderV3 order = ((OrderV3) extension.get("order"));
order.setLastUpdateTime("2019-09-24T19:00:00.877Z");

// Update order status
PurchaseOrderExtension purchaseOrderExtension = order.getPurchase();
purchaseOrderExtension.setStatus("CONFIRMED");
purchaseOrderExtension.setUserVisibleStatusLabel("Order confirmed");
order.setPurchase(purchaseOrderExtension);

// Order update
OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setType("SNAPSHOT")
    .setReason("Reason string")
    .setOrder(order);

Map<String, Object> conversationData = request.getConversationData();
String orderId = (String) conversationData.get("latestOrderId");
responseBuilder
    .add("Transaction completed! Your order " + orderId + " is all set!")
    .addSuggestions(new String[] {"send order update"})
    .add(new StructuredResponse().setOrderUpdateV3(orderUpdate));

JSON

{
    "payload": {
        "google": {
          "expectUserResponse": true,
          "richResponse": {
                "items": [
                    {
                        "simpleResponse": {
                        "textToSpeech": "Transaction completed! Your order undefined is all set!"
                        }
                    },
                    {
                        "structuredResponse": {
                        "orderUpdateV3": {
                            "order": {
                            "buyerInfo": {
                                "displayName": "Jane Doe",
                                "email": "janedoe@gmail.com",
                                "firstName": "Jane",
                                "lastName": "Doe"
                            },
                            "contents": {
                                "lineItems": [
                                {
                                    "description": "A four cheese pizza.",
                                    "id": "LINE_ITEM_ID",
                                    "name": "Pizza",
                                    "notes": [
                                    "Extra cheese."
                                    ],
                                    "priceAttributes": [
                                    {
                                        "amount": {
                                        "amountInMicros": 8990000,
                                        "currencyCode": "USD"
                                        },
                                        "name": "Line Item Price",
                                        "state": "ACTUAL",
                                        "taxIncluded": true,
                                        "type": "REGULAR"
                                    },
                                    {
                                        "amount": {
                                        "amountInMicros": 9990000,
                                        "currencyCode": "USD"
                                        },
                                        "name": "Total Price",
                                        "state": "ACTUAL",
                                        "taxIncluded": true,
                                        "type": "TOTAL"
                                    }
                                    ],
                                    "purchase": {
                                    "itemOptions": [
                                        {
                                        "id": "ITEM_OPTION_ID",
                                        "name": "Pepperoni",
                                        "note": "Extra pepperoni",
                                        "prices": [
                                            {
                                            "amount": {
                                                "amountInMicros": 1000000,
                                                "currencyCode": "USD"
                                            },
                                            "name": "Item Price",
                                            "state": "ACTUAL",
                                            "taxIncluded": true,
                                            "type": "REGULAR"
                                            },
                                            {
                                            "amount": {
                                                "amountInMicros": 1000000,
                                                "currencyCode": "USD"
                                            },
                                            "name": "Total Price",
                                            "state": "ACTUAL",
                                            "taxIncluded": true,
                                            "type": "TOTAL"
                                            }
                                        ],
                                        "quantity": 1,
                                        "subOptions": []
                                        }
                                    ],
                                    "quantity": 1,
                                    "unitMeasure": {
                                        "measure": 1,
                                        "unit": "POUND"
                                    }
                                    }
                                }
                                ]
                            },
                            "createTime": "2019-09-24T18:00:00.877Z",
                            "followUpActions": [
                                {
                                "openUrlAction": {
                                    "url": "http://example.com"
                                },
                                "title": "View details",
                                "type": "VIEW_DETAILS"
                                },
                                {
                                "openUrlAction": {
                                    "url": "tel:+16501112222"
                                },
                                "title": "Call us",
                                "type": "CALL"
                                },
                                {
                                "openUrlAction": {
                                    "url": "mailto:person@example.com"
                                },
                                "title": "Email us",
                                "type": "EMAIL"
                                }
                            ],
                            "lastUpdateTime": "2019-09-24T19:00:00.877Z",
                            "merchantOrderId": "ORDER_ID",
                            "note": "Sale event",
                            "priceAttributes": [
                                {
                                "amount": {
                                    "amountInMicros": 9990000,
                                    "currencyCode": "USD"
                                },
                                "name": "Subtotal",
                                "state": "ESTIMATE",
                                "taxIncluded": true,
                                "type": "SUBTOTAL"
                                },
                                {
                                "amount": {
                                    "amountInMicros": 2000000,
                                    "currencyCode": "USD"
                                },
                                "name": "Delivery",
                                "state": "ACTUAL",
                                "taxIncluded": true,
                                "type": "DELIVERY"
                                },
                                {
                                "amount": {
                                    "amountInMicros": 3780000,
                                    "currencyCode": "USD"
                                },
                                "name": "Tax",
                                "state": "ESTIMATE",
                                "taxIncluded": true,
                                "type": "TAX"
                                },
                                {
                                "amount": {
                                    "amountInMicros": 15770000,
                                    "currencyCode": "USD"
                                },
                                "name": "Total Price",
                                "state": "ESTIMATE",
                                "taxIncluded": true,
                                "type": "TOTAL"
                                }
                            ],
                            "promotions": [
                                {
                                "coupon": "COUPON_CODE"
                                }
                            ],
                            "purchase": {
                                "fulfillmentInfo": {
                                "expectedFulfillmentTime": {
                                    "timeIso8601": "2019-09-25T18:00:00.877Z"
                                },
                                "fulfillmentContact": {
                                    "displayName": "John Johnson",
                                    "email": "johnjohnson@gmail.com",
                                    "firstName": "John",
                                    "lastName": "Johnson"
                                },
                                "fulfillmentType": "DELIVERY",
                                "id": "FULFILLMENT_SERVICE_ID",
                                "location": {},
                                "price": {
                                    "amount": {
                                    "amountInMicros": 2000000,
                                    "currencyCode": "USD"
                                    },
                                    "name": "Delivery Price",
                                    "state": "ACTUAL",
                                    "taxIncluded": true,
                                    "type": "REGULAR"
                                }
                                },
                                "purchaseLocationType": "ONLINE_PURCHASE",
                                "returnsInfo": {
                                "daysToReturn": 1,
                                "isReturnable": false,
                                "policyUrl": "http://www.example.com"
                                },
                                "status": "CONFIRMED",
                                "type": "FOOD",
                                "userVisibleStatusLabel": "Order confirmed"
                            },
                            "termsOfServiceUrl": "www.example.com",
                            "transactionMerchant": {
                                "id": "http://www.example.com",
                                "name": "Example Merchant"
                            },
                            "userVisibleOrderId": "ORDER_ID"
                            },
                            "reason": "Reason string",
                            "type": "SNAPSHOT"
                        }
                        }
                    }
                ],
                "suggestions": [
                    {
                        "title": "send order update"
                    }
                ]
            }
        }
      }
}

JSON

{
    "expectUserResponse": true,
    "expectedInputs": [
      {
        "possibleIntents": [
          {
            "intent": "actions.intent.TEXT"
          }
        ],
        "inputPrompt": {
          "richInitialPrompt": {
            "items": [
              {
                "simpleResponse": {
                  "textToSpeech": "Transaction completed! Your order ORDER_ID is all set!"
                }
              },
              {
                "structuredResponse": {
                  "orderUpdateV3": {
                    "type": "SNAPSHOT",
                    "reason": "Reason string",
                    "order": {
                      "googleOrderId": "05528125187071048269",
                      "merchantOrderId": "ORDER_ID",
                      "userVisibleOrderId": "ORDER_ID",
                      "buyerInfo": {
                        "email": "janedoe@example.com",
                        "firstName": "Jane",
                        "lastName": "Doe",
                        "displayName": "Jane Doe"
                      },
                      "createTime": "2019-09-24T18:00:00.877Z",
                      "lastUpdateTime": "2019-09-24T19:00:00.877Z",
                      "transactionMerchant": {
                        "id": "http://www.example.com",
                        "name": "Example Merchant"
                      },
                      "contents": {
                        "lineItems": [
                          {
                            "id": "LINE_ITEM_ID",
                            "name": "Pizza",
                            "priceAttributes": [
                              {
                                "type": "REGULAR",
                                "name": "Item Price",
                                "state": "ACTUAL",
                                "amount": {
                                  "currencyCode": "USD",
                                  "amountInMicros": "8990000"
                                },
                                "taxIncluded": true
                              },
                              {
                                "type": "TOTAL",
                                "name": "Total Price",
                                "state": "ACTUAL",
                                "amount": {
                                  "currencyCode": "USD",
                                  "amountInMicros": "9990000"
                                },
                                "taxIncluded": true
                              }
                            ],
                            "description": "A four cheese pizza.",
                            "notes": [
                              "Extra cheese."
                            ],
                            "purchase": {
                              "quantity": 1,
                              "itemOptions": [
                                {
                                  "id": "ITEM_OPTION_ID",
                                  "name": "Pepperoni",
                                  "prices": [
                                    {
                                      "type": "REGULAR",
                                      "name": "Item Price",
                                      "state": "ACTUAL",
                                      "amount": {
                                        "currencyCode": "USD",
                                        "amountInMicros": "1000000"
                                      },
                                      "taxIncluded": true
                                    },
                                    {
                                      "type": "TOTAL",
                                      "name": "Total Price",
                                      "state": "ACTUAL",
                                      "amount": {
                                        "currencyCode": "USD",
                                        "amountInMicros": "1000000"
                                      },
                                      "taxIncluded": true
                                    }
                                  ],
                                  "note": "Extra pepperoni",
                                  "quantity": 1
                                }
                              ],
                              "unitMeasure": {
                                "measure": 1,
                                "unit": "POUND"
                              }
                            },
                            "vertical": {
                              "@type": "type.googleapis.com/google.actions.orders.v3.verticals.purchase.PurchaseItemExtension",
                              "quantity": 1,
                              "itemOptions": [
                                {
                                  "id": "ITEM_OPTION_ID",
                                  "name": "Pepperoni",
                                  "prices": [
                                    {
                                      "type": "REGULAR",
                                      "name": "Item Price",
                                      "state": "ACTUAL",
                                      "amount": {
                                        "currencyCode": "USD",
                                        "amountInMicros": "1000000"
                                      },
                                      "taxIncluded": true
                                    },
                                    {
                                      "type": "TOTAL",
                                      "name": "Total Price",
                                      "state": "ACTUAL",
                                      "amount": {
                                        "currencyCode": "USD",
                                        "amountInMicros": "1000000"
                                      },
                                      "taxIncluded": true
                                    }
                                  ],
                                  "note": "Extra pepperoni",
                                  "quantity": 1
                                }
                              ],
                              "unitMeasure": {
                                "measure": 1,
                                "unit": "POUND"
                              }
                            }
                          }
                        ]
                      },
                      "priceAttributes": [
                        {
                          "type": "SUBTOTAL",
                          "name": "Subtotal",
                          "state": "ESTIMATE",
                          "amount": {
                            "currencyCode": "USD",
                            "amountInMicros": "9990000"
                          },
                          "taxIncluded": true
                        },
                        {
                          "type": "DELIVERY",
                          "name": "Delivery",
                          "state": "ACTUAL",
                          "amount": {
                            "currencyCode": "USD",
                            "amountInMicros": "2000000"
                          },
                          "taxIncluded": true
                        },
                        {
                          "type": "TAX",
                          "name": "Tax",
                          "state": "ESTIMATE",
                          "amount": {
                            "currencyCode": "USD",
                            "amountInMicros": "3780000"
                          },
                          "taxIncluded": true
                        },
                        {
                          "type": "TOTAL",
                          "name": "Total Price",
                          "state": "ESTIMATE",
                          "amount": {
                            "currencyCode": "USD",
                            "amountInMicros": "15770000"
                          },
                          "taxIncluded": true
                        }
                      ],
                      "followUpActions": [
                        {
                          "type": "VIEW_DETAILS",
                          "title": "View details",
                          "openUrlAction": {
                            "url": "http://example.com"
                          }
                        },
                        {
                          "type": "CALL",
                          "title": "Call us",
                          "openUrlAction": {
                            "url": "tel:+16501112222"
                          }
                        },
                        {
                          "type": "EMAIL",
                          "title": "Email us",
                          "openUrlAction": {
                            "url": "mailto:person@example.com"
                          }
                        }
                      ],
                      "termsOfServiceUrl": "http://www.example.com",
                      "note": "Sale event",
                      "paymentData": {
                        "paymentResult": {
                          "merchantPaymentMethodId": "12345678"
                        },
                        "paymentInfo": {
                          "paymentMethodDisplayInfo": {
                            "paymentType": "PAYMENT_CARD",
                            "paymentMethodDisplayName": "VISA **** 1234"
                          },
                          "paymentMethodProvenance": "PAYMENT_METHOD_PROVENANCE_MERCHANT"
                        }
                      },
                      "promotions": [
                        {
                          "coupon": "COUPON_CODE"
                        }
                      ],
                      "purchase": {
                        "status": "CONFIRMED",
                        "type": "FOOD",
                        "returnsInfo": {
                          "daysToReturn": 1,
                          "policyUrl": "http://www.example.com"
                        },
                        "fulfillmentInfo": {
                          "id": "FULFILLMENT_SERVICE_ID",
                          "fulfillmentType": "DELIVERY",
                          "expectedFulfillmentTime": {
                            "timeIso8601": "2019-09-25T18:00:00.877Z"
                          },
                          "location": {
                            "coordinates": {
                              "latitude": 37.421578499999995,
                              "longitude": -122.0837816
                            },
                            "zipCode": "94043-1351",
                            "city": "MOUNTAIN VIEW",
                            "postalAddress": {
                              "regionCode": "US",
                              "postalCode": "94043-1351",
                              "administrativeArea": "CA",
                              "locality": "MOUNTAIN VIEW",
                              "addressLines": [
                                "1600 AMPHITHEATRE PKWY"
                              ],
                              "recipients": [
                                "John Doe"
                              ]
                            },
                            "phoneNumber": "+1 123-456-7890"
                          },
                          "price": {
                            "type": "REGULAR",
                            "name": "Delivery Price",
                            "state": "ACTUAL",
                            "amount": {
                              "currencyCode": "USD",
                              "amountInMicros": "2000000"
                            },
                            "taxIncluded": true
                          },
                          "fulfillmentContact": {
                            "email": "johnjohnson@gmail.com",
                            "firstName": "John",
                            "lastName": "Johnson",
                            "displayName": "John Johnson"
                          }
                        },
                        "purchaseLocationType": "ONLINE_PURCHASE",
                        "userVisibleStatusLabel": "Order confirmed"
                      },
                      "vertical": {
                        "@type": "type.googleapis.com/google.actions.orders.v3.verticals.purchase.PurchaseOrderExtension",
                        "status": "CREATED",
                        "type": "FOOD",
                        "returnsInfo": {
                          "daysToReturn": 1,
                          "policyUrl": "http://www.example.com"
                        },
                        "fulfillmentInfo": {
                          "id": "FULFILLMENT_SERVICE_ID",
                          "fulfillmentType": "DELIVERY",
                          "expectedFulfillmentTime": {
                            "timeIso8601": "2019-09-25T18:00:00.877Z"
                          },
                          "location": {
                            "coordinates": {
                              "latitude": 37.421578499999995,
                              "longitude": -122.0837816
                            },
                            "zipCode": "94043-1351",
                            "city": "MOUNTAIN VIEW",
                            "postalAddress": {
                              "regionCode": "US",
                              "postalCode": "94043-1351",
                              "administrativeArea": "CA",
                              "locality": "MOUNTAIN VIEW",
                              "addressLines": [
                                "1600 AMPHITHEATRE PKWY"
                              ],
                              "recipients": [
                                "John Doe"
                              ]
                            },
                            "phoneNumber": "+1 123-456-7890"
                          },
                          "price": {
                            "type": "REGULAR",
                            "name": "Delivery Price",
                            "state": "ACTUAL",
                            "amount": {
                              "currencyCode": "USD",
                              "amountInMicros": "2000000"
                            },
                            "taxIncluded": true
                          },
                          "fulfillmentContact": {
                            "email": "johnjohnson@gmail.com",
                            "firstName": "John",
                            "lastName": "Johnson",
                            "displayName": "John Johnson"
                          }
                        },
                        "purchaseLocationType": "ONLINE_PURCHASE",
                        "userVisibleStatusLabel": "CREATED"
                      }
                    }
                  }
                }
              }
            ],
            "suggestions": [
              {
                "title": "send order update"
              }
            ]
          }
        }
      }
    ],
    "conversationToken": "{\"data\":{\"paymentType\":\"merchant_payment\",\"location\":{\"coordinates\":{\"latitude\":37.421578499999995,\"longitude\":-122.0837816},\"zipCode\":\"94043-1351\",\"city\":\"MOUNTAIN VIEW\",\"postalAddress\":{\"regionCode\":\"US\",\"postalCode\":\"94043-1351\",\"administrativeArea\":\"CA\",\"locality\":\"MOUNTAIN VIEW\",\"addressLines\":[\"1600 AMPHITHEATRE PKWY\"],\"recipients\":[\"John Doe\"]},\"phoneNumber\":\"+1 123-456-7890\"},\"latestOrderId\":\"ORDER_ID\"}}"
  }

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

Bạn cần thông báo cho người dùng biết về trạng thái của đơn đặt hàng trong suốt vòng đời của nó. Gửi thông tin cập nhật đơn đặt hàng của người dùng bằng cách gửi HTTP PATCH yêu cầu Orders API kèm theo 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 Orders API

Các yêu cầu cập nhật đơn đặt hàng đối với Orders API được cấp phép bằng quyền truy cập mã thông báo. Để cập nhật thông tin đơn đặt hàng cho Orders API, hãy tải một tệp JSON xuống khoá tài khoản dịch vụ được liên kết với dự án Actions Console của bạn, sau đó trao đổi mã tài khoản dịch vụ cho mã thông báo mang 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ụ, hãy làm theo các bước sau:

  1. Trong bảng điều khiển Google Cloud, chuyển đến Trình đơn PublisherCode > 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 Vai trò thành 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, bạn có thể đổi khoá dịch vụ lấy mã thông báo mang bằng cách sử dụng thư viện ứng dụng API của Google và phạm vi &quot;https://www.googleapis.com/auth/actions.order.developer&quot;. Bạn có thể tìm thấy các bước cài đặt và các ví dụ trên trang GitHub của thư viện ứng dụng API.

Bạn cũng có thể tham khảo order-update.js trong các mẫu Node.jsJava của chúng tôi để một ví dụ về trao đổi khoá.

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

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

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

Hãy 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 phương thức truyền OAuth mà bạn đã đổi khoá tài khoản dịch vụ.
  • "Content-Type: application/json".

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

{ "orderUpdate": OrderUpdate }

OrderUpdate đối tượng 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 mà bạn đang cập nhật. Để cập nhật trạng thái đơn đặt hàng, đặt giá trị thành purchase.status, purchase.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 đơn đặt hàng, hãy thiết lập giá trị thành đối tượng Order đã cập nhật. Nếu bạn đang cập nhật trạng thái của đơn đặt hàng (ví dụ: từ "CONFIRMED" đến "SHIPPED"), đối tượng này sẽ chứa các trường sau:

    • merchantOrderId – Mã nhận dạng mà bạn đặt trong đố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 PurchaseStatus, chẳng hạn như "SHIPPED" hoặc "DELIVERED".
      • userVisibleStatusLabel – 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ư "Đơn đặt hàng của bạn đã được vận chuyển và đang ở trên ".
  • userNotification (không bắt buộc) – Một 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. Ghi chú việc bao gồm đối tượng này không đảm bảo rằng thông báo sẽ xuất hiện thiết bị của người dùng.

Mã mẫu sau đây cho thấy ví dụ về OrderUpdate cập nhật trạng thái của đơn đặt hàng để DELIVERED:

Node.js

// Import the 'googleapis' module for authorizing the request.
const {google} = require('googleapis');
// Import the 'request-promise' module for sending an HTTP POST request.
const request = require('request-promise');
// 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.
// Replacing the string path with a path to your service account key.
// i.e. const serviceAccountKey = 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(
    serviceAccountKey.client_email,
    null,
    serviceAccountKey.private_key,
    ['https://www.googleapis.com/auth/actions.order.developer'],
    null,
);

// Authorize the client
let tokens = await jwtClient.authorize();

// Declare order update
const orderUpdate = new OrderUpdate({
    updateMask: [
      'lastUpdateTime',
      'purchase.status',
      'purchase.userVisibleStatusLabel',
    ].join(','),
    order: {
      merchantOrderId: orderId, // Specify the ID of the order to update
      lastUpdateTime: new Date().toISOString(),
      purchase: {
        status: 'DELIVERED',
        userVisibleStatusLabel: 'Order delivered',
      },
    },
    reason: 'Order status updated to delivered.',
});

// Set up the PATCH request header and body,
// including the authorized token and order update.
let options = {
  method: 'PATCH',
  uri: `https://actions.googleapis.com/v3/orders/${orderId}`,
  auth: {
    bearer: tokens.access_token,
  },
  body: {
    header: {
      isInSandbox: true,
    },
    orderUpdate,
  },
  json: true,
};

// Send the PATCH request to the Orders API.
try {
  await request(options);
  conv.close(`The order has been updated.`);
} catch (e) {
  console.log(`Error: ${e}`);
  conv.close(`There was an error sending an order update.`);
}

Node.js

// Import the 'googleapis' module for authorizing the request.
const {google} = require('googleapis');
// Import the 'request-promise' module for sending an HTTP POST request.
const request = require('request-promise');
// 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.
// Replacing the string path with a path to your service account key.
// i.e. const serviceAccountKey = 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(
    serviceAccountKey.client_email,
    null,
    serviceAccountKey.private_key,
    ['https://www.googleapis.com/auth/actions.order.developer'],
    null,
);

// Authorize the client
let tokens = await jwtClient.authorize();

// Declare order update
const orderUpdate = new OrderUpdate({
    updateMask: [
      'lastUpdateTime',
      'purchase.status',
      'purchase.userVisibleStatusLabel',
    ].join(','),
    order: {
      merchantOrderId: orderId, // Specify the ID of the order to update
      lastUpdateTime: new Date().toISOString(),
      purchase: {
        status: 'DELIVERED',
        userVisibleStatusLabel: 'Order delivered',
      },
    },
    reason: 'Order status updated to delivered.',
});

// Set up the PATCH request header and body,
// including the authorized token and order update.
let options = {
  method: 'PATCH',
  uri: `https://actions.googleapis.com/v3/orders/${orderId}`,
  auth: {
    bearer: tokens.access_token,
  },
  body: {
    header: {
      isInSandbox: true,
    },
    orderUpdate,
  },
  json: true,
};

// Send the PATCH request to the Orders API.
try {
  await request(options);
  conv.close(`The order has been updated.`);
} catch (e) {
  console.log(`Error: ${e}`);
  conv.close(`There was an error sending an order update.`);
}

Java

// Setup service account credentials
String serviceAccountFile = MyActionsApp.class.getClassLoader()
    .getResource(SERVICE_ACCOUNT_KEY_FILE_NAME)
    .getFile();
InputStream actionsApiServiceAccount = new FileInputStream(
    serviceAccountFile);
ServiceAccountCredentials serviceAccountCredentials = (ServiceAccountCredentials)
    ServiceAccountCredentials.fromStream(actionsApiServiceAccount)
        .createScoped(Collections.singleton(
            "https://www.googleapis.com/auth/actions.order.developer"));
AccessToken token = serviceAccountCredentials.refreshAccessToken();

// Setup request with headers
HttpPatch patchRequest = new HttpPatch(
    "https://actions.googleapis.com/v3/orders/" + orderId);
patchRequest.setHeader("Content-type", "application/json");
patchRequest.setHeader("Authorization", "Bearer " + token.getTokenValue());

// Create order update
FieldMask fieldMask = FieldMask.newBuilder().addAllPaths(Arrays.asList(
    "lastUpdateTime",
    "purchase.status",
    "purchase.userVisibleStatusLabel"))
    .build();

OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setOrder(new OrderV3()
        .setMerchantOrderId(orderId)
        .setLastUpdateTime(Instant.now().toString())
        .setPurchase(new PurchaseOrderExtension()
            .setStatus("DELIVERED")
            .setUserVisibleStatusLabel("Order delivered.")))
    .setUpdateMask(FieldMaskUtil.toString(fieldMask))
    .setReason("Order status was updated to delivered.");

// 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());
patchRequest.setEntity(entity);

// Make request
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse response = httpClient.execute(patchRequest);
LOGGER.info(response.getStatusLine().getStatusCode() + " " + response
    .getStatusLine().getReasonPhrase());

return getResponseBuilder(request)
    .add("The order has been updated.")
    .build();

Java

// Setup service account credentials
String serviceAccountFile = MyActionsApp.class.getClassLoader()
    .getResource(SERVICE_ACCOUNT_KEY_FILE_NAME)
    .getFile();
InputStream actionsApiServiceAccount = new FileInputStream(
    serviceAccountFile);
ServiceAccountCredentials serviceAccountCredentials = (ServiceAccountCredentials)
    ServiceAccountCredentials.fromStream(actionsApiServiceAccount)
        .createScoped(Collections.singleton(
            "https://www.googleapis.com/auth/actions.order.developer"));
AccessToken token = serviceAccountCredentials.refreshAccessToken();

// Setup request with headers
HttpPatch patchRequest = new HttpPatch(
    "https://actions.googleapis.com/v3/orders/" + orderId);
patchRequest.setHeader("Content-type", "application/json");
patchRequest.setHeader("Authorization", "Bearer " + token.getTokenValue());

// Create order update
FieldMask fieldMask = FieldMask.newBuilder().addAllPaths(Arrays.asList(
    "lastUpdateTime",
    "purchase.status",
    "purchase.userVisibleStatusLabel"))
    .build();

OrderUpdateV3 orderUpdate = new OrderUpdateV3()
    .setOrder(new OrderV3()
        .setMerchantOrderId(orderId)
        .setLastUpdateTime(Instant.now().toString())
        .setPurchase(new PurchaseOrderExtension()
            .setStatus("DELIVERED")
            .setUserVisibleStatusLabel("Order delivered.")))
    .setUpdateMask(FieldMaskUtil.toString(fieldMask))
    .setReason("Order status was updated to delivered.");

// 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());
patchRequest.setEntity(entity);

// Make request
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse response = httpClient.execute(patchRequest);
LOGGER.info(response.getStatusLine().getStatusCode() + " " + response
    .getStatusLine().getReasonPhrase());

return getResponseBuilder(request)
    .add("The order has been updated.")
    .build();
Đặt trạng thái mua hàng

status của đơn đặt hàng mới cập nhật phải mô tả trạng thái hiện tại của đơn đặt hàng. Trong order.purchase.status của bản cập nhật , hãy sử dụng một trong các giá trị sau:

  • CREATED - Đơn đặt hàng được người dùng chấp nhận và "đã tạo" từ góc nhìn của Hành động, nhưng yêu cầu xử lý thủ công trên phần phụ trợ.
  • CONFIRMED – Đơn đặt hàng đang hoạt động và đang được xử lý để thực hiện đơn hàng.
  • IN_PREPARATION – Đơn đặt hàng đang được chuẩn bị để vận chuyển/giao hàng, chẳng hạn như thực phẩm đang được nấu chín hoặc một mặt hàng được đóng gói.
  • READY_FOR_PICKUP – Người nhận có thể đến lấy đơn đặt hàng.
  • DELIVERED - Đơn đặt hàng đã được giao cho người nhận
  • OUT_OF_STOCK – Một hoặc nhiều mặt hàng trong đơn đặt hàng đã hết hàng.
  • CHANGE_REQUESTED - Người dùng đã yêu cầu thay đổi đối với đơn đặt hàng và thay đổi đó đang được xử lý.
  • RETURNED – Đơn đặt hàng đã bị người dùng trả lại sau khi giao hàng.
  • REJECTED – Nếu bạn không thể xử lý, sạc hoặc không thể xử lý "kích hoạt" đơn đặt hàng.
  • CANCELLED - Đơn đặt hàng đã bị người dùng hủy.

Bạn nên gửi thông tin cập nhật về đơn đặt hàng cho từng trạng thái có liên quan đến giao dịch. Ví dụ: nếu giao dịch của bạn yêu cầu xử lý thủ công để ghi lại đơn đặt hàng sau khi đặt, gửi thông tin cập nhật đơn đặt hàng trên CREATED cho đến đã xử lý thêm. Không phải đơn đặt hàng nào cũng yêu cầu mọi giá trị trạng thái.

Khắc phục sự cố

Nếu gặp vấn đề trong quá trình thử nghiệm, bạn nên đọc các bước khắc phục sự cố của chúng tôi cho các giao dịch.