Función de pedidos por adelantado de v1

Puedes agregar compatibilidad en tu entrega para que los usuarios programen la retirada y la entrega de pedidos de comida 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).

Horarios para pedidos por adelantado

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

Para recuperar los horarios propuestos para el pedido anticipado, usa los siguientes valores del campo fulfillmentPreference del objeto FoodCartExtension en la confirmación de la compra:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Implementa pedidos por adelantado 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 entregar el pedido por adelantado para el horario solicitado. Acepta el carrito P0M ("lo antes posible") o FUTURE_SLOT creando un ProposedOrder con el mismo espacio. Para ver un ejemplo de una respuesta de confirmación de la compra que acepta un horario, consulta este fragmento de código.
No se puede entregar el pedido anticipado para el horario solicitado. Tu entrega debe hacer lo siguiente:
  1. Rechaza el carrito P0M o FUTURE_SLOT solicitado y, luego, indica el motivo por el que no se puede completar el pedido en el objeto FoodErrorExtension.
    • Si no se puede entregar el pedido debido a la capacidad, especifica un FoodOrderError de tipo de error NO_CAPACITY.
    • Si el pedido no se puede entregar porque el restaurante está cerrado, especifica un FoodOrderError de tipo de error CLOSED.
    • Si el pedido no se puede entregar por algún otro motivo, especifica un FoodOrderError de tipo de error UNAVAILABLE_SLOT.
  2. Si es posible, proporciona valores alternativos de P0M o FUTURE_SLOT en correctedProposedOrder. Estos valores deben ser todos los intervalos de entrega válidos para los próximos 7 días a partir de la hora actual. Incluye el espacio P0M cuando corresponda.

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

Horarios alternativos para la preparación de pedidos

En la confirmación de la compra, si los horarios de pedido anticipado que propone Google no son adecuados, el proceso de entrega puede sugerir alternativas con el objeto CheckoutResponseMessage.

Para especificar horarios alternativos para pedidos por adelantado, responde 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.

Los horarios alternativos deben ser para los próximos 7 días a partir del momento en que se realiza el pedido y deben incluir todos los horarios en los que se puede entregar el carrito solicitado por el usuario.

Por ejemplo, supongamos que los especiales de almuerzo están disponibles solo 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, la entrega debe retener los especiales de almuerzo en el carrito y mostrar solo los horarios de 11 a.m. a 1 p.m. durante los próximos 7 días.

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

Si no hay horarios disponibles o si el restaurante o el servicio no admiten pedidos por adelantado, no es necesario que proporciones un correctedProposedOrder.

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

Ejemplo: CheckoutRequest con un horario de entrega

En el siguiente fragmento, se muestra un ejemplo de una solicitud de confirmación de la compra con un horario de entrega de pedido anticipado.

{
  "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: CheckoutResponse acepta el espacio

En el siguiente fragmento, se muestra un ejemplo de una respuesta de confirmación de la compra en la que tu entrega acepta los horarios de pedido anticipado 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 horarios alternativos para pedidos por adelantado. Ten en cuenta que se debe omitir el objeto correctedProposedOrder.Cart.fulfillmentPreference 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 por adelantado en el envío del pedido

Cuando envíes el pedido, si hay un problema con los horarios de los pedidos por adelantado, 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 lo acepte. Incluye el horario seleccionado en el correo electrónico de confirmación que le envíes al usuario.

Si la 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 envío del pedido de tu entrega o en las actualizaciones de pedidos asíncronos 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 el tiempo de entrega o de retiro estimado.

Ejemplo: SubmitOrderRequest con un horario de entrega

En el siguiente fragmento, se muestra un ejemplo de una solicitud de envío de pedido que indica el horario de pedido anticipado 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 envío de pedido 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 la falta de disponibilidad del horario

En el siguiente fragmento, se muestra un ejemplo de una respuesta de envío de pedido en la que tu entrega rechaza el pedido por adelantado de un usuario debido a que no hay 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 por adelantado

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

Nota: Existen 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 entrega 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 puedes especificar que el servicio está disponible para los pedidos el mismo día en Navidad, pero cerrado para los pedidos anticipados programados para ese día. Este ejemplo admite las siguientes situaciones:

  • Los usuarios pueden realizar un pedido el 25 de diciembre para la entrega el mismo día.
  • Los usuarios pueden realizar un pedido anticipado el 25 de diciembre para que se entregue el 27 de diciembre.
  • Los usuarios no pueden realizar un pedido anticipado el 22 de diciembre para una entrega programada 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 puedes especificar que el servicio está cerrado para los pedidos el mismo día o los pedidos anticipados programados para el día de Navidad, pero está abierto para los pedidos anticipados programados para otro día. Este ejemplo admite las siguientes situaciones:

  • Los usuarios no pueden realizar pedidos el 25 de diciembre para entrega el mismo día.
  • Los usuarios pueden realizar un pedido anticipado el 25 de diciembre para que se entregue el 27 de diciembre.
  • Los usuarios no pueden realizar un pedido anticipado el 22 de diciembre para una entrega programada 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 ejemplo acepta pedidos las 24 horas, todos los días, y realiza entregas de 10 a.m. a 2:59:59 p.m., de lunes a viernes:

...
{
  "@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 ejemplo acepta pedidos todos los días de 8 a.m. a 4:59:59 p.m., y los clientes pueden optar por una entrega en el plazo de una hora o elegir uno de los siguientes horarios:

...
{
  "@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 a.m. a 4:59:59 p.m. los días de semana, pero de 8 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"
      }
    }
  ]
}
...