En esta guía, se explica el proceso de desarrollo de un proyecto de Actions que usa la API de pedidos a fin de realizar reservas.
Flujo de transacción
Cuando tu proyecto de Actions controla las reservas, usa el siguiente flujo:
- Valida los requisitos de las transacciones (opcional): Usa el asistente de requisitos de transacciones al comienzo de la conversación para asegurarte de que el usuario pueda llevar a cabo una transacción.
- Compila el pedido: Guía al usuario a través de un “ensamblaje de carrito” en el que compile los detalles de su reserva.
- Propón el pedido: Una vez que se complete el "carrito", propone la reserva al "pedido" al usuario, de modo que pueda confirmar que es correcta. Si se confirma la reserva, recibirás una respuesta con los detalles de la reserva.
- Terminar el pedido y enviar un recibo: Una vez que se confirme el pedido, actualiza tu sistema de reservas y envía un recibo al usuario.
- Enviar actualizaciones de pedidos: Durante el ciclo de vida de la reserva, envía actualizaciones del estado de la reserva del usuario enviando solicitudes PATCH a la API de pedidos.
Restricciones y lineamientos de revisión
Ten en cuenta que se aplican políticas adicionales a las acciones que usan la API de transaction y pedidos. La revisión de las Acciones con transacciones puede tardar hasta seis semanas, así que ten en cuenta ese tiempo cuando planifiques tu programación de lanzamiento. A fin de facilitar el proceso de revisión, asegúrate de cumplir con los lineamientos y políticas de las transacciones antes de enviar tu acción para su revisión.
Solo puedes implementar acciones que usen la API de pedidos en los siguientes países:
Australia Brasil Canadá Indonesia |
Japón México Catar Rusia |
Singapur Suiza Tailandia Turquía Reino Unido Estados Unidos |
Cómo compilar un proyecto
Para ver un ejemplo extenso de conversaciones transaccionales, consulta nuestra muestra de transacciones en Node.js.
Configuración
Cuando creas tu acción, debes especificar que deseas realizar transacciones en la Consola de Actions.
Para configurar tu proyecto y la entrega, haz lo siguiente:
- Crea un proyecto nuevo o importa uno existente.
- Navegue a Implementar > Información del directorio.
En Información adicional > Transacciones > marca la casilla que dice "¿Tus acciones usan la API de transacciones para realizar transacciones de bienes físicos?".
Validar los requisitos de las transacciones (opcional)
En cuanto el usuario indique que desea configurar una reserva, debes verificar que pueda solicitarla. Por ejemplo, cuando se invoca, tu acción puede preguntar "¿Quieres reservar un lugar?" Si el usuario dice "sí", debes asegurarte de que pueda continuar y darle la oportunidad de corregir cualquier configuración que le impida continuar con la transacción. Para ello, debes hacer la transición a una escena que realice una verificación de requisitos de transacción.
Crear escena de verificación de requisitos de transacción
- En la pestaña Escenas, agrega una escena nueva con el nombre
TransactionRequirementsCheck
. - En Relleno de ranuras, haz clic en + para agregar un espacio nuevo.
- En Seleccionar tipo, selecciona
actions.type.TransactionRequirementsCheckResult
como tipo de espacio. - En el campo del nombre de la ranura, asígnale el nombre
TransactionRequirementsCheck
. - Habilita la casilla de verificación Personalizar la escritura de valores de ranura (habilitada de forma predeterminada).
Haz clic en Guardar.
Una verificación de requisitos de transacción da como resultado uno de los siguientes resultados:
- Si se cumplen los requisitos, el parámetro de sesión se establece con una condición de éxito y puedes continuar con la compilación del pedido del usuario.
- Si no se pueden cumplir uno o más de los requisitos, el parámetro de sesión se establece con una condición de falla. En este caso, debes alejar la conversación de la experiencia transaccional o finalizarla.
- Si el usuario puede corregir cualquier error que genere el estado de falla, se le pedirá que lo resuelva. Si la conversación se lleva a cabo en una plataforma de solo voz, se iniciará una transferencia al teléfono del usuario.
Resultado de la verificación de los requisitos de la transacción
- En la pestaña Scenes, selecciona la escena
TransactionRequirementsCheck
que acabas de crear. - En Condición, haz clic en + para agregar una condición nueva.
En el campo de texto, ingresa la siguiente sintaxis para verificar la condición correcta:
scene.slots.status == "FINAL" && session.params.TransactionRequirementsCheck.resultType == "CAN_TRANSACT"
Coloca el cursor sobre la condición que acabas de agregar y haz clic en la flecha hacia arriba para colocarla antes de
if scene.slots.status == "FINAL"
.Habilita Enviar mensajes y proporciona un mensaje simple que informe al usuario que está listo para realizar una transacción.
candidates: - first_simple: variants: - speech: >- Looks like you're good to go!.
En Transition, selecciona otra escena, lo que le permite al usuario continuar la conversación y continuar con la transacción.
Selecciona la condición
else if scene.slots.status == "FINAL"
.Habilita Enviar mensajes y proporciona un mensaje simple para que el usuario sepa que no puede realizar una transacción.
candidates: - first_simple: variants: - speech: Transaction requirements check failed.
En Transición, selecciona Finalizar conversación para finalizar la conversación si un usuario no puede realizar transacciones.
Cree el pedido
Una vez que tengas la información del usuario que necesitas, crea una experiencia de "montaje de carrito" que lo guíe para que cree su reserva. Cada acción tendrá un flujo de ensamblado de carrito ligeramente diferente según corresponda para su servicio.
En una experiencia de ensamblado de carrito básico, un usuario selecciona opciones de una lista para agregar a su reserva, aunque puedes diseñar la conversación a fin de simplificar la experiencia del usuario. Por ejemplo, crea una experiencia de ensamblado de carritos que permita al usuario programar una reserva mensual con una simple pregunta de sí o no. También puedes presentar al usuario un carrusel o una tarjeta de lista de reservas "recomendados".
Recomendamos usar respuestas enriquecidas a fin de presentar las opciones del usuario de forma visual, pero también diseñar la conversación para que el usuario pueda crear su carrito solo con su voz. Para conocer algunas prácticas recomendadas y ejemplos de experiencias de ensamblado de carritos, consulta los lineamientos de diseño.
Crea un pedido
Durante la conversación, recopila los detalles de la reserva del usuario y, luego, crea un objeto Order
.
Como mínimo, tu Order
debe contener lo siguiente:
buyerInfo
: Es la información sobre el usuario que realiza la compra.transactionMerchant
: Es la información sobre el comercio que facilitó el pedido.contents
: El contenido real del pedido que aparece comolineItems
.
Consulta la documentación de respuesta de Order
para construir el carrito. Ten en cuenta que es posible que debas incluir campos diferentes según la reserva.
En el siguiente código de muestra, se muestra un pedido de reserva completo, incluidos los campos opcionales:
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: 'Dinner reservation',
description: 'A world of flavors all in one destination.',
reservation: {
status: 'PENDING',
userVisibleStatusLabel: 'Reservation is pending.',
type: 'RESTAURANT',
reservationTime: {
timeIso8601: '2020-01-16T01:30:15.01Z',
},
userAcceptableTimeRange: {
timeIso8601: '2020-01-15/2020-01-17',
},
partySize: 6,
staffFacilitators: [
{
name: 'John Smith',
},
],
location: {
zipCode: '94086',
city: 'Sunnyvale',
postalAddress: {
regionCode: 'US',
postalCode: '94086',
administrativeArea: 'CA',
locality: 'Sunnyvale',
addressLines: [
'222, Some other Street',
],
},
},
},
},
],
},
buyerInfo: {
email: 'janedoe@gmail.com',
firstName: 'Jane',
lastName: 'Doe',
displayName: 'Jane Doe',
},
followUpActions: [
{
type: 'VIEW_DETAILS',
title: 'View details',
openUrlAction: {
url: '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'
};
Crear opciones de pedido y presentación
const orderOptions = {
'requestDeliveryAddress': false,
};
const presentationOptions = {
'actionDisplayName': 'RESERVE'
};
Guardar datos del pedido en el parámetro de la sesión
Desde tu entrega, guarda los datos del pedido en un parámetro de sesión. El objeto de orden se usará en las escenas de la misma sesión.
conv.session.params.order = {
'@type': 'type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec',
order: order,
orderOptions: orderOptions,
presentationOptions: presentationOptions
};
Proponer el pedido
Una vez que hayas creado un pedido de reserva, debes presentarlo al usuario para que lo confirme o lo rechace. Para hacerlo, debes hacer la transición a una escena que realice una decisión de transacción.
Crear escena de decisiones de transacción
- En la pestaña Escenas, agrega una escena nueva con el nombre
TransactionDecision
. - En Relleno de ranuras, haz clic en + para agregar un espacio nuevo.
- En Seleccionar tipo, selecciona
actions.type.TransactionDecisionValue
como tipo de espacio. - En el campo del nombre de la ranura, asígnale el nombre
TransactionDecision
. - Habilita la casilla de verificación Personalizar la escritura de valores de ranura (habilitada de forma predeterminada).
- En Configurar espacio, selecciona Usar parámetro de sesión en el menú desplegable.
- En Configurar ranura, ingresa el nombre del parámetro de la sesión que se usó para almacenar el pedido en el campo de texto (es decir,
$session.params.order
). Haz clic en Guardar.
En un intento por llenar un espacio TransactionDecisionValue
, Asistente inicia una experiencia integrada en la que el Order
que pasaste se renderiza directamente en una "tarjeta de vista previa del carrito". El usuario puede decir “programar reserva”, rechazar la transacción o solicitar cambiar los detalles de la reserva.
En este momento, el usuario también puede solicitar cambios en el pedido. En este caso, debes asegurarte de que tu entrega pueda controlar las solicitudes de cambio de pedido después de finalizar la experiencia de ensamblado del carrito.
Manejar el resultado de la decisión de transacción
Cuando se llena un espacio TransactionDecisionValue
, la respuesta del usuario a la decisión de la transacción se almacenará en un parámetro de sesión. Este valor contiene lo siguiente:
ORDER_ACCEPTED
,ORDER_REJECTED
CART_CHANGE_REQUESTED
USER_CANNOT_TRANSACT
.
Para manejar un resultado de decisión de transacción, haz lo siguiente:
- En la pestaña Scenes, selecciona la escena
TransactionDecision
que acabas de crear. - En Condición, haz clic en + para agregar una condición nueva.
En el campo de texto, ingresa la siguiente sintaxis para verificar la condición correcta:
scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
Coloca el cursor sobre la condición que acabas de agregar y haz clic en la flecha hacia arriba para colocarla antes de
if scene.slots.status == "FINAL"
.Habilita Enviar mensajes y proporciona un mensaje simple que le informe al usuario que se completó la reserva:
candidates: - first_simple: variants: - speech: >- Transaction completed! Your reservation $session.params.TransactionDecision.order.merchantOrderId is all set!
En Transición, selecciona Finalizar conversación para finalizarla.
En Condición, haz clic en + para agregar una condición nueva.
En el campo de texto, ingresa la siguiente sintaxis para verificar las condiciones de falla:
scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_REJECTED"
Coloca el cursor sobre la condición que acabas de agregar y haz clic en la flecha hacia arriba para colocarla antes de
if scene.slots.status == "FINAL"
.Habilita Enviar mensajes y proporciona un mensaje simple que informe al usuario que se rechazó el pedido:
candidates: - first_simple: variants: - speech: Looks like you don't want to set up a reservation. Goodbye.
En Transición, selecciona Finalizar conversación para finalizarla.
Selecciona la condición
else if scene.slots.status == "FINAL"
.Habilita Enviar mensajes y proporciona un mensaje simple para que el usuario sepa que no puede realizar una transacción.
candidates: - first_simple: variants: - speech: >- Transaction failed with status $session.params.TransactionDecision.transactionDecision
En Transición, selecciona Finalizar conversación para finalizarla si un usuario no puede realizar transacciones.
Finaliza la reserva y envía un recibo
Cuando la ranura TransactionDecisionValue
muestra un resultado de ORDER_ACCEPTED
, debes realizar de inmediato cualquier procesamiento necesario para programar la reserva (como conservarlo en tu propia base de datos).
Envía una respuesta simple para mantener la conversación activa. El usuario recibe una "tarjeta de recibo contraída" junto con tu respuesta.
Para enviar una actualización inicial del pedido:
- En la pestaña Scenes, selecciona tu escena
TransactionDecision
. En Condición, selecciona la condición que verifica el resultado correcto,
ORDER_ACCEPTED
:scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
Para esta condición, habilita Llama a tu webhook y proporciona un nombre de controlador de intent, como
update_order
.En tu código de webhook, agrega un controlador de intents para enviar una actualización del pedido inicial:
app.handle('update_order', conv => { const currentTime = new Date().toISOString(); let order = conv.session.params.TransactionDecision.order; conv.add(new OrderUpdate({ 'updateMask': { 'paths': [ 'reservation.status', 'reservation.user_visible_status_label', 'reservation.confirmation_code' ] }, 'order': { 'merchantOrderId': order.merchantOrderId, 'lastUpdateTime': currentTime, 'reservation': { 'status': 'CONFIRMED', 'userVisibleStatusLabel': 'Reservation confirmed', 'confirmationCode': '123ABCDEFGXYZ', }, }, 'reason': 'Reason string' })); });
Enviar actualizaciones del pedido
El estado de la reserva cambia a lo largo de su vida útil. Enviar las actualizaciones del pedido de reserva del usuario con solicitudes HTTP PATCH a la API de pedidos, que contengan el estado y los detalles del pedido
Cómo configurar solicitudes asíncronas a la API de Orders
Las solicitudes de actualización de pedidos a la API de Orders se autorizan mediante un token de acceso. Para PACAR una actualización de pedido a la API de Orders, descarga una clave de cuenta de servicio JSON asociada con tu proyecto de Actions Console y, luego, intercambia la clave de la cuenta de servicio por un token del portador que pueda pasarse al encabezado Authorization
de la solicitud HTTP.
Para recuperar la clave de tu cuenta de servicio, sigue estos pasos:
- En la consola de Google Cloud, ve a Menú ☰ > APIs y servicios > Credenciales > Crear credenciales > Clave de cuenta de servicio.
- En Cuenta de servicio, selecciona Nueva cuenta de servicio.
- Establece la cuenta de servicio en
service-account
. - Configura la Función como Proyecto > Propietario.
- Establece el tipo de clave en JSON.
- Seleccione Crear.
- Se descargará una clave de cuenta de servicio JSON privada en tu máquina local.
En el código de actualizaciones de tu pedido, intercambia tu clave de servicio por un token del portador usando la biblioteca cliente de las API de Google y el alcance "https://www.googleapis.com/auth/actions.order.developer". Puedes encontrar pasos y ejemplos de instalación en la página de GitHub de la biblioteca cliente de la API.
Haz referencia a order-update.js
en nuestra muestra de Node.js para ver un ejemplo de intercambio de claves.
Enviar actualizaciones del pedido
Una vez que hayas intercambiado tu clave de cuenta de servicio por un token del portador de OAuth, envía actualizaciones del pedido como solicitudes PATCH autorizadas a la API de pedidos.
URL de la API de pedidos:
PATCH https://actions.googleapis.com/v3/orders/${orderId}
Proporciona los siguientes encabezados en la solicitud:
"Authorization: Bearer token"
por el token del portador de OAuth para el que intercambiaste la clave de tu cuenta de servicio."Content-Type: application/json"
.
La solicitud PATCH debe tener un cuerpo JSON con el siguiente formato:
{ "orderUpdate": OrderUpdate }
El objeto OrderUpdate
consta de los siguientes campos de nivel superior:
updateMask
: Son los campos del pedido que estás actualizando. Para actualizar el estado de reserva, establece el valor enreservation.status, reservation.userVisibleStatusLabel
.order
: El contenido de la actualización Si actualizas el contenido de la reserva, establece el valor en el objetoOrder
actualizado. Si solo actualizas el estado de la reserva (por ejemplo, de"PENDING"
a"FULFILLED"
), el objeto contiene los siguientes campos:merchantOrderId
: Es el mismo ID que configuraste en el objetoOrder
.lastUpdateTime
: Es la marca de tiempo de esta actualización.purchase
: Un objeto que contiene lo siguiente:status
: Es el estado del pedido comoReservationStatus
, como "CONFIRMED
" o "CANCELLED
".userVisibleStatusLabel
: Es una etiqueta para el usuario que proporciona detalles sobre el estado del pedido, como “Se confirmó la reserva”.
userNotification
(opcional): Es un objetouserNotification
que se puede mostrar en el dispositivo del usuario cuando se envía esta actualización. Ten en cuenta que incluir este objeto no garantiza que aparezca una notificación en el dispositivo del usuario.
En el siguiente código de muestra, se muestra un OrderUpdate
de ejemplo en el que se actualiza el estado del pedido de reserva a FULFILLED
:
// 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 client library.
const {OrderUpdate} = require('@assistant/conversation');
// 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 the ID of the order to update.
const orderId = '<UNIQUE_MERCHANT_ORDER_ID>';
// Declare order update
const orderUpdate = new OrderUpdate({
updateMask: {
paths: [
'contents.lineItems.reservation.status',
'contents.lineItems.reservation.userVisibleStatusLabel'
]
},
order: {
merchantOrderId: orderId, // Specify the ID of the order to update
lastUpdateTime: new Date().toISOString(),
contents: {
lineItems: [
{
reservation: {
status: 'FULFILLED',
userVisibleStatusLabel: 'Reservation fulfilled',
},
}
]
},
},
reason: 'Reservation status was updated to fulfilled.',
});
// Set up the PATCH request header and body,
// including the authorized token and order update.
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);
} catch (e) {
console.log(`Error: ${e}`);
}
Establece el estado de la reserva
La ReservationStatus
de la actualización de un pedido debe describir el estado actual del pedido. En el campo order.ReservationStatus
de la actualización, usa uno de los siguientes valores:
PENDING
: La acción "creó" la reserva, pero requiere procesamiento adicional en tu backend.CONFIRMED
: La reserva se confirma en el backend de programación.CANCELLED
: El usuario canceló su reserva.FULFILLED
: El servicio realizó la reserva del usuario.CHANGE_REQUESTED
: El usuario solicitó un cambio en la reserva y se está procesando.REJECTED
: Si no pudiste procesar o confirmar de otra manera la reserva.
Envía actualizaciones del pedido para cada estado relevante para tu reserva. Por ejemplo, si tu reserva requiere procesamiento manual para confirmar la reserva después de que se solicita, envía una actualización del pedido PENDING
hasta que se complete el procesamiento adicional. No todas las reservas requieren todos los valores de estado.
Prueba tu proyecto
Cuando pruebas tu proyecto, puedes habilitar el modo de zona de pruebas en la Consola de Actions para probar tu acción sin cobrar una forma de pago. Para habilitar el modo de zona de pruebas, sigue estos pasos:
- En la Consola de Actions, haz clic en Test en el menú de navegación.
- Haz clic en Configuración.
- Habilita la opción Zona de pruebas de desarrollo.
Para las transacciones físicas, también puedes configurar el campo isInSandbox
como true
en tu muestra. Esta acción es equivalente a habilitar la configuración del modo de zona de pruebas en la
Consola de Actions. Para ver un fragmento de código que usa isInSandbox
, consulta la sección Cómo enviar actualizaciones de pedidos.
Solución de problemas
Si tienes algún problema durante la prueba, lee nuestros pasos para solucionar problemas relacionados con las transacciones.