Función de pedido por adelantado v1

Puedes agregar compatibilidad en tu entrega para que los usuarios programen pedidos de comida para retirar y entregar con anticipación. Antes de implementar esta compatibilidad en la entrega, crea un feed de inventario de servicios que especifique las horas en las que los usuarios pueden realizar pedidos anticipados, como se describe en el esquema del feed de inventario (AdvanceServiceDeliveryHoursSpecification).

Ranuras para pedidos anticipados

Google propone horarios disponibles para pedidos en incrementos de 15 minutos, hasta 7 días antes, según los tiempos de entrega de un restaurante o servicio (como se define en AdvanceServiceDeliveryHoursSpecification).

Para recuperar los horarios propuestos de pedido por adelantado, usa los siguientes valores del campo fulfillmentPreference del objeto FoodCartExtension cuando confirmes la compra:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Implementa pedidos anticipados en la confirmación de la compra

En la siguiente tabla, se enumeran las posibles formas en que puedes implementar la respuesta de tu entrega en el momento de la confirmación de la compra cuando los usuarios intentan realizar pedidos.

Situación Comportamiento de entrega
Se puede completar el pedido anticipado para el horario disponible. Para aceptar el carrito de P0M ("lo antes posible") o FUTURE_SLOT, crea un objeto ProposedOrder con el mismo espacio. Para ver un ejemplo de una respuesta de confirmación de la compra que acepta un espacio, consulta este fragmento de código.
No se puede completar el pedido anticipado para el horario disponible solicitado. La entrega debe hacer lo siguiente:
  1. Rechaza el carrito de P0M o FUTURE_SLOT solicitado, e indica el motivo por el que no se puede entregar el pedido en el objeto FoodErrorExtension.
    • Si el pedido no se puede entregar debido a la capacidad, especifica una FoodOrderError de tipo de error NO_CAPACITY.
    • Si no se puede entregar el pedido porque el restaurante está cerrado, especifica una FoodOrderError de tipo de error CLOSED.
    • Si el pedido no se puede entregar por algún otro motivo, especifica una FoodOrderError de tipo de error UNAVAILABLE_SLOT.
  2. Si es posible, proporciona valores P0M o FUTURE_SLOT alternativos en correctedProposedOrder. Estos valores deben ser todas las ranuras de entrega válidas para los próximos 7 días a partir de la hora actual. Incluye el espacio P0M siempre que corresponda.

Para ver un ejemplo de una respuesta de confirmación de la compra que propone ranuras alternativas, consulta este fragmento de código.

Ranuras alternativas para la entrega de pedidos

Durante la confirmación de la compra, si el pedido por adelantado propuesto por Google no es adecuado, tu entrega puede sugerir alternativas con el objeto CheckoutResponseMessage.

Para especificar horarios alternativos para pedidos anticipados, responde a la solicitud de confirmación de la compra con un FoodErrorExtension y establece los siguientes valores:

  1. En el parámetro foodOrderErrors, especifica el tipo de error (como UNAVAILABLE_SLOT, NO_CAPACITY o CLOSED).
  2. En el parámetro correctedProposedOrder, proporciona valores alternativos de P0M o FUTURE_SLOT a través de availableFulfillmentOptions.

Las ranuras alternativas deben ser para los próximos 7 días a partir del momento de la realización del pedido y deben incluir todas las ranuras en las que se puede entregar el carrito solicitado por el usuario.

Por ejemplo, supongamos que los especiales de almuerzo solo están disponibles de lunes a viernes, de 11 a.m. a 1 p.m. Luego, el usuario intenta agregar especiales de almuerzo a su carrito, pero el horario seleccionado no está disponible. En este caso, tu entrega debe retener los especiales de almuerzo en el carrito y devolver solo los horarios disponibles de 11 a.m. a 1 p.m. durante los siguientes 7 días.

Debes omitir el objeto correctedProposedOrder.Cart.fulfillmentPreference en tu respuesta.

Si no hay horarios disponibles o si el restaurante o servicio no admite pedidos anticipados, no es necesario que proporciones un correctedProposedOrder.

Consulta los siguientes ejemplos para ver los mensajes JSON entre tu entrega y Google durante la solicitud de confirmación de la compra y el flujo de respuesta de un pedido anticipado, cuando el restaurante o servicio está disponible para aceptar pedidos por adelantado.

Ejemplo: CheckoutRequest con horario disponible

En el siguiente fragmento, se muestra un ejemplo de una solicitud de confirmación de la compra con un horario disponible para la entrega de pedidos anticipados.

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

Ejemplo: Respuesta de confirmación de la compra acepta el horario disponible

En el siguiente fragmento, se muestra un ejemplo de una respuesta de confirmación de la compra en la que tu entrega acepta los espacios para pedidos anticipados propuestos.

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

Ejemplo: CheckoutResponse con ranuras alternativas

En el siguiente fragmento, se muestra un ejemplo de una respuesta de confirmación de la compra en la que tu entrega propone ranuras para pedidos anticipados alternativas. Ten en cuenta que el objeto correctedProposedOrder.Cart.fulfillmentPreference debe omitirse en tu respuesta.

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

Implementa pedidos anticipados en el momento de envío

Cuando se envía un pedido, si hay un problema con los horarios disponibles del pedido anticipado, tu SubmitOrderResponseMessage debe incluir el motivo (como UNAVAILABLE_SLOT o UNKNOWN) en el objeto RejectionInfo.

Actualiza el estado del pedido de CREATED a CONFIRMED en el objeto OrderState cuando el proveedor acepte el pedido. Incluye el horario seleccionado en el correo electrónico de confirmación que enviarás al usuario.

Si tu entrega envía el pedido al restaurante más tarde, envía una actualización a Google con la acción de actualización de pedido asíncrona.

En el objeto OrderUpdate de la respuesta de pedido de envío de tu entrega o de las actualizaciones de pedido asíncronas posteriores, incluye un estimatedFulfillmentTimeIso8601 con el valor establecido de la siguiente manera:

  • Cuando el estado del pedido sea CREATED o CONFIRMED, establece el valor en la hora de entrega o retiro que el usuario programó para su pedido anticipado.
  • Cuando haya un tiempo de entrega estimado más preciso del restaurante o servicio, establece el valor en la hora estimada de entrega o retiro.

Ejemplo: SubmitOrderRequest con el horario disponible para la entrega

En el siguiente fragmento, se muestra un ejemplo de una solicitud de envío de pedido que indica el horario disponible que seleccionó el usuario.

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

Ejemplo: SubmitOrderResponse que acepta el pedido

En el siguiente fragmento, se muestra un ejemplo de una respuesta de pedido de envío en la que tu entrega confirma que aceptó el pedido por adelantado del usuario.

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

Ejemplo: SubmitOrderResponse rechaza el pedido debido a que el horario disponible no está disponible

En el siguiente fragmento, se muestra un ejemplo de una respuesta de pedido de envío en la que tu entrega rechaza el pedido anticipado de un usuario debido a un horario disponible.

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

Ejemplos de pedidos anticipados

El tipo AdvanceServiceDeliveryHoursSpecification se puede usar para especificar las horas de entrega o retiro a fin de que los usuarios programen su pedido con anticipación.

Nota: Hay dos períodos separados que debes especificar para la entrega del servicio: el período de pedido, que especifica cuándo los usuarios pueden realizar un pedido, y el período de entrega, que especifica cuándo se debe entregar el pedido. El objeto OpeningHoursSpecification define cuándo el usuario puede realizar el pedido. Sus tiempos de entrega secundarios (ServiceDeliveryHoursSpecification o AdvanceServiceDeliveryHoursSpecification) definen cuándo se puede entregar el pedido.

En el siguiente ejemplo, se definen las horas de un servicio para aceptar pedidos por adelantado, con intervalos de servicio 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"
          }
        }
      ]
    }
  ]
}

En el siguiente ejemplo, se muestra cómo podrías especificar que el servicio está abierto para pedidos el mismo día el día de Navidad, pero cerrado para pedidos avanzados programados para ese día. En este ejemplo, se admiten las siguientes situaciones:

  • Los usuarios pueden hacer un pedido el 25 de diciembre con entrega en el mismo día.
  • Los usuarios pueden hacer un pedido por adelantado el 25 de diciembre con la entrega programada para el 27 de diciembre.
  • Los usuarios no pueden hacer un pedido por adelantado el 22 de diciembre para la entrega programada para el 25 de diciembre.
{
  "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"
  }
}

En el siguiente ejemplo, se muestra cómo especificar que el servicio está cerrado para pedidos el mismo día o pedidos anticipados programados para Navidad, pero abierto para pedidos avanzados programados para un día posterior. En este ejemplo, se admiten las siguientes situaciones:

  • Los usuarios no pueden hacer un pedido el 25 de diciembre para la entrega el mismo día.
  • Los usuarios pueden hacer un pedido por adelantado el 25 de diciembre con la entrega programada para el 27 de diciembre.
  • Los usuarios no pueden hacer un pedido por adelantado el 22 de diciembre para la entrega programada para el 25 de diciembre.
{
  "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"
    }
  ]
}

El siguiente servicio de muestra acepta pedidos las 24 horas, todos los días, con entregas de 10:00 a.m. a 2:59:59 p.m. los días de semana:

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

El siguiente servicio de muestra acepta pedidos todos los días de 8:00 a.m. a 4:59:59 p.m., y los clientes pueden optar por una entrega dentro de una hora o elegir uno de los horarios disponibles:

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

En el siguiente ejemplo, se muestra un caso en el que la tienda abre de 8:00 a.m. a 4:59:59 p.m. los días de semana, pero de 8:00 a.m. a 6:59 p.m. los fines de semana. No se aceptan pedidos las 24 horas, todos los días.

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