Atualização do pedido assíncrono

Depois que o cliente enviar um pedido de comida, você poderá enviar uma mensagem de atualização do pedido para o serviço de Pedido de ponta a ponta para nos notificar sobre a mudança.

Aqui estão alguns motivos comuns para enviar atualizações de pedidos:

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

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

Estados de ordem de transição

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

Ordenar transições de estado

Quando um cliente envia um pedido pela primeira vez, o pedido começa com o estado de CREATED, CONFIRMED ou REJECTED. Você pode enviar uma mensagem de atualização do pedido para atualiza o estado de um pedido, desde que a transição de estado seja válida. 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 uma entrega agregador. O agregador de entregas recebe a entrega do Google, e o agregador envia as informações para o restaurante. Depois que o restaurante recebeu e confirmou a disponibilidade do pedido, o estado agora pode ser CONFIRMED. Caso contrário, REJECTED.

Em seguida, um pedido no estado CONFIRMED passa para o estado IN_PREPARATION. Use o estado READY_FOR_PICKUP ou IN_TRANSIT, dependendo se o pedido é para retirada ou entrega. Quando a comida é entregue ou retirada, o pedido é definido com o estado FULFILLED.

Se você permitir que os clientes cancelem pedidos, poderá usar o estado CANCELLED. Um pedido pode ser cancelado nos estados CREATED, CONFIRMED, IN_PREPARATION, READY_FOR_PICKUP ou IN_TRANSIT. Seu serviço de pedidos de ponta a ponta emitirá reembolsos dependendo da sua a política de cancelamento e o estado dos pagamentos no momento do cancelamento.

O serviço de pedidos de ponta a ponta não precisa suportar todos os estados disponíveis e transições. No entanto, o estado final do pedido precisa ser FULFILLED, REJECTED ou CANCELLED.

Como fornecer um tempo de atendimento estimado

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

Envie estimatedFulfillmentTimeIso8601 nos seguintes horários:

  • Quando o tempo estimado estiver disponível, de preferência na ordem CREATED ou CONFIRMED.
  • Quando o tempo estimado muda, como atualizar o tempo estimado para ser mais preciso quando o pedido é IN_TRANSIT.

Para gerenciar as expectativas do usuário de forma eficaz, seja conservador em suas estimativas e fornecer um período de data e hora em vez de uma data e hora fixas. Você deve considere variações como condições de trânsito sempre que possível. Para exemplo, você pode enviar uma estimativa de 12h45 (limite inferior) para 13h15 (limite superior vinculado) para um pedido em que o tempo de entrega estimado é 13h.

Fornecer ações de gerenciamento de pedidos

Ao enviar uma atualização de pedido, você pode fornecer recursos aos clientes que ajudam que gerenciam o pedido na forma de um OrderManagementAction. Após um o cliente fizer um pedido, ele precisará entrar em contato com você ou com o restaurante atender ao pedido para acompanhar o progresso, fazer alterações ou cancelar o pedido.

Com um OrderManagementAction, os clientes podem enviar e-mails, ligar ou vincular a uma URL diretamente do dispositivo. Use as mesmas informações em OrderManagementAction conforme consta no e-mail de confirmação do pedido enviado para usuário.

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

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

Cada atualização de pedido precisa conter pelo menos uma ação de gerenciamento de pedidos. 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, o CUSTOMER_SERVICE pode direcionar para o número de telefone do atendimento ao cliente. Quando o estado do pedido atualizações de IN_TRANSIT, a ação CUSTOMER_SERVICE poderá apontar para o o número de telefone do restaurante.

Enviando atualizações de pedidos

Você usa o tipo de mensagem AsyncOrderUpdateRequestMessage para enviar um pedido ao serviço de pedidos de ponta a ponta. O Google responde com um AsyncOrderUpdateResponseMessage: Por exemplo, se você quiser informar um ao cliente que o pedido é válido e aceito, envie uma AsyncOrderUpdateRequestMessage para mudar o estado do pedido para CONFIRMED com o rótulo Accepted by restaurant.

Diagrama de atualização do pedido

Como definir a mensagem de atualização do pedido

Ao enviar um AsyncOrderUpdateRequestMessage para o 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 um exemplo de solicitação de atualização de pedido que notifica o usuário que o pedido seja confirmado com um recibo e uma entrega estimada tempo de resposta.

{
  "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"
      }
    }
  }
}
    

REJEITADO

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

{
  "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."
        }
      ]
      }
    }
  }
}
    

CANCELADO

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário que o pedido foi cancelado com um motivo de 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"
            }
          }
        }
      ]
    }
  }
}
    

IN_PREPARATION

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário que a comida está sendo preparada no momento.

{
  "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 que a comida está pronta 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"
      }
    }
  }
}
    

IN_TRANSIT

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário se 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"
      }
    }
  }
}
  

ATIVIDADE

Este exemplo mostra um exemplo de solicitação de atualização de pedido que notifica o usuário se 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 avançadas de pedidos.

Gerar o token de autorização e enviar a mensagem

Atualizações de pedidos exigem um token de autorização para que o pedido pode verificar se a mensagem é do serviço da Web de pedidos de ponta a ponta.

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

  1. Gere um token de autorização seguindo estas etapas:
    1. Usar a biblioteca do Google Auth para ler as credenciais do seu serviço arquivo de conta de serviço.
    2. Token de solicitação usando o seguinte escopo de API: https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. Use esse token para enviar uma solicitação POST HTTP autenticada ao seguinte endpoint: 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

Este 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

Este 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

Este 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 pedido bem-sucedidas sem erros, o Google retorna uma resposta HTTP 200 com um payload vazio. Se houve um problema, como a atualização malformado, o Google retornará um erro.