Criar reservas

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:

  1. 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.
  2. Criar o pedido: oriente o usuário sobre uma "montagem de carrinho" em que ele cria os detalhes da reserva.
  3. 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.
  4. Finalizar o pedido e enviar um comprovante: depois de confirmar o pedido, atualize o sistema de reservas e envie um comprovante ao usuário.
  5. 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:

  1. Crie um novo projeto ou importe um existente.
  2. Navegue até Implantar > Informações do diretório.
  3. 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

  1. Na guia Scenes, adicione uma nova cena com o nome TransactionRequirementsCheck.
  2. Em Preenchimento de slot, clique em + para adicionar um novo slot.
  3. Em Selecionar tipo, selecione actions.type.TransactionRequirementsCheckResult como o tipo de slot.
  4. No campo do nome do slot, digite o nome TransactionRequirementsCheck.
  5. Ative a caixa de seleção Personalizar gravação do valor do slot (ativada por padrão).
  6. 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

  1. Na guia Scenes, selecione a cena TransactionRequirementsCheck recém-criada.
  2. Em Condição, clique em + para adicionar uma nova condição.
  3. 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"
    
  4. 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".

  5. 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!.
    
  6. Em Transition, selecione outra cena, permitindo que o usuário continue a conversa e prossiga para a transação.

  7. Selecione a condição else if scene.slots.status == "FINAL".

  8. 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.
    
  9. 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 como lineItems.

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

  1. Na guia Cenas, adicione uma nova cena com o nome TransactionDecision.
  2. Em Preenchimento de slot, clique em + para adicionar um novo slot.
  3. Em Selecionar tipo, selecione actions.type.TransactionDecisionValue como o tipo de slot.
  4. No campo do nome do slot, digite o nome TransactionDecision.
  5. Ative a caixa de seleção Personalizar gravação do valor do slot (ativada por padrão).
  6. Em Configurar slot, selecione Usar parâmetro de sessão no menu suspenso.
  7. 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).
  8. 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:

  1. Na guia Scenes, selecione a cena TransactionDecision recém-criada.
  2. Em Condição, clique em + para adicionar uma nova condição.
  3. 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"
    
  4. 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".

  5. 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!
    
  6. Em Transição, selecione Encerrar conversa para encerrar a conversa.

  7. Em Condição, clique em + para adicionar uma nova condição.

  8. 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"
    
  9. 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".

  10. 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.
    
  11. Em Transição, selecione Encerrar conversa para encerrar a conversa.

  12. Selecione a condição else if scene.slots.status == "FINAL".

  13. 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
    
  14. 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:

  1. Na guia Scenes, selecione a cena TransactionDecision.
  2. 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"
    
  3. Para essa condição, ative Call your webhook e forneça um nome de gerenciador de intent, como update_order.

  4. 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:

  1. No Console do Google Cloud, acesse Menu ☰ > APIs e serviços > Credenciais > Criar credenciais > Chave da conta de serviço.
  2. Em Conta de serviço, selecione Nova conta de serviço.
  3. Defina a conta de serviço como service-account.
  4. Defina o Papel como Projeto > Proprietário.
  5. Defina o tipo de chave como JSON.
  6. Selecione Criar.
  7. 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 como reservation.status, reservation.userVisibleStatusLabel.
  • order: o conteúdo da atualização. Se você estiver atualizando o conteúdo da reserva, defina o valor como o objeto Order 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 objeto Order.
    • lastUpdateTime: o carimbo de data/hora dessa atualização.
    • purchase: um objeto que contém o seguinte:
      • status: o status do pedido como um ReservationStatus, 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:

  1. No Console do Actions, clique em Testar na navegação.
  2. Clique em Configurações.
  3. 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.