O processo de finalização da compra é invocado quando um usuário cria um carrinho. O conteúdo do carrinho do usuário e os detalhes sobre o pedido são enviados ao seu serviço da Web de ponta a ponta. Essas informações são validadas pelo seu serviço da Web e, em seguida, é possível prosseguir ou fazer ajustes no carrinho, conforme necessário.
O gerenciador de finalização de compra do seu serviço da Web precisa responder a solicitações POST. Quando um cliente escolhe finalizar a compra, o Google envia ao serviço da Web de Pedidos de ponta a ponta um corpo de solicitação JSON na forma de CheckoutRequestMessage
, que contém os detalhes da Cart
de um cliente. Seu serviço da Web responde com CheckoutResponseMessage
. No diagrama a seguir, ilustramos o processo.
Ao receber uma solicitação de finalização de compra, seu serviço da Web de ponta a ponta precisa fazer o seguinte:
- Verifique a validade do carrinho com base nos preços do item, na disponibilidade e no serviço do provedor.
- Calcule o preço total, incluindo descontos, tributos e taxas de entrega.
- Se conseguir, responda com um carrinho sem modificações.
- Se não tiver sucesso, responda com uma mensagem de erro e um novo pedido proposto.
Antes de começar a implementar a finalização da compra, recomendamos que você consulte a documentação Visão geral do fulfillment.
Mensagem de pedido de finalização da compra
Para validar o carrinho do cliente, quando ele decidir finalizar a compra, o Google envia uma solicitação ao seu serviço da Web com um corpo JSON na forma de CheckoutRequestMessage
. O pedido do cliente não é enviado até mais tarde, no fluxo
de Pedidos de ponta a ponta.
Os dados contidos em um
CheckoutRequestMessage
incluem:
- Intent: o campo
inputs[0].intent
de cada corpo de solicitação de finalização de compra contém o valor da stringactions.foodordering.intent.CHECKOUT
. - Carrinho: o campo
inputs[0].arguments[0].extension
de uma solicitação de finalização de compra contém um objetoCart
que representa o carrinho do cliente. - Entrega ou retirada: o campo de extensão do objeto
Cart
contém um objetoFoodCartExtension
que especifica as propriedades de entrega ou retirada:- Para pedidos de entrega, o objeto
FoodCartExtension
inclui o endereço de entrega. - Para pedidos de retirada ou retirada, o objeto
FoodCartExtension
não contém informações de local.
- Para pedidos de entrega, o objeto
- Sandbox: o campo
isInSandbox
de uma solicitação de finalização de compra contém um valor booleano que indica se a transação usa pagamentos por sandbox.
Exemplo de solicitação de finalização de compra
Confira abaixo um exemplo de CheckoutRequestMessage
:
{
"user": {},
"conversation": {
"conversationId": "CTZbZfUlHCybEdcz_5PB3Ttf"
},
"inputs": [
{
"intent": "actions.foodordering.intent.CHECKOUT",
"arguments": [
{
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.Cart",
"merchant": {
"id": "restaurant/Restaurant/QWERTY",
"name": "Tep Tep Chicken Club"
},
"lineItems": [
{
"name": "Spicy Fried Chicken",
"type": "REGULAR",
"id": "299977679",
"quantity": 2,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "AUD",
"units": "39",
"nanos": 600000000
}
},
"offerId": "MenuItemOffer/QWERTY/scheduleId/496/itemId/143",
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
}
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "P0M"
}
}
},
"location": {
"coordinates": {
"latitude": -33.8376441,
"longitude": 151.0868736
},
"formattedAddress": "Killoola St, 1, Concord West NSW 2138",
"zipCode": "2138",
"city": "Concord West",
"postalAddress": {
"regionCode": "AU",
"postalCode": "2138",
"administrativeArea": "NSW",
"locality": "Concord West",
"addressLines": [
"Killoola St",
"1"
]
}
}
}
}
}
]
}
],
"directActionOnly": true,
"isInSandbox": true
}
Mensagem de resposta na finalização da compra
Depois de receber uma solicitação do serviço de ponta a ponta de pedidos, o serviço da Web de finalização de compra
precisa processá-la e responder com um CheckoutResponseMessage
. O CheckoutResponseMessage
precisa cobrir uma solicitação bem-sucedida ou não.
Solicitação bem-sucedida
Se uma solicitação de finalização de compra for bem-sucedida, CheckoutResponseMessage
precisará incluir
ProposedOrder
e
PaymentOptions
:
ProposedOrder
cart
: um objetocart
idêntico ao carrinho fornecido noCheckoutRequestMessage
. Se algum conteúdo do carrinho precisar ser modificado, oCheckoutResponseMessage
precisará incluir umaFoodErrorExtension
com umProposedOrder
corrigido.otherItems
: itens adicionados pelo provedor, como cobranças de entrega, tributos e outras taxas. Também pode conter gratificação adicionada pelo usuário.totalPrice
: preço total do pedido.extension
: umaFoodOrderExtension
que define as informações de fulfillment para o pedido, como o tempo de entrega.
PaymentOptions
- A configuração do processamento de pagamentos é abordada posteriormente em Configurar o Google
Pay.
Use o JSON de marcador de posição no
CheckoutResponseMessage
até que esteja tudo pronto para implementar o processamento de pagamentos. - Para adicionar opções de pagamento de marcador de posição no seu
CheckoutResponseMessage
, consulte o exemplo abaixo, que usa um exemplo de gateway de pagamento paraPaymentOptions
.
- A configuração do processamento de pagamentos é abordada posteriormente em Configurar o Google
Pay.
Use o JSON de marcador de posição no
Exemplo de resposta bem-sucedida
{
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"checkoutResponse": {
"proposedOrder": {
"cart": {
"merchant": {
"id": "restaurant/Restaurant/QWERTY",
"name": "Tep Tep Chicken Club"
},
"lineItems": [
{
"name": "Spicy Fried Chicken",
"type": "REGULAR",
"id": "299977679",
"quantity": 2,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "AUD",
"units": "39",
"nanos": 600000000
}
},
"offerId": "MenuItemOffer/QWERTY/scheduleId/496/itemId/143",
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
}
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "P0M"
}
}
},
"location": {
"coordinates": {
"latitude": -33.8376441,
"longitude": 151.0868736
},
"formattedAddress": "Killoola St, 1, Concord West NSW 2138",
"zipCode": "2138",
"city": "Concord West",
"postalAddress": {
"regionCode": "AU",
"postalCode": "2138",
"administrativeArea": "NSW",
"locality": "Concord West",
"addressLines": [
"Killoola St",
"1"
]
}
}
}
},
"totalPrice": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "AUD",
"units": "43",
"nanos": 100000000
}
},
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
"availableFulfillmentOptions": [
{
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "P0M"
}
}
}
]
},
"otherItems": [
{
"name": "Delivery fee",
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "AUD",
"units": "3",
"nanos": 500000000
}
},
"type": "DELIVERY"
}
]
},
"paymentOptions": {
"googleProvidedOptions": {
"facilitationSpecification": "{\"apiVersion\":2,\"apiVersionMinor\":0,\"merchantInfo\":{\"merchantName\":\"merchantName\"},\"allowedPaymentMethods\":[{\"type\":\"CARD\",\"parameters\":{\"allowedAuthMethods\":[\"PAN_ONLY\"],\"allowedCardNetworks\":[\"VISA\",\"MASTERCARD\"],\"billingAddressRequired\":true,\"cvcRequired\":false},\"tokenizationSpecification\":{\"type\":\"PAYMENT_GATEWAY\",\"parameters\":{\"gatewayMerchantId\":\"YOUR_MERCHANT_ID\",\"gateway\":\"cybersource\"}}}],\"transactionInfo\":{\"currencyCode\":\"AUD\",\"totalPriceStatus\":\"ESTIMATED\",\"totalPrice\":\"43.1\"}} "
}
},
"additionalPaymentOptions": [
{
"actionProvidedOptions": {
"paymentType": "ON_FULFILLMENT",
"displayName": "Pay when you get your food.",
"onFulfillmentPaymentData": {
"supportedPaymentOptions": []
}
}
}
]
}
}
}
]
}
}
}
Falha na solicitação
Se uma solicitação de finalização de compra não for bem-sucedida, CheckoutResponseMessage
vai precisar
incluir FoodErrorExtension
, que contém uma lista de
itens FoodOrderError
que descrevem os erros ocorridos. Se houver erros recuperáveis
no pedido, como uma mudança de preço de um item no carrinho, o
FoodErrorExtension
precisa incluir o correctedProposedOrder
.
Exemplo de resposta malsucedida
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"error": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
"foodOrderErrors": [
{
"error": "CLOSED",
"description": "The restaurant is closed."
}
]
}
}
}
]
}
}
}
Implementação da finalização de compra
Siga estas etapas ao implementar a finalização da compra.
Validar o serviço
Retorne um FoodOrderError para a primeira condição de erro de serviço encontrada. Esses erros não são recuperáveis. Portanto, o primeiro erro encontrado precisa ser retornado. Consulte Como processar erros para ver uma descrição dos erros recuperáveis.
- Leia a propriedade FulfillmentOptionInfo na solicitação para determinar se o tipo de fulfillment é
delivery
oupickup
. Se necessário, retorne os seguintes tipos de erro:
Tipo de erro Caso de uso INVALID O tipo de fulfillment é inválido. NOT_FOUND O tipo de fulfillment não foi encontrado. CLOSED - Não há janelas OperationHours para o pedido.
- O pedido é "Assim que possível" e não há ServiceHours disponíveis para o horário atual.
- Há uma interdição de emergência ou o serviço
isDisabled
é verdadeiro.
UNAVAILABLE_SLOT Não é possível concluir o pedido com antecedência. NO_CAPACITY O restaurante está ocupado e não aceita pedidos no momento. OUT_OF_SERVICE_AREA Não é possível entregar o pedido no endereço do usuário. Consulte Validação do endereço de entrega para ver um exemplo. NO_COURIER_AVAILABLE Não foi possível entregar o pedido porque a equipe de entrega é limitada.
Validar e definir o preço do carrinho
Pesquise cada Carrinho.
lineItems
e valide com os dados atuais no seu sistema ou no sistema do comerciante. O valor MenuItemOffer.sku
da entidade do feed é incluído como LineItem.offerId
. Crie um FoodOrderError para cada item de linha, se necessário. Crie no máximo um erro para cada item. Retorne os seguintes tipos de erro, se necessário:Tipo de erro Caso de uso Recuperável INVALID Os dados do item ou qualquer um dos dados das opções são inválidos. Não NOT_FOUND O item ou qualquer uma das opções não foi encontrado. Não PRICE_CHANGED O preço de um item ou combinação de complemento foi alterado. Esse erro pode ser tratado como recuperável. Sim AVAILABILITY_CHANGED O valor solicitado para os itens de linha ou qualquer uma das opções não está disponível. Sim REQUIREMENTS_NOT_MET O pedido mínimo ou máximo não foi atingido. Isso pode ser determinado ao verificar se o preço do carrinho está abaixo da Taxa. eligibleTransactionVolumeMin
ou acima da Taxa.eligibleTransactionVolumeMax
. Confira o exemplo na validação do valor mínimo do pedido.Não Retorne a lista validada de lineItems com LineItemType
REGULAR
. A soma de todos os preços de itens de linha do carrinho é o preço do carrinho ouSUBTOTAL
.
Veja exemplos em validação de itens do carrinho.
Calcular as taxas de serviço
- Encontre a entidade Taxa correta para o serviço com base em
eligibleRegion
,validFrom
,validThrough
epriority
. - Calcule o valor da taxa com base na definição da entidade com uma propriedade
price
,percentageOfCart
oupricePerMeter
. - Retorne a taxa de serviço de entrega ou retirada como um LineItem com um
LineItemType
DELIVERY
ouFEE
, respectivamente. Adicione a taxa ao Carrinho.otherItems
Aplicar promoções
- Encontre a entidade Deal com base na correspondência do valor de Promoção.
coupon
com a Transação.dealCode
. Valide o negócio e devolva um FoodOrderError, se necessário. Esses erros podem ser tratados como recuperáveis. Retorne os seguintes tipos de erro, se necessário:
Tipo de erro Caso de uso PROMO_NOT_RECOGNIZED O código do cupom não foi reconhecido. PROMO_EXPIRED A validade da oferta expirou. PROMO_ORDER_INELIGIBLE O pedido não está qualificado para o cupom. PROMO_NOT_APPLICABLE Qualquer outro motivo. Calcule o valor do preço da oferta com base em Transação.
discount
ou Transação.discountPercentage
.Aplique o valor do preço da oferta usando o total do carrinho ou o total da taxa, dependendo da oferta.
dealType
.Devolva o Carrinho.
promotions
com a promoção aplicada.Retorne a promoção como LineItem com LineItemType
DISCOUNT
. Adicione o desconto à lista Carrinho.otherItems
com um preço negativo.
Retornar a resposta
- Crie o ProposedOrder.
cart
, o carrinho de resposta é igual ao carrinho de solicitações se nenhum erro for encontrado durante a validação. - Retorne a lista ProposedOrder.
otherItems
incluindo tributos, taxas, gratuidade e desconto, se aplicados. Consulte Gratuity para mais detalhes sobre como configurar o item. - Inclua o ProposedOrder.
totalPrice
adicionando o preço, as taxas, o desconto, os tributos e a gratuidade do carrinho. - Retorne a
FoodOrderExtension.
availableFulfillmentOptions
com a respectiva FulfillmentOption. Atualize o tempo estimado de retirada ou entrega para o horário esperado. - Se houver FoodOrderErrors gerados nas verificações de validação anteriores:
- Inclua StructuredResponse.
error
e a lista de erros em FoodErrorExtension.foodOrderErrors
. - Retorne o ProposedOrder no campo
correctedProposedOrder
se todos os erros forem recuperáveis. - Retorne PaymentOptions no campo
paymentOptions
se todos os erros forem recuperáveis. - Se quiser, inclua
additionalPaymentOptions
se houver outras opções de pagamento disponíveis e se todos os erros forem recuperáveis.
- Inclua StructuredResponse.
- Se não houver erros de validação, retorne
proposedOrder
epaymentOptions
no objeto CheckoutResponse. Se quiser, incluaadditionalPaymentOptions
se houver outras opções de pagamento disponíveis.