Atualização assíncrona do pedido

Depois que um cliente envia um pedido de comida, você pode enviar uma mensagem de atualização do pedido para o serviço Pedir com o Google para nos avisar sobre a alteração.

Veja alguns motivos comuns para enviar atualizações de pedidos:

  • O tempo estimado de atendimento para o pedido é disponibilizado ou alterado.
  • O estado de um pedido muda.
  • Não é mais possível concluir o pedido.
  • O preço de um item de menu incluído no pedido foi alterado.
  • O cliente tem uma nova maneira de gerenciar o pedido, como um suporte ao cliente ou um número de telefone de um restaurante.
  • O recibo do pedido será disponibilizado.

As próximas seções fornecem detalhes sobre como lidar com esses diferentes cenários usando atualizações de pedidos.

Como fazer a transição de estados do pedido

Um pedido tem seis estados possíveis. Esses estados e as possíveis transições deles estão descritos no diagrama a seguir:

Transições de estado do pedido

Quando um cliente envia um pedido pela primeira vez, o pedido começa com um estado de CREATED, CONFIRMED ou REJECTED. É possível enviar uma mensagem de atualização do pedido para atualizar o estado de um pedido, desde que a transição de estado seja válida. O estado CREATED é usado quando a plataforma do parceiro não pode confirmar ou rejeitar o pedido imediatamente. Um exemplo de caso de uso é quando um cliente faz um pedido por meio de um agregador de entrega. O agregador de entrega recebe a entrega do Google e envia as informações para o restaurante. Depois que o restaurante receber e confirmar a disponibilidade do pedido, o estado poderá ser CONFIRMED. Caso contrário, será REJECTED.

Em seguida, um pedido no estado CONFIRMED é movido para o estado IN_PREPARATION. Se o pedido for para retirada ou entrega, use o estado READY_FOR_PICKUP ou IN_TRANSIT. Quando a comida é entregue ou retirada, o pedido é definido como FULFILLED.

Se você permitir que os clientes cancelem pedidos, use o estado CANCELLED. Um pedido pode ser cancelado no estado CREATED, CONFIRMED, IN_PREPARATION, READY_FOR_PICKUP ou IN_TRANSIT. Seu serviço do Pedir com o Google precisa emitir reembolsos dependendo da política de cancelamento e do estado dos pagamentos no momento do cancelamento.

O serviço Pedir com o Google não precisa aceitar todos os estados e transições disponíveis. No entanto, o estado final do pedido precisa ser FULFILLED, REJECTED ou CANCELLED.

Como fornecer um tempo estimado de atendimento do pedido

Você pode fornecer aos usuários um tempo estimado para a entrega do pedido ou a retirada do pedido. Use o campo estimatedFulfillmentTimeIso8601 de FoodOrderUpdateExtension para fornecer um período estimado para quando o pedido de um cliente estará pronto para retirada ou entrega.

Envie estimatedFulfillmentTimeIso8601 nos seguintes horários:

  • Quando o tempo estimado for disponibilizado, de preferência no estado CREATED ou CONFIRMED do pedido.
  • Quando o tempo estimado muda, como a atualização para ser mais precisa quando o pedido é IN_TRANSIT.

Para gerenciar as expectativas do usuário de maneira eficaz, seja conservador em suas estimativas e forneça uma data e hora em vez de uma data e hora fixas. Considere variações, como condições de tráfego, sempre que possível. Por exemplo, é possível enviar uma estimativa das 12h45 (limite inferior) às 13h15 (limite superior) de um pedido em que o tempo de entrega estimado é de 13h.

Como fornecer ações de gerenciamento de pedidos

Ao enviar uma atualização de pedido, você pode fornecer recursos aos clientes para ajudá-los a gerenciar o pedido na forma de um OrderManagementAction. Depois que um cliente faz um pedido, ele pode precisar entrar em contato com você ou com o restaurante que o atende para rastrear o progresso, fazer alterações ou cancelar o pedido.

Um OrderManagementAction permite que os clientes enviem e-mails, chamadas ou links para um URL diretamente do dispositivo. Use as mesmas informações no OrderManagementAction da confirmação de pedido por e-mail que você envia ao usuário.

As ações de gerenciamento de pedidos incluem os seguintes tipos:

  • CUSTOMER_SERVICE: oferece aos clientes uma ação para entrar em contato com o atendimento ao cliente. Este tipo de ação de gerenciamento é obrigatório para atualizações de pedidos.
  • EMAIL: oferece aos clientes uma ação para enviar um e-mail ao endereço de e-mail fornecido.
  • CALL: oferece aos clientes uma ação para ligar para o número de telefone fornecido.
  • VIEW_DETAIL: oferece aos clientes uma ação para visualizar os detalhes do pedido.

Cada atualização do pedido precisa conter pelo menos uma ação de gerenciamento de pedido. No entanto, as ações de gerenciamento de pedidos fornecidas podem variar com base no estado do pedido. Por exemplo, quando um pedido está no estado CONFIRMED, a ação CUSTOMER_SERVICE pode apontar para o número de telefone de atendimento ao cliente. Quando esse estado do pedido é atualizado para IN_TRANSIT, a ação CUSTOMER_SERVICE pode apontar para o número de telefone do restaurante de atendimento do pedido.

Enviando atualizações de pedido

Use o tipo de mensagem AsyncOrderUpdateRequestMessage para enviar uma atualização do pedido ao serviço Pedido com o Google. O Google responde com um AsyncOrderUpdateResponseMessage. Por exemplo, se você quiser informar um cliente que o pedido foi válido e aceito, envie um AsyncOrderUpdateRequestMessage para alterar o estado do pedido para CONFIRMED com o rótulo Accepted by restaurant.

Diagrama de atualização do pedido

Como configurar a mensagem de atualização do pedido

Ao enviar um AsyncOrderUpdateRequestMessage ao Google, você precisa incluir informações sobre o estado do pedido usando o campo OrderUpdate.

Os exemplos a seguir mostram uma amostra de AsyncOrderUpdateRequestMessage para cada estado do pedido:

CONFIRMADO

Este exemplo mostra uma amostra de solicitação de atualização de pedido que notifica o usuário de que o pedido está confirmado com um recibo e um tempo de entrega estimado.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "CONFIRMED",
        "label": "Provider confirmed"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime": "2017-07-17T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "2017-07-17T13:00:00Z/2017-07-17T13:30:00Z"
      }
    }
  }
}
    

REJEITADA

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário que o pedido foi rejeitado por um motivo.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "REJECTED",
        "label": "Order rejected"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "rejectionInfo": {
        "type": "UNKNOWN",
        "reason": "Sorry, the restaurant cannot take your order right now."
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
      "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
      "foodOrderErrors": [
        {
        "error": "NO_CAPACITY",
        "description": "Sorry, the restaurant cannot take your order right now."
        }
      ]
      }
    }
  }
}
    

CANCELADA

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário de que o pedido foi cancelado com um motivo para cancelamento.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "CANCELLED",
        "label": "Order cancelled"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "cancellationInfo": {
        "reason": "Customer requested"
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ]
    }
  }
}
    

EM_PREPARAÇÃO

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário de que o alimento está sendo preparado.

{
  "isInSandbox":true,
  "customPushMessage":{
    "orderUpdate":{
      "actionOrderId":"sample_action_order_id",
      "orderState":{
        "state":"IN_PREPARATION",
        "label":"Order is being prepared"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime":"2018-04-15T11:30:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension":{
        "@type":"type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601":"PT20M"
      }
    }
  }
}
    

READY_FOR_PICKUP

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário de que o alimento está pronto para retirada.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "READY_FOR_PICKUP",
        "label": "Order is ready for pickup"
      },
      "receipt": {
        "userVisibleOrderId": "userVisibleId1234"
      },
      "updateTime": "2018-04-15T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "PT20M"
      }
    }
  }
}
    

EM_TRANSPORTE

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário de que o pedido está em trânsito com um tempo de entrega estimado.

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
        "state": "IN_TRANSIT",
        "label": "Order is on the way"
      },
      "inTransitInfo": {
        "updatedTime": "2017-07-17T12:00:00Z"
      },
      "updateTime": "2017-07-17T12:00:00Z",
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ],
      "infoExtension": {
        "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
        "estimatedFulfillmentTimeIso8601": "PT20M"
      }
    }
  }
}
  

CONCLUÍDO

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário de que o pedido foi retirado ou entregue:

{
  "isInSandbox": true,
  "customPushMessage": {
    "orderUpdate": {
      "actionOrderId": "sample_action_order_id",
      "orderState": {
      "state": "FULFILLED",
      "label": "Order delivered"
      },
      "updateTime": "2017-05-10T02:30:00.000Z",
      "fulfillmentInfo": {
        "deliveryTime": "2017-05-10T02:30:00.000Z"
      },
      "orderManagementActions": [
        {
          "type": "CUSTOMER_SERVICE",
          "button": {
            "title": "Contact customer service",
            "openUrlAction": {
              "url": "mailto:support@example.com"
            }
          }
        },
        {
          "type": "EMAIL",
          "button": {
            "title": "Email restaurant",
            "openUrlAction": {
              "url": "mailto:person@example.com"
            }
          }
        },
        {
          "type": "CALL_RESTAURANT",
          "button": {
            "title": "Call restaurant",
            "openUrlAction": {
              "url": "tel:+16505554679"
            }
          }
        },
        {
          "type": "CALL_DRIVER",
          "button": {
            "title": "Call driver",
            "openUrlAction": {
              "url": "tel:+16505554681"
            }
          }
        }
      ]
    }
  }
}
    

Para mais exemplos de solicitações de atualização de pedido em diferentes casos de uso, leia Implementar atualizações de pedido avançadas.

Gerar token de autorização e enviar a mensagem

As atualizações do Pedido exigem um token de autorização para que o serviço do Pedido com o Google possa verificar se a mensagem é do serviço da Web do Pedido com o Google.

Para implementar atualizações de pedidos no seu projeto, siga estas etapas:

  1. Gere um token de autorização seguindo estas etapas:
    1. Use a biblioteca do Google Auth para ler as credenciais do arquivo da conta de serviço.
    2. Token de solicitação usando o seguinte escopo da API: https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. Use esse token para enviar uma solicitação HTTP POST autenticada ao endpoint a seguir: https://actions.googleapis.com/v2/conversations:send
  3. Defina o cabeçalho Content-Type como application/json como parte da solicitação.

Os exemplos a seguir demonstram como implementar atualizações de pedidos:

Node.js

Esse código usa a biblioteca de autenticação do Google para Node.js.

const {auth} = require('google-auth-library')
const request = require('request');
// The service account client secret file downloaded from the Google Cloud Console
const serviceAccountJson = require('./service-account.json')
// order-update.json is a file that contains the payload
const jsonBody = require('./order-update.json')

/**
 * Get the authorization token using a service account.
 */
async function getAuthToken() {
  let client = auth.fromJSON(serviceAccountJson)
  client.scopes = ['https://www.googleapis.com/auth/actions.fulfillment.conversation']
  const tokens = await client.authorize()
  return tokens.access_token;
}

/**
 * Send an order update request
 */
async function sendOrderUpdate() {
  const token = await getAuthToken()
  request.post({
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`
    },
    url: 'https://actions.googleapis.com/v2/conversations:send',
    body: jsonBody,
    json: true
  },
  (err, res, body) => {
    if (err) { return console.log(err); }
    console.log(`Response: ${JSON.stringify(res)}`)
  })
}
    

Python

Esse código usa a biblioteca de autenticação do Google para Python.

from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
import json

# service-account.json is the service account client secret file downloaded from the
# Google Cloud Console
credentials = service_account.Credentials.from_service_account_file(
    'service-account.json')

scoped_credentials = credentials.with_scopes(
    ['https://www.googleapis.com/auth/actions.fulfillment.conversation'])

authed_session = AuthorizedSession(scoped_credentials)

# order-update.json is a file that contains the payload
json_payload=json.load(open('order-update.json'))

response = authed_session.post(
    'https://actions.googleapis.com/v2/conversations:send',
    json=json_payload)
    

Java

Esse código usa a biblioteca de autenticação do Google para Java.

/**
 * Get the authorization token using a service account.
 */
private static String getAuthToken() {
  InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json");
  ServiceAccountCredentials.Builder credentialsSimpleBuilder =
      ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder();
  credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/actions.fulfillment.conversation"));
  AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken();
  return accessToken.getTokenValue();
}

/**
 * Send an order update request
 */
public void sendOrderUpdate() {
  String authToken = getAuthToken();
  // Execute POST request
  executePostRequest("https://actions.googleapis.com/v2/conversations:send",
      authToken, "update_order_example.json",);
}
    

Para atualizações de pedidos bem-sucedidas sem erros, o Google retorna uma resposta HTTP 200 com um payload vazio. Se houver um problema, como a atualização mal formada, o Google retornará um erro.