Mapowanie plików danych menu i pozycji koszyka realizacji
Gdy klienci dodają do koszyka produkty z pliku danych Menu i sfinalizują transakcję, Google wysyła te produkty do punktu realizacji, aby zweryfikować ich cenę i dostępność. Po potwierdzeniu cen i dostępności klient może złożyć zamówienie. W tej sekcji pokazano, jak mapować elementy menu do elementów koszyka fulfillment.
Przykłady w tej sekcji to uproszczone wersje pliku danych menu i schematu koszyka. Wyświetlane są tylko pola, które mają znaczenie dla mapowania danych z pliku danych Menu do obiektu Koszyk. Pełne schematy znajdziesz w artykułach Menu
i Cart
.
Produkty z pliku danych Menu
, które są dodawane do koszyka, są wysyłane w obiekcie Cart
zarówno w przypadku płatności, jak i przesyłania zamówienia.
- Prosty element
MenuItem
jest reprezentowany jakoLineItem
w tablicylineItems
, gdzieofferId
to elementoffer.id
wybranego elementu menu w pliku danych Menu. - Element
MenuItem
z wymaganymMenuItemOption
jest reprezentowany jakoLineItem
w tablicylineItems
, gdzieofferId
to wybrana opcjaoffer.id
z Menu w pliku danych. - Element
AddOnMenuItem
tablicyLineItem
jest reprezentowany jako elementFoodItemOption
w tablicyoptions
tablicyFoodItemExtension
. Każda opcja maofferId
, który odpowiadaoffer.id
wybranego elementu menu dodatku z pliku danych menu. Pamiętaj, że element AddOnMenuItem może też zawierać zagnieżdżone elementy AddOnMenuItem, które są reprezentowane jakosubOptions
w ramach każdej opcji.
W poniższych przykładach elementy menu są mapowane między plikiem danych menu a koszykiem realizacji zamówień.
Ten przykład zawiera listę prostych pozycji menu.
Pozycje menu w pliku danych menu:
{ "@type": "Menu", "@id": "menu_id", "hasMenuItem": [ { "@type": "MenuItem", "@id": "menuitem_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_1", "price": "p_1", "priceCurrency": "USD" } ] }, { "@type": "MenuItem", "@id": "menuitem_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_2", "price": "p_2", "priceCurrency": "USD" } ] } ] }
Elementy menu powiązane z koszykiem realizacji:
{ "@type": "Cart", "lineItems": [ { "offerId": "menuitem_offer_id_1", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_1*p_1)", "nanos": "cent(q_1*p_1)" } }, "quantity": "q_1" }, { "offerId": "menuitem_offer_id_2", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_2*p_2)", "nanos": "cent(q_2*p_2)" } }, "quantity": "q_2" } ] }
Ten przykład zawiera pozycję menu z co najmniej 1 elementem menu dodatkowym.
Pozycje menu w pliku danych menu:
{ "@type": "Menu", "@id": "menu_id", "hasMenuItem": [ { "@type": "MenuItem", "@id": "menuitem_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_1", "price": "p_1", "priceCurrency": "USD" } ], "menuAddOn": [ { "@type": "MenuAddOnSection", "@id": "menuaddon_section_id_1", "hasMenuItem": [ { "@type": "AddOnMenuItem", "@id": "menuitem_addon_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_addon_offer_id_1", "price": "addon_p_1", "priceCurrency": "USD" } ] }, { "@type": "AddOnMenuItem", "@id": "menuitem_addon_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_addon_offer_id_2", "price": "addon_p_2", "priceCurrency": "USD" } ] } ] } ] }, { "@type": "MenuItem", "@id": "menuitem_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_2", "price": "p_2", "priceCurrency": "USD" } ] } ] }
Elementy menu powiązane z koszykiem realizacji:
{ "@type": "Cart", "lineItems": [ { "offerId": "menuitem_offer_id_1", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*addon_p_2))", "nanos": "cent(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*addon_p_2))" } }, "quantity": "q_1", "extension": { "@type": "FoodItemExtension", "options": [ { "offerId": "menuitem_addon_offer_id_1", "price": { "currencyCode": "USD", "units": "dollar(addon_q_1*addon_p_1)", "nanos": "cent(addon_q_1*addon_p_1)" }, "quantity": "addon_q_1" }, { "offerId": "menuitem_addon_offer_id_2", "price": { "currencyCode": "USD", "units": "dollar(addon_q_2*addon_p_2)", "nanos": "cent(addon_q_2*addon_p_2)" }, "quantity": "addon_q_2" } ] } }, { "offerId": "menuitem_offer_id_2", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_2*p_2)", "nanos": "cent(q_2*p_2)" } }, "quantity": "q_2" } ] }
Ten przykład zawiera pozycję menu z opcjami pozycji menu, AddOnMenuItems i zagnieżdżonymi elementami AddOnMenuItems.
Pozycje menu w pliku danych menu:
{ "@type": "MenuItem", "@id": "menuitem_id_1", "hasMenuItemOptions": [ { "@type": "MenuItemOption", "value": { "@type": "PropertyValue", "name": "OPTION", "value": "Large", "offers": [ { "@type": "Offer", "@id": "menuitem_option_offer_id_1", "price": "p_1", "priceCurrency": "USD" } ], "menuAddOn": [ { "@type": "AddOnMenuSection", "@id": "menuitem_option_addon_section_id_1", "hasMenuItem": [ { "@type": "AddOnMenuItem", "@id": "menuitem_option_addon_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_option_addon_offer_id_1", "price": "addon_p_1", "priceCurrency": "USD" } ] }, { "@type": "AddOnMenuItem", "@id": "menuitem_option_addon_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_option_addon_offer_id_2", "price": "addon_p_2", "priceCurrency": "USD" } ], "menuAddOn": [ { "@type": "AddOnMenuSection", "@id": "menuitem_option_subaddon_section_id_1", "hasMenuItem": [ { "@type": "AddOnMenuItem", "@id": "menuitem_option_subaddon_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_option_subaddon_offer_id_1", "price": "subaddon_p_1", "priceCurrency": "USD" } ] } ] } ] } ] } ] } } ] }
Elementy menu powiązane z koszykiem realizacji:
{ "@type": "Cart", "lineItems": [ { "offerId": "menuitem_option_offer_id_1", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1)))", "nanos": "cent(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1)))" } }, "quantity": "q_1", "extension": { "@type": "FoodItemExtension", "options": [ { "offerId": "menuitem_option_addon_offer_id_1", "price": { "currencyCode": "USD", "units": "dollar(addon_q_1*addon_p_1)", "nanos": "cent(addon_q_1*addon_p_1)" }, "quantity": "addon_q_1" }, { "offerId": "menuitem_option_addon_offer_id_2", "price": { "currencyCode": "USD", "units": "dollar(addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1))", "nanos": "cent(addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1))" }, "quantity": "addon_q_2", "subOptions": [ { "offerId": "menuitem_option_subaddon_offer_id_1", "price": { "currencyCode": "USD", "units": "dollar(subaddon_q_1*subaddon_p_1)", "nanos": "cent(subaddon_q_1*subaddon_p_1)" }, "quantity": "subaddon_q_1" } ] } ] } } ] }
Obsługa błędów
Jeśli podczas przetwarzania żądania CheckoutRequestMessage
wystąpią problemy, możesz odpowiedzieć za pomocą odpowiedzi CheckoutResponseMessage
zawierającej element FoodErrorExtension
zamiast elementu CheckoutResponse. Dzięki tej odpowiedzi możesz zidentyfikować co najmniej 1 błąd, który wystąpił podczas przetwarzania.
Błędy można obsłużyć na 2 sposoby:
- Błędy, które można naprawić: użytkownik nie musi edytować koszyka, aby złożyć zamówienie. Jeśli na przykład stwierdzisz, że cena produktu w sekcji
Cart
uległa zmianie, możesz odpowiedzieć z błędem typuFoodOrderError
(PRICE_CHANGED
) oraz wartościamicorrectedProposedOrder
ipaymentOptions
. Google informuje użytkownika o zmianie, ale pozwala mu przesłać formularz z opcjącorrectedProposedOrder
. Użytkownik może też wrócić i w razie potrzeby edytować koszyk. Otrzymasz nową kartęCheckoutRequestMessage
lub kartęSubmitOrderRequestMessage
. - Nieodwracalne błędy: użytkownik musi edytować koszyk przed złożeniem zamówienia. Jeśli na przykład ustalisz, że restauracja jest zamknięta, możesz odpowiedzieć za pomocą błędu
FoodOrderError
typuCLOSED
. Google informuje użytkownika i zarządza interakcją, aby zaktualizować dane restauracji. Otrzymasz nowyCheckoutRequestMessage
dla nowego koszyka.
Ogólnie rzecz biorąc, nie można odzyskać błędów na poziomie koszyka ani błędów na poziomie produktu. Pełną listę typów błędów i ich znaczenie znajdziesz w artykule FoodOrderError
.
Obsługa zmian cen
Zmiany cen podczas płatności
Jeśli podczas przetwarzania żądania płatności klienta wystąpi problem z ceną, wykonaj te czynności:
- Odpowiedz na żądanie
CheckoutRequestMessage
za pomocą odpowiedziCheckoutResponseMessage
zawierającejFoodErrorExtension
, zgodnie z opisem w sekcji Obsługa błędów. - W odpowiedzi na błąd użyj elementu
correctedProposedOrder.cart
, aby zaktualizować cenę do prawidłowej wartości. Google otrzyma poprawiony nakaz i może wydać nowyCheckoutRequestMessage
.
Po zakończeniu płatności Google wyświetla użytkownikowi stronę potwierdzenia zamówienia niezależnie od tego, czy ProposedOrder
została zmieniona.
Jeśli proponowany porządek został poprawiony, Google może wyświetlić dodatkowe ostrzeżenia, aby poinformować użytkownika o zmianach. Jeśli użytkownik zgodzi się na złożenie zamówienia, nie będzie już żadnych kolejnych próśb o płatność. Proces przechodzi do wysyłania zamówienia z poprawionym ProposedOrder
.
Użytkownik może jednak zmienić zdanie i ponownie edytować koszyk. Gdy w ten sposób zaktualizuje swój koszyk, Google wyśle nowe CheckoutRequestMessage
.
Zmiany cen podczas składania zamówienia
Jeśli podczas przetwarzania przesłaniania zamówienia (wystąpiła intencja actions.intent.TRANSACTION_DECISION
) wystąpił problem z ceną, nie odpowiadaj błędem ani nie aktualizuj ceny w odpowiedzi. Jeśli ceny, ilości lub inne szczegóły w SubmitOrderRequestMessage
nie odpowiadają Twoim danym, odpowiedz z ustawieniem orderState
na REJECTED
, aby wskazać, że zamówienia nie można złożyć zgodnie z żądaniem.
Następnie, jeśli szczegóły zamówienia i płatności są prawidłowe, ustaw wartość parametru orderState
na CREATED
lub CONFIRMED
. Dodaj też actionOrderId
, aby reprezentować identyfikator zamówienia w Twoim systemie. Musisz go używać podczas wysyłania kolejnych aktualizacji.
Jeśli nie możesz przetworzyć płatności i zostało już wysłane SubmitOrderRequestMessage
, możesz wysłać AsyncOrderUpdateRequestMessage
z wartością orderState
równą REJECTED
, aby poinformować użytkownika, że zamówienie nie zostanie zrealizowane.
Zmiana ceny po przesłaniu zamówienia
Jeśli ustalisz, że cena została zmieniona w stosunku do ceny użytej, gdy klient przesłał zamówienie, możesz wydać AsyncOrderUpdateRequestMessage
z nową ceną, zgodnie z opisem w sekcji Wdrażanie asynchronicznych aktualizacji zamówień.
Aby zaktualizować ceny za pomocą asynchronicznych aktualizacji zamówień:
- Zmień cenę w
lineItemUpdates[x].price
. Ta wartość odzwierciedla łączny koszt produktu, w tym dodatków, pomnożony przez ilość. (Więcej informacji znajdziesz w opisie polaprice
w kolumnieLineItem
). - Wpisz wyjaśnienie w sekcji
lineItemUpdates[x].reason
. - Ustaw
lineItemUpdates[x].orderState
naCONFIRMED
.
Możesz spróbować obciążyć instrument płatności przed wysłaniem wiadomości AsyncOrderUpdateRequestMessage lub po jej wysłaniu. Jeśli transakcja nie powiedzie się (być może z powodu zbyt dużej różnicy w cenie), prześlij wiadomość AsyncOrderUpdateRequestMessage z tymi ustawieniami w OrderUpdate
, aby poinformować Google o błędzie:
- Ustaw
orderState
naREJECTED
. - Opisz błąd w polu
label
.
Weryfikacja płatności
Jak opisano w kroku 4. Zaimplementuj proces płatności, punkt końcowy realizacji zamówienia powinien przeprowadzać weryfikację każdego przychodzącego CheckoutRequestMessage
i odpowiadać za pomocą CheckoutResponseMessage
.
Oto przykład CheckoutResponseMessage
dla prawidłowej walidacji:
Przypadek użycia | Jak wdrożyć |
---|---|
Przypadek użycia 1: weryfikacja się powiodła | Zwrot: CheckoutResponse . Musi zawierać ProposedOrder i PaymentOptions .
ProposedOrder obejmuje podatek, opłaty i łączną cenę koszyka. |
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "checkoutResponse": { "proposedOrder": { "id": "sample_proposed_order_id_1", "otherItems": [ { "name":"New customer discount", "price": { "type":"ESTIMATE", "amount": { "currencyCode":"USD", "units":"-5", "nanos": -500000000 } }, "type": "DISCOUNT" }, { "name": "Delivery fee", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "3", "nanos": 500000000 } }, "type": "DELIVERY" }, { "name": "Tax", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "1", "nanos": 500000000 } }, "type": "TAX" } ], "cart": { "merchant": { "id": "https://www.exampleprovider.com/merchant/id1", "name": "Falafel Bite" }, "lineItems": [ { "name": "Pita Chips", "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": "2", "nanos": 750000000 } }, "subLines": [ { "note": "Notes for this item." } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension", "options": [ { "id": "sample_addon_offer_id_1", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id1", "name": "Honey Mustard", "price": { "currencyCode": "USD" }, "quantity": 1 }, { "id": "sample_addon_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id2", "name": "BBQ Sauce", "price": { "currencyCode": "USD", "nanos": 500000000 }, "quantity": 1 } ] } }, { "name": "Chicken Shwarma Wrap", "type": "REGULAR", "id": "sample_item_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/offer/id2", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "8" } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Greek Salad", "type": "REGULAR", "id": "sample_item_offer_id_3", "offerId": "https://www.exampleprovider.com/menu/item/offer/id3", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "9", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Prawns Biryani", "type": "REGULAR", "id": "sample_item_offer_id_4", "offerId": "https://www.exampleprovider.com/menu/item/offer/id4", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "15", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension", "fulfillmentPreference": { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } } }, "location": { "coordinates": { "latitude": 37.788783, "longitude": -122.41384 }, "formattedAddress": "1350 CHARLESTON ROAD, MOUNTAIN VIEW, CA, United States", "zipCode": "94043", "city": "Mountain View", "postalAddress": { "regionCode": "US", "postalCode": "94043", "administrativeArea": "CA", "locality": "Mountain View", "addressLines": [ "1350 Charleston Road" ] }, "notes": "Gate code is #111" } } }, "totalPrice": { "type": "ESTIMATE", "amount": { // Represents $36.73 "currencyCode": "USD", "units": "36", "nanos": 730000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension", "availableFulfillmentOptions": [ { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } }, "expiresAt": "2017-07-17T12:30:00Z" } ] } }, "paymentOptions": { "googleProvidedOptions": { "tokenizationParameters": { "tokenizationType": "PAYMENT_GATEWAY", "parameters": { "gateway": "stripe", "stripe:publishableKey": "pk_live_stripe_client_key", "stripe:version": "2017-04-06" } }, "supportedCardNetworks": [ "AMEX", "DISCOVER", "MASTERCARD", "JCB", "VISA" ], "prepaidCardDisallowed": true } } } } } ] } } }
Weryfikacja adresu dostawy
Punkt końcowy realizacji zamówienia powinien weryfikować adres dostawy zawarty w każdym CheckoutRequestMessage
.
Jeśli wystąpi problem z adresem dostawy, np. będzie on poza zasięgiem usługi dostawy, zwrócony przez usługę CheckoutResponseMessage
powinien zawierać FoodOrderError
odpowiedniego typu.
Przypadek użycia | Jak wdrożyć |
---|---|
Przypadek użycia 1: weryfikacja nie powiodła się, ponieważ adres dostawy jest poza zasięgiem lub wystąpił problem z adresem dostawy | Zwraca FoodErrorExtension z FoodOrderError
typu błędu OUT_OF_SERVICE_AREA . |
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "OUT_OF_SERVICE_AREA", "description": "Sorry, the restaurant cannot deliver to your address." } ] } } } ] } } }
Weryfikacja minimalnej wartości zamówienia
Punkt końcowy realizacji zamówienia powinien weryfikować minimalną wartość zamówienia dla każdego CheckoutRequestMessage
.
Jeśli minimalna wartość zamówienia nie zostanie osiągnięta, CheckoutResponseMessage
zwrócone przez usługę realizacji zamówienia powinno zawierać FoodOrderError
typu błędu REQUIREMENTS_NOT_MET
.
Przypadek użycia | Jak wdrożyć |
---|---|
Przypadek użycia 1: walidacja nie powiodła się, ponieważ nie została osiągnięta minimalna wartość zamówienia | Zwraca FoodErrorExtension z FoodOrderError
typu błędu REQUIREMENTS_NOT_MET . |
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "REQUIREMENTS_NOT_MET", "description": "The cart subtotal must be over $20." } ] } } } ] } } }
Weryfikacja okna zamówienia
Punkt końcowy realizacji powinien weryfikować wszystkie czynniki, które mogą wpływać na okno zamawiania każdego CheckoutRequestMessage
.
Jeśli na przykład restauracja jest zamknięta lub nie przyjmuje w tej chwili zamówień, zwracany przez usługę przetwarzania parametr CheckoutResponseMessage
powinien zawierać odpowiednio typ błędu FoodOrderError
CLOSED
lub NO_CAPACITY
.
Przypadek użycia | Jak wdrożyć |
---|---|
Przypadek 1: weryfikacja nie powiodła się, ponieważ restauracja jest zamknięta lub nie jest już obsługiwana | Zwraca FoodErrorExtension z FoodOrderError
typu błędu CLOSED . |
Przypadek użycia 2: weryfikacja nie powiodła się, ponieważ restauracja jest zajęta i nie przyjmuje w tej chwili zamówień | Zwraca FoodErrorExtension z FoodOrderError
typu błędu NO_CAPACITY . |
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "CLOSED", "description": "The restaurant is closed." } ] } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "NO_CAPACITY", "description": "Sorry, the restaurant is busy at the moment." } ] } } } ] } } }
Walidacja elementów koszyka
Punkt końcowy realizacji powinien weryfikować ceny i dostępność każdego produktu w koszyku zawartego w CheckoutRequestMessage
.
Jeśli dostępność lub cena się zmieniły, zwracany przez usługę realizacji zamówienia element CheckoutResponseMessage
powinien zawierać odpowiednio typ błędu FoodOrderError
AVAILABILITY_CHANGED
lub PRICE_CHANGED
.
Przypadek użycia | Jak wdrożyć |
---|---|
Przypadek 1: weryfikacja nie powiodła się, ponieważ niektóre pozycje menu lub ich modyfikacje są nieprawidłowe lub niedostępne | Zwraca FoodErrorExtension z wartością correctedProposedOrder ,
PaymentOptions i FoodOrderError typu błędu
AVAILABILITY_CHANGED . Nieprawidłowe elementy muszą zostać usunięte z CorrectedProposedOrder . |
Przypadek 2: weryfikacja nie powiodła się, ponieważ niektóre pozycje menu lub ich modyfikacje są nieprawidłowe lub niedostępne. Poprawiony koszyk nie spełnia już wymagań dotyczących minimalnej wartości zamówienia. | Zwracaj FoodErrorExtension z wartością FoodOrderError dla typów błędów AVAILABILITY_CHANGED i REQUIREMENTS_NOT_MET . |
Przypadek 3: weryfikacja nie powiodła się, ponieważ zmieniły się ceny niektórych pozycji menu lub ceny dostosowań | Zwraca FoodErrorExtension z wartością correctedProposedOrder ,
PaymentOptions i FoodOrderError typu błędu
PRICE_CHANGED . Nieaktualne ceny należy zaktualizować w CorrectedProposedOrder . |
Przypadek 4: walidacja nie powiodła się, ponieważ zmieniły się ceny niektórych pozycji menu lub ceny dostosowań. skorygowany koszyk nie spełnia już wymaganej minimalnej wartości zamówienia; | Zwracaj FoodErrorExtension z FoodOrderError
typów błędów PRICE_CHANGED i REQUIREMENTS_NOT_MET . |
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "AVAILABILITY_CHANGED", "id": "sample_item_offer_id_1", "description": "The item is no longer available." }, { "error": "AVAILABILITY_CHANGED", "id": "sample_item_offer_id_2", "description": "The item is no longer available." } ], "correctedProposedOrder": { "id": "sample_corrected_proposed_order_id_1", "otherItems": [ { "name":"New customer discount", "price": { "type":"ESTIMATE", "amount": { "currencyCode":"USD", "units":"-5", "nanos": -500000000 } }, "type": "DISCOUNT" }, { "name": "Delivery fee", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "3", "nanos": 500000000 } }, "type": "DELIVERY" }, { "name": "Tax", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "1", "nanos": 500000000 } }, "type": "TAX" } ], "cart": { "merchant": { "id": "https://www.exampleprovider.com/merchant/id1", "name": "Falafel Bite" }, "lineItems": [ { "name": "Greek Salad", "type": "REGULAR", "id": "sample_item_offer_id_3", "offerId": "https://www.exampleprovider.com/menu/item/offer/id3", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "9", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Prawns Biryani", "type": "REGULAR", "id": "sample_item_offer_id_4", "offerId": "https://www.exampleprovider.com/menu/item/offer/id4", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "15", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension", "fulfillmentPreference": { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } } }, "location": { "coordinates": { "latitude": 37.788783, "longitude": -122.41384 }, "formattedAddress": "1350 CHARLESTON ROAD, MOUNTAIN VIEW, CA, United States", "zipCode": "94043", "city": "Mountain View", "postalAddress": { "regionCode": "US", "postalCode": "94043", "administrativeArea": "CA", "locality": "Mountain View", "addressLines": [ "1350 Charleston Road" ] }, "notes": "Gate code is #111" } } }, "totalPrice": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "36", "nanos": 730000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension", "availableFulfillmentOptions": [ { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } }, "expiresAt": "2017-07-17T12:30:00Z" } ] } }, "paymentOptions": { "googleProvidedOptions": { "tokenizationParameters": { "tokenizationType": "PAYMENT_GATEWAY", "parameters": { "gateway": "stripe", "stripe:publishableKey": "pk_live_stripe_client_key", "stripe:version": "2017-04-06" } }, "supportedCardNetworks": [ "AMEX", "DISCOVER", "MASTERCARD", "JCB", "VISA" ], "prepaidCardDisallowed": true } } } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "REQUIREMENTS_NOT_MET", "description": "The cart subtotal must be over $20." }, { "error": "AVAILABILITY_CHANGED", "id": "cart_lineitem_id" "description": "cart_lineitem_id is no longer available." } ] } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "PRICE_CHANGED", "id": "sample_item_offer_id_1", "description": "The price has changed.", "updatedPrice": { "currencyCode": "USD", "units": "2", "nanos": 750000000 } }, { "error": "PRICE_CHANGED", "id": "sample_item_offer_id_2", "description": "The price has changed.", "updatedPrice": { "currencyCode": "USD", "units": "8" } } ], "correctedProposedOrder": { "id": "sample_corrected_proposed_order_id_1", "otherItems": [ { "name":"New customer discount", "price": { "type":"ESTIMATE", "amount": { "currencyCode":"USD", "units":"-5", "nanos": -500000000 } }, "type": "DISCOUNT" }, { "name": "Delivery fee", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "3", "nanos": 500000000 } }, "type": "DELIVERY" }, { "name": "Tax", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "1", "nanos": 500000000 } }, "type": "TAX" } ], "cart": { "merchant": { "id": "https://www.exampleprovider.com/merchant/id1", "name": "Falafel Bite" }, "lineItems": [ { "name": "Pita Chips", "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": "2", "nanos": 750000000 } }, "subLines": [ { "note": "Notes for this item." } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension", "options": [ { "id": "sample_addon_offer_id_1", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id1", "name": "Honey Mustard", "price": { "currencyCode": "USD" }, "quantity": 1 }, { "id": "sample_addon_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id2", "name": "BBQ Sauce", "price": { "currencyCode": "USD", "nanos": 500000000 }, "quantity": 1 } ] } }, { "name": "Chicken Shwarma Wrap", "type": "REGULAR", "id": "sample_item_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/offer/id2", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "8" } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Greek Salad", "type": "REGULAR", "id": "sample_item_offer_id_3", "offerId": "https://www.exampleprovider.com/menu/item/offer/id3", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "9", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Prawns Biryani", "type": "REGULAR", "id": "sample_item_offer_id_4", "offerId": "https://www.exampleprovider.com/menu/item/offer/id4", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "15", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension", "fulfillmentPreference": { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } } }, "location": { "coordinates": { "latitude": 37.788783, "longitude": -122.41384 }, "formattedAddress": "1350 CHARLESTON ROAD, MOUNTAIN VIEW, CA, United States", "zipCode": "94043", "city": "Mountain View", "postalAddress": { "regionCode": "US", "postalCode": "94043", "administrativeArea": "CA", "locality": "Mountain View", "addressLines": [ "1350 Charleston Road" ] }, "notes": "Gate code is #111" } } }, "totalPrice": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "36", "nanos": 730000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension", "availableFulfillmentOptions": [ { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } }, "expiresAt": "2017-07-17T12:30:00Z" } ] } }, "paymentOptions": { "googleProvidedOptions": { "tokenizationParameters": { "tokenizationType": "PAYMENT_GATEWAY", "parameters": { "gateway": "stripe", "stripe:publishableKey": "pk_live_stripe_client_key", "stripe:version": "2017-04-06" } }, "supportedCardNetworks": [ "AMEX", "DISCOVER", "MASTERCARD", "JCB", "VISA" ], "prepaidCardDisallowed": true } } } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "REQUIREMENTS_NOT_MET", "description": "The cart subtotal must be over $20." }, { "error": "PRICE_CHANGED", "id": "cart_lineitem_id" "description": "cart_lineitem_id price has been updated." "updatedPrice": { "currencyCode": "USD", "units": "2", "nanos": 750000000 } } ] } } } ] } } }
Przesyłanie potwierdzenia zamówienia
Jak opisano w kroku 7. Zaimplementuj metodę Submit Order, punkt końcowy realizacji zamówienia powinien weryfikować każdą przychodzącą prośbę SubmitOrderRequestMessage
i odpowiadać za pomocą odpowiedzi SubmitOrderResponseMessage
.
Oto przykład SubmitOrderResponseMessage
dla prawidłowej walidacji:
Przypadek użycia | Jak wdrożyć |
---|---|
Przypadek 1: zamówienie zostało utworzone | SubmitOrderResponseMessage w stanie CREATED . Musi zawierać actionOrderId , userVisibleId , orderManagementActions i estimatedFulfillmentTime . |
Przypadek użycia 2: zamówienie jest odrzucane z powodu problemów z płatnością | SubmitOrderResponseMessage w stanie REJECTED . Musi zawierać elementy actionOrderId , userVisibleId , orderManagementActions i rejectionInfo typu PAYMENT_DECLINED . |
Przypadek użycia 3. Zamówienie jest odrzucane, ponieważ użytkownik został oznaczony jako zablokowany | SubmitOrderResponseMessage z zamówieniem o stanie REJECTED . Musi zawierać elementy actionOrderId , userVisibleId , orderManagementActions i rejectionInfo typu INELIGIBLE . |
Przypadek użycia 4: zamówienie zostało odrzucone, ponieważ informacje o użytkowniku są niekompletne lub nieprawidłowe | SubmitOrderResponseMessage w stanie REJECTED . Musi zawierać elementy actionOrderId , userVisibleId , orderManagementActions i rejectionInfo typu INELIGIBLE . |
Przypadek 5: zamówienie zostało odrzucone z nieznanego powodu | SubmitOrderResponseMessage w stanie REJECTED . Musi zawierać elementy actionOrderId , userVisibleId , orderManagementActions i rejectionInfo typu UNKNOWN . |
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "CREATED", "label": "Order received" }, "updateTime": "2017-05-10T02:30:00.000Z", "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "PAYMENT_DECLINED", "reason": "Insufficient funds" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "INELIGIBLE", "reason": "Sorry, we are not able to take orders from this user" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "INELIGIBLE", "reason": "Sorry, the phone number must not be blank" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "UNKNOWN", "reason": "Sorry, there is something wrong with this order." }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }