Configurar finalização da compra

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.

A CheckoutResponseMessage retorna o carrinho não modificado do cliente ou um erro.

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 string actions.foodordering.intent.CHECKOUT.
  • Carrinho: o campo inputs[0].arguments[0].extension de uma solicitação de finalização de compra contém um objeto Cart que representa o carrinho do cliente.
  • Entrega ou retirada: o campo de extensão do objeto Cart contém um objeto FoodCartExtension 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.
  • 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 objeto cart idêntico ao carrinho fornecido no CheckoutRequestMessage. Se algum conteúdo do carrinho precisar ser modificado, o CheckoutResponseMessage precisará incluir uma FoodErrorExtension com um ProposedOrder 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: uma FoodOrderExtension 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 para PaymentOptions.

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.

  1. Leia a propriedade FulfillmentOptionInfo na solicitação para determinar se o tipo de fulfillment é delivery ou pickup.
  2. 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.
    As janelas especiais têm prioridade em relação às normais. Confira exemplos em validação da janela de pedidos e remover entidades de serviço temporariamente.
    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

  1. 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
  2. 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 ou SUBTOTAL.

Veja exemplos em validação de itens do carrinho.

Calcular as taxas de serviço

  1. Encontre a entidade Taxa correta para o serviço com base em eligibleRegion, validFrom, validThrough e priority.
  2. Calcule o valor da taxa com base na definição da entidade com uma propriedade price, percentageOfCart ou pricePerMeter.
  3. Retorne a taxa de serviço de entrega ou retirada como um LineItem com um LineItemType DELIVERY ou FEE, respectivamente. Adicione a taxa ao Carrinho.otherItems

Aplicar promoções

  1. Encontre a entidade Deal com base na correspondência do valor de Promoção.coupon com a Transação.dealCode.
  2. 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.
  3. Calcule o valor do preço da oferta com base em Transação.discount ou Transação.discountPercentage.

  4. Aplique o valor do preço da oferta usando o total do carrinho ou o total da taxa, dependendo da oferta.dealType.

  5. Devolva o Carrinho.promotions com a promoção aplicada.

  6. Retorne a promoção como LineItem com LineItemType DISCOUNT. Adicione o desconto à lista Carrinho.otherItems com um preço negativo.

Retornar a resposta

  1. Crie o ProposedOrder.cart, o carrinho de resposta é igual ao carrinho de solicitações se nenhum erro for encontrado durante a validação.
  2. Retorne a lista ProposedOrder.otherItems incluindo tributos, taxas, gratuidade e desconto, se aplicados. Consulte Gratuity para mais detalhes sobre como configurar o item.
  3. Inclua o ProposedOrder.totalPrice adicionando o preço, as taxas, o desconto, os tributos e a gratuidade do carrinho.
  4. Retorne a FoodOrderExtension.availableFulfillmentOptions com a respectiva FulfillmentOption. Atualize o tempo estimado de retirada ou entrega para o horário esperado.
  5. 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.
  6. Se não houver erros de validação, retorne proposedOrder e paymentOptions no objeto CheckoutResponse. Se quiser, inclua additionalPaymentOptions se houver outras opções de pagamento disponíveis.