v1 функция заказа вперед

Вы можете добавить поддержку в свое выполнение, чтобы пользователи могли заранее планировать самовывоз и доставку заказов на еду. Прежде чем реализовать эту поддержку при выполнении, создайте канал инвентаризации услуг, в котором указываются часы, в течение которых пользователи могут размещать предварительные заказы, как описано в схеме канала инвентаризации ( AdvanceServiceDeliveryHoursSpecification ).

Слоты для предварительных заказов

Google предлагает интервалы для предварительных заказов с шагом в 15 минут на срок до 7 дней вперед в зависимости от сроков выполнения ресторана или услуги (как определено в AdvanceServiceDeliveryHoursSpecification ).

Чтобы получить предлагаемые интервалы предзаказа, используйте следующие значения из поля fulfillmentPreference объекта FoodCartExtension при оформлении заказа:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Осуществлять предварительные заказы на кассе

В таблице ниже перечислены возможные способы реализации реакции на выполнение заказа во время оформления заказа, когда пользователи пытаются разместить заказы.

Сценарий Поведение выполнения
Предварительный заказ может быть выполнен для запрошенного слота. Примите корзину P0M («как можно скорее») или FUTURE_SLOT , создав ProposedOrder с тем же слотом. Пример ответа на оформление заказа, принимающего слот, см. в этом фрагменте кода .
Предварительный заказ не может быть выполнен для запрошенного слота. Ваше выполнение должно сделать следующее:
  1. Отклонить запрошенную корзину P0M или FUTURE_SLOT , а в объекте FoodErrorExtension указать причину, по которой заказ не может быть выполнен.
    • Если заказ не может быть выполнен из-за емкости, укажите FoodOrderError типа ошибки NO_CAPACITY .
    • Если заказ не может быть выполнен из-за закрытия ресторана, укажите FoodOrderError типа ошибки CLOSED .
    • Если заказ не может быть выполнен по какой-либо другой причине, укажите FoodOrderError типа ошибки UNAVAILABLE_SLOT .
  2. Если возможно, предоставьте альтернативные значения P0M или FUTURE_SLOT в correctedProposedOrder . Эти значения должны соответствовать всем действительным слотам выполнения в течение следующих 7 дней, начиная с текущего времени. Включите слот P0M , когда это возможно.

Пример ответа при оформлении заказа, предлагающего альтернативные места, см. в этом фрагменте кода .

Альтернативные слоты для выполнения заказов

Если при оформлении заказа предложенные Google слоты для предварительного заказа не подходят, ваш исполнитель может предложить альтернативы с помощью объекта CheckoutResponseMessage .

Чтобы указать альтернативные интервалы предварительного заказа, ответьте на запрос оформления заказа FoodErrorExtension и установите следующие значения:

  1. В параметре foodOrderErrors укажите тип ошибки (например UNAVAILABLE_SLOT , NO_CAPACITY или CLOSED ).
  2. В параметре 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"
      }
    }
  ]
}
...