Configurar la confirmación de la compra

El proceso de confirmación de la compra se invoca cuando un usuario crea un carrito. El contenido del carrito del usuario y los detalles del pedido se envían a tu servicio web de extremo a extremo de pedidos. Tu servicio web valida esta información y, luego, puedes continuar o hacer ajustes en su carrito según sea necesario.

El controlador de confirmación de la compra para tu servicio web debe responder a las solicitudes POST. Cuando un cliente elige pagar, Google envía al servicio web de extremo a extremo de pedidos un cuerpo de solicitud JSON en forma de un CheckoutRequestMessage, que contiene los detalles del Cart de un cliente. Luego, tu servicio web responde con un CheckoutResponseMessage. En el siguiente diagrama, se ilustra el proceso.

CheckResponseMessage muestra el carrito del cliente sin modificar o un error.

Cuando recibas una solicitud de confirmación de la compra, tu servicio web de extremo a extremo de pedidos debe hacer lo siguiente:

  • Comprueba la validez del carrito según los precios actuales del artículo, la disponibilidad y el servicio del proveedor.
  • Calcula el precio total (incluidos los descuentos, los impuestos y las tarifas de envío).
  • Si el proceso es satisfactorio, responde con un carrito sin modificar.
  • Si el problema persiste, responde con un mensaje de error y un nuevo pedido propuesto.

Antes de comenzar a implementar la confirmación de la compra, te recomendamos que revises la documentación de Descripción general de la entrega.

Mensaje de solicitud de confirmación de la compra

Para validar el carrito del cliente, cuando un cliente elige pagar, Google envía una solicitud a tu servicio web con un cuerpo JSON en forma de CheckoutRequestMessage. El pedido del cliente no se envía hasta más adelante en el flujo de pedidos de extremo a extremo.

Entre los datos que se incluyen en un CheckoutRequestMessage, se incluyen los siguientes:

  • Intent: El campo inputs[0].intent del cuerpo de cada solicitud de confirmación de la compra contiene el valor de string actions.foodordering.intent.CHECKOUT.
  • Carrito: El campo inputs[0].arguments[0].extension de una solicitud de confirmación de la compra contiene un objeto Cart que representa el carrito del cliente.
  • Entrega o comida para llevar: El campo de extensión del objeto Cart contiene un objeto FoodCartExtension que especifica las propiedades para la entrega o la exportación:
    • Para los pedidos de entrega, el objeto FoodCartExtension incluye la dirección de entrega.
    • En el caso de los pedidos para llevar o para llevar, el objeto FoodCartExtension no contiene información de ubicación.
  • Zona de pruebas: El campo isInSandbox de una solicitud de confirmación de la compra contiene un valor booleano que indica si la transacción usa pagos de zona de pruebas.

Ejemplo de solicitud de confirmación de la compra

A continuación, se muestra un ejemplo 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
}

Mensaje de respuesta de confirmación de la compra

Después de recibir una solicitud del servicio de pedidos de extremo a extremo, el servicio web de confirmación de la compra debe procesarla y responder con un CheckoutResponseMessage. El CheckoutResponseMessage debe cubrir una solicitud correcta o no.

Solicitud correcta

Si una solicitud de confirmación de la compra se realiza correctamente, CheckoutResponseMessage debe incluir ProposedOrder y PaymentOptions:

  • ProposedOrder

    • cart: Es un objeto cart idéntico al carrito que se proporciona en CheckoutRequestMessage. Si es necesario cambiar algún contenido del carrito, CheckoutResponseMessage debe incluir, en cambio, una FoodErrorExtension con un ProposedOrder corregido.
    • otherItems: Elementos que agrega el proveedor, como cargos de envío, impuestos y otras tarifas. También puede contener una propina agregada por el usuario.
    • totalPrice: Es el precio total del pedido.
    • extension: Es un FoodOrderExtension que define la información de entrega del pedido, como el tiempo de entrega.
  • PaymentOptions

    • La configuración del procesamiento de pagos se aborda más adelante en Configura Google Pay. Puedes usar el marcador de posición JSON en tu CheckoutResponseMessage hasta que estés listo para implementar el procesamiento de pagos.
    • Para agregar opciones de pago de marcadores de posición en tu CheckoutResponseMessage, consulta el ejemplo a continuación, que usa una puerta de enlace de pagos de ejemplo para PaymentOptions.

Ejemplo de respuesta correcta

{
    "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": []
                                        }
                                    }
                                }
                            ]
                        }
                    }
                }
            ]
        }
    }
}

Solicitud incorrecta

Si una solicitud de confirmación de la compra no es exitosa, CheckoutResponseMessage debe incluir FoodErrorExtension, que contiene una lista de elementos FoodOrderError que describen los errores que se produjeron. Si hay errores recuperables en el pedido, como un cambio de precio de un elemento en el carrito, el FoodErrorExtension debe incluir el correctedProposedOrder.

Ejemplo de respuesta no exitosa

{
  "expectUserResponse": false,
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "structuredResponse": {
            "error": {
              "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
              "foodOrderErrors": [
                {
                  "error": "CLOSED",
                  "description": "The restaurant is closed."
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Implementación en la confirmación de la compra

Se deben seguir los siguientes pasos para implementar la confirmación de la compra.

Valida el servicio

Muestra un FoodOrderError para la primera condición de error de servicio que se encuentra. Estos errores no se pueden recuperar, por lo que debería mostrarse el primer error encontrado. Consulta Manejo de errores para obtener una descripción de los errores recuperables.

  1. Lee la propiedad FulfillmentOptionInfo en la solicitud a fin de determinar si el tipo de entrega es para delivery o pickup.
  2. Muestra los siguientes tipos de errores si es necesario:

    Tipo de error Caso de uso
    INVALID El tipo de entrega no es válido.
    NOT_FOUND No se encontró el tipo de entrega.
    CERRADA
    • No hay períodos de OperationHours para el pedido.
    • El pedido es lo antes posible y no hay ServiceHours disponibles para este momento.
    • Se produjo un cierre de emergencia o el servicio isDisabled es verdadero.
    Ten en cuenta que las ventanas especiales tienen prioridad sobre las ventanas normales. Consulta algunos ejemplos en cómo validar la ventana de pedidos y cómo quitar entidades de servicio de manera temporal.
    UNAVAILABLE_SLOT No se puede completar el pedido con antelación.
    NO_CAPACITY El restaurante está ocupado y no toma pedidos en este momento.
    OUT_OF_SERVICE_AREA El pedido no se puede entregar a la dirección del usuario. Consulta Validación de la dirección de entrega para ver un ejemplo.
    NO_COURIER_AVAILABLE El pedido no se puede entregar porque el personal de entrega es limitado.

Valida el carrito y ponle un precio

  1. Busca cada Carrito.lineItems y valídalo con los datos actuales en tu sistema o en el sistema del comercio. El valor MenuItemOffer.sku de la entidad del feed se incluye como LineItem.offerId. Crea un FoodOrderError para cada línea de pedido si es necesario. Crea un máximo de un error para cada elemento. Muestra los siguientes tipos de errores si es necesario:

    Tipo de error Caso de uso Recuperable
    INVALID Los datos del artículo o cualquiera de las opciones no son válidos. No
    NOT_FOUND No se encontró el elemento ni ninguna de las opciones. No
    PRICE_CHANGED Cambió el precio de un elemento o una combinación de complementos. Este error se puede tratar como recuperable.
    AVAILABILITY_CHANGED El importe solicitado para las líneas de pedido o cualquiera de las opciones no está disponible.
    REQUIREMENTS_NOT_MET No se cumple el pedido máximo o mínimo del pedido. Para ello, verifica si el precio del carrito es inferior a la tarifa.eligibleTransactionVolumeMin o superior a la tarifa.eligibleTransactionVolumeMax Consulta el ejemplo de validación del valor mínimo de pedido. No
  2. Muestra la lista validada de elementos de una sola línea con LineItemType REGULAR. La suma de todos los precios de elementos de una sola línea del carrito es el precio del carrito o SUBTOTAL.

Consulta ejemplos en validación de artículos del carrito.

Calcula los cargos del servicio

  1. Encuentra la entidad Tarifa correcta para el servicio según eligibleRegion, validFrom, validThrough y priority.
  2. Calcula el importe de la tarifa en función de si la entidad se definió con una propiedad price, percentageOfCart o pricePerMeter.
  3. Muestra los cargos del servicio de entrega o comida para llevar como un LineItem con LineItemType DELIVERY o FEE, respectivamente. Agrega la tarifa a la lista del Carrito.otherItems

Aplica promociones

  1. Busca la entidad Deal según la coincidencia del valor Promoción.coupon con el Acuerdo.dealCode.
  2. Valida el acuerdo y muestra un FoodOrderError si es necesario. Estos errores se pueden tratar como recuperables. Muestra los siguientes tipos de errores si es necesario:

    Tipo de error Caso de uso
    PROMO_NOT_RECOGNIZED No se reconoció el código del cupón.
    PROMO_EXPIRED Venció la validez del acuerdo.
    PROMO_ORDER_INELIGIBLE El pedido no es apto para el cupón.
    PROMO_NOT_APPLICABLE Cualquier otro motivo
  3. Calcula el importe del precio del acuerdo según Acuerdo.discount o Acuerdo.discountPercentage

  4. Aplica el importe del precio del acuerdo con el total del carrito o el total de la tarifa según el Acuerdo.dealType

  5. Devuelve el carrito.promotions con la promoción aplicada.

  6. Muestra la promoción como un LineItem con LineItemType DISCOUNT. Agrega el descuento a la lista del Carrito.otherItems con un precio negativo.

Devuelve la respuesta

  1. Crea el ProposedOrder.cart, el carrito de respuestas es el mismo que el carrito de solicitudes si no se encuentran errores durante la validación.
  2. Muestra la lista ProposedOrder.otherItems, incluidos los impuestos, las tarifas, las propinas y el descuento, si se aplican. Consulta Gratuidad para obtener más detalles sobre cómo configurar el elemento de propina.
  3. Incluye el ProposedOrder.totalPrice si agregas el precio del carrito, las tarifas, el descuento, los impuestos y la propina.
  4. Muestra FoodOrderExtension.availableFulfillmentOptions con la FulfillmentOption respectiva. Actualiza el tiempo estimado de retiro o entrega a la hora esperada.
  5. Si se generaron FoodOrderErrors en las verificaciones de validación anteriores, haz lo siguiente:
    • Incluye StructuredResponse.error y la lista de errores en FoodErrorExtension.foodOrderErrors.
    • Muestra ProposedOrder en el campo correctedProposedOrder si todos los errores se pueden recuperar.
    • Muestra PaymentOptions en el campo paymentOptions si todos los errores se pueden recuperar.
    • De manera opcional, puedes incluir additionalPaymentOptions si hay otras opciones de pago disponibles y si todos los errores se pueden recuperar.
  6. Si no hay errores de validación, muestra proposedOrder y paymentOptions en el objeto CheckoutResponse. De manera opcional, puedes incluir additionalPaymentOptions si hay otras opciones de pago disponibles.