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 do pedido são enviados para seu serviço da Web de ponta a ponta. Essas informações são validadas pelo seu serviço da Web, e você pode continuar 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 no formato de CheckoutRequestMessage
, que contém os
detalhes do Cart
de um cliente. Seu serviço da Web responde com um
CheckoutResponseMessage
. No diagrama a seguir, ilustramos o processo.
Ao receber uma solicitação de finalização de compra, seu serviço da Web de pedidos de ponta a ponta precisa fazer o seguinte:
- Verifique a validade do carrinho com base nos preços, na disponibilidade e no serviço do provedor de itens atuais.
- Calcule o preço total (incluindo descontos, tributos e taxas de entrega).
- Se for bem-sucedido, responda com um carrinho não modificado.
- Se não for bem-sucedido, responda com uma mensagem de erro e uma nova ordem proposta.
Antes de começar a implementar o processo de finalização da compra, recomendamos que você leia a documentação Visão geral da conclusão.
Mensagem de solicitação de finalização de compra
Para validar o carrinho do cliente, quando ele escolhe finalizar a compra,
o Google envia uma solicitação ao seu serviço da Web com um corpo JSON no formato de
CheckoutRequestMessage
. O pedido do cliente só é enviado mais tarde no
fluxo de finalização de pedidos.
Os dados contidos em um
CheckoutRequestMessage
incluem o seguinte:
- 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
. - Cart: 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 propriedades para entrega ou retirada:- Para pedidos de entrega, o objeto
FoodCartExtension
inclui o endereço de entrega. - Para pedidos de retirada ou entrega, 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 do 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 de finalização de compra
Depois de receber uma solicitação do serviço de finalização de compra, seu serviço da Web de finalização de compra
precisa processá-la e responder com um CheckoutResponseMessage
. O
CheckoutResponseMessage
precisa abranger uma solicitação bem-sucedida ou não
concluída.
Pedido concluído
Se uma solicitação de finalização de compra for bem-sucedida, o CheckoutResponseMessage
precisará incluir
ProposedOrder
e
PaymentOptions
:
ProposedOrder
cart
: um objetocart
idêntico ao carrinho fornecido noCheckoutRequestMessage
. Se algum conteúdo do carrinho precisar ser alterado, oCheckoutResponseMessage
precisará incluir umFoodErrorExtension
com umProposedOrder
corrigido.otherItems
: itens adicionados pelo provedor, como taxas de entrega, tributos e outras taxas. Também pode conter gorjeta adicionada pelo usuário.totalPrice
: o preço total do pedido.extension
: umFoodOrderExtension
que define informações de preenchimento do pedido, como o tempo de entrega.
PaymentOptions
- A configuração do processamento de pagamentos será abordada mais adiante em Configurar o Google
Pay.
Você pode usar o marcador de posição JSON no
CheckoutResponseMessage
até que esteja pronto para implementar o processamento de pagamentos. - Para adicionar opções de pagamento de marcador de posição no
CheckoutResponseMessage
, consulte o exemplo abaixo, que usa um gateway de pagamento de exemplo paraPaymentOptions
.
- A configuração do processamento de pagamentos será abordada mais adiante em Configurar o Google
Pay.
Você pode usar o marcador de posição JSON 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": []
}
}
}
]
}
}
}
]
}
}
}
Pedido não realizado
Se uma solicitação de finalização de compra falhar, o CheckoutResponseMessage
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
precisará incluir o correctedProposedOrder
.
Exemplo de resposta com falha
{
"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 da compra
Siga as etapas abaixo ao implementar o pagamento.
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, então o primeiro erro encontrado precisa ser retornado. Consulte Como lidar com erros para conferir uma descrição dos erros recuperáveis.
- Leia a propriedade FulfillmentOptionInfo na
solicitação para determinar se o tipo de fulfillment é para
delivery
oupickup
. Retorne os seguintes tipos de erro, se necessário:
Tipo de erro Caso de uso INVALID O tipo de fulfillment é inválido. NOT_FOUND O tipo de atendimento não foi encontrado. CLOSED - Não há janelas de OperationHours para o pedido.
- O pedido é "Assim que possível" e não há ServiceHours disponíveis para o momento.
- Há uma interdição de emergência ou o serviço
isDisabled
é verdadeiro.
UNAVAILABLE_SLOT O pedido com antecedência não pode ser atendido. NO_CAPACITY O restaurante está ocupado e não está aceitando pedidos no momento. OUT_OF_SERVICE_AREA O pedido não pode ser entregue no endereço do usuário. Consulte Validação do endereço de entrega para conferir um exemplo. NO_COURIER_AVAILABLE O pedido não pode ser entregue devido à limitação de pessoal de entrega.
Validar e definir o preço do carrinho
Procure cada carrinho.
lineItems
e valide com os dados atuais no seu sistema ou no 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 de qualquer uma 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 de uma combinação de complementos mudou. 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 atendido. Isso pode ser determinado verificando se o preço do carrinho está abaixo da taxa. eligibleTransactionVolumeMin
ou acima da taxa.eligibleTransactionVolumeMax
. Consulte o exemplo em Validação do valor mínimo do pedido.Não Retorne a lista validada de itens de linha com LineItemType
REGULAR
. A soma de todos os preços dos itens de linha do carrinho é o preço do carrinho ouSUBTOTAL
.
Confira exemplos em Validação de itens do carrinho.
Calcular as taxas de serviço
- Encontre a entidade Fee correta para o serviço com base em
eligibleRegion
,validFrom
,validThrough
epriority
. - Calcule o valor da taxa com base em se a entidade foi definida com uma propriedade
price
,percentageOfCart
oupricePerMeter
. - Retorne a taxa de serviço de entrega ou retirada como um LineItem com
LineItemType
DELIVERY
ouFEE
, respectivamente. Adicione a taxa à lista Cart.otherItems
.
Aplicar promoções
- Encontre a entidade Deal com base na correspondência do valor
Promotion.
coupon
com o Deal.dealCode
. Valide a transação e retorne 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 transação com base em Transação.
discount
ou Transação.discountPercentage
.Aplique o valor do preço da oferta usando o total do carrinho ou da taxa, dependendo da oferta.
dealType
.Retorna o carrinho.
promotions
com a promoção aplicada.Retorne a promoção como um LineItem com LineItemType
DISCOUNT
. Adicione o desconto à lista Cart.otherItems
com um preço negativo.
Retornar a resposta
- Crie a ProposedOrder.
cart
. O carrinho de resposta será o mesmo que o de solicitação se nenhum erro for encontrado durante a validação. - Retorna a lista ProposedOrder.
otherItems
, incluindo impostos, taxas, gorjetas e descontos, se aplicável. Consulte Gratuidade para mais detalhes sobre como configurar o item de gorjeta. - Inclua a ProposedOrder.
totalPrice
adicionando o preço, as taxas, o desconto, os tributos e a gorjeta do carrinho. - Retorne a
FoodOrderExtension.
availableFulfillmentOptions
com a respectiva FulfillmentOption. Atualize o horário de retirada ou entrega estimado. - Se houver erros de pedido de comida gerados pelas verificações de validação anteriores:
- Inclua StructuredResponse.
error
e a lista de erros em FoodErrorExtension.foodOrderErrors
. - Retorne ProposedOrder no campo
correctedProposedOrder
se todos os erros forem recuperáveis. - Retorne PaymentOptions no campo
paymentOptions
se todos os erros forem recuperáveis. - Opcionalmente, inclua
additionalPaymentOptions
se houver outras opções de pagamento disponíveis e todos os erros forem recuperáveis.
- Inclua StructuredResponse.
- Se não houver erros de validação, retorne o
proposedOrder
,paymentOptions
no objeto CheckoutResponse. Se quiser, incluaadditionalPaymentOptions
se houver outras opções de pagamento disponíveis.