Neste guia, mostramos o processo de desenvolvimento de um projeto do Actions que usa a API Orders para fazer reservas.
Fluxo de transações
Quando o projeto do Actions processa reservas, ele usa o seguinte fluxo:
- Validar os requisitos de transação (opcional): use o auxiliar de requisitos de transações no início da conversa para garantir que o usuário possa realizar uma transação.
- Criar o pedido: oriente o usuário sobre uma "montagem de carrinho" em que ele cria os detalhes da reserva.
- Propor o pedido: depois que o "carrinho" for concluído, proponha a "ordem" da reserva ao usuário, para que ele possa confirmar que está correto. Se a reserva for confirmada, você receberá uma resposta com os detalhes da reserva.
- Finalizar o pedido e enviar um comprovante: depois de confirmar o pedido, atualize o sistema de reservas e envie um comprovante ao usuário.
- Enviar atualizações de pedidos: ao longo do tempo de vida útil da reserva, forneça ao usuário atualizações do status da reserva enviando solicitações PATCH para a API Orders.
Restrições e diretrizes de revisão
Lembre-se de que outras políticas se aplicam a ações que usam as transações e a API Orders. Pode levar até seis semanas para analisar as Ações com transações. Portanto, considere esse tempo ao planejar a programação de lançamentos. Para facilitar o processo de revisão, verifique se você está em conformidade com as políticas e diretrizes para transações antes de enviar sua ação para análise.
Só é possível implantar ações que usam a API Orders nos seguintes países:
Austrália Brasil Canadá Indonésia |
Japão México Catar Rússia |
Singapura Suíça Tailândia Turquia Reino Unido Estados Unidos |
Criar o projeto
Para um exemplo abrangente de conversas transacionais, veja nosso exemplo de transações em Node.js.
Configuração
Ao criar sua ação, você precisa especificar que quer realizar transações no Console do Actions.
Para configurar o projeto e o fulfillment, faça o seguinte:
- Crie um novo projeto ou importe um existente.
- Navegue até Implantar > Informações do diretório.
Em Informações adicionais > Transações > marque a caixa que diz "Suas ações usam a API Transações para realizar transações de produtos físicos?".
Validar os requisitos da transação (opcional)
Assim que o usuário indicar que quer configurar uma reserva, verifique se ele pode solicitá-la. Por exemplo, quando invocada, a ação pode perguntar: "Você quer reservar um assento?" Se o usuário disser "sim", verifique se ele pode prosseguir e dê a ele a oportunidade de corrigir todas as configurações que o impedem de continuar com a transação. Para isso, faça a transição para um cenário que realiza uma verificação de requisitos de transação.
Criar cena de verificação de requisitos de transação
- Na guia Scenes, adicione uma nova cena com o nome
TransactionRequirementsCheck
. - Em Preenchimento de slot, clique em + para adicionar um novo slot.
- Em Selecionar tipo, selecione
actions.type.TransactionRequirementsCheckResult
como o tipo de slot. - No campo do nome do slot, digite o nome
TransactionRequirementsCheck
. - Ative a caixa de seleção Personalizar gravação do valor do slot (ativada por padrão).
Clique em Salvar.
Uma verificação de requisitos de transação resulta em um dos seguintes resultados:
- Se os requisitos forem atendidos, o parâmetro de sessão será definido com uma condição de sucesso e você poderá prosseguir com a criação do pedido do usuário.
- Se não for possível atender a um ou mais dos requisitos, o parâmetro da sessão será definido com uma condição de falha. Nesse caso, afaste a conversa
da experiência transacional ou encerre a conversa.
- Se algum erro que resulte no estado de falha puder ser corrigido pelo usuário, ele receberá uma solicitação para resolver esses problemas no dispositivo. Se a conversa estiver ocorrendo em uma superfície somente de voz, uma transferência será iniciada para o smartphone do usuário.
Processar o resultado da verificação de requisitos da transação
- Na guia Scenes, selecione a cena
TransactionRequirementsCheck
recém-criada. - Em Condição, clique em + para adicionar uma nova condição.
No campo de texto, insira a seguinte sintaxe de condição para verificar a condição bem-sucedida:
scene.slots.status == "FINAL" && session.params.TransactionRequirementsCheck.resultType == "CAN_TRANSACT"
Passe o cursor sobre a condição que você acabou de adicionar e clique na seta para cima para colocá-la antes de
if scene.slots.status == "FINAL"
.Ative Enviar solicitações e forneça uma solicitação simples, informando ao usuário que está pronto para fazer uma transação:
candidates: - first_simple: variants: - speech: >- Looks like you're good to go!.
Em Transition, selecione outra cena, permitindo que o usuário continue a conversa e prossiga para a transação.
Selecione a condição
else if scene.slots.status == "FINAL"
.Ative Enviar solicitações e forneça uma solicitação simples, informando ao usuário que não é possível fazer uma transação:
candidates: - first_simple: variants: - speech: Transaction requirements check failed.
Em Transição, selecione Encerrar conversa para encerrar a conversa se um usuário não conseguir fazer transações.
Criar o pedido
Quando você tiver as informações necessárias do usuário, crie uma experiência de "montagem do carrinho" que oriente o usuário a criar a reserva. Cada ação terá um fluxo de montagem do carrinho um pouco diferente, conforme apropriado para o serviço.
Em uma experiência básica de montagem de carrinho, um usuário seleciona opções de uma lista para adicionar à reserva, embora você possa projetar a conversa para simplificar a experiência do usuário. Por exemplo, crie uma experiência de montagem de carrinho que permita ao usuário agendar uma reserva mensal com uma simples pergunta de sim ou não. Também é possível apresentar ao usuário um carrossel ou um card de lista de reservas "recomendadas".
Recomendamos o uso de respostas avançadas para apresentar visualmente as opções do usuário, mas também projete a conversa de modo que o usuário possa criar o carrinho usando apenas a voz. Para conferir algumas práticas recomendadas e exemplos de experiências de montagem de carrinhos, consulte as diretrizes de design.
Criar um pedido
Ao longo da conversa, reúna os detalhes da reserva do usuário e
crie um objeto Order
.
No mínimo, Order
precisa conter o seguinte:
buyerInfo
: informações sobre o usuário que fez a compra.transactionMerchant
: informações sobre o comerciante que facilitou o pedido.contents
: o conteúdo real do pedido listado comolineItems
.
Consulte a documentação da resposta Order
para criar seu carrinho. Talvez seja necessário incluir campos diferentes dependendo da reserva.
O exemplo de código abaixo mostra um pedido de reserva completo, incluindo campos opcionais:
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'
};
Criar opções de ordem e apresentação
const orderOptions = {
'requestDeliveryAddress': false,
};
const presentationOptions = {
'actionDisplayName': 'RESERVE'
};
Salvar dados do pedido no parâmetro da sessão
No fulfillment, salve os dados do pedido em um parâmetro de sessão. O objeto "order" será usado em todas as cenas da mesma sessão.
conv.session.params.order = {
'@type': 'type.googleapis.com/google.actions.transactions.v3.TransactionDecisionValueSpec',
order: order,
orderOptions: orderOptions,
presentationOptions: presentationOptions
};
Propor o pedido
Depois de criar um pedido de reserva, você precisa apresentá-lo ao usuário para confirmar ou rejeitar. Para isso, faça a transição para um cenário que toma a decisão de transação.
Criar cenário de decisão da transação
- Na guia Cenas, adicione uma nova cena com o nome
TransactionDecision
. - Em Preenchimento de slot, clique em + para adicionar um novo slot.
- Em Selecionar tipo, selecione
actions.type.TransactionDecisionValue
como o tipo de slot. - No campo do nome do slot, digite o nome
TransactionDecision
. - Ative a caixa de seleção Personalizar gravação do valor do slot (ativada por padrão).
- Em Configurar slot, selecione Usar parâmetro de sessão no menu suspenso.
- Em Configurar slot, insira no campo de texto o nome do parâmetro de sessão usado para
armazenar a ordem (ou seja,
$session.params.order
). Clique em Salvar.
Para preencher um slot TransactionDecisionValue
, o Google Assistente inicia
uma experiência integrada em que o Order
transmitido é renderizado diretamente em
um "card de visualização de carrinho". O usuário pode dizer "agendar reserva", recusar a transação ou pedir para alterar os detalhes da reserva.
O usuário também pode solicitar alterações no pedido nesse momento. Nesse caso, verifique se o fulfillment pode processar solicitações de alteração de pedidos após a conclusão da experiência de montagem do carrinho.
Processar o resultado da decisão da transação
Quando um slot TransactionDecisionValue
for preenchido, a resposta do usuário à decisão da transação será armazenada em um parâmetro de sessão. Esse valor contém
o seguinte:
ORDER_ACCEPTED
,ORDER_REJECTED
,CART_CHANGE_REQUESTED
USER_CANNOT_TRANSACT
.
Para processar o resultado de uma decisão da transação:
- Na guia Scenes, selecione a cena
TransactionDecision
recém-criada. - Em Condição, clique em + para adicionar uma nova condição.
No campo de texto, insira a seguinte sintaxe de condição para verificar a condição bem-sucedida:
scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
Passe o cursor sobre a condição que você acabou de adicionar e clique na seta para cima para colocá-la antes de
if scene.slots.status == "FINAL"
.Ative Enviar solicitações e forneça um comando simples informando ao usuário que a reserva foi concluída:
candidates: - first_simple: variants: - speech: >- Transaction completed! Your reservation $session.params.TransactionDecision.order.merchantOrderId is all set!
Em Transição, selecione Encerrar conversa para encerrar a conversa.
Em Condição, clique em + para adicionar uma nova condição.
No campo de texto, insira a seguinte sintaxe de condição para verificar as condições de falha:
scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_REJECTED"
Passe o cursor sobre a condição que você acabou de adicionar e clique na seta para cima para colocá-la antes de
if scene.slots.status == "FINAL"
.Ative Enviar solicitações e forneça uma solicitação simples informando ao usuário que o pedido foi rejeitado:
candidates: - first_simple: variants: - speech: Looks like you don't want to set up a reservation. Goodbye.
Em Transição, selecione Encerrar conversa para encerrar a conversa.
Selecione a condição
else if scene.slots.status == "FINAL"
.Ative Enviar solicitações e forneça uma solicitação simples informando ao usuário que não é possível realizar uma transação:
candidates: - first_simple: variants: - speech: >- Transaction failed with status $session.params.TransactionDecision.transactionDecision
Em Transição, selecione Encerrar conversa para encerrar a conversa se um usuário não conseguir fazer transações.
Finalizar a reserva e enviar um comprovante
Quando o slot TransactionDecisionValue
retorna um resultado de ORDER_ACCEPTED
,
você precisa executar imediatamente qualquer processamento necessário para programar a
reserva (como persistir no seu próprio banco de dados).
Envie uma resposta simples para não perder o ritmo da conversa. O usuário recebe um "cartão de comprovante recolhido" com sua resposta.
Para enviar uma atualização inicial do pedido:
- Na guia Scenes, selecione a cena
TransactionDecision
. Em Condição, selecione a condição que verifica o resultado de sucesso,
ORDER_ACCEPTED
:scene.slots.status == "FINAL" && session.params.TransactionDecision.transactionDecision == "ORDER_ACCEPTED"
Para essa condição, ative Call your webhook e forneça um nome de gerenciador de intent, como
update_order
.No código do webhook, adicione um gerenciador de intent para enviar uma atualização inicial do pedido:
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 atualizações do pedido
O status da reserva muda ao longo do ciclo de vida. Envie ao usuário atualizações do pedido de reserva com solicitações HTTP PATCH para a API Orders, contendo o status e os detalhes do pedido.
Configurar solicitações assíncronas para a API Orders
As solicitações de atualização do pedido para a API Orders são autorizadas por um token de acesso. Para fazer o PATCH de uma atualização de pedido para a API Orders, faça o download de uma chave
de conta de serviço JSON associada ao seu projeto do Console do Actions e troque
a chave da conta de serviço por um token do portador que pode ser transmitido para o
cabeçalho Authorization
da solicitação HTTP.
Para recuperar a chave da conta de serviço, siga estas etapas:
- No Console do Google Cloud, acesse Menu ☰ > APIs e serviços > Credenciais > Criar credenciais > Chave da conta de serviço.
- Em Conta de serviço, selecione Nova conta de serviço.
- Defina a conta de serviço como
service-account
. - Defina o Papel como Projeto > Proprietário.
- Defina o tipo de chave como JSON.
- Selecione Criar.
- Uma chave privada da conta de serviço JSON será transferida por download para a máquina local.
No código de atualização do pedido, troque a chave de serviço por um token do portador usando a biblioteca de cliente das APIs do Google e o escopo "https://www.googleapis.com/auth/actions.order.developer". Você encontra etapas e exemplos de instalação na página do GitHub da biblioteca de cliente da API.
Consulte order-update.js
na nossa amostra Node.js
para ver um exemplo de troca de chaves.
Enviar atualizações do pedido
Depois de trocar a chave da sua conta de serviço por um token do portador OAuth, envie atualizações de pedidos como solicitações PATCH autorizadas para a API Orders.
URL da API Orders:
PATCH https://actions.googleapis.com/v3/orders/${orderId}
Forneça os seguintes cabeçalhos na sua solicitação:
"Authorization: Bearer token"
pelo token do portador OAuth pelo qual você trocou a chave da conta de serviço."Content-Type: application/json"
.
A solicitação PATCH precisa ter um corpo JSON no seguinte formato:
{ "orderUpdate": OrderUpdate }
O objeto OrderUpdate
consiste nos seguintes campos de nível superior:
updateMask
: os campos do pedido que você está atualizando. Para atualizar o status da reserva, defina o valor comoreservation.status, reservation.userVisibleStatusLabel
.order
: o conteúdo da atualização. Se você estiver atualizando o conteúdo da reserva, defina o valor como o objetoOrder
atualizado. Se você estiver apenas atualizando o status da reserva (por exemplo, de"PENDING"
para"FULFILLED"
), o objeto conterá os seguintes campos:merchantOrderId
: o mesmo ID que você definiu no objetoOrder
.lastUpdateTime
: o carimbo de data/hora dessa atualização.purchase
: um objeto que contém o seguinte:status
: o status do pedido como umReservationStatus
, como "CONFIRMED
" ou "CANCELLED
".userVisibleStatusLabel
: um rótulo voltado ao usuário que fornece detalhes sobre o status do pedido, como "Sua reserva foi confirmada".
userNotification
que pode ser exibido no dispositivo do usuário quando essa atualização é enviada. A inclusão desse objeto não garante que uma notificação seja exibida no dispositivo do usuário.
A amostra de código a seguir mostra um exemplo de OrderUpdate
que atualiza o status do pedido de reserva para 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}`);
}
Definir o status da reserva
O ReservationStatus
de uma atualização de pedido
precisa descrever o estado atual dele. No campo order.ReservationStatus
da atualização, use um dos seguintes valores:
PENDING
: a reserva foi "criada" pela sua ação, mas requer um processamento adicional no seu back-end.CONFIRMED
: a reserva é confirmada no back-end da programação.CANCELLED
: o usuário cancelou a reserva.FULFILLED
: a reserva do usuário foi atendida pelo serviço.CHANGE_REQUESTED
: o usuário solicitou uma alteração na reserva, e a alteração está sendo processada.REJECTED
: se não foi possível processar ou confirmar a reserva.
Envie atualizações de pedido para cada status relevante para sua reserva. Por exemplo, se a reserva exigir processamento manual para confirmar a reserva após ser solicitada, envie uma atualização do pedido PENDING
até que o processamento adicional seja concluído. Nem todas as reservas exigem todos os valores de status.
Testar o projeto
Ao testar o projeto, você pode ativar o modo sandbox no Console do Actions para testar a ação sem cobrar uma forma de pagamento. Para ativar o modo sandbox, siga estas etapas:
- No Console do Actions, clique em Testar na navegação.
- Clique em Configurações.
- Ative a opção Sandbox de desenvolvimento.
Para transações físicas, também é possível definir o campo isInSandbox
como true
na
amostra. Esta ação é equivalente a ativar a configuração do modo sandbox no
Console do Actions. Para conferir um snippet de código que usa isInSandbox
, consulte a seção
Enviar atualizações de pedidos.
Solução de problemas
Se você tiver problemas durante o teste, leia nossas etapas de solução de problemas para transações.