W ramach realizacji zamówienia możesz zapewnić użytkownikom pomoc w planowaniu z wyprzedzeniem zamówień jedzenia z odbiorem i dostawą. Zanim wdrożysz tę obsługę, utwórz plik danych o asortymencie usługi zawierający godziny, w których użytkownicy mogą składać zamówienia w zamówieniu zgodnie ze schematem pliku danych o asortymencie (AdvanceServiceDeliveryHoursSpecification
).
Przedziały zamówień z wyprzedzeniem
Google oferuje terminy składania zamówień z wyprzedzeniem w odstępach 15-minutowych, z maksymalnie 7-dniowym wyprzedzeniem, na podstawie czasu realizacji zamówienia w przypadku restauracji lub usługi (zgodnie z definicją w AdvanceServiceDeliveryHoursSpecification
).
Aby pobrać proponowane przedziały zamówienia z wyprzedzeniem, użyj tych wartości w polu fulfillmentPreference
obiektu FoodCartExtension
w momencie płatności:
PickupInfo.pickupTimeIso8601
DeliveryInfo.deliveryTimeIso8601
Wdrażanie zamówień z góry w momencie płatności
W tabeli poniżej znajdziesz możliwe sposoby wdrożenia odpowiedzi na żądanie realizacji w momencie płatności, gdy użytkownicy próbują złożyć zamówienie.
Scenariusz | Sposób realizacji |
---|---|
W przypadku żądanego przedziału czasu można zrealizować zamówienie z wyprzedzeniem. | Zaakceptuj koszyk P0M („jak najszybciej”) lub FUTURE_SLOT , tworząc ProposedOrder z tym samym przedziałem. Przykład odpowiedzi płatności akceptującej przedział czasu znajdziesz w tym fragmentie kodu. |
W przypadku żądanego przedziału czasu nie można zrealizować zamówienia z wyprzedzeniem. | Realizacja zamówienia powinna wyglądać tak:
Przykład odpowiedzi dotyczącej płatności z propozycją alternatywnych przedziałów znajdziesz w tym fragmentie kodu. |
Alternatywne przedziały do realizacji zamówień
Jeśli w momencie płatności proponowane przez Google terminy składania zamówień z wyprzedzeniem nie są odpowiednie, realizacja może zasugerować alternatywne rozwiązanie za pomocą obiektu CheckoutResponseMessage
.
Aby określić alternatywne przedziały dla zamówień z wyprzedzeniem, odpowiedz na żądanie płatności za pomocą atrybutu FoodErrorExtension
i ustaw te wartości:
- W parametrze
foodOrderErrors
określ typ błędu (np.UNAVAILABLE_SLOT
,NO_CAPACITY
lubCLOSED
). - W parametrze
correctedProposedOrder
podaj alternatywne wartościP0M
lubFUTURE_SLOT
za pomocąavailableFulfillmentOptions
.
Alternatywne przedziały czasu powinny obejmować następne 7 dni od momentu złożenia zamówienia i zawierać wszystkie przedziały, w których można zrealizować wybrany przez użytkownika koszyk.
Załóżmy na przykład, że oferty specjalne lunchowe są dostępne tylko od poniedziałku do piątku w godzinach 11:00–13:00. Użytkownik próbuje dodać do koszyka dania specjalne, ale wybrane przez niego miejsce jest niedostępne. W tym przypadku realizacja zamówienia powinna zawierać specjalne danie w koszyku i zwracać przez kolejne 7 dni tylko przedziały czasu między 11:00 a 13:00.
W odpowiedzi pomiń obiekt correctedProposedOrder.Cart.fulfillmentPreference
.
Jeśli nie mamy wolnych terminów albo restauracja lub usługa nie obsługuje zamówień z wyprzedzeniem, nie musisz podawać właściwości correctedProposedOrder
.
Poniżej znajdziesz przykłady komunikatów JSON między Twoją realizacją zamówień a Google w trakcie procesu płatności i odpowiedzi na zamówienie z wyprzedzeniem, gdy restauracja lub usługa są dostępne do składania zamówień w przedsprzedaży.
Przykład: żądanie płatności z przedziałem dostawy
Fragment kodu poniżej przedstawia przykład żądania płatności z przedziałem czasu dostawy zamówienia z wyprzedzeniem.
{
"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": {
...
}
}
}
}
]
}
]
}
Przykład: CheckoutResponse akceptuje przedział
Fragment kodu poniżej pokazuje przykładową odpowiedź na płatność, w której realizacja akceptuje proponowane przedziały dotyczące zamówień z wyprzedzeniem.
{
"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": {
...
}
}
}
}
]
}
}
}
Przykład: odpowiedź na żądanie płatności z dodatkowymi przedziałami
Fragment kodu poniżej pokazuje przykładową odpowiedź na płatność, w której realizacja proponuje alternatywne przedziały czasu w przypadku zamówień z wyprzedzeniem. Pamiętaj, że w odpowiedzi należy pominąć obiekt 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": {
...
}
}
}
}
]
}
}
}
Wdrażanie zamówień z wyprzedzeniem podczas składania zamówienia
Jeśli przy przesyłaniu zamówienia wystąpi problem z przedziałami dla zamówień z wyprzedzeniem, SubmitOrderResponseMessage
powinien podać przyczynę (np. UNAVAILABLE_SLOT
lub UNKNOWN
) w obiekcie RejectionInfo
.
Po zaakceptowaniu zamówienia przez dostawcę zaktualizuj stan zamówienia z CREATED
na CONFIRMED
w obiekcie OrderState
. Podaj wybrany przedział czasu w e-mailu z potwierdzeniem wysłanym do użytkownika.
Jeśli po złożeniu zamówienia zamówienie zostanie wysłane do restauracji później, wyślij do Google aktualizację, korzystając z asynchronicznego działania aktualizacji zamówienia.
W obiekcie OrderUpdate
w odpowiedzi na przesłanie zamówienia lub kolejnych asynchronicznych aktualizacjach zamówień umieść tag estimatedFulfillmentTimeIso8601
z tą wartością:
- Gdy stan zamówienia to
CREATED
lubCONFIRMED
, jako wartość ustaw czas dostawy lub odbioru, który użytkownik zaplanował w związku z zamówieniem z wyprzedzeniem. - Jeśli istnieje dokładniejszy przewidywany czas dostawy do restauracji lub usługi, ustaw wartość na szacowany czas dostawy lub odbioru.
Przykład: SubmitOrderRequest z boksem dostawy
Fragment kodu poniżej pokazuje przykład prośby o przesłanie zamówienia, która wskazuje przedział wcześniejszego zamówienia wybrany przez użytkownika.
{
"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": {
...
}
}
}
}
]
}
]
}
Przykład: przesłana odpowiedź na zamówienie akceptacja zamówienia
Fragment kodu poniżej pokazuje przykładową odpowiedź na zamówienie, w której Twoja realizacja potwierdza, że przyjęła ona zamówienie z wyprzedzeniem użytkownika.
{
"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"
}
}
}
}
]
}
}
}
Przykład: odrzucenie zamówienia z powodu niedostępności przedziału czasu
Fragment kodu poniżej pokazuje przykładową odpowiedź na zamówienie, w której realizacja odrzuca z wyprzedzeniem zamówienie użytkownika z powodu niedostępnego przedziału.
{
"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": [
...
]
}
}
}
]
}
}
}
Przykłady zamówień zaawansowanych
Typu AdvanceServiceDeliveryHoursSpecification
możesz użyć do określenia godzin dostawy lub odbioru, w przypadku których użytkownicy będą mogli zaplanować zamówienie z wyprzedzeniem.
Uwaga: w przypadku realizacji usługi musisz podać 2 oddzielne przedziały czasowe: okres składania zamówień, który określa, kiedy użytkownicy mogą złożyć zamówienie, i okres realizacji, który określa, kiedy zamówienie zostanie zrealizowane. Obiekt
określa, kiedy użytkownik może złożyć zamówienie. Czas realizacji zamówienia podrzędnego (OpeningHoursSpecification
lub ServiceDeliveryHoursSpecification
) określa, kiedy można zrealizować zamówienie.AdvanceServiceDeliveryHoursSpecification
Poniższy przykład określa godziny pracy usługi w przypadku akceptowania zamówień z wyprzedzeniem przy 15-minutowych odstępach czasu.
{ "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" } } ] } ] }
Poniższy przykład pokazuje, jak możesz określić, że usługa jest dostępna w przypadku zamówień tego samego dnia w Boże Narodzenie, ale zamknięta w przypadku zamówień zaawansowanych zaplanowanych na ten dzień. Ten przykład obsługuje następujące scenariusze:
- Użytkownicy mogą złożyć zamówienie 25 grudnia, aby otrzymać przesyłkę tego samego dnia.
- Użytkownicy mogą złożyć zamówienie z wyprzedzeniem 25 grudnia, a dostawa zaplanowana na 27 grudnia.
- Użytkownicy nie mogą składać zamówień z wyprzedzeniem 22 grudnia w przypadku dostawy zaplanowanej na 25 grudnia.
{ "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" } }
Poniższy przykład pokazuje, jak możesz określić, że usługa jest zamknięta w przypadku zamówień składanych tego samego dnia lub zamówień z wyprzedzeniem zaplanowanych na Boże Narodzenie, ale jest otwarta w przypadku zamówień zaawansowanych zaplanowanych na późniejszy dzień. W tym przykładzie opisano te scenariusze:
- Użytkownicy nie mogą złożyć zamówienia 25 grudnia na dostawę tego samego dnia.
- Użytkownicy mogą złożyć zamówienie z wyprzedzeniem 25 grudnia, a dostawa zaplanowana na 27 grudnia.
- Użytkownicy nie mogą składać zamówień z wyprzedzeniem 22 grudnia w przypadku dostawy zaplanowanej na 25 grudnia.
{ "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" } ] }
Poniższa przykładowa usługa akceptuje zamówienia przez całą dobę, 7 dni w tygodniu od 10:00 do 14:59:59 w dni robocze:
... { "@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" } } } ...
Poniższa przykładowa usługa przyjmuje zamówienia codziennie od 8:00 do 16:59:59. Klienci mogą zdecydować się na dostawę w ciągu godziny lub wybrać jeden z przedziałów:
... { "@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" } } ] } ...
Poniższy przykład przedstawia przypadek, w którym sklep jest otwarty od 8:00 do 16:59:59 w dni powszednie, ale od 8:00 do 18:59 w weekendy. Zamówienia nie są przyjmowane przez całą dobę, 7 dni w tygodniu.
... { // 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" } } ] } ...