Mappatura dei feed del menu e degli articoli del carrello per l'evasione degli ordini
Quando i clienti aggiungono articoli dal feed Menu al carrello e pagano, Google invia questi articoli al tuo endpoint di evasione degli ordini per verificarne il prezzo e la disponibilità del servizio. Una volta convalidati i prezzi e la disponibilità, il cliente può effettuare l'ordine. Questa sezione illustra come mappare gli elementi del feed del menu a gli articoli del carrello per l'evasione dell'ordine.
Gli esempi in questa sezione sono versioni essenziali del feed Menu e del carrello
. Solo i campi pertinenti per illustrare la mappatura tra il feed del menù e
dell'oggetto Cart. Per gli schemi completi, vedi Menu
e Cart
.
Gli articoli nel feed Menu
che vengono aggiunti a un carrello vengono inviati nel Cart
sia per il pagamento che per l'invio dell'ordine.
- Un
MenuItem
semplice è rappresentato come unLineItem
nel campolineItems
array in cuiofferId
è iloffer.id
della voce di menu selezionata nel menu feed. - Un elemento
MenuItem
conMenuItemOption
obbligatorio è rappresentato come unLineItem
nell'arraylineItems
in cuiofferId
è l'elemento selezionatooffer.id
dell'opzione della voce di menu del feed del menu. - Un
AddOnMenuItem
diLineItem
è rappresentato come unFoodItemOption
nell'arrayoptions
diFoodItemExtension
. Ogni opzione ha unofferId
che corrisponde al menu del componente aggiuntivo selezionatooffer.id
dell'elemento dal feed del menu. Tieni presente che un componente AddOnMenuItem può avere anche Elementi AddOnMenuItem nidificati, rappresentati comesubOptions
all'interno di ciascuno .
I seguenti esempi mappano voci di menu tra il feed del menù e l'evasione degli ordini carrello.
JSON
Questo esempio contiene un elenco di voci di menu semplici.
Voci di menu in un feed 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" } ] } ] }
Voci di menu associate a un carrello degli ordini:
{ "@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
Questo esempio contiene una voce di menu con uno o più AddOnMenuItems.
Voci di menu in un feed 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" } ] } ] }
Voci di menu associate a un carrello degli ordini:
{ "@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
Questo esempio contiene una voce di menu con le relative opzioni, AddOnMenuItems, e gli oggetti AddOnMenuItem nidificati
Voci di menu in un feed 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" } ] } ] } ] } ] } ] } } ] }
Voci di menu associate a un carrello degli ordini:
{ "@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" } ] } ] } } ] }
Gestione degli errori
Se riscontri problemi durante l'elaborazione di una CheckoutRequestMessage
,
può rispondere con un CheckoutResponseMessage
che contiene un
FoodErrorExtension
anziché una CheckoutResponse. Puoi utilizzare questo
risposta per identificare uno o più errori che si sono verificati durante l'elaborazione.
Esistono due modi per gestire gli errori:
- Errori recuperabili: l'utente non deve modificare il carrello per inviare la
ordine. Ad esempio, se stabilisci che un elemento in
Cart
ha un variazione di prezzo, puoi rispondere con un errore di tipoFoodOrderError
PRICE_CHANGED
, insieme acorrectedProposedOrder
epaymentOptions
. Google informa l'utente della modifica, ma consente all'utente di inviare la richiesta con ilcorrectedProposedOrder
. L'utente può anche tornare indietro e modificare il carrello se desiderato. Riceverai un nuovoCheckoutRequestMessage
o unSubmitOrderRequestMessage
. - Errori irreversibili: l'utente deve modificare il carrello prima del giorno
inviando l'ordine. Ad esempio, se stabilisci che il ristorante
chiusa, puoi rispondere con un errore
FoodOrderError
di tipoCLOSED
. Google informa l'utente e gestisce l'interazione per eseguire l'aggiornamento a un nuovo in un ristorante. Riceverai un nuovoCheckoutRequestMessage
per un nuovo carrello.
In generale, rendere irrecuperabili gli errori a livello di carrello e quelli a livello di articolo
recuperabili. Per un elenco completo dei tipi di errore e del relativo significato, consulta la pagina
FoodOrderError
Gestione delle variazioni di prezzo
Variazioni di prezzo durante il pagamento
Se riscontri un problema di prezzo durante l'elaborazione del pagamento di un cliente richiesta, procedi nel seguente modo:
- Rispondi alla
CheckoutRequestMessage
con unCheckoutResponseMessage
che contiene unFoodErrorExtension
, come descritta in Gestione degli errori. - Nella risposta di errore, utilizza
correctedProposedOrder.cart
per aggiornare il prezzo al valore corretto. Google riceve l'ordine corretto e potrebbe emettere un nuovoCheckoutRequestMessage
Dopo il pagamento, Google mostra all'utente finale una pagina di conferma dell'ordine.
indipendentemente dal fatto che ProposedOrder
sia stato modificato o meno.
Se il ProposedOrder è stato corretto, Google potrebbe mostrare ulteriori avvisi a
informare l'utente delle modifiche. Se l'utente accetta di effettuare l'ordine,
non ci saranno altre richieste di pagamento. Il flusso continua con l'invio dell'ordine,
il valore ProposedOrder
corretto.
Tuttavia, l'utente può sempre cambiare idea e modificare nuovamente il carrello. Quando
gli aggiornamenti del carrello in questo modo, Google invia un nuovo CheckoutRequestMessage
.
Modifiche di prezzo durante l'invio dell'ordine
Se riscontri un problema di prezzo durante l'elaborazione dell'invio dell'ordine
(è stato attivato l'intent actions.intent.TRANSACTION_DECISION
), non rispondere
con un errore o aggiorna il prezzo nella risposta. Se i prezzi, le quantità,
o altri dettagli in SubmitOrderRequestMessage
non corrispondono
i tuoi dati, rispondi con il valore orderState
impostato su REJECTED
per indicare che
impossibile effettuare l'ordine come richiesto.
Successivamente, se i dati dell'ordine e del pagamento sono validi, imposta orderState
su CREATED
o CONFIRMED
. Inoltre, includi actionOrderId
per rappresentare l'ID dell'ordine in
del tuo sistema. Questo ID deve essere utilizzato per l'invio di aggiornamenti successivi.
Se non sei in grado di elaborare il pagamento e hai già inviato
SubmitOrderRequestMessage
, puoi inviare
AsyncOrderUpdateRequestMessage
con orderState
impostato su REJECTED
per consentire
l'utente saprà che l'ordine non verrà elaborato.
Modifiche di prezzo dopo l'invio dell'ordine
Se determini che un prezzo è cambiato rispetto a quello utilizzato quando un cliente
ha inviato l'ordine, puoi emettere una AsyncOrderUpdateRequestMessage
,
descritto in Implementazione degli aggiornamenti degli ordini asincroni, con il nuovo prezzo.
Per aggiornare i prezzi utilizzando gli aggiornamenti asincroni degli ordini:
- Modifica il prezzo in
lineItemUpdates[x].price
. Questo il valore riflette il costo totale dell'articolo, inclusi i componenti aggiuntivi e moltiplicato dalla quantità. Per ulteriori informazioni, consulta la descrizione campoprice
diLineItem
.) - Inserisci una spiegazione in
lineItemUpdates[x].reason
. - Imposta
lineItemUpdates[x].orderState
aCONFIRMED
.
Puoi tentare di addebitare sullo strumento di pagamento prima o dopo l'invio del
AsyncOrderUpdateRequestMessage, a tua discrezione. Se la transazione non va a buon fine
(probabilmente perché il delta di prezzo è troppo alto), invia un
AsyncOrderUpdateRequestMessage con le seguenti impostazioni nel campo
OrderUpdate
per informare Google dell'errore:
- Imposta
orderState
suREJECTED
. - Descrivi l'errore nel campo
label
.
Convalida del pagamento
Come descritto nel Passaggio 4: implementa pagamento, i tuoi
l'endpoint di evasione degli ordini deve eseguire la convalida su ogni endpoint in entrata
CheckoutRequestMessage
e rispondi con un CheckoutResponseMessage
.
Ecco un esempio di CheckoutResponseMessage
per una richiesta
convalida:
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida è riuscita | Restituisci CheckoutResponse . Deve avere
ProposedOrder e PaymentOptions .
ProposedOrder include tasse, commissioni e il prezzo totale della
carrello. |
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 } } } } } ] } } }
Convalida dell'indirizzo di consegna
L'endpoint di evasione degli ordini deve convalidare l'indirizzo di consegna contenuto in ogni
CheckoutRequestMessage
Se si è verificato un problema con l'indirizzo di consegna, ad esempio perché è fuori dal raggio d'azione
il servizio di consegna, il valore di CheckoutResponseMessage
restituito dal tuo
Il completamento deve contenere un valore FoodOrderError
del tipo appropriato.
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida non è riuscita perché l'indirizzo di consegna è fuori dell'intervallo o si è verificato un problema con l'indirizzo di consegna | Restituisci FoodErrorExtension con FoodOrderError
di tipo 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." } ] } } } ] } } }
Convalida del valore minimo dell'ordine
L'endpoint di evasione degli ordini deve convalidare il valore minimo dell'ordine di ogni
CheckoutRequestMessage
Se non viene raggiunto il valore minimo dell'ordine, CheckoutResponseMessage
restituiti dal completamento devono contenere un valore di tipo FoodOrderError
REQUIREMENTS_NOT_MET
.
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: convalida non riuscita perché il valore minimo dell'ordine non è soddisfatto | Restituisci FoodErrorExtension con FoodOrderError
di tipo 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." } ] } } } ] } } }
Convalida finestra di ordine
L'endpoint di evasione degli ordini deve convalidare tutti i fattori che possono influire sulle
finestra di ordinazione di ogni CheckoutRequestMessage
.
Ad esempio, se il ristorante è chiuso o non accetta più ordini al
momento, l'importo di CheckoutResponseMessage
restituito dal tuo evasione degli ordini dovrebbe
contiene un valore FoodOrderError
di tipo di errore CLOSED
o NO_CAPACITY
,
rispettivamente.
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida non è riuscita perché il ristorante è chiuso o non più supportato | Restituisci FoodErrorExtension con FoodOrderError
di tipo CLOSED . |
Caso d'uso 2: la convalida non è riuscita perché il ristorante è occupato e non accetta ordini al momento | Restituisci FoodErrorExtension con FoodOrderError
di tipo 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." } ] } } } ] } } }
Convalida degli articoli del carrello
L'endpoint di evasione degli ordini deve convalidare i prezzi e la disponibilità di ogni
articolo del carrello contenuto in un CheckoutRequestMessage
.
Se la disponibilità o i prezzi sono cambiati, CheckoutResponseMessage
restituiti dal completamento devono contenere un valore di tipo FoodOrderError
rispettivamente AVAILABILITY_CHANGED
o PRICE_CHANGED
.
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida non è riuscita a causa di alcune voci di menu e/o le loro personalizzazioni non sono valide o non sono disponibili | Restituisci FoodErrorExtension con correctedProposedOrder ,
PaymentOptions e FoodOrderError di tipo di errore
AVAILABILITY_CHANGED . Gli elementi non validi devono essere rimossi da
CorrectedProposedOrder . |
Caso d'uso 2: la convalida non è riuscita a causa di alcune voci di menu e/o le relative personalizzazioni non sono valide o non sono disponibili. Il carrello corretto non soddisfa più il requisito relativo al valore minimo dell'ordine. | Restituisci FoodErrorExtension con FoodOrderError
dei tipi di errore AVAILABILITY_CHANGED e
REQUIREMENTS_NOT_MET . |
Caso d'uso 3: la convalida non è riuscita a causa di una voce di menu e/o i prezzi della personalizzazione sono cambiati | Restituisci FoodErrorExtension con correctedProposedOrder ,
PaymentOptions e FoodOrderError di tipo di errore
PRICE_CHANGED . I prezzi obsoleti devono essere aggiornati in
CorrectedProposedOrder . |
Caso d'uso 4: la convalida non è riuscita a causa di una voce di menu e/o i prezzi della personalizzazione sono cambiati. Il carrello corretto non soddisfa più i requisito del valore minimo dell'ordine | Restituisci FoodErrorExtension con FoodOrderError
dei tipi di errore PRICE_CHANGED e
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 } } ] } } } ] } } }
Invia convalida ordine
Come descritto nel Passaggio 7: implementa l'invio dell'ordine, i campi
l'endpoint di evasione degli ordini deve eseguire la convalida su ogni endpoint in entrata
SubmitOrderRequestMessage
e rispondi con un
SubmitOrderResponseMessage
.
Ecco un esempio di SubmitOrderResponseMessage
per una richiesta
convalida:
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: l'ordine è stato creato | Un ordine SubmitOrderResponseMessage con CREATED
stato. Deve avere actionOrderId ,
userVisibleId , orderManagementActions e
estimatedFulfillmentTime . |
Caso d'uso 2: l'ordine è stato rifiutato a causa di problemi di pagamento | Un ordine SubmitOrderResponseMessage con REJECTED
stato. Deve avere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo PAYMENT_DECLINED . |
Caso d'uso 3: l'ordine viene rifiutato a causa dell'utente contrassegnato come vietato | Un ordine SubmitOrderResponseMessage con REJECTED
. Deve avere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo INELIGIBLE . |
Caso d'uso 4: l'ordine è rifiutato perché le informazioni dell'utente sono incompleto o non valido | Un ordine SubmitOrderResponseMessage con REJECTED
stato. Deve avere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo INELIGIBLE . |
Caso d'uso 5: l'ordine è stato rifiutato per un motivo sconosciuto | Un ordine SubmitOrderResponseMessage con REJECTED
stato. Deve avere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo 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" } } } ] } } } ] } } }