É possível adicionar suporte ao fulfillment para que os usuários programem pedidos de retirada e
entrega de comida com antecedência. Antes de implementar esse suporte no
fulfillment, crie um feed de inventário de serviços que especifique o horário de funcionamento dos usuários
para fazer pedidos antecipados, conforme descrito no esquema do feed de inventário
(AdvanceServiceDeliveryHoursSpecification
).
Slots de pedidos antecipados
O Google propõe horários de pedidos antecipados em incrementos de 15 minutos e até 7 dias
de antecedência, com base nos tempos de atendimento de um restaurante ou serviço (conforme definido em
AdvanceServiceDeliveryHoursSpecification
).
Para recuperar os horários de pedido antecipado propostos, use os seguintes valores do campo fulfillmentPreference
do objeto FoodCartExtension
na finalização da compra:
PickupInfo.pickupTimeIso8601
DeliveryInfo.deliveryTimeIso8601
Implemente pedidos antecipados na finalização da compra
A tabela abaixo lista as possíveis maneiras de implementar a resposta do atendimento do pedido no momento da finalização da compra, quando os usuários tentam fazer pedidos.
Cenário | Comportamento de atendimento |
---|---|
Os pedidos com antecedência podem ser atendidos para o espaço solicitado. | Aceite o carrinho de P0M ("assim que possível") ou
FUTURE_SLOT criando um ProposedOrder com o
mesmo slot. Para conferir um exemplo de uma resposta de finalização de compra aceita um slot, consulte
este snippet de código. |
Não é possível atender ao pedido antecipado para o espaço solicitado. | O fulfillment deve fazer o seguinte:
Para conferir um exemplo de uma resposta de finalização de compra propondo espaços alternativos, consulte este snippet de código. |
Slots alternativos para o atendimento do pedido
Na finalização da compra, se os slots de pedidos antecipados propostos pelo Google não forem adequados, o
fulfillment poderá sugerir alternativas usando o objeto
CheckoutResponseMessage
.
Para especificar slots de pedidos antecipados alternativos, responda à solicitação de finalização de compra com um
FoodErrorExtension
e defina os seguintes valores:
- No parâmetro
foodOrderErrors
, especifique o tipo de erro (comoUNAVAILABLE_SLOT
,NO_CAPACITY
ouCLOSED
). - No parâmetro
correctedProposedOrder
, forneça valores alternativos deP0M
ouFUTURE_SLOT
usandoavailableFulfillmentOptions
.
Os horários alternativos precisam ser dos próximos sete dias a partir do momento da realização do pedido e incluir todos os espaços em que o carrinho solicitado pelo usuário pode ser atendido.
Por exemplo, digamos que os pratos executivos estejam disponíveis apenas de segunda a sexta-feira, das 11h às 13h. O usuário tenta adicionar pratos executivos ao carrinho, mas o horário selecionado não está disponível. Nesse caso, o atendimento do pedido precisa reter as promoções de almoço no carrinho e retornar apenas os horários das 11h às 13h nos próximos sete dias.
Omita o objeto correctedProposedOrder.Cart.fulfillmentPreference
na resposta.
Se não houver slots disponíveis ou se o restaurante ou serviço não
atender a pedidos antecipados, você não vai precisar fornecer um
correctedProposedOrder
.
Confira os exemplos abaixo para as mensagens JSON entre seu fulfillment e o Google durante a solicitação de finalização da compra e o fluxo de resposta de um pedido antecipado, quando o restaurante ou serviço estiver disponível para encomendas.
Exemplo: CheckoutRequest com slot de entrega
O snippet abaixo mostra um exemplo de solicitação de finalização de compra com um espaço de entrega de pedido antecipado.
{
"inputs": [
{
"intent": "actions.foodordering.intent.CHECKOUT",
"arguments": [
{
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.Cart",
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Cucina Venti"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
// Deliver at 6:30PM.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
},
"location": {
...
}
}
}
}
]
}
]
}
Exemplo: CheckoutResponse que aceita o espaço
O snippet abaixo mostra um exemplo de resposta de finalização de compra em que o fulfillment aceita os espaços de pedidos antecipados propostos.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"checkoutResponse": {
"proposedOrder": {
"id": "sample_proposed_order_id_1",
"cart": {
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Falafel Bite"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
// Same as the time in the request.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
},
"location": {
...
}
}
},
"totalPrice": {
"type": "ESTIMATE",
"amount": {
// Represents $16.75
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
// Send whole proposed order back.
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
// Same as the time in the request.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
]
}
},
"paymentOptions": {
...
}
}
}
}
]
}
}
}
Exemplo: CheckoutResponse com slots alternativos
O snippet abaixo mostra um exemplo de resposta de finalização de compra em que o fulfillment propõe slots de pedido antecipado alternativos. O objeto correctedProposedOrder.Cart.fulfillmentPreference
precisa ser omitido na resposta.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"error": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
"foodOrderErrors": [
{
"error": "UNAVAILABLE_SLOT", // Cart level error
"description": "The restaurant is closed."
}
],
"correctedProposedOrder": {
// Send whole original cart back,
// without the fulfillmentPreference.
"cart": {
...
},
"otherItems": {
...
},
"totalPrice": {
...
},
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T19:00:00-07:00"
}
},
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T19:30:00-07:00"
}
},
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T20:00:00-07:00"
}
}
]
}
},
"paymentOptions": {
...
}
}
}
}
]
}
}
}
Implementar pedidos antecipados no envio do pedido
Ao enviar o pedido, se houver um problema com os slots de pedidos antecipados, o
SubmitOrderResponseMessage
precisará incluir o motivo (como
UNAVAILABLE_SLOT
ou UNKNOWN
) no objeto RejectionInfo
.
Atualize o estado do pedido de CREATED
para CONFIRMED
no objeto
OrderState
quando o pedido for aceito pelo provedor. Inclua o
horário selecionado no e-mail de confirmação enviado ao usuário.
Se o fulfillment enviar o pedido ao restaurante mais tarde, informe ao Google uma atualização usando a ação assíncrona de atualização de pedido.
No objeto OrderUpdate
da resposta do pedido de envio do fulfillment ou nas
atualizações de pedido assíncronas subsequentes, inclua um
estimatedFulfillmentTimeIso8601
com o valor definido da seguinte maneira:
- Quando o status do pedido for
CREATED
ouCONFIRMED
, defina o valor como o horário de entrega ou retirada que o usuário agendou para o pedido antecipado. - Quando houver um tempo de entrega estimado mais preciso do restaurante ou do serviço, defina o valor como o tempo estimado para entrega ou retirada.
Exemplo: SubmitOrderRequest com espaço de entrega
O snippet abaixo mostra um exemplo de solicitação de envio de pedido que indica o slot do pedido avançado que o usuário selecionou.
{
"inputs": [
{
"intent": "actions.intent.TRANSACTION_DECISION",
"arguments": [
{
"transactionDecisionValue": {
"order": {
"finalOrder": {
"cart": {
"notes": "Guest prefers their food to be hot when it is delivered.",
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Cucina Venti"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
}
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
}
"contact": {
...
}
}
},
"totalPrice": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
"id": "sample_final_order_id",
"extension": {
// Send whole proposed order back.
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
]
}
},
"googleOrderId": "sample_google_order_id",
"orderDate": "2017-07-17T12:00:00Z",
"paymentInfo": {
...
}
}
}
}
]
}
]
}
Exemplo: SubmitOrderResponse aceitando o pedido
O snippet abaixo mostra um exemplo de resposta de envio de pedido em que o fulfillment confirma que aceitou o pedido antecipado do usuário.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"orderUpdate": {
"actionOrderId": "sample_action_order_id",
"orderState": {
"state": "CREATED",
"label": "Order placed"
},
"receipt": {
"userVisibleOrderId": "userVisibleId1234"
},
"updateTime": "2017-07-17T12:00:00Z",
"orderManagementActions": [
...
],
"infoExtension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
// Same as the user selected time.
"estimatedFulfillmentTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
}
}
]
}
}
}
Exemplo: SubmitOrderResponse recusa o pedido por indisponibilidade de horário
O snippet abaixo mostra um exemplo de resposta de envio de pedido em que o fulfillment recusa o pedido antecipado de um usuário devido a um espaço indisponível.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"orderUpdate": {
"actionOrderId": "sample_action_order_id",
"orderState": {
"state": "REJECTED",
"label": "Unavailable slot"
},
"rejectionInfo": {
// Note that this UNAVAILABLE_SLOT is different from the enum
// with the same name proposed for FoodOrderError.
"state": "UNAVAILABLE_SLOT",
"label": "Unavailable slot"
},
"updateTime": "2017-07-17T12:00:00Z",
"orderManagementActions": [
...
]
}
}
}
]
}
}
}
Exemplos de pedidos avançados
O tipo AdvanceServiceDeliveryHoursSpecification
pode ser usado para especificar
os horários de entrega ou retirada para que os usuários programem o pedido com antecedência.
Observação : há dois períodos que precisam ser especificados
para o fulfillment do serviço: a janela de pedido, que especifica quando os usuários podem fazer um
pedido, e a janela de fulfillment, que especifica quando o pedido será atendido. O
objeto
define quando o usuário
pode fazer o pedido. Os tempos de fulfillment filhos (OpeningHoursSpecification
ou ServiceDeliveryHoursSpecification
) definem quando o pedido pode ser
atendido.AdvanceServiceDeliveryHoursSpecification
O exemplo a seguir define o horário de funcionamento de um serviço para aceitar pedidos antecipados, com intervalos de atendimento de 15 minutos.
{ "hoursAvailable": [ { "@type": "OpeningHoursSpecification", "opens": "T00:00:00", // Ordering available 24 hours "closes": "T23:59:59", "deliveryHours": [ { "@type": "ServiceDeliveryHoursSpecification", "opens": "T09:00:00", // ASAP orders b/w 9am and 8:59:59pm "closes": "T21:00:00", "deliveryLeadTime": { "value": "60", "unitCode": "MIN" } }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T10:00:00", // Delivery between 10AM and 7:59:59PM "closes": "T20:00:00", "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart (ISO8601) "advanceBookingRequirement": { "minValue": 60, // The slot should be at least 60 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } ] } ] }
O exemplo a seguir mostra como especificar que o serviço está aberto para pedidos no mesmo dia no Natal, mas fechado para pedidos avançados programados para esse dia. Este exemplo é compatível com os seguintes cenários:
- Os usuários podem fazer um pedido em 25 de dezembro para entrega no mesmo dia.
- Os usuários podem fazer um pedido antecipado em 25 de dezembro para entrega programada para 27 de dezembro.
- Os usuários não podem fazer um pedido antecipado em 22 de dezembro para entrega programada para 25 de dezembro.
{ "specialOpeningHoursSpecification": { "@type": "AdvanceServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // No advance ordering "closes": "T00:00:00" } }
O exemplo a seguir mostra como especificar que o serviço está fechado para pedidos no mesmo dia ou pedidos antecipados programados para o Natal, mas aberto para pedidos avançados programados para um dia posterior. Este exemplo é compatível com os seguintes cenários:
- Os usuários não podem fazer um pedido em 25 de dezembro para entrega no mesmo dia.
- Os usuários podem fazer um pedido antecipado em 25 de dezembro para entrega programada para 27 de dezembro.
- Os usuários não podem fazer um pedido antecipado em 22 de dezembro para entrega programada para 25 de dezembro.
{ "specialOpeningHoursSpecification": [ { "@type": "ServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // No ASAP ordering on Christmas "closes": "T00:00:00" }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // Orders cannot be scheduled for Christmas "closes": "T00:00:00" } ] }
O exemplo de serviço a seguir aceita pedidos 24 horas por dia, 7 dias por semana, e entregas das 10h às 14h59:59 nos dias úteis:
... { "@type": "OpeningHoursSpecification", "opens": "T00:00:00", "closes": "T23:59:59", "deliveryHours": { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T10:00:00", // Delivery starts at 10:00AM "closes": "T15:00:00", // Delivery ends at 3:00PM. Delivery from 10AM-2:59:59PM. "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart "advanceBookingRequirement": { "minValue": 60, // The slot should be at least 60 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } } ...
O exemplo de serviço a seguir aceita pedidos todos os dias das 8h às 16h59:59. Os clientes podem optar por uma entrega no prazo de uma hora ou escolher um dos horários:
... { "@type": "OpeningHoursSpecification", "opens": "T08:00:00", // Ordering opens at 8:00AM "closes": "T17:00:00", // Ordering closes at 5:00PM, last order at 4:59:59PM "deliveryHours": [ { "@type": "ServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "deliveryLeadTime": { "@type": "QuantitativeValue", "value": "60", // If no exact deliveryLeadTime, put a maximum time "unitCode": "MIN" } }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart "advanceBookingRequirement": { "minValue": 90, // The slot should be at least 90 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } ] } ...
O exemplo a seguir mostra um caso em que a loja abre das 8h às 16h59:59 nos dias úteis, mas das 8h às 18h59 nos fins de semana. Pedidos não são aceitos 24 horas por dia, 7 dias por semana.
... { // On weekdays, ordering open from 8AM-4:59:59PM. "@type": "OpeningHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "deliveryHours": [ { // Fulfillment between 8AM-4:59:59PM on weekdays. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } }, { // Fulfillment between 8AM-6:59:59PM on weekends (even for orders placed on a // weekday). "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } } ] }, { // On weekends, one can place orders upto 6:59:59PM. "@type": "OpeningHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "deliveryHours": [ { // But fulfillment on weekdays is only till 4:59:59PM. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } }, { // Fulfillment on weekends is till 6:59:59PM. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } } ] } ...