Вы можете добавить поддержку в свое выполнение, чтобы пользователи могли заранее планировать самовывоз и доставку заказов на еду. Прежде чем реализовать эту поддержку при выполнении, создайте канал инвентаризации услуг, в котором указываются часы, в течение которых пользователи могут размещать предварительные заказы, как описано в схеме канала инвентаризации ( AdvanceServiceDeliveryHoursSpecification
).
Слоты для предварительных заказов
Google предлагает интервалы для предварительных заказов с шагом в 15 минут на срок до 7 дней вперед в зависимости от сроков выполнения ресторана или услуги (как определено в AdvanceServiceDeliveryHoursSpecification
).
Чтобы получить предлагаемые интервалы предзаказа, используйте следующие значения из поля fulfillmentPreference
объекта FoodCartExtension
при оформлении заказа:
-
PickupInfo.pickupTimeIso8601
-
DeliveryInfo.deliveryTimeIso8601
Осуществлять предварительные заказы на кассе
В таблице ниже перечислены возможные способы реализации реакции на выполнение заказа во время оформления заказа, когда пользователи пытаются разместить заказы.
Сценарий | Поведение выполнения |
---|---|
Предварительный заказ может быть выполнен для запрошенного слота. | Примите корзину P0M («как можно скорее») или FUTURE_SLOT , создав ProposedOrder с тем же слотом. Пример ответа на оформление заказа, принимающего слот, см. в этом фрагменте кода . |
Предварительный заказ не может быть выполнен для запрошенного слота. | Ваше выполнение должно сделать следующее:
Пример ответа при оформлении заказа, предлагающего альтернативные места, см. в этом фрагменте кода . |
Альтернативные слоты для выполнения заказов
Если при оформлении заказа предложенные Google слоты для предварительного заказа не подходят, ваш исполнитель может предложить альтернативы с помощью объекта CheckoutResponseMessage
.
Чтобы указать альтернативные интервалы предварительного заказа, ответьте на запрос оформления заказа FoodErrorExtension
и установите следующие значения:
- В параметре
foodOrderErrors
укажите тип ошибки (например,UNAVAILABLE_SLOT
,NO_CAPACITY
илиCLOSED
). - В параметре
correctedProposedOrder
укажите альтернативные значенияP0M
илиFUTURE_SLOT
черезavailableFulfillmentOptions
.
Альтернативные слоты должны быть рассчитаны на следующие 7 дней с момента размещения заказа и включать все слоты, в которых может быть заполнена запрошенная пользователем корзина.
Например, предположим, что специальные обеды доступны только с понедельника по пятницу с 11:00 до 13:00. Затем пользователь пытается добавить специальные обеды в корзину, но выбранное им место недоступно. В этом случае при выполнении заказа в корзине должны быть сохранены специальные обеды и возвращены только интервалы с 11:00 до 13:00 в течение следующих 7 дней.
В своем ответе вам следует опустить объект correctedProposedOrder.Cart.fulfillmentPreference
.
Если свободных мест нет или ресторан или услуга не поддерживает предварительные заказы, вам не нужно предоставлять correctedProposedOrder
.
В приведенных ниже примерах показаны сообщения JSON между вашим выполнением и Google во время запроса на оформление заказа и потока ответа на предварительный заказ, когда ресторан или услуга доступны для приема предварительных заказов.
Пример: CheckoutRequest со слотом доставки
В приведенном ниже фрагменте показан пример запроса на оформление заказа со слотом для доставки предварительного заказа.
{
"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": {
...
}
}
}
}
]
}
]
}
Пример: CheckoutResponse принимает слот
В приведенном ниже фрагменте показан пример ответа на оформление заказа, в котором ваше выполнение принимает предложенные слоты для предварительного заказа.
{
"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": {
...
}
}
}
}
]
}
}
}
Пример: CheckoutResponse с альтернативными слотами
В приведенном ниже фрагменте показан пример ответа на оформление заказа, в котором при выполнении заказа предлагаются альтернативные места для предварительного заказа. Обратите внимание, что в вашем ответе объект correctedProposedOrder.Cart.fulfillmentPreference
должен быть опущен.
{
"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": {
...
}
}
}
}
]
}
}
}
Выполнение предварительных заказов при отправке заказа
Если при отправке заказа возникает проблема со слотами предварительного заказа, ваше SubmitOrderResponseMessage
должно включать причину (например, UNAVAILABLE_SLOT
или UNKNOWN
) в объект RejectionInfo
.
Обновите состояние заказа с CREATED
на CONFIRMED
в объекте OrderState
, когда заказ принят поставщиком. Включите выбранный временной интервал в электронное письмо с подтверждением, отправленное пользователю.
Если в результате выполнения заказ будет отправлен в ресторан позже, отправьте Google обновление с помощью действия по асинхронному обновлению заказа .
В объект OrderUpdate
вашего ответа на отправку заказа или последующих асинхронных обновлений заказа включите estimatedFulfillmentTimeIso8601
со следующим значением:
- Когда статус заказа
CREATED
илиCONFIRMED
, установите значение времени доставки или самовывоза, которое пользователь запланировал для своего предварительного заказа. - Если имеется более точное расчетное время доставки из ресторана или службы, установите в качестве значения расчетное время доставки или время самовывоза.
Пример: SubmitOrderRequest со слотом доставки
В приведенном ниже фрагменте показан пример запроса на отправку заказа с указанием интервала предварительного заказа, выбранного пользователем.
{
"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": {
...
}
}
}
}
]
}
]
}
Пример: SubmitOrderResponse принимает заказ
В приведенном ниже фрагменте показан пример ответа на отправку заказа, в котором ваше выполнение подтверждает, что он принял предварительный заказ пользователя.
{
"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"
}
}
}
}
]
}
}
}
Пример: SubmitOrderResponse отклоняет заказ из-за недоступности слота.
В приведенном ниже фрагменте показан пример ответа на отправку заказа, в котором при выполнении отклоняется предварительный заказ пользователя из-за недоступного слота.
{
"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": [
...
]
}
}
}
]
}
}
}
Примеры предварительных заказов
Тип AdvanceServiceDeliveryHoursSpecification
можно использовать для указания часов доставки или получения, чтобы пользователи могли заранее запланировать свой заказ.
Примечание. Для выполнения услуги необходимо указать два отдельных временных окна: окно заказа , которое определяет, когда пользователи могут разместить заказ, и окно выполнения , которое определяет, когда заказ будет выполнен. Объект
определяет, когда пользователь может разместить заказ. Время его дочернего выполнения ( OpeningHoursSpecification
или ServiceDeliveryHoursSpecification
) определяет, когда заказ может быть выполнен.AdvanceServiceDeliveryHoursSpecification
В следующем примере определяются часы приема предварительных заказов службой с 15-минутными интервалами обслуживания.
{ "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" } } ] } ] }
В следующем примере показано, как можно указать, что служба открыта для заказов в тот же день в день Рождества, но закрыта для предварительных заказов, запланированных на этот день. Этот пример поддерживает следующие сценарии:
- Пользователи могут сделать заказ 25 декабря с доставкой в тот же день.
- Пользователи могут сделать предварительный заказ 25 декабря, чтобы доставка запланирована на 27 декабря.
- Пользователи не могут сделать предварительный заказ 22 декабря на доставку, запланированную на 25 декабря.
{ "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" } }
В следующем примере показано, как можно указать, что служба закрыта для заказов в тот же день или предварительных заказов, запланированных на Рождество, но открыта для предварительных заказов, запланированных на более поздний день. Этот пример поддерживает следующие сценарии:
- Пользователи не могут сделать заказ 25 декабря с доставкой в тот же день.
- Пользователи могут сделать предварительный заказ 25 декабря, чтобы доставка запланирована на 27 декабря.
- Пользователи не могут сделать предварительный заказ 22 декабря на доставку, запланированную на 25 декабря.
{ "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" } ] }
Следующий пример Службы принимает заказы круглосуточно и без выходных и осуществляет доставку с 10:00 до 14:59:59 по будням:
... { "@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" } } } ...
Следующий пример Службы принимает заказы каждый день с 8:00 до 16:59:59, и клиенты могут либо выбрать доставку в течение часа, либо выбрать одно из временных интервалов:
... { "@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" } } ] } ...
В следующем примере показан случай, когда магазин открыт с 8:00 до 16:59:59 в будние дни, но с 8:00 до 18:59 по выходным. Заказы не принимаются круглосуточно.
... { // 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" } } ] } ...