Mapowanie plików danych menu i pozycji koszyka na zakupy
Gdy klienci dodają produkty z pliku danych menu do koszyka i dokonują płatności, Google wysyła je do punktu końcowego realizacji zamówienia, aby sprawdzić ich cenę i dostępność. Po zweryfikowaniu cen i dostępności klient będzie mógł złożyć zamówienie. W tej sekcji dowiesz się, jak mapować elementy w pliku danych z menu na elementy koszyka.
Przykłady w tej sekcji to skrócone wersje pliku danych Menu i schematu koszyka. Wyświetlane są tylko pola ilustrujące mapowanie między plikiem danych w menu i obiektem koszyka. Pełne schematy znajdziesz w artykułach Menu
i Cart
.
Produkty w pliku danych Menu
, które zostały dodane do koszyka, są wysyłane w obiekcie Cart
zarówno w przypadku procesu płatności, jak i przesyłania zamówienia.
- Prosta
MenuItem
jest reprezentowana jakoLineItem
w tablicylineItems
, gdzieofferId
to elementoffer.id
wybranej pozycji menu w pliku danych. - Element
MenuItem
z wymaganymMenuItemOption
jest reprezentowany w tablicylineItems
jakoLineItem
, gdzieofferId
tooffer.id
wybrana opcja elementu menu. - Element
AddOnMenuItem
elementuLineItem
jest reprezentowany jakoFoodItemOption
w tablicyoptions
w elemencieFoodItemExtension
. Każda opcja ma atrybutofferId
odpowiadający wartościoffer.id
wybranego elementu menu dodatku z pliku danych Menu. Pamiętaj, że element AddOnMenuItem może też mieć zagnieżdżone elementy AddOnMenuItem(i), które są reprezentowane przez elementsubOptions
w obrębie każdej opcji.
Podane niżej przykłady mapują pozycje menu między plikiem danych z menu a koszykiem z realizacją.
JSON
Ten przykład zawiera listę prostych elementów menu.
Pozycje menu w pliku danych o 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" } ] } ] }
Pozycje menu zmapowane na koszyk 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" } ] }
JSON
Ten przykład zawiera pozycję menu z co najmniej jednym elementem AddOnMenuItem.
Pozycje menu w pliku danych o 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" } ] } ] }
Pozycje menu zmapowane na koszyk 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" } ] }
JSON
Ten przykład zawiera pozycję menu z opcjami pozycji menu, AddOnMenuItems i zagnieżdżonymi elementami AddOnMenuItems
Pozycje menu w pliku danych o 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" } ] } ] } ] } ] } ] } } ] }
Pozycje menu zmapowane na koszyk 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 CheckoutRequestMessage
wystąpią problemy, możesz w odpowiedzi użyć CheckoutResponseMessage
, który zawiera FoodErrorExtension
zamiast CheckoutResponse. Możesz użyć tej odpowiedzi, aby zidentyfikować co najmniej 1 błąd, który wystąpił podczas przetwarzania.
Błędy można usuwać na 2 sposoby:
- Błędy możliwe do naprawienia: użytkownik nie musi edytować koszyka, aby przesłać zamówienie. Jeśli na przykład stwierdzisz, że cena produktu w elemencie
Cart
uległa zmianie, możesz w odpowiedzi przekazaćFoodOrderError
typu błęduPRICE_CHANGED
orazcorrectedProposedOrder
ipaymentOptions
. Google informuje użytkownika o zmianie, ale umożliwia przesłanie prośby za pomocą funkcjicorrectedProposedOrder
. W razie potrzeby użytkownik może też wrócić do koszyka i go edytować. Otrzymasz nowyCheckoutRequestMessage
lubSubmitOrderRequestMessage
. - Nieodwracalne błędy: przed wysłaniem zamówienia użytkownik musi zmodyfikować koszyk. Jeśli na przykład stwierdzisz, że restauracja jest zamknięta, możesz wysłać
FoodOrderError
typu błęduCLOSED
. Google informuje użytkownika i zarządza interakcją polegającą na aktualizacji do nowej restauracji. Otrzymasz nowy koszykCheckoutRequestMessage
.
Ogólnie rzecz biorąc, błędy na poziomie koszyka są niemożliwe do naprawienia, a na poziomie produktu – nie można ich naprawić. Pełną listę typów błędów i ich znaczeń znajdziesz w sekcji FoodOrderError
.
Obsługa zmian cen
Cena zmienia się podczas płatności
Jeśli podczas przetwarzania żądania płatności klienta pojawi się problem z ceną:
- Odpowiedz na
CheckoutRequestMessage
, używając koduCheckoutResponseMessage
zawierającegoFoodErrorExtension
zgodnie z opisem w sekcji Obsługa błędów. - W odpowiedzi o błędzie użyj
correctedProposedOrder.cart
, aby zaktualizować cenę do prawidłowej wartości. Google otrzymuje poprawione zamówienie i może wysłać noweCheckoutRequestMessage
.
Po dokonaniu płatności Google wyświetla użytkownikowi stronę z potwierdzeniem zamówienia, niezależnie od tego, czy ProposedOrder
został zmieniony czy nie.
Jeśli proponowana pozycja została poprawiona, Google może wyświetlać dodatkowe ostrzeżenia, aby poinformować użytkownika o zmianach. Jeśli użytkownik zgodzi się na złożenie zamówienia, prośby o zamówienie nie będą już przesyłane. Proces składania zamówień jest kontynuowany z poprawioną wartością ProposedOrder
.
Zawsze może jednak zmienić zdanie i ponownie zmodyfikować koszyk. Gdy koszyk jest aktualizowany w ten sposób, Google wysyła nowy adres CheckoutRequestMessage
.
Ceny zmieniają się podczas składania zamówienia
Jeśli podczas przetwarzania przesłania zamówienia wystąpi problem z ceną (uruchomiono intencję actions.intent.TRANSACTION_DECISION
), nie udzielaj odpowiedzi z komunikatem o błędzie ani nie aktualizuj ceny. Jeśli ceny, ilość lub inne informacje w SubmitOrderRequestMessage
nie są zgodne z Twoimi danymi, w odpowiedzi podaj wartość orderState
ustawioną na REJECTED
, aby wskazać, że nie można złożyć zamówienia w ten sposób.
Następnie, jeśli zamówienie i dane do płatności są prawidłowe, ustaw orderState
na CREATED
lub CONFIRMED
. Dołącz też actionOrderId
reprezentujący identyfikator zamówienia w Twoim systemie. Należy go używać przy wysyłaniu kolejnych aktualizacji.
Jeśli nie możesz przetworzyć płatności, a SubmitOrderRequestMessage
został już wysłany, możesz wysłać AsyncOrderUpdateRequestMessage
z wartością REJECTED
jako REJECTED
, aby poinformować użytkownika, że zamówienie nie zostanie zrealizowane.orderState
Ceny zmienią się po złożeniu zamówienia
Jeśli ustalisz, że cena różniła się od ceny użytej w momencie złożenia zamówienia przez klienta, możesz wysłać AsyncOrderUpdateRequestMessage
z nową ceną zgodnie z opisem w sekcji Wdrażanie asynchronicznych aktualizacji zamówień.
Aby zaktualizować ceny za pomocą aktualizacji zamówień asynchronicznych:
- Zmień cenę w:
lineItemUpdates[x].price
. Ta wartość odzwierciedla łączny koszt produktu (w tym dodatki) pomnożony przez ilość. Więcej informacji znajdziesz w opisie polaprice
wLineItem
. - Wpisz wyjaśnienie w języku:
lineItemUpdates[x].reason
. - Ustaw
lineItemUpdates[x].orderState
naCONFIRMED
.
Możesz spróbować obciążyć instrument płatniczy przed lub po wysłaniu wiadomości AsyncOrderUpdateRequestMessage według własnego uznania. Jeśli transakcja się nie powiedzie (prawdopodobnie dlatego, że różnica ceny jest zbyt wysoka), wyślij żądanie AsyncOrderUpdateRequestMessage z tymi ustawieniami w OrderUpdate
, aby poinformować Google o błędzie:
- Ustaw wartość
orderState
naREJECTED
. - Opisz błąd w polu
label
.
Weryfikacja płatności
Jak wspomnieliśmy w kroku 4. Wdróż proces płatności, Twój punkt końcowy realizacji powinien przeprowadzać weryfikację każdego przychodzącego elementu CheckoutRequestMessage
i odpowiedzieć komunikatem CheckoutResponseMessage
.
Oto przykład znacznika CheckoutResponseMessage
, który zapewnia pomyślną weryfikację:
Przypadek użycia | Jak to zrobić |
---|---|
Przypadek użycia 1. Weryfikacja zakończyła się powodzeniem. | Zwróć CheckoutResponse . Musi zawierać ProposedOrder i PaymentOptions .
ProposedOrder obejmuje podatki, opłaty i łączną cenę koszyka. |
JSON
{ "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 powinien weryfikować adres dostawy podany w każdym elemencie CheckoutRequestMessage
.
Jeśli jest problem z adresem dostawy, na przykład jest poza zasięgiem usługi dostawy, wartość CheckoutResponseMessage
zwracana przez realizację zawiera wartość FoodOrderError
odpowiedniego typu.
Przypadek użycia | Jak to zrobić |
---|---|
Przypadek użycia 1: weryfikacja nie powiodła się, ponieważ adres dostawy jest poza zakresem lub wystąpił problem z adresem dostawy. | Zwróć FoodErrorExtension z FoodOrderError typu błędu OUT_OF_SERVICE_AREA . |
JSON
{ "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 każdego typu CheckoutRequestMessage
.
Jeśli minimalna wartość zamówienia nie zostanie osiągnięta, wartość CheckoutResponseMessage
zwrócona przez realizację powinna zawierać FoodOrderError
typu błędu REQUIREMENTS_NOT_MET
.
Przypadek użycia | Jak to zrobić |
---|---|
Przypadek użycia 1: weryfikacja nie powiodła się, ponieważ nie została osiągnięta minimalna wartość zamówienia | Zwróć FoodErrorExtension z FoodOrderError typu błędu REQUIREMENTS_NOT_MET . |
JSON
{ "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 sortowania
Punkt końcowy realizacji zamówienia powinien weryfikować wszystkie czynniki, które mogą mieć wpływ na okno wyświetlania poszczególnych elementów CheckoutRequestMessage
.
Jeśli na przykład restauracja jest zamknięta lub w tej chwili nie przyjmuje już zamówień, wartość CheckoutResponseMessage
zwracana przez realizację zamówień powinien zawierać parametr FoodOrderError
typu błędu CLOSED
lub NO_CAPACITY
.
Przypadek użycia | Jak to zrobić |
---|---|
Przypadek użycia 1. weryfikacja się nie udała, ponieważ restauracja jest zamknięta lub nie jest już obsługiwana | Zwróć FoodErrorExtension z FoodOrderError typu błędu CLOSED . |
Przypadek użycia 2: weryfikacja nie powiodła się, ponieważ restauracja jest zajęta i w tej chwili nie przyjmuje zamówień. | Zwróć FoodErrorExtension z FoodOrderError typu błędu NO_CAPACITY . |
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "CLOSED", "description": "The restaurant is closed." } ] } } } ] } } }
JSON
{ "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." } ] } } } ] } } }
Weryfikacja produktów w koszyku
Punkt końcowy realizacji zamówienia powinien weryfikować cenę i dostępność każdego elementu koszyka zawartego w elemencie CheckoutRequestMessage
.
Jeśli dostępność lub ceny uległy zmianie, element CheckoutResponseMessage
zwracany przez realizację powinien zawierać odpowiednio wartość FoodOrderError
typu błędu AVAILABILITY_CHANGED
lub PRICE_CHANGED
.
Przypadek użycia | Jak to zrobić |
---|---|
Przypadek użycia 1: weryfikacja nie powiodła się, ponieważ niektóre elementy menu lub ich dostosowania są nieprawidłowe lub są niedostępne | Zwróć FoodErrorExtension z correctedProposedOrder , PaymentOptions i FoodOrderError typu błędu AVAILABILITY_CHANGED . Nieprawidłowe elementy należy usunąć z CorrectedProposedOrder . |
Przypadek użycia 2: weryfikacja nie powiodła się, ponieważ niektóre elementy menu lub ich dostosowania są nieprawidłowe lub są niedostępne. Poprawiony koszyk nie spełnia już wymagań dotyczących minimalnej wartości zamówienia. | Zwróć FoodErrorExtension z FoodOrderError typów błędów AVAILABILITY_CHANGED i REQUIREMENTS_NOT_MET . |
Przypadek użycia 3: weryfikacja nie powiodła się, ponieważ zmieniły się niektóre pozycje menu lub ceny dostosowania | Zwróć FoodErrorExtension z correctedProposedOrder , PaymentOptions i FoodOrderError typu błędu PRICE_CHANGED . Nieaktualne ceny należy zaktualizować w regionie CorrectedProposedOrder . |
Przypadek użycia 4: weryfikacja nie powiodła się, ponieważ zmieniły się niektóre pozycje menu lub ceny dostosowania. Poprawiony koszyk nie spełnia już wymogu minimalnej wartości zamówienia | Zwróć FoodErrorExtension z FoodOrderError typów błędów PRICE_CHANGED i REQUIREMENTS_NOT_MET . |
JSON
{ "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 } } } } } ] } } }
JSON
{ "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." } ] } } } ] } } }
JSON
{ "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 } } } } } ] } } }
JSON
{ "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 } } ] } } } ] } } }
Prześlij weryfikację zamówienia
Jak wspomnieliśmy w kroku 7. Wdrożenie przesyłania zamówienia, punkt końcowy realizacji powinien przeprowadzać weryfikację każdego przychodzącego elementu SubmitOrderRequestMessage
i odpowiedzieć poleceniem SubmitOrderResponseMessage
.
Oto przykład znacznika SubmitOrderResponseMessage
, który zapewnia pomyślną weryfikację:
Przypadek użycia | Jak to zrobić |
---|---|
Przypadek użycia 1: utworzenie zamówienia. | SubmitOrderResponseMessage ze stanem zamówienia CREATED . Musi zawierać actionOrderId , userVisibleId , orderManagementActions i estimatedFulfillmentTime . |
Przypadek użycia 2. Zamówienie zostało odrzucone z powodu problemów z płatnością. | SubmitOrderResponseMessage ze stanem zamówienia REJECTED . Musi mieć actionOrderId , userVisibleId , orderManagementActions i rejectionInfo typu PAYMENT_DECLINED . |
Przypadek użycia 3: zamówienie zostało odrzucone, gdy użytkownik jest oznaczony jako zablokowany | SubmitOrderResponseMessage ze stanem zamówienia REJECTED . Musi mieć 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 ze stanem zamówienia REJECTED . Musi mieć actionOrderId , userVisibleId , orderManagementActions i rejectionInfo typu INELIGIBLE . |
Przypadek użycia 5. Zamówienie zostało odrzucone z nieznanego powodu. | SubmitOrderResponseMessage ze stanem zamówienia REJECTED . Musi mieć actionOrderId , userVisibleId , orderManagementActions i rejectionInfo typu UNKNOWN . |
JSON
{ "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" } } } ] } } } ] } } }
JSON
{ "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" } } } ] } } } ] } } }
JSON
{ "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" } } } ] } } } ] } } }
JSON
{ "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" } } } ] } } } ] } } }
JSON
{ "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" } } } ] } } } ] } } }