Como mapear feeds de menu e itens do carrinho de atendimento do pedido
Quando os clientes adicionam itens do seu feed ao carrinho e finalizam a compra, O Google envia esses itens ao endpoint de processamento do pedido para verificar o preço e disponibilidade. Depois que o preço e a disponibilidade são validados, o cliente pode fazer o pedido. Esta seção mostra como mapear itens de feed para itens do carrinho de compras.
Os exemplos desta seção são versões reduzidas do feed do cardápio e do carrinho
esquema. Somente os campos relevantes para ilustrar o mapeamento entre o feed do cardápio e
o objeto Carrinho são mostrados. Para ver os esquemas completos, consulte Menu
e Cart
.
Os itens no feed Menu
adicionados a um carrinho são enviados no Cart
para finalizar a compra e enviar o pedido.
- Uma
MenuItem
simples é representada como umaLineItem
no objetolineItems
. matriz comofferId
sendo ooffer.id
do item de menu selecionado no menu se alimentam. - Um
MenuItem
com umMenuItemOption
obrigatório é representado comoLineItem
na matrizlineItems
comofferId
sendo o valor selecionado da opçãooffer.id
do item de menu no feed. - Uma
AddOnMenuItem
de umLineItem
é representada como umaFoodItemOption
na matrizoptions
deFoodItemExtension
. Cada opção tem umofferId
que corresponde ao menu do complemento selecionadooffer.id
do item no feed do cardápio. Um AddOnMenuItem também pode ter AddOnMenuItem(s) aninhados que são representados comosubOptions
dentro de cada é a melhor opção.
Os exemplos a seguir mapeiam os itens do menu entre o feed de cardápio e o atendimento de pedidos carrinho.
JSON
Este exemplo contém uma lista de itens de menu simples.
Itens de cardápio em um feed de cardápio:
{ "@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" } ] } ] }
Itens de menu mapeados para um carrinho de atendimento de pedidos:
{ "@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
Este exemplo contém um item de menu com um ou mais AddOnMenuItems.
Itens de cardápio em um feed de cardápio:
{ "@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" } ] } ] }
Itens de menu mapeados para um carrinho de atendimento de pedidos:
{ "@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
Este exemplo contém um item de menu com opções de item de menu, AddOnMenuItems, e AddOnMenuItems aninhados
Itens de cardápio em um feed de cardápio:
{ "@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" } ] } ] } ] } ] } ] } } ] }
Itens de menu mapeados para um carrinho de atendimento de pedidos:
{ "@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" } ] } ] } } ] }
Como processar os erros
Se você tiver problemas ao processar uma CheckoutRequestMessage
, faça o seguinte:
pode responder com um CheckoutResponseMessage
que contenha um
FoodErrorExtension
em vez de uma CheckoutResponse. Você pode usar isso
para identificar um ou mais erros que ocorreram durante o processamento.
Há duas maneiras de lidar com os erros:
- Erros recuperáveis: o usuário não precisa editar o carrinho para enviar o
ordem. Por exemplo, se você determinar que um item na
Cart
tem um mudança de preço, você pode responder com umFoodOrderError
do tipo de erroPRICE_CHANGED
, junto comcorrectedProposedOrder
epaymentOptions
. O Google informa o usuário sobre a mudança, mas permite que ele envie com acorrectedProposedOrder
: O usuário também pode voltar e editar o carrinho se quiser. Você vai receber um novoCheckoutRequestMessage
ou umSubmitOrderRequestMessage
- Erros irrecuperáveis: o usuário precisa editar o carrinho antes de
enviar o pedido. Por exemplo, se você determinar que o restaurante
fechado, responda com
FoodOrderError
do tipo de erroCLOSED
. O Google informa o usuário e gerencia a interação para atualizar para uma nova restaurante. Você receberá um novoCheckoutRequestMessage
para um novo carrinho.
Em geral, torne os erros no nível do carrinho irrecuperáveis e os no nível do item
por tempo indefinido. Para uma lista completa dos tipos de erros e seus significados, consulte
FoodOrderError
Como processar mudanças de preço
O preço muda na finalização da compra
Se você encontrar um problema de preço ao processar a compra de um cliente faça o seguinte:
- Responda ao
CheckoutRequestMessage
com umaCheckoutResponseMessage
que contém umFoodErrorExtension
, conforme descritos em Tratamento de erros. - Na resposta de erro, use
correctedProposedOrder.cart
para atualizar o preço. para o valor correto. O Google recebe o pedido corrigido e pode emitir um novoCheckoutRequestMessage
Após a finalização da compra, o Google mostra uma página de confirmação do pedido para o usuário final,
independentemente de a ProposedOrder
ter sido alterada ou não.
Se o ProposedOrder for corrigido, o Google poderá mostrar avisos adicionais aos
informar o usuário sobre as mudanças. Se o usuário concordar em fazer o pedido,
não haverá mais solicitações de checkout. O fluxo continua o envio do pedido, com
o ProposedOrder
corrigido.
No entanto, o usuário pode mudar de ideia e editar o carrinho novamente a qualquer momento. Quando
as atualizações do carrinho dessa maneira, o Google envia um novo CheckoutRequestMessage
.
Mudanças de preço durante o envio do pedido
Se você encontrar um problema de preço ao processar o envio do pedido
(a intent actions.intent.TRANSACTION_DECISION
foi acionada), não responda
com um erro ou atualize o preço na sua resposta. Se os preços, as quantidades
ou outros detalhes no SubmitOrderRequestMessage
não correspondem
seus dados, responda com orderState
definido como REJECTED
para indicar que os
não é possível fazer o pedido conforme solicitado.
Então, se o pedido e os detalhes da forma de pagamento forem válidos, defina orderState
como CREATED
ou CONFIRMED
. Além disso, inclua um actionOrderId
para representar o ID do pedido no
seu sistema. Esse ID precisa ser usado no envio de atualizações subsequentes.
Se você não conseguir processar o pagamento e já tiver enviado o
SubmitOrderRequestMessage
, é possível enviar uma
AsyncOrderUpdateRequestMessage
com orderState
definido como REJECTED
para permitir
que o usuário saiba que o pedido não será processado.
O preço muda após o envio do pedido
Se você determinar que um preço mudou em relação ao preço usado quando um cliente
enviou o pedido, você pode emitir um AsyncOrderUpdateRequestMessage
, conforme
descritos em Como implementar atualizações de pedidos assíncronos, com o novo preço.
Para atualizar os preços usando atualizações de pedidos assíncronas:
- Mude o preço em
lineItemUpdates[x].price
. Isso valor reflete o custo total do item, incluindo complementos e multiplicado pela quantidade. Para mais informações, consulte a descrição campoprice
deLineItem
. - Insira uma explicação em
lineItemUpdates[x].reason
. - Definir
lineItemUpdates[x].orderState
paraCONFIRMED
.
Você pode tentar fazer a cobrança no instrumento de pagamento antes ou depois de enviar o
AsyncOrderUpdateRequestMessage, a seu critério. Se a transação falhar
(possivelmente porque o delta de preço é muito alto), envie uma
AsyncOrderUpdateRequestMessage com as seguintes configurações no
OrderUpdate
para informar o Google sobre a falha:
- Defina
orderState
comoREJECTED
. - Descreva a falha no campo
label
.
Validação da finalização da compra
Conforme discutido na Etapa 4: implementar a finalização da compra, seus
endpoint de atendimento do pedido deve realizar uma validação em cada
CheckoutRequestMessage
e responda com uma CheckoutResponseMessage
.
Confira um exemplo de CheckoutResponseMessage
para uma campanha
validação:
Caso de uso | Como fazer a implementação |
---|---|
Caso de uso 1: a validação foi bem-sucedida | Retorne o CheckoutResponse . Ele deve ter
ProposedOrder e PaymentOptions .
ProposedOrder inclui tributos, taxas e o preço total do
carrinho. |
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 } } } } } ] } } }
Validação do endereço de entrega
Seu endpoint de atendimento precisa validar o endereço de entrega contido em cada
CheckoutRequestMessage
Se houver um problema com o endereço de entrega, por exemplo, ele está fora do alcance
o serviço de entrega, o valor de CheckoutResponseMessage
retornado pelo seu
o fulfillment precisa conter um FoodOrderError
do tipo apropriado.
Caso de uso | Como fazer a implementação |
---|---|
Caso de uso 1:a validação falhou porque o endereço de entrega está ausente ou se há um problema com o endereço de entrega | Devolver FoodErrorExtension com FoodOrderError
do tipo de erro 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." } ] } } } ] } } }
Validação do valor mínimo do pedido
O endpoint de atendimento do pedido precisa validar o valor mínimo do pedido de cada
CheckoutRequestMessage
Se o valor mínimo do pedido não for atingido, o CheckoutResponseMessage
retornados pelo fulfillment devem conter um FoodOrderError
do tipo de erro
REQUIREMENTS_NOT_MET
.
Caso de uso | Como fazer a implementação |
---|---|
Caso de uso 1:a validação falhou porque o valor mínimo do pedido não atende | Devolver FoodErrorExtension com FoodOrderError
do tipo de erro 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." } ] } } } ] } } }
Validação da janela de pedidos
Seu endpoint de atendimento precisa validar todos os fatores que podem afetar o
janela de pedidos de cada CheckoutRequestMessage
.
Por exemplo, se o restaurante estiver fechado ou não receber mais pedidos
momento, o CheckoutResponseMessage
retornado pelo fulfillment deverá
contêm um FoodOrderError
do tipo de erro CLOSED
ou NO_CAPACITY
.
respectivamente.
Caso de uso | Como fazer a implementação |
---|---|
Caso de uso 1:a validação falhou porque o restaurante está fechado ou não é mais compatível | Devolver FoodErrorExtension com FoodOrderError
do tipo de erro CLOSED . |
Caso de uso 2:a validação falhou porque o restaurante está ocupado e não está aceitando pedidos no momento | Devolver FoodErrorExtension com FoodOrderError
do tipo de erro 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." } ] } } } ] } } }
Validação de itens do carrinho
Seu endpoint de atendimento precisa validar o preço e a disponibilidade de cada
item do carrinho em uma CheckoutRequestMessage
.
Se a disponibilidade ou o preço tiverem mudado, o CheckoutResponseMessage
retornados pelo fulfillment devem conter um FoodOrderError
do tipo de erro
AVAILABILITY_CHANGED
ou PRICE_CHANGED
, respectivamente.
Caso de uso | Como fazer a implementação |
---|---|
Caso de uso 1:a validação falhou porque alguns itens de menu e/ou se as personalizações são válidas ou estão esgotados | Retorne FoodErrorExtension com correctedProposedOrder ,
PaymentOptions e FoodOrderError do tipo de erro
AVAILABILITY_CHANGED . Os itens inválidos devem ser removidos de
CorrectedProposedOrder : |
Caso de uso 2:a validação falhou porque alguns itens de menu e/ou se as personalizações são válidas ou estão em falta. O carrinho corrigido não atende mais ao requisito de valor mínimo do pedido. | Devolver FoodErrorExtension com FoodOrderError
dos tipos de erro AVAILABILITY_CHANGED e
REQUIREMENTS_NOT_MET . |
Caso de uso 3:a validação falhou porque algum item de menu e/ou os preços de personalização mudaram | Retorne FoodErrorExtension com correctedProposedOrder ,
PaymentOptions e FoodOrderError do tipo de erro
PRICE_CHANGED . Os preços desatualizados devem ser atualizados em
CorrectedProposedOrder : |
Caso de uso 4:a validação falhou porque algum item de menu e/ou os preços de personalização mudaram. O carrinho corrigido não atende mais ao requisito de valor mínimo do pedido | Devolver FoodErrorExtension com FoodOrderError
dos tipos de erro 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 } } ] } } } ] } } }
Enviar validação do pedido
Conforme discutido na Etapa 7: implementar o pedido de envio, seu
endpoint de atendimento do pedido deve realizar uma validação em cada
SubmitOrderRequestMessage
e responda com
SubmitOrderResponseMessage
.
Confira um exemplo de SubmitOrderResponseMessage
para uma campanha
validação:
Caso de uso | Como fazer a implementação |
---|---|
Caso de uso 1:o pedido foi criado | Uma SubmitOrderResponseMessage com um pedido de CREATED
estado. Ele precisa ter actionOrderId ,
userVisibleId , orderManagementActions e
estimatedFulfillmentTime . |
Caso de uso 2:o pedido é rejeitado devido a problemas de pagamento. | Uma SubmitOrderResponseMessage com um pedido de REJECTED
estado. Ele precisa ter actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo do tipo PAYMENT_DECLINED . |
Caso de uso 3: o pedido é rejeitado porque o usuário é sinalizado como banido. | Uma SubmitOrderResponseMessage com um pedido de REJECTED
o status atual da conta. Ele precisa ter actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo do tipo INELIGIBLE . |
Caso de uso 4:o pedido é rejeitado porque as informações do usuário foram incompleta ou inválida | Uma SubmitOrderResponseMessage com um pedido de REJECTED
estado. Ele precisa ter actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo do tipo INELIGIBLE . |
Caso de uso 5:o pedido é rejeitado por motivo desconhecido. | Uma SubmitOrderResponseMessage com um pedido de REJECTED
estado. Ele precisa ter actionOrderId ,
userVisibleId , orderManagementActions e
rejectionInfo do 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" } } } ] } } } ] } } }