Configurer le paiement

Le processus de paiement est appelé lorsqu'un utilisateur crée un panier. Le contenu du panier de l'utilisateur et les détails de la commande sont envoyés à votre service Web de commande de bout en bout. Ces informations sont validées par votre service Web. Vous pouvez ensuite continuer ou modifier le panier si nécessaire.

Le gestionnaire de paiement de votre service Web doit répondre aux requêtes POST. Lorsqu'un client choisit de procéder au paiement, Google envoie au service Web de commande de bout en bout un corps de requête JSON sous la forme d'un CheckoutRequestMessage, qui contient les détails de l'Cart du client. Votre service Web répond ensuite par un CheckoutResponseMessage. Le schéma suivant illustre le processus.

La réponse CheckoutResponseMessage renvoie le panier non modifié du client ou une erreur.

À la réception d'une demande de paiement, votre service Web de commande de bout en bout doit:

  • Vérifiez la validité du panier en fonction des prix actuels des articles, de la disponibilité et du service du fournisseur.
  • Calculez le prix total (y compris les remises, les taxes et les frais de livraison).
  • Si l'opération réussit, renvoyez un panier non modifié.
  • En cas d'échec, envoyez un message d'erreur et proposez une nouvelle commande.

Avant de commencer à implémenter le règlement, nous vous recommandons de consulter la documentation Présentation du traitement.

Message de demande de paiement

Afin de valider le panier du client, lorsqu'un client choisit de payer, Google envoie une requête à votre service Web avec un corps JSON sous la forme d'un CheckoutRequestMessage. La commande client n'est pas passée avant la fin du processus de commande de bout en bout.

Les données contenues dans une CheckoutRequestMessage incluent les éléments suivants:

  • Intent: le champ inputs[0].intent de chaque corps de requête de paiement contient la valeur de la chaîne actions.foodordering.intent.CHECKOUT.
  • Panier: le champ inputs[0].arguments[0].extension d'une requête de paiement contient un objet Cart qui représente le panier du client.
  • Livraison ou récupération: le champ d'extension de l'objet Cart contient un objet FoodCartExtension qui spécifie les propriétés de la livraison ou de la récupération :
    • Pour les commandes en livraison, l'objet FoodCartExtension inclut l'adresse de livraison.
    • Pour les commandes à emporter ou à emporter, l'objet FoodCartExtension ne contient aucune information de localisation.
  • Bac à sable: le champ isInSandbox d'une requête de paiement contient une valeur booléenne indiquant si la transaction utilise les paiements en bac à sable.

Exemple de demande de paiement

Voici un exemple 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
}

Message de réponse au règlement

Après avoir reçu une requête du service de commande de bout en bout, votre service Web de paiement doit la traiter et répondre avec une CheckoutResponseMessage. L'élément CheckoutResponseMessage doit couvrir une requête réussie ou échouée.

Requête réussie

Si une requête de paiement aboutit, CheckoutResponseMessage doit inclure ProposedOrder et PaymentOptions:

  • ProposedOrder

    • cart: objet cart identique au panier fourni dans CheckoutRequestMessage. Si le contenu du panier doit être modifié, le CheckoutResponseMessage doit inclure à la place un FoodErrorExtension avec un ProposedOrder corrigé.
    • otherItems: éléments ajoutés par le fournisseur, comme les frais de livraison, les taxes et autres frais. Il peut également inclure des pourboires ajoutés par l'utilisateur.
    • totalPrice: prix total de la commande.
    • extension: FoodOrderExtension qui définit les informations de traitement de la commande, telles que le délai de livraison.
  • PaymentOptions

    • La configuration du traitement des paiements est abordée ultérieurement dans Configurer Google Pay. Vous pouvez utiliser l'espace réservé JSON dans votre CheckoutResponseMessage jusqu'à ce que vous soyez prêt à implémenter le traitement des paiements.
    • Pour ajouter des options de paiement d'espaces réservés dans votre CheckoutResponseMessage, consultez l'exemple ci-dessous, qui utilise un exemple de passerelle de paiement pour PaymentOptions.

Exemple de réponse réussie

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

Échec de la demande

Si une demande de règlement échoue, CheckoutResponseMessage doit inclure FoodErrorExtension, qui contient une liste d'éléments FoodOrderError décrivant les erreurs qui se sont produites. En cas d'erreur récupérable concernant la commande, telle qu'un changement de prix d'un article dans le panier, FoodErrorExtension doit inclure l'correctedProposedOrder.

Exemple de réponse indiquant un échec

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

Implémentation du règlement

Suivez les étapes ci-dessous lors de la mise en œuvre du règlement.

Valider le service

Renvoie FoodOrderError pour la première condition d'erreur de service détectée. Comme ces erreurs ne peuvent pas être récupérées, la première erreur rencontrée doit être renvoyée. Consultez la section Gérer les erreurs pour obtenir une description des erreurs récupérables.

  1. Lisez la propriété FulfillmentOptionInfo de la requête pour déterminer si le type de traitement est pour delivery ou pickup.
  2. Renvoyez les types d'erreur suivants si nécessaire:

    Type d'erreur Cas d'utilisation
    INVALID Le type de traitement n'est pas valide.
    NOT_FOUND Le type de traitement est introuvable.
    FERMÉE
    • Aucune fenêtre OperationHours n'est associée à la commande.
    • Il s'agit d'une commande "Dès que possible", et aucune heure de service ServiceHours n'est disponible pour l'heure actuelle.
    • Il y a une fermeture en urgence ou le service isDisabled est vrai.
    Notez que les fenêtres spéciales sont prioritaires sur les fenêtres standards. Consultez des exemples sur la validation de la fenêtre de commande et la suppression temporaire d'entités de service.
    UNAVAILABLE_SLOT La commande à l'avance ne peut pas être traitée.
    NO_CAPACITY Le restaurant est occupé et ne prend pas les commandes en ce moment.
    OUT_OF_SERVICE_AREA La commande ne peut pas être livrée à l'adresse de l'utilisateur. Consultez l'article Validation de l'adresse de livraison pour obtenir un exemple.
    NO_COURIER_AVAILABLE Impossible de livrer la commande en raison du personnel de livraison limité.

Valider le panier et définir son prix

  1. Recherchez chaque panier.lineItems et validez-le avec les données actuelles de votre système ou de celui du marchand. La valeur MenuItemOffer.sku de l'entité de flux est incluse en tant que LineItem.offerId. Si nécessaire, créez une erreur FoodOrderError pour chaque article. Créez un maximum d'une erreur pour chaque élément. Renvoyez les types d'erreur suivants si nécessaire:

    Type d'erreur Cas d'utilisation Restauration possible
    INVALID Les données sur les articles ou les données d'options ne sont pas valides. Non
    NOT_FOUND L'élément ou l'une des options est introuvable. Non
    PRICE_CHANGED Le prix d'un article ou d'une combinaison de modules complémentaires a changé. Cette erreur peut être considérée comme récupérable. Oui
    AVAILABILITY_CHANGED Le montant demandé pour les éléments de campagne ou l'une des options ne sont pas disponibles. Oui
    REQUIREMENTS_NOT_MET Le montant minimal ou maximal de la commande n'est pas atteint. Pour le déterminer, vérifiez si le prix du panier est inférieur aux frais.eligibleTransactionVolumeMin ou supérieur aux frais.eligibleTransactionVolumeMax Consultez l'exemple de validation du montant minimal de commande. Non
  2. Renvoyez la liste validée des éléments de ligne avec le paramètre LineItemType REGULAR. La somme de tous les prix de la ligne du panier est le prix du panier ou SUBTOTAL.

Consultez des exemples dans la section sur la validation des articles du panier.

Calculer les frais de service

  1. Recherchez l'entité Frais correcte pour le service en fonction des valeurs eligibleRegion, validFrom, validThrough et priority.
  2. Calculez le montant des frais selon que l'entité a été définie avec une propriété price, percentageOfCart ou pricePerMeter.
  3. Renvoyez les frais de service de livraison ou de vente à emporter en tant que LineItem avec LineItemType DELIVERY ou FEE respectivement. Ajoutez les frais à la liste Panier.otherItems.

Appliquer les promotions

  1. Recherchez l'entité Offre en fonction de la valeur de l'élément Promotion.coupon correspondant à l'offre.dealCode
  2. Validez l'offre et renvoyez une erreur FoodOrderError, si nécessaire. Ces erreurs peuvent être considérées comme récupérables. Renvoyez les types d'erreur suivants si nécessaire:

    Type d'erreur Cas d'utilisation
    PROMO_NOT_RECOGNIZED Le code promotionnel n'a pas été reconnu.
    PROMO_EXPIRED L'accord a expiré.
    PROMO_ORDER_INELIGIBLE La commande ne permet pas de bénéficier du bon de réduction.
    PROMO_NOT_APPLICABLE Toute autre raison.
  3. Calculez le montant de l'accord en fonction de l'accord.discount ou de l'accord.discountPercentage

  4. Appliquez le montant de l'accord en utilisant le montant total du panier ou les frais totaux, en fonction de l'accord.dealType.

  5. Retournez le Panier.promotions avec la promotion appliquée.

  6. Renvoyez la promotion en tant que LineItem avec LineItemType DISCOUNT. Ajoutez la remise à Panier.otherItems avec un prix négatif.

Renvoyer la réponse

  1. Créez le ProposedOrder.cart, le panier de réponse est identique au panier de requête si aucune erreur n'est détectée lors de la validation.
  2. Renvoyez la liste ProposedOrder.otherItems, y compris les taxes, les frais, les pourboires et la remise, le cas échéant. Pour savoir comment configurer les récompenses, consultez la section Sans frais.
  3. Incluez la valeur ProposedOrder.totalPrice en ajoutant le prix du panier, les frais, la remise, les taxes et les pourboires.
  4. Renvoyez l'extension FoodOrderExtension.availableFulfillmentOptions avec l'option FulfillmentOption correspondante. Mettez à jour le délai de retrait ou de livraison estimé sur l'heure prévue.
  5. Si des erreurs FoodOrderError ont été générées lors des vérifications de validation précédentes :
    • Ajoutez StructuredResponse.error ainsi que la liste des erreurs dans FoodErrorExtension.foodOrderErrors.
    • Renvoyez ProposedOrder dans le champ correctedProposedOrder si toutes les erreurs peuvent être récupérées.
    • Renvoyez les PaymentOptions dans le champ paymentOptions si toutes les erreurs peuvent être récupérées.
    • Vous pouvez également inclure additionalPaymentOptions si d'autres options de paiement sont disponibles et si toutes les erreurs peuvent être récupérées.
  6. En l'absence d'erreurs de validation, renvoyez proposedOrder, paymentOptions dans l'objet CheckoutResponse. Vous pouvez également inclure additionalPaymentOptions si d'autres options de paiement sont disponibles.