Mise en correspondance des flux de menu et des articles du panier de traitement
Lorsque des clients ajoutent des articles de votre flux "Menu" à leur panier et finalisent leur achat, Google envoie ces articles à votre point de terminaison de traitement pour vérifier leur prix et la disponibilité. Une fois la tarification et la disponibilité validées, le client peut pour passer la commande. Cette section explique comment associer les éléments de flux du menu articles du panier de traitement des commandes.
Les exemples de cette section sont des versions simplifiées du flux "Menu" et du panier
du schéma. Seuls les champs pertinents pour illustrer le mappage entre le flux de menu et
l'objet "Panier" sont affichés. Pour obtenir des schémas complets, consultez Menu
et Cart
.
Les articles du flux Menu
qui sont ajoutés à un panier sont envoyés dans le Cart
.
pour le règlement et l'envoi de la commande.
- Un
MenuItem
simple est représenté par unLineItem
dans lelineItems
tableau, oùofferId
correspond à l'élémentoffer.id
de l'élément de menu sélectionné dans le menu flux. - Un
MenuItem
avec unMenuItemOption
obligatoire est représenté par unLineItem
dans le tableaulineItems
,offerId
étant l'élément sélectionné de l'option de l'élément de menuoffer.id
dans le flux de menu. - Le
AddOnMenuItem
d'unLineItem
est représenté sous la formeFoodItemOption
dans le tableauoptions
duFoodItemExtension
. Chaque option est associée à unofferId
qui correspond au menu du module complémentaire sélectionnéoffer.id
de l'article dans le flux Menu. Notez qu'un AddOnMenuItem peut également avoir Éléments AddOnMenuItem(s) imbriqués représentés parsubOptions
dans chacun d'eux .
Les exemples suivants mettent en correspondance des éléments de menu entre le flux de menus et le traitement panier.
JSON
Cet exemple contient une liste d'éléments de menu simples.
Éléments de menu dans un flux de 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" } ] } ] }
Éléments de menu mappés à un panier de traitement des commandes:
{ "@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
Cet exemple contient un élément de menu avec un ou plusieurs AddOnMenuItems.
Éléments de menu dans un flux de 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" } ] } ] }
Éléments de menu mappés à un panier de traitement des commandes:
{ "@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
Cet exemple contient un élément de menu avec des options d'élément de menu, AddOnMenuItems, et les éléments AddOnMenuItems imbriqués
Éléments de menu dans un flux de 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" } ] } ] } ] } ] } ] } } ] }
Éléments de menu mappés à un panier de traitement des commandes:
{ "@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" } ] } ] } } ] }
Traiter les erreurs
Si vous rencontrez des problèmes lors du traitement d'une CheckoutRequestMessage
, vous
peut répondre avec un CheckoutResponseMessage
qui contient un
FoodErrorExtension
au lieu d'une CheckoutResponse. Vous pouvez utiliser cette
pour identifier une ou plusieurs erreurs qui se sont produites pendant le traitement.
Il existe deux façons de gérer les erreurs:
- Erreurs récupérables: l'utilisateur n'est pas tenu de modifier son panier pour envoyer le
commande. Par exemple, si vous déterminez qu'un élément de la colonne
Cart
a un le changement de prix, vous pouvez répondre avec unFoodOrderError
de type d'erreurPRICE_CHANGED
, ainsi quecorrectedProposedOrder
etpaymentOptions
. Google informe l'utilisateur de la modification, mais lui permet d'envoyer le formulairecorrectedProposedOrder
L'utilisateur peut également revenir en arrière et modifier son panier si comme vous le souhaitez. Vous recevrez un nouveauCheckoutRequestMessage
ou unSubmitOrderRequestMessage
- Erreurs irrécupérables: l'utilisateur doit modifier son panier avant le
l'envoi de la commande. Par exemple, si vous déterminez que le restaurant
fermé, vous pouvez répondre avec un
FoodOrderError
de type d'erreurCLOSED
. Google informe l'utilisateur et gère l'interaction pour passer à une nouvelle dans un restaurant. Vous recevrez un nouveauCheckoutRequestMessage
pour un nouveau panier.
En général, assurez-vous que les erreurs au niveau du panier et des articles sont irrécupérables
récupérables. Pour obtenir la liste complète des types d'erreurs et de leur signification, consultez
FoodOrderError
Gérer les changements de prix
Changements de prix lors du règlement
Si vous rencontrez un problème de prix lors du traitement du paiement d'un client , procédez comme suit:
- Répondez à la
CheckoutRequestMessage
avec uneCheckoutResponseMessage
contenant unFoodErrorExtension
, comme décrites dans la section Gérer les erreurs. - Dans la réponse d'erreur, utilisez
correctedProposedOrder.cart
pour mettre à jour le prix. à la bonne valeur. Google reçoit la commande corrigée et peut émettre une nouvelleCheckoutRequestMessage
Après le règlement, Google affiche une page de confirmation de commande pour l'utilisateur final.
que ProposedOrder
ait été modifié ou non.
Si la valeur "ProposedOrder" a été corrigée, Google peut afficher des avertissements supplémentaires pour
informer l'utilisateur des modifications. Si l'utilisateur accepte de passer commande,
il n'y aura plus de demandes de paiement. Le flux continue d'envoyer l'ordre, avec
la ProposedOrder
corrigée.
Toutefois, l'utilisateur peut toujours changer d'avis et modifier à nouveau son panier. Quand ?
ses mises à jour de panier de cette manière, Google envoie une nouvelle CheckoutRequestMessage
.
Changements de prix lors de l'envoi de la commande
Si vous rencontrez un problème de prix lors du traitement de l'envoi de la commande
(l'intent actions.intent.TRANSACTION_DECISION
a été déclenché), ne répondez pas
en cas d'erreur ou modifiez le prix dans votre réponse. Si les prix, les quantités,
ou d'autres informations dans le SubmitOrderRequestMessage
ne correspondent pas à
vos données, répondez avec le orderState
défini sur REJECTED
pour indiquer que
commande ne peut pas être passée comme demandé.
Ensuite, si les détails de la commande et du paiement sont valides, définissez orderState
sur CREATED
ou CONFIRMED
. Ajoutez également un actionOrderId
pour représenter l'ID de la commande dans
votre système. Cet ID doit être utilisé lors de l'envoi de mises à jour ultérieures.
Si vous ne parvenez pas à traiter le paiement et que vous avez déjà envoyé le
SubmitOrderRequestMessage
, vous pouvez envoyer une
AsyncOrderUpdateRequestMessage
avec orderState
défini sur REJECTED
pour laisser
l'utilisateur sache que
la commande ne sera pas finalisée.
Changements de prix après l'envoi de la commande
Si vous constatez qu'un prix est différent de celui utilisé lorsqu'un client
envoyé sa commande, vous pouvez émettre un AsyncOrderUpdateRequestMessage
, comme
décrit dans Implémenter des mises à jour de commandes asynchrones, avec le nouveau prix.
Pour mettre à jour les prix à l'aide de commandes asynchrones, procédez comme suit:
- Modifiez le prix dans le pays suivant :
lineItemUpdates[x].price
. Ce la valeur représente le coût total de l'article, y compris les modules complémentaires et multiplié en fonction de la quantité. Pour en savoir plus, consultez la description du champprice
deLineItem
.) - Saisissez une explication dans
lineItemUpdates[x].reason
. - Définir la valeur "
lineItemUpdates[x].orderState
" àCONFIRMED
.
Vous pouvez essayer de débiter le mode de paiement avant ou après l'envoi de la
AsyncOrderUpdateRequestMessage, à votre discrétion. Si la transaction échoue
(peut-être parce que le delta du prix est trop élevé), envoyez une
AsyncOrderUpdateRequestMessage avec les paramètres suivants dans le
OrderUpdate
pour informer Google de l'échec:
- Définissez
orderState
surREJECTED
. - Décrivez l'échec dans le champ
label
.
Validation du règlement
Comme indiqué à l'Étape 4: Mettez en œuvre le règlement, votre
le point de terminaison de fulfillment doit effectuer une validation sur chaque
CheckoutRequestMessage
et répondre avec un CheckoutResponseMessage
.
Voici un exemple de CheckoutResponseMessage
pour une règle
de validation:
Cas d'utilisation | Mise en œuvre |
---|---|
Cas d'utilisation 1:la validation a réussi | Renvoyez CheckoutResponse . Il doit contenir
ProposedOrder et PaymentOptions .
ProposedOrder comprend les taxes, les frais et le prix total du
panier. |
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 } } } } } ] } } }
Validation de l'adresse de livraison
Votre point de terminaison de fulfillment doit valider l'adresse de livraison contenue dans chaque
CheckoutRequestMessage
En cas de problème avec l'adresse de livraison, par exemple si elle est hors de portée
le service de livraison, la valeur CheckoutResponseMessage
renvoyée par votre
fulfillment doit contenir un FoodOrderError
du type approprié.
Cas d'utilisation | Mise en œuvre |
---|---|
Cas d'utilisation 1:échec de la validation, car l'adresse de livraison n'est pas spécifiée ou si l'adresse de livraison présente un problème | Renvoyez FoodErrorExtension avec FoodOrderError
de type d'erreur 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." } ] } } } ] } } }
Validation du montant minimal de commande
Votre point de terminaison de traitement doit valider le montant minimal de commande de chaque
CheckoutRequestMessage
Si le montant minimal de commande n'est pas atteint, la CheckoutResponseMessage
renvoyé par votre traitement doit contenir un FoodOrderError
de type d'erreur
REQUIREMENTS_NOT_MET
Cas d'utilisation | Mise en œuvre |
---|---|
Cas d'utilisation 1:échec de la validation, car le montant minimal de commande non satisfaite | Renvoyez FoodErrorExtension avec FoodOrderError
de type d'erreur 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." } ] } } } ] } } }
Validation des fenêtres de commande
Votre point de terminaison de fulfillment doit valider tous les facteurs susceptibles d'affecter le
période de tri de chaque CheckoutRequestMessage
.
Par exemple, si le restaurant est fermé ou qu'il n'accepte plus les commandes au
À un moment donné, le CheckoutResponseMessage
renvoyé par votre traitement doit
contiennent un FoodOrderError
de type d'erreur CLOSED
ou NO_CAPACITY
;
respectivement.
Cas d'utilisation | Mise en œuvre |
---|---|
Cas d'utilisation 1:échec de la validation, car le restaurant est fermé ou n'est plus accepté | Renvoyez FoodErrorExtension avec FoodOrderError
de type d'erreur CLOSED . |
Cas d'utilisation 2:échec de la validation, car le restaurant est occupé et ne prend pas de commande pour le moment | Renvoyez FoodErrorExtension avec FoodOrderError
de type d'erreur 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." } ] } } } ] } } }
Validation des articles du panier
Votre point de terminaison de fulfillment doit valider la tarification et la disponibilité de chaque
article du panier contenu dans un élément CheckoutRequestMessage
.
Si la disponibilité ou le prix a changé, le CheckoutResponseMessage
renvoyé par votre traitement doit contenir un FoodOrderError
de type d'erreur
AVAILABILITY_CHANGED
ou PRICE_CHANGED
, respectivement.
Cas d'utilisation | Mise en œuvre |
---|---|
Cas d'utilisation 1:échec de la validation, car certains éléments de menu et/ou leurs personnalisations ne sont pas valides ou ne sont pas disponibles | Renvoyez FoodErrorExtension avec correctedProposedOrder .
PaymentOptions et FoodOrderError de type d'erreur
AVAILABILITY_CHANGED Vous devez supprimer les éléments non valides
CorrectedProposedOrder |
Cas d'utilisation 2:échec de la validation, car certains éléments de menu et/ou leurs personnalisations ne sont pas valides ou ne sont pas disponibles. Panier corrigé ne répond plus au montant minimal de commande exigé. | Renvoyez FoodErrorExtension avec FoodOrderError
des types d'erreurs AVAILABILITY_CHANGED et
REQUIREMENTS_NOT_MET |
Cas d'utilisation 3:échec de la validation, car un élément de menu et/ou les prix de personnalisation ont changé | Renvoyez FoodErrorExtension avec correctedProposedOrder .
PaymentOptions et FoodOrderError de type d'erreur
PRICE_CHANGED Les prix obsolètes doivent être mis à jour dans
CorrectedProposedOrder |
Cas d'utilisation 4:échec de la validation, car un élément de menu et/ou les prix de personnalisation ont changé. Le panier corrigé ne respecte plus les montant minimal de commande exigé | Renvoyez FoodErrorExtension avec FoodOrderError
des types d'erreurs PRICE_CHANGED et
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 } } ] } } } ] } } }
Envoyer la validation de la commande
Comme indiqué à l'Étape 7: Implémenter l'envoi de la commande, votre
le point de terminaison de fulfillment doit effectuer une validation sur chaque
SubmitOrderRequestMessage
, puis répondez avec un
SubmitOrderResponseMessage
.
Voici un exemple de SubmitOrderResponseMessage
pour une règle
de validation:
Cas d'utilisation | Mise en œuvre |
---|---|
Cas d'utilisation 1:la commande a bien été créée | Un SubmitOrderResponseMessage avec une commande CREATED
de l'état. Il doit contenir actionOrderId ,
userVisibleId , orderManagementActions et
estimatedFulfillmentTime |
Cas d'utilisation 2:commande refusée en raison de problèmes de paiement | Un SubmitOrderResponseMessage avec une commande REJECTED
de l'état. Il doit contenir actionOrderId ,
userVisibleId , orderManagementActions et
rejectionInfo de type PAYMENT_DECLINED . |
Cas d'utilisation 3:la commande est refusée, car l'utilisateur est signalé comme exclu | Un SubmitOrderResponseMessage avec une commande REJECTED
état. Il doit contenir actionOrderId ,
userVisibleId , orderManagementActions et
rejectionInfo de type INELIGIBLE . |
Cas d'utilisation 4:la commande est refusée, car les informations sur l'utilisateur incomplètes ou non valides | Un SubmitOrderResponseMessage avec une commande REJECTED
de l'état. Il doit contenir actionOrderId ,
userVisibleId , orderManagementActions et
rejectionInfo de type INELIGIBLE . |
Cas d'utilisation 5:commande refusée pour une raison inconnue | Un SubmitOrderResponseMessage avec une commande REJECTED
de l'état. Il doit contenir actionOrderId ,
userVisibleId , orderManagementActions et
rejectionInfo de type 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" } } } ] } } } ] } } }