Как создавать транзакции с физическими товарами и платежами, управляемыми продавцом (Dialogflow)

В этом руководстве описан процесс разработки проекта Actions, который включает транзакции для физических товаров с использованием способов оплаты, управляемых вашим сайтом.

Процесс транзакции

Если в вашем проекте Actions физические транзакции обрабатываются с помощью платежей, управляемых продавцом, используется следующий процесс:

  1. Сбор информации (необязательно). В зависимости от характера транзакции в начале разговора вы можете запросить у пользователя следующую информацию:
    1. Проверка требований к транзакциям. Используйте помощник по требованиям к транзакциям в начале разговора, чтобы убедиться, что платежная информация пользователя правильно настроена и доступна, прежде чем пользователь начнет собирать корзину.
    2. Запрос адреса доставки. Если для транзакции требуется адрес доставки, запросите его у пользователя с помощью вспомогательного намерения.
  2. Сбор заказа. Пользователь выбирает товары, которые хочет купить.
  3. Свяжите аккаунты. Чтобы пользователь мог выбрать способ оплаты, сохраненный в вашем сервисе, свяжите его аккаунт Google с аккаунтом в вашем сервисе.
  4. Предложите заказ. Когда корзина будет заполнена, предложите пользователю заказ, чтобы он мог подтвердить его правильность. Если заказ подтвержден, вы получите ответ с информацией о нем и токеном оплаты.
  5. Завершите заказ и отправьте чек. После подтверждения заказа обновите данные о наличии товаров или другие сервисы выполнения заказов, а затем отправьте пользователю чек.
  6. Отправка обновлений заказа. На протяжении всего процесса выполнения заказа отправляйте пользователю обновления, отправляя запросы PATCH в Orders API.

Ограничения и правила проверки

Обратите внимание, что к действиям с транзакциями применяются дополнительные правила. Проверка действий с транзакциями может занять до шести недель, поэтому учитывайте это при планировании графика выпуска. Чтобы упростить процесс проверки, убедитесь, что вы соблюдаете правила и рекомендации для транзакций, прежде чем отправлять действие на проверку.

Действия, связанные с продажей физических товаров, можно развертывать только в следующих странах:

Австралия
Бразилия
Индонезия
Канада
Япония
Мексика
Катар
Россия
Сингапур
США
Таиланд
Турция
Швейцария

Создайте проект

Примеры диалогов, связанных с транзакциями, можно найти в примерах транзакций на Node.js и Java.

Настройка проекта

При создании действия необходимо указать в консоли Actions, что вы хотите выполнять транзакции. Если вы используете клиентскую библиотеку Node.JS, настройте фулфилмент так, чтобы он работал с последней версией Orders API.

Чтобы настроить проект и выполнение, сделайте следующее:

  1. Создайте новый проект или импортируйте существующий.
  2. Перейдите в раздел Deploy (Развертывание) > Directory information (Информация в каталоге).
  3. В разделе Дополнительная информация > Транзакции установите флажок "Используют ли ваши действия Transactions API для продажи физических товаров?".

  4. Если вы используете клиентскую библиотеку Node.JS для создания фулфилмента Action, откройте код фулфилмента и обновите объявление приложения, чтобы установить для флага ordersv3 значение true. В приведенном ниже фрагменте кода показан пример объявления приложения для Orders API версии 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,
});

Настройка входа

Если вы используете собственный способ оплаты, рекомендуем связать аккаунт Google пользователя с его аккаунтом в вашем сервисе, чтобы получать, показывать и использовать сохраненные там способы оплаты.

Для этого мы предлагаем связывание аккаунтов с помощью OAuth 2.0. Мы настоятельно рекомендуем включить поток утверждений OAuth 2.0, так как он значительно упрощает работу пользователей.

Мы предоставляем намерение actions.intent.SIGN_IN, которое позволяет запрашивать у пользователя связь аккаунтов в середине разговора. Чтобы использовать намерение actions.intent.SIGN_IN, необходимо включить связывание аккаунтов в консоли Actions.

Используйте это намерение, если вы не можете найти accessToken в объекте User в запросе вебхука. Это означает, что пользователь ещё не связал свой аккаунт.

После запроса намерения actions.intent.SIGN_IN вы получите Argument, содержащий SignInStatus со значением "OK", "CANCELLED" или "ERROR". Если статус – "OK", то в объекте User должен быть accessToken.

выполнение заказов;

Запросить вход

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\"}}"
}
Получение результата входа

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. Сбор информации (необязательно)

Прежде всего проверьте репутацию своего канала. Проверка требований к транзакциям (необязательно)

Для пользователей

Активируйте намерение actions.intent.TRANSACTION_REQUIREMENTS_CHECK, чтобы быстро проверить, смогут ли пользователи совершить транзакцию. Это позволит пользователям продолжить и даст им возможность исправить любые настройки, мешающие выполнению транзакции.

Например, при вызове ваше действие может спросить: "Вы хотите заказать обувь или проверить баланс своего счета?" Если пользователь говорит "заказать обувь", вы должны сразу же запросить это намерение, чтобы он мог продолжить и исправить любые настройки, мешающие ему продолжить транзакцию.

Запрос намерения проверки требований к транзакциям приведет к одному из следующих результатов:

  • Если требования соблюдены, намерение будет отправлено обратно в ваш ответ с условием успеха, и вы сможете продолжить создание заказа пользователя.
  • Если одно или несколько требований не могут быть выполнены, намерение будет отправлено обратно в ваш фулфилмент с условием сбоя. В этом случае вам следует перевести разговор на другую тему или завершить его.
    • Если пользователь может устранить ошибки, которые привели к сбою, ему будет предложено сделать это на устройстве. Если разговор происходит на устройстве, поддерживающем только голосовое взаимодействие, будет инициирована передача на телефон пользователя.
выполнение заказов;

Чтобы убедиться, что пользователь соответствует требованиям к транзакциям, запросите выполнение намерения actions.intent.TRANSACTION_REQUIREMENTS_CHECK с объектом TransactionRequirementsCheckSpec.

Требования

Проверить, соответствует ли пользователь требованиям для транзакций, можно с помощью клиентской библиотеки:

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\"}}"
}
Получение результатов проверки требований

После выполнения намерения Ассистент отправляет вашему сервису запрос с намерением actions.intent.TRANSACTION_REQUIREMENTS_CHECK и результатом проверки. Чтобы правильно обработать этот запрос, объявите намерение Dialogflow, которое активируется событием actions_intent_TRANSACTION_REQUIREMENTS_CHECK. Когда он сработает, обработайте его в своем выполнении с помощью клиентской библиотеки:

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. Запрос адреса доставки (необязательно)

Если для транзакции требуется адрес доставки, вы можете запросить выполнение намерения actions.intent.DELIVERY_ADDRESS. Это может быть полезно для определения общей стоимости, места доставки/самовывоза или для того, чтобы убедиться, что пользователь находится в вашем регионе обслуживания.

При запросе на выполнение этого намерения вы передаете параметр reason, который позволяет вам предварить запрос Ассистента на получение адреса строкой. Например, если вы укажете "чтобы знать, куда отправить заказ", Ассистент может спросить у пользователя:

"Чтобы знать, куда отправить заказ, мне нужен ваш адрес доставки"

Для пользователей

На устройствах с экраном пользователь может выбрать адрес, который будет использоваться для транзакции. Если адрес не был указан ранее, его можно будет ввести.

На устройствах, поддерживающих только голосовое управление, Ассистент попросит у пользователя разрешение на передачу адреса по умолчанию для транзакции. Если пользователь не указывал адрес ранее, ему будет предложено ввести его на телефоне.

Запросить адрес

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\"}}"
}
Получить адрес

После выполнения намерения Ассистент отправляет вашему сервису запрос с намерением actions.intent.DELIVERY_ADDRESS.

Чтобы правильно обработать этот запрос, объявите намерение Dialogflow, которое активируется событием actions_intent_DELIVERY_ADDRESS. Когда он сработает, обработайте его в своем выполнении с помощью клиентской библиотеки:

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. Создание заказа

Для пользователей

Получив нужную информацию о пользователе, вы создаете интерфейс для сборки корзины, который помогает пользователю сформировать заказ. Для каждого действия будет использоваться свой процесс сборки корзины, подходящий для конкретного товара или услуги.

Самый простой способ – предложить пользователю выбрать товары из списка. Однако вы можете упростить процесс, Вы можете создать интерфейс сборки корзины, который позволит пользователю повторно заказать свою последнюю покупку с помощью простого вопроса "да" или "нет". Вы также можете показать пользователю карусель или список рекомендуемых товаров.

Рекомендуем использовать расширенные ответы, чтобы наглядно представить пользователю доступные варианты, но при этом построить диалог так, чтобы пользователь мог собрать корзину, используя только голосовые команды. Рекомендации и примеры качественного оформления корзины можно найти в руководстве по дизайну транзакций.

выполнение заказов;

В ходе разговора вам нужно будет собрать товары, которые пользователь хочет купить, а затем создать объект Order.

В Order должна быть указана следующая информация:

  • buyerInfo – информация о пользователе, совершающем покупку.
  • transactionMerchant – информация о продавце, который выполнил заказ.
  • contents – фактическое содержимое заказа, указанное как lineItems.
  • priceAttributes – сведения о цене заказа, включая его общую стоимость со скидками и налогами.

Чтобы создать корзину, ознакомьтесь с документацией по ответу Order. Обратите внимание, что в зависимости от заказа вам может потребоваться включить разные поля.

Ниже приведен образец кода для полного заказа, включая необязательные поля.

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. Свяжите аккаунты

Если вы используете собственный способ оплаты, рекомендуем связать аккаунт Google пользователя с его аккаунтом в вашем сервисе, чтобы получать, показывать и использовать сохраненные там способы оплаты.

Для этого мы предлагаем связывание аккаунтов с помощью OAuth 2.0. Мы настоятельно рекомендуем включить поток утверждений OAuth 2.0, так как он значительно упрощает работу пользователей.

Мы предоставляем намерение actions.intent.SIGN_IN, которое позволяет запрашивать у пользователя связь аккаунтов в середине разговора. Чтобы использовать намерение actions.intent.SIGN_IN, необходимо включить связывание аккаунтов в консоли Actions.

Используйте это намерение, если вы не можете найти accessToken в объекте User в запросе вебхука. Это означает, что пользователь ещё не связал свой аккаунт.

После запроса намерения actions.intent.SIGN_IN вы получите Argument, содержащий SignInStatus со значением "OK", "CANCELLED" или "ERROR". Если статус – "OK", то в объекте User должен быть accessToken.

выполнение заказов;

Запросить вход

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\"}}"
}
Получение результата входа

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. Предложить заказ

После того как вы создали заказ, вы должны показать его пользователю, чтобы он мог подтвердить или отклонить его. Запросите намерение actions.intent.TRANSACTION_DECISION и предоставьте заказ, созданный с использованием сохраненной платежной информации пользователя.

Удобство для пользователей

Когда вы запрашиваете намерение actions.intent.TRANSACTION_DECISION, Ассистент запускает встроенную функцию, в которой переданный вами объект Order отображается непосредственно на карточке предварительного просмотра корзины. Пользователь может сказать "Разместить заказ", отклонить транзакцию, изменить способ оплаты, например кредитную карту или адрес, или попросить изменить содержимое заказа.

Пользователь также может запросить изменения в заказе. В этом случае убедитесь, что ваш сервис выполнения заказов может обрабатывать запросы на изменение заказа после завершения сборки корзины.

выполнение заказов;

При запросе намерения actions.intent.TRANSACTION_DECISION вы создадите объект TransactionDecision, который содержит Order, а также orderOptions и paymentParameters. Объект paymentParameters содержит объект merchantPaymentOption с полями, описывающими способ оплаты пользователя.

Ниже приведен пример объекта TransactionsDecision для заказа, оплаченного кредитной картой 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\"}}"
}

Как обрабатывать решение пользователя

После выполнения намерения Ассистент отправляет вашему сервису запрос с намерением actions_intent_TRANSACTION_DECISION, содержащим ответ пользователя на решение о транзакции. Вы получите Argument, содержащий TransactionDecisionValue. Это значение будет содержать следующее:

  • transactionDecision – решение пользователя по предложенному заказу. Возможные значения: ORDER_ACCEPTED, ORDER_REJECTED, DELIVERY_ADDRESS_UPDATED, CART_CHANGE_REQUESTED и USER_CANNOT_TRANSACT.
  • deliveryAddress – обновленный адрес доставки, если пользователь его изменил. В этом случае значением transactionDecision будет DELIVERY_ADDRESS_UPDATED.

Чтобы правильно обработать этот запрос, объявите намерение Dialogflow, которое активируется событием actions_intent_TRANSACTION_DECISION. Когда он сработает, обработайте его в своем фулфилменте:

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. Завершите заказ и отправьте чек

Когда намерение actions.intent.TRANSACTION_DECISION возвращает transactionDecision со значением ORDER_ACCEPTED, вы должны немедленно выполнить все необходимые действия, чтобы подтвердить заказ (например, сохранить его в своей базе данных и списать средства со счета пользователя).

Вы можете завершить разговор этим ответом, но вы должны включить простой ответ, чтобы продолжить разговор. Когда вы предоставите этот начальный orderUpdate, пользователь увидит свернутую карточку чека вместе с остальной частью вашего ответа. Эта карточка будет дублировать чек, который пользователь видит в истории заказов.

При подтверждении заказа объект заказа может включать userVisibleOrderId, который является идентификатором, который пользователь видит для заказа. Вы можете повторно использовать merchantOrderId для этого поля.

Часть объекта OrderUpdate должна содержать объект action, который представляет собой кнопки URL внизу страницы сведений о заказе. Пользователь может найти их в истории заказов Ассистента.

выполнение заказов;

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. Отправлять уведомления о заказах

Вам нужно будет информировать пользователя о статусе заказа на протяжении всего его жизненного цикла. Отправьте пользователю информацию о заказе, отправив HTTP-запросы PATCH в Orders API со статусом и деталями заказа.

Как настроить асинхронные запросы к Orders API

Запросы на обновление заказов, отправляемые в Orders API, авторизуются с помощью токена доступа. Чтобы отправить запрос PATCH в Orders API, скачайте ключ сервисного аккаунта JSON, связанный с вашим проектом в консоли Actions, а затем обменяйте его на токен на предъявителя, который можно передать в заголовке Authorization HTTP-запроса.

Чтобы получить ключ сервисного аккаунта, выполните следующие действия:

  1. В консоли Google Cloud выберите Меню ☰ > APIs & Services (API и сервисы) > Credentials (Учетные данные) > Create credentials (Создать учетные данные) > Service account key (Ключ сервисного аккаунта).
  2. В разделе Service Account (Сервисный аккаунт) выберите New Service Account (Новый сервисный аккаунт).
  3. Установите для сервисного аккаунта значение service-account.
  4. В поле Role (Роль) выберите Project (Проект) > Owner (Владелец).
  5. В качестве типа ключа выберите JSON.
  6. Нажмите Создать.
  7. Закрытый ключ сервисного аккаунта в формате JSON будет скачан на ваш компьютер.

В коде обновления заказа вы можете обменять ключ сервиса на токен на предъявителя, используя клиентскую библиотеку Google API и область действия "https://www.googleapis.com/auth/actions.order.developer". Инструкции по установке и примеры можно найти на странице клиентской библиотеки API в GitHub.

Вы также можете посмотреть пример обмена ключами order-update.js в наших примерах для Node.js и Java.

Отправлять уведомления о заказах

Обменяв ключ сервисного аккаунта на токен на предъявителя OAuth, вы сможете отправлять обновления заказов в виде авторизованных запросов PATCH в Orders API.

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

В запросе укажите следующие заголовки:

  • "Authorization: Bearer token" токеном на предъявителя OAuth, на который вы обменяли ключ сервисного аккаунта.
  • "Content-Type: application/json".

Тело запроса PATCH должно иметь следующий формат JSON:

{ "orderUpdate": OrderUpdate }

Объект OrderUpdate состоит из следующих полей верхнего уровня:

  • updateMask – поля заказа, которые вы обновляете. Чтобы обновить состояние заказа, задайте значение purchase.status, purchase.userVisibleStatusLabel.
  • order – содержимое обновления. Если вы обновляете содержимое заказа, задайте значение для обновленного объекта Order. Если вы обновляете статус заказа (например, с "CONFIRMED" на "SHIPPED"), объект содержит следующие поля:

    • merchantOrderId – тот же идентификатор, который вы указали в объекте Order.
    • lastUpdateTime – временная метка обновления.
    • purchase – объект, содержащий следующие элементы:
      • status – статус заказа в виде PurchaseStatus, например "SHIPPED" или "DELIVERED".
      • userVisibleStatusLabel – пользовательский ярлык с подробными сведениями о состоянии заказа, например "Ваш заказ отправлен и находится в пути".
  • userNotification (необязательно) – объект userNotification, который может показываться на устройстве пользователя при отправке этого обновления. Обратите внимание, что наличие этого объекта не гарантирует, что на устройстве пользователя появится уведомление.

В примере кода ниже показан запрос OrderUpdate, который обновляет статус заказа на 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();
Как задать статус покупки

Свойство status в обновлении заказа должно описывать текущее состояние заказа. В поле order.purchase.status укажите одно из следующих значений:

  • CREATED – заказ принят пользователем и создан с точки зрения вашего действия, но требует обработки вручную на сервере.
  • CONFIRMED – заказ активен и обрабатывается для выполнения.
  • IN_PREPARATION – заказ готовится к отправке или доставке, например еда готовится или товар упаковывается.
  • READY_FOR_PICKUP – заказ готов к выдаче.
  • DELIVERED – заказ доставлен получателю.
  • OUT_OF_STOCK – одного или нескольких товаров из заказа нет в наличии.
  • CHANGE_REQUESTED – пользователь запросил изменение заказа, и запрос обрабатывается.
  • RETURNED – заказ возвращен пользователем после доставки.
  • REJECTED – если вы не смогли обработать, оплатить или иным образом активировать заказ.
  • CANCELLED – заказ отменен пользователем.

Вы должны отправлять обновления статуса заказа для каждого статуса, который относится к вашей транзакции. Например, если для регистрации заказа после его размещения требуется ручная обработка, отправьте обновление заказа CREATED, пока эта дополнительная обработка не будет выполнена. Не у каждого заказа есть все статусы.

Устранение неполадок

Если во время тестирования у вас возникнут проблемы, ознакомьтесь с инструкциями по устранению неполадок.