Mappatura dei feed del menu e degli articoli del carrello di evasione
Quando i clienti aggiungono gli articoli del tuo feed del menu al carrello e pagano, Google li invia al tuo endpoint di evasione degli ordini per verificarne il prezzo e la disponibilità. Una volta convalidati i prezzi e la disponibilità, il cliente può effettuare l'ordine. Questa sezione illustra come mappare gli articoli del feed del menu agli articoli del carrello di evasione degli ordini.
Gli esempi in questa sezione sono versioni semplificate del feed del menu e dello schema del carrello. Vengono visualizzati solo i campi pertinenti per illustrare la mappatura tra il feed Menu e
l'oggetto Carrello. Per gli schemi completi, consulta Menu
e Cart
.
Gli articoli nel feed Menu
aggiunti a un carrello vengono inviati nell'oggetto Cart
per il pagamento e l'invio dell'ordine.
- Un semplice
MenuItem
è rappresentato comeLineItem
nell'arraylineItems
, doveofferId
è iloffer.id
dell'elemento del menu selezionato nel feed del menu. - Un
MenuItem
con unMenuItemOption
obbligatorio è rappresentato comeLineItem
nell'arraylineItems
, doveofferId
è iloffer.id
dell'opzione di elemento del menu selezionato dal feed del menu. - Un
AddOnMenuItem
di unLineItem
è rappresentato come unFoodItemOption
nell'arrayoptions
diFoodItemExtension
. Ogni opzione ha unofferId
che corrisponde aloffer.id
dell'elemento del menu del componente aggiuntivo selezionato nel feed del menu. Tieni presente che un elemento AddOnMenuItem può avere anche elementi AddOnMenuItem nidificati che sono rappresentati comesubOptions
all'interno di ogni opzione.
Gli esempi riportati di seguito mappano le voci del menu tra il feed del menu e il carrello di evasione.
Questo esempio contiene un elenco di semplici elementi del menu.
Voci di menu in un feed di 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 di evasione 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" } ] }
Questo esempio contiene una voce di menu con uno o più elementi di menu aggiuntivi.
Voci di menu in un feed di 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 di evasione 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" } ] }
Questo esempio contiene una voce di menu con opzioni di voci di menu, elementi di menu aggiuntivi ed elementi di menu aggiuntivi nidificati
Voci di menu in un feed di 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 di evasione 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 un CheckoutRequestMessage
, puoi rispondere con un CheckoutResponseMessage
contenente un FoodErrorExtension
anziché un CheckoutResponse. Puoi utilizzare questa 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 è tenuto a modificare il carrello per inviare l'ordine. Ad esempio, se stabilisci che un articolo in
Cart
ha subito un cambio di prezzo, puoi rispondere con unFoodOrderError
di tipo di errorePRICE_CHANGED
, insieme acorrectedProposedOrder
epaymentOptions
. Google informa l'utente della modifica, ma gli consente di inviare il messaggio con il valorecorrectedProposedOrder
. Se lo desidera, l'utente può anche tornare indietro e modificare il carrello. Riceverai un nuovoCheckoutRequestMessage
o unSubmitOrderRequestMessage
. - Errori non recuperabili: l'utente deve modificare il carrello prima di inviare l'ordine. Ad esempio, se stabilisci che il ristorante è chiuso, puoi rispondere con un
FoodOrderError
di tipo di erroreCLOSED
. Google informa l'utente e gestisce l'interazione per l'aggiornamento a un nuovo Ristorante. Riceverai un nuovoCheckoutRequestMessage
per un nuovo carrello.
In generale, rendi non recuperabili gli errori a livello di carrello e recuperabili quelli a livello di articolo. Per un elenco completo dei tipi di errore e dei relativi significati, consulta
FoodOrderError
.
Gestione delle variazioni di prezzo
Variazioni di prezzo durante il pagamento
Se riscontri un problema di prezzo durante l'elaborazione della richiesta di pagamento di un cliente, procedi nel seguente modo:
- Rispondi al messaggio
CheckoutRequestMessage
con un messaggioCheckoutResponseMessage
contenente un messaggioFoodErrorExtension
, come descritto in Gestione degli errori. - Nella risposta all'errore, utilizza
correctedProposedOrder.cart
per aggiornare il prezzo al valore corretto. Google riceve l'ordine corretto e può emettere un nuovoCheckoutRequestMessage
.
Dopo il pagamento, Google mostra all'utente finale una pagina di conferma dell'ordine, indipendentemente dal fatto che il ProposedOrder
sia stato modificato o meno.
Se l'ordine proposto è stato corretto, Google potrebbe mostrare avvisi aggiuntivi per informare l'utente delle modifiche. Se l'utente accetta di effettuare l'ordine, non verranno più richieste di pagamento. Il flusso continua con l'invio dell'ordine, con il valore corretto ProposedOrder
.
Tuttavia, l'utente può sempre cambiare idea e modificare di nuovo il carrello. Quando il carrello si aggiorna in questo modo, Google invia un nuovo CheckoutRequestMessage
.
Modifiche al prezzo durante l'invio dell'ordine
Se si verifica 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 aggiornare il prezzo nella risposta. Se i prezzi, le quantità o altri dettagli in SubmitOrderRequestMessage
non corrispondono ai tuoi dati, rispondi con orderState
impostato su REJECTED
per indicare che l'ordine non può essere effettuato come richiesto.
Se i dettagli dell'ordine e del pagamento sono validi, imposta orderState
su CREATED
o CONFIRMED
. Includi anche un actionOrderId
per rappresentare l'ID dell'ordine nel
tuo sistema. Questo ID deve essere utilizzato per l'invio di aggiornamenti successivi.
Se non riesci a elaborare il pagamento e hai già inviato il messaggio SubmitOrderRequestMessage
, puoi inviare un messaggio AsyncOrderUpdateRequestMessage
con orderState
impostato su REJECTED
per comunicare all'utente che l'ordine non verrà completato.
Modifiche al prezzo dopo l'invio dell'ordine
Se stabilisci che un prezzo è cambiato rispetto a quello utilizzato quando un cliente ha inviato l'ordine, puoi emettere un AsyncOrderUpdateRequestMessage
, come descritto in Implementazione degli aggiornamenti degli ordini asincroni, con il nuovo prezzo.
Per aggiornare i prezzi utilizzando gli aggiornamenti degli ordini asincroni:
- Modifica il prezzo in
lineItemUpdates[x].price
. Questo valore riflette il costo totale dell'articolo, inclusi i componenti aggiuntivi, moltiplicato per la quantità. Per ulteriori informazioni, consulta la descrizione del campoprice
diLineItem
. - Inserisci una spiegazione in
lineItemUpdates[x].reason
. - Imposta
lineItemUpdates[x].orderState
suCONFIRMED
.
Puoi tentare di addebitare lo strumento di pagamento prima o dopo l'invio di AsyncOrderUpdateRequestMessage, a tua discrezione. Se la transazione non va a buon fine
(forse perché il delta del prezzo è troppo elevato), invia un messaggio
AsyncOrderUpdateRequestMessage con le seguenti impostazioni in
OrderUpdate
per informare Google del mancato pagamento:
- Imposta
orderState
suREJECTED
. - Descrivi l'errore nel campo
label
.
Convalida del pagamento
Come discusso nel passaggio 4: implementazione del pagamento, l'endpoint di evasione degli ordini deve eseguire la convalida su ogni CheckoutRequestMessage
in entrata e rispondere con un CheckoutResponseMessage
.
Ecco un esempio di CheckoutResponseMessage
per una convalida riuscita:
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida è riuscita | Ritorno: CheckoutResponse . Deve avere
ProposedOrder e PaymentOptions .
ProposedOrder include tasse, commissioni e il prezzo totale del
carrello. |
{ "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 } } } } } ] } } }
Verifica dell'indirizzo di consegna
L'endpoint di evasione degli ordini deve convalidare l'indirizzo di consegna contenuto in ogni
CheckoutRequestMessage
.
Se si verifica un problema con l'indirizzo di consegna, ad esempio se non rientra nell'area di servizio di consegna, il valore CheckoutResponseMessage
restituito dal tuo Fulfillment deve contenere un FoodOrderError
del tipo appropriato.
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida non è riuscita perché l'indirizzo di consegna è fuori range o si è verificato un problema con l'indirizzo di consegna | Restituisce FoodErrorExtension con FoodOrderError
di tipo di errore 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." } ] } } } ] } } }
Convalida del valore minimo dell'ordine
L'endpoint di evasione degli ordini deve convalidare il valore minimo dell'ordine di ogni
CheckoutRequestMessage
.
Se il valore minimo dell'ordine non viene raggiunto, il valore CheckoutResponseMessage
fornito dal tuo Fulfillment deve contenere un FoodOrderError
di tipo di errore REQUIREMENTS_NOT_MET
.
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida non è riuscita perché il valore minimo dell'ordine non è stato raggiunto | Restituisce FoodErrorExtension con FoodOrderError
di tipo di errore 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." } ] } } } ] } } }
Convalida della finestra di ordinazione
L'endpoint di evasione degli ordini deve convalidare tutti i fattori che possono influire sulla finestra di ordinazione di ogni CheckoutRequestMessage
.
Ad esempio, se il ristorante è chiuso o al momento non accetta più ordini, il valore CheckoutResponseMessage
restituito dal tuo Fulfillment deve contenere un 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 | Restituisce FoodErrorExtension con FoodOrderError
di tipo di errore CLOSED . |
Caso d'uso 2: la convalida non è riuscita perché il ristorante è occupato e al momento non accetta ordini | Restituisce FoodErrorExtension con FoodOrderError
di tipo di errore 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." } ] } } } ] } } }
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, il valore CheckoutResponseMessage
fornito dal tuo Fulfillment deve contenere un FoodOrderError
di tipo di errore AVAILABILITY_CHANGED
o PRICE_CHANGED
.
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: la convalida non è riuscita perché alcuni elementi del menu e/o le relative personalizzazioni non sono validi o non sono disponibili | Restituisce 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 perché alcuni elementi del menu e/o le relative personalizzazioni non sono validi o non sono disponibili. Il carrello corretto non soddisfa più il requisito del valore minimo dell'ordine. | Restituisce FoodErrorExtension con FoodOrderError
dei tipi di errore AVAILABILITY_CHANGED e
REQUIREMENTS_NOT_MET . |
Caso d'uso 3: la convalida non è riuscita perché alcuni prezzi di voci di menu e/o personalizzazioni sono cambiati | Restituisce 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 perché alcuni prezzi di voci di menu e/o personalizzazioni sono cambiati. Il carrello corretto non soddisfa più il requisito del valore minimo dell'ordine | Restituisce FoodErrorExtension con FoodOrderError
dei tipi di errore PRICE_CHANGED e
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 } } ] } } } ] } } }
Invio della convalida dell'ordine
Come spiegato nel passaggio 7: implementa Invia ordine, il tuo endpoint di evasione degli ordini deve eseguire la convalida di ogni SubmitOrderRequestMessage
in entrata e rispondere con un SubmitOrderResponseMessage
.
Ecco un esempio di SubmitOrderResponseMessage
per una convalida riuscita:
Caso d'uso | Come implementare |
---|---|
Caso d'uso 1: l'ordine viene creato correttamente | Un SubmitOrderResponseMessage con stato dell'ordine CREATED . Deve contenere actionOrderId ,
userVisibleId , orderManagementActions e
estimatedFulfillmentTime . |
Caso d'uso 2: l'ordine viene rifiutato a causa di problemi di pagamento | Un SubmitOrderResponseMessage con stato dell'ordine REJECTED . Deve contenere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo PAYMENT_DECLINED . |
Caso d'uso 3: l'ordine viene rifiutato perché l'utente è contrassegnato come bannato | Un SubmitOrderResponseMessage con stato dell'ordine REJECTED . Deve contenere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo INELIGIBLE . |
Caso d'uso 4: l'ordine viene rifiutato perché le informazioni dell'utente sono incomplete o non valide | Un SubmitOrderResponseMessage con stato dell'ordine REJECTED . Deve contenere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo INELIGIBLE . |
Caso d'uso 5: l'ordine viene rifiutato per un motivo sconosciuto | Un SubmitOrderResponseMessage con stato dell'ordine REJECTED . Deve contenere actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo di tipo 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" } } } ] } } } ] } } }