Recurso de pedido antecipado v1

Você pode adicionar suporte à sua entrega para que os usuários programem a retirada e a entrega de pedidos de comida com antecedência. Antes de implementar esse suporte no atendimento, crie um feed de inventário de serviço que especifique os horários em que os usuários podem fazer pedidos antecipados, conforme descrito no esquema do feed de inventário (AdvanceServiceDeliveryHoursSpecification).

Horários de pedidos antecipados

O Google propõe horários de pedidos antecipados em incrementos de 15 minutos, com até sete 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 agendamento de pedidos antecipados propostos, use os seguintes valores do campo fulfillmentPreference do objeto FoodCartExtension na finalização da compra:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Implementar pedidos antecipados na finalização da compra

A tabela abaixo lista as maneiras possíveis de implementar a resposta da sua conclusão no momento do pagamento quando os usuários tentam fazer pedidos.

Cenário Comportamento de fulfillment
O pedido antecipado pode ser atendido no horário solicitado. Aceite o P0M ("assim que possível") ou o carrinho FUTURE_SLOT criando um ProposedOrder com o mesmo slot. Para conferir um exemplo de uma resposta de finalização de compra que aceita um slot, consulte este snippet de código.
O pedido antecipado não pode ser atendido no horário solicitado. Sua entrega precisa fazer o seguinte:
  1. Rejeite o carrinho P0M ou FUTURE_SLOT solicitado e indique o motivo pelo qual o pedido não pode ser atendido no objeto FoodErrorExtension.
    • Se o pedido não puder ser atendido devido à capacidade, especifique um FoodOrderError do tipo de erro NO_CAPACITY.
    • Se o pedido não puder ser atendido porque o restaurante está fechado, especifique um FoodOrderError do tipo de erro CLOSED.
    • Se o pedido não puder ser atendido por algum outro motivo, especifique um FoodOrderError do tipo de erro UNAVAILABLE_SLOT.
  2. Se possível, forneça valores alternativos de P0M ou FUTURE_SLOT em correctedProposedOrder. Esses valores precisam ser todos os intervalos de fulfillment válidos para os próximos sete dias, a partir do horário atual. Inclua o slot P0M sempre que aplicável.

Para conferir um exemplo de resposta de finalização de compra que propõe horários alternativos, consulte este snippet de código.

Horários alternativos para atendimento do pedido

Na finalização da compra, se os horários de pedido antecipado propostos pelo Google não forem adequados, o atendimento poderá sugerir alternativas usando o objeto CheckoutResponseMessage.

Para especificar horários de reserva antecipada alternativos, responda à solicitação de finalização de compra com um FoodErrorExtension e defina os seguintes valores:

  1. No parâmetro foodOrderErrors, especifique o tipo de erro (como UNAVAILABLE_SLOT, NO_CAPACITY ou CLOSED).
  2. No parâmetro correctedProposedOrder, forneça valores alternativos de P0M ou FUTURE_SLOT usando availableFulfillmentOptions.

Os slots alternativos devem ser para os próximos sete dias a partir do momento do pedido e incluir todos os slots em que o carrinho solicitado pelo usuário pode ser atendido.

Por exemplo, digamos que os pratos do dia só estão disponíveis de segunda a sexta-feira, das 11h às 13h. O usuário tenta adicionar itens especiais de almoço ao carrinho, mas o horário selecionado não está disponível. Nesse caso, o atendimento precisa manter os itens especiais de almoço no carrinho e retornar apenas os horários de 11h às 13h nos próximos sete dias.

O objeto correctedProposedOrder.Cart.fulfillmentPreference precisa ser omitido na resposta.

Se não houver horários disponíveis ou se o restaurante ou serviço não aceitar pedidos antecipados, não será necessário fornecer um correctedProposedOrder.

Confira os exemplos abaixo das mensagens JSON entre seu fulfillment e o Google durante o fluxo de solicitação e resposta de finalização de compra de um pedido antecipado, quando o restaurante ou serviço está disponível para receber encomendas antecipadas.

Exemplo: CheckoutRequest com slot de entrega

O snippet abaixo mostra um exemplo de uma solicitação de finalização de compra com um horário 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 aceitando o slot

O snippet abaixo mostra um exemplo de resposta de finalização de compra em que a entrega aceita os horários 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 a fulfillment propõe horários alternativos de pedidos antecipados. 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 ao enviar o pedido

No envio do pedido, se houver um problema com os horários de reserva antecipada, 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, envie uma atualização ao Google usando a ação de atualização de pedido assíncrono.

No objeto OrderUpdate da resposta de envio de pedido do fulfillment ou nas atualizações assíncronas subsequentes do pedido, inclua um estimatedFulfillmentTimeIso8601 com o valor definido da seguinte maneira:

  • Quando o status do pedido for CREATED ou CONFIRMED, defina o valor como o horário de entrega ou retirada que o usuário programou para o pedido antecipado.
  • Quando houver um tempo de entrega estimado mais preciso do restaurante ou serviço, defina o valor como o tempo estimado de entrega ou retirada.

Exemplo: enviar uma solicitação de pedido com horário de entrega

O snippet abaixo mostra um exemplo de solicitação de envio de pedido indicando o horário de pedido antecipado 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 atendimento 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 recusando o pedido devido à indisponibilidade de slot

O snippet abaixo mostra um exemplo de uma resposta de envio de pedido em que o atendimento recusa o pedido antecipado de um usuário devido a um horário 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 antecipados

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á duas janelas de tempo separadas que precisam ser especificadas para a realização do serviço: a janela de pedidos, que especifica quando os usuários podem fazer um pedido, e a janela de fulfillment, que especifica quando o pedido é realizado. O objeto OpeningHoursSpecification define quando o usuário pode fazer o pedido. Os tempos de atendimento das crianças (ServiceDeliveryHoursSpecification ou AdvanceServiceDeliveryHoursSpecification) definem quando o pedido pode ser cumprido.

O exemplo a seguir define os horários de um serviço para aceitar pedidos antecipados, com intervalos 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 em 27 de dezembro.
  • Os usuários não podem fazer um pedido antecipado em 22 de dezembro para entrega programada em 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 dia de Natal, mas aberto para pedidos antecipados programados para um dia posterior. Este exemplo oferece suporte aos 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 em 27 de dezembro.
  • Os usuários não podem fazer um pedido antecipado em 22 de dezembro para entrega programada em 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 e faz entregas das 10h às 16h59 (horário local) 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, e os clientes podem optar por uma entrega em até 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, sete 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"
      }
    }
  ]
}
...