Promotions

Les promotions vous permettent, ainsi qu'à Google, d'inciter les clients à essayer votre service de commande de repas avec des remises. Google prend en charge l'intégration des actions de bout en bout pour vos commandes dans votre système de gestion des promotions.

Les types de remises suivants sont acceptés:

  • Codes promotionnels sponsorisés par Google:codes promotionnels qui sont préremplis automatiquement par Google ou saisis par les utilisateurs.
  • Codes promotionnels sponsorisés par des tiers:codes promotionnels que les utilisateurs peuvent saisir et fournis par votre service de commande de repas.
  • Remises automatiques sponsorisées par un tiers:remises que votre service de commande de repas applique automatiquement sans code promotionnel.

Quel que soit le type de remise, Google envoie un appel de paiement au traitement de votre commande de repas pour vérifier et appliquer la remise.

En tant que développeur d'un service de commande de repas, vous devez apporter quelques modifications à votre implémentation afin de calculer des remises pour les codes promotionnels valides ou d'envoyer des erreurs en cas de codes promotionnels non valides, de gérer les limites d'utilisation des codes promotionnels et de suivre les données comptables pour les remboursements.

Traiter les promotions

Pour implémenter un traitement compatible avec les promotions, procédez comme suit:

  1. Configurer l'intégration des promotions (Ignorez cette étape si vous n'utilisez pas de codes promotionnels sponsorisés par Google.)
  2. Implémentez le règlement avec des promotions.
  3. Utilisez l'option "Envoyer une commande avec promotions".

Configurer l'intégration des promotions

Cette section explique comment configurer l'intégration des promotions si vous prévoyez d'utiliser des codes promotionnels sponsorisés par Google. Si vous souhaitez n'accepter que les codes promotionnels ou les remises dont bénéficie un tiers, vous pouvez spécifier votre propre configuration et ignorer cette section.

Google spécifie le type de promotion à sponsoriser et vous contacte pour configurer l'intégration. Nous fournissons les informations suivantes:

  • Montant de la remise.
  • Valeur minimale du panier.
  • Les dates de début et de fin d'utilisation des codes promotionnels.
  • Montant maximal en dollars alloué à la campagne de promotion.
  • Nombre de fois où les codes promotionnels peuvent être utilisés.

Exemples de codes promotionnels:

  • FopaNewUser: 10% (pourcentage fixe) avec un maximum de 50 $de remise.
  • FopaMoreThan50: 10 $ (remise fixe)

Si Google décide de ne plus appliquer le code, vous serez contacté.

Configurer les paiements

Contactez votre consultant Google EAP pour mettre en place le processus de versement. Google ne rembourse les transactions impliquant des codes promotionnels sponsorisés par Google que si l'état final de la commande correspond à l'un des états suivants:

  • CONFIRMED
  • IN_TRANSIT
  • READY_FOR_PICKUP
  • IN_PREPARATION
  • FULFILLED

Implémenter le paiement avec des promotions

Cette section explique comment implémenter le processus de règlement lorsque vous acceptez les codes promotionnels (parrainés par Google ou par un tiers). Pour les remises automatiques sponsorisées par des tiers, il vous suffit de renvoyer la ligne de remise dans la CheckoutResponseMessage (aucune vérification du code promotionnel n'est nécessaire).

Lors du traitement de la commande de repas, Google envoie un seul code promotionnel dans la CheckoutRequestMessage à votre traitement. Les utilisateurs peuvent modifier leur panier ou leur code promotionnel en cas de demande de paiement répétée.

Pour vérifier si c'est la première fois que l'utilisateur applique un code promotionnel, procédez comme suit:

  • Codes promotionnels sponsorisés par Google: Google vérifie si un utilisateur connu essaie à nouveau d'utiliser le même code promotionnel. Aucune action n'est requise de votre part.
  • Codes promotionnels sponsorisés par des tiers ou remises automatiques: si vous n'avez pas implémenté l'association de comptes ni l'activation par l'utilisateur, vous ne pourrez pas consulter les informations de l'utilisateur lors du traitement de sa demande de règlement. Vérifiez plutôt cela lors du traitement SubmitOrderRequestMessage, à l'aide des détails Contact (tels que l'adresse e-mail de l'utilisateur) de l'objet FoodCartExtension.

Identifiez les erreurs ou calculez les remises sur votre traitement en fonction de la dernière demande de paiement. Lorsque vous procédez ainsi, assurez-vous que votre système ne conserve pas d'informations d'état obsolètes.

Vérifier la validité des codes promotionnels

Votre traitement doit vérifier la validité ou l'éligibilité d'un code promotionnel donné par rapport à des conditions spécifiques, telles que la date d'expiration, l'utilisation maximale et la remise maximale. Ensuite, répondez de manière appropriée dans le CheckoutResponseMessage avec la remise calculée ou avec foodOrderErrors si le code promotionnel ne peut pas être appliqué. Si vous détectez des erreurs dans le code promotionnel, suivez la procédure décrite dans la section Gérer les erreurs liées aux promotions.

L'extrait de code suivant présente un exemple d'attribut foodOrderErrors pour un code promotionnel. Assurez-vous que correctedProposedOrder n'inclut pas le nœud de promotions.

"foodOrderErrors": [
  {
    "error": "PROMO_NOT_APPLICABLE",
    // Copy promotions.coupon string from CheckoutRequest as the ID
    "id": "GoogleNewUser",
    "description": "Promotion could not be applied"
  }
],
"correctedProposedOrder": {// required ...},
"paymentOptions": {// required ...}

Remises sur le calcul

Si le code promotionnel est valide, votre traitement doit calculer la valeur en dollars de remise et renvoyer une valeur CheckoutResponseMessage avec la valeur de remise calculée dans le tableau otherItems. Le prix total de la commande ne doit pas être négatif. Si le montant de la remise dépasse le montant du panier, renvoyez le montant maximal en dollars pour que le montant total de la commande soit égal à 0 $.

L'extrait de code suivant présente un exemple de section CheckoutResponseMessage pour la remise promotionnelle:

"proposedOrder": {
   "otherItems": [
      . . .
      {
        "name": "Discount",
        // copy promotions.coupon field from CheckoutRequest as the id
        "id": "GoogleNewUser",
        "price": {
          "type": "ESTIMATE",
          "amount": {
          "currencyCode": "USD",
          "units": "-3",
          "nanos": -500000000
        }
      },
      "type": "DISCOUNT",
    }
  ]
}

Lancement de promotions inutilisées

Toutes les demandes de paiement ne mènent pas à une demande d'envoi de commande. Si votre traitement met en attente une promotion au moment du règlement, assurez-vous de mettre en place un mécanisme permettant de lever cette suspension si la promotion n'est pas revendiquée via l'envoi de la commande après un certain temps. Cela garantit que votre service de commande de repas respecte le quota de campagne approprié.

Gérer les erreurs liées aux promotions

Si votre traitement détermine que le code promotionnel d'un CheckoutRequestMessage n'est pas valide (par exemple, s'il a expiré, n'est pas valide ou n'est pas reconnu), envoyez une CheckoutResponseMessage avec un foodOrderError contenant le code d'erreur applicable et le texte de motif, ainsi que les objets correctedProposedOrder et paymentOptions.

Si le traitement détecte plusieurs erreurs de code promotionnel à partir de la même requête, renvoyez les erreurs non récupérables avant de renvoyer les erreurs récupérables. Hiérarchisez vos vérifications comme suit (de la priorité élevée à faible):

  • PROMO_NOT_RECOGNIZED
  • PROMO_EXPIRED
  • PROMO_USER_INELIGIBLE
  • PROMO_ORDER_INELIGIBLE
  • PROMO_NOT_APPLICABLE

Exemples

Voici un exemple de demande de règlement avec un code promotionnel:

{
    "accessToken": "test_access_token",
    "lastSeen": "2018-06-22T19:25:39Z"
  },
  "conversation": {
    "conversationId": "XYZ"
  },
  "inputs": [
    {
      "intent": "actions.foodordering.intent.CHECKOUT",
      "arguments": [
        {
          "extension": {
            "@type": "type.googleapis.com/google.actions.v2.orders.Cart",
            "merchant": {
              "id": "https://www.exampleprovider.com/merchant/id1",
              "name": "Falafel Bite"
            },
            "lineItems": [
              {
                "name": "Falafel Tray",
                "type": "REGULAR",
                "id": "sample_item_offer_id_1",
                "quantity": 1,
                "price": {
                  "type": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "units": "9",
                    "nanos": 950000000
                  }
                },
                "offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
                "extension": {
                  "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                }
              }
            ],
            "promotions": [
              {
                "coupon": "FOPAACTIVECODE"
              }
            ],
            "extension": {
              "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
              "fulfillmentPreference": {
                "fulfillmentInfo": {
                  "pickup": {
                    "pickupTimeIso8601": "P0M"
                  }
                }
              }
            }
          }
        }
      ]
    }
  ],
  "directActionOnly": true,
  "isInSandbox": true
}

Voici la réponse du processus de règlement correspondant si le code promotionnel est valide:

{
  "expectUserResponse": false,
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "structuredResponse": {
            "checkoutResponse": {
              "proposedOrder": {
                "otherItems": [
                  {
                    "name": "Delivery Fees",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "3",
                        "nanos": 500000000
                      }
                    },
                    "type": "DELIVERY"
                  },
                  {
                    "name": "Tax",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "1",
                        "nanos": 370000000
                      }
                    },
                    "type": "TAX"
                  },
                  {
                    "name": "Promotion",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "-5",
                        "nanos": 0
                      }
                    },
                    "id": "FOPAACTIVECODE",
                    "type": "DISCOUNT"
                  }
                ],
                "cart": {
                  "merchant": {
                    "id": "https://www.exampleprovider.com/merchant/id1",
                    "name": "Falafel Bite"
                  },
                  "lineItems": [
                    {
                      "name": "Falafel Tray",
                      "type": "REGULAR",
                      "id": "2529103",
                      "quantity": 1,
                      "price": {
                        "type": "ESTIMATE",
                        "amount": {
                          "currencyCode": "USD",
                          "units": "9",
                          "nanos": 950000000
                        }
                      },
                      "offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
                      "extension": {
                        "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                      }
                    }
                  ],
                  "promotions": [
                    {
                      "coupon": "FOPAACTIVECODE"
                    }
                  ],
                  "extension": {
                    "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
                    "fulfillmentPreference": {
                      "fulfillmentInfo": {
                        "pickup": {
                          "pickupTimeIso8601": "P0M"
                        }
                      }
                    }
                  }
                },
                "totalPrice": {
                  "type": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "units": "9",
                    "nanos": 820000000
                  }
                },
                "extension": {
                  "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
                  "availableFulfillmentOptions": [
                    {
                      "fulfillmentInfo": {
                        "pickup": {
                          "pickupTimeIso8601": "P0M"
                        }
                      },
                      "expiresAt": "2018-06-22T19:30:52.596Z"
                    }
                  ]
                }
              },
              "orderOptions": {},
              "paymentOptions": {
                "googleProvidedOptions": {
                  "tokenizationParameters": {
                    "tokenizationType": "PAYMENT_GATEWAY",
                    "parameters": {
                      "gateway": "stripe",
                      "stripe:publishableKey": "example_stripe_client_key",
                      "stripe:version": "2017-04-06"
                    }
                  },
                  "supportedCardNetworks": [
                    "AMEX",
                    "DISCOVER",
                    "MASTERCARD",
                    "VISA",
                    "JCB"
                  ],
                  "prepaidCardDisallowed": true
                }
              }
            }
          }
        }
      ],
      "suggestions": []
    }
  }
}

Voici un exemple de réponse au règlement si le code promotionnel n'est pas valide:

{
  "expectUserResponse": false,
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "structuredResponse": {
            "error": {
              "foodOrderErrors": [
                {
                  "error": "PROMO_NOT_RECOGNIZED",
                  "id": "SOMEPROMO",
                  "description": "Coupon not found"
                }
              ],
              "correctedProposedOrder": {
                "cart": {
                  "merchant": {
                    "id": "https://www.exampleprovider.com/merchant/id1",
                    "name": "Falafel Bite"
                  },
                  "lineItems": [
                    {
                      "id": "sample_item_offer_id_4",
                      "name": "Prawns Biryani",
                      "type": "REGULAR",
                      "quantity": 1,
                      "price": {
                        "type": "ESTIMATE",
                        "amount": {
                          "currencyCode": "USD",
                          "units": "18",
                          "nanos": 750000000
                        }
                      },
                      "offerId": "https://www.exampleprovider.com/menu/item/offer/id4",
                      "extension": {
                        "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                      }
                    }
                  ],
                  "extension": {
                    "fulfillmentPreference": {
                      "fulfillmentInfo": {
                        "pickup": {
                          "pickupTimeIso8601": "P0M"
                        }
                      }
                    },
                    "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension"
                  },
                  "promotions": []
                },
                "otherItems": [
                  {
                    "name": "Tax",
                    "type": "TAX",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "1",
                        "nanos": 650000000
                      }
                    }
                  }
                ],
                "termsOfServiceUrl": "https://exampleprovider.com/terms",
                "totalPrice": {
                  "type": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "units": "20",
                    "nanos": 400000000
                  }
                },
                "extension": {
                  "availableFulfillmentOptions": [
                    {
                      "fulfillmentInfo": {
                        "pickup": {
                          "pickupTimeIso8601": "PT0M"
                        }
                      }
                    }
                  ],
                  "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension"
                }
              },
              "paymentOptions": {
                "googleProvidedOptions": {
                  "prepaidCardDisallowed": false,
                  "billingAddressRequired": true,
                  "tokenizationParameters": {
                    "tokenizationType": "PAYMENT_GATEWAY",
                    "parameters": {
                      "gateway": "braintree",
                      "braintree:apiVersion": "v1",
                      "braintree:sdkVersion": "1.4.0",
                      "braintree:merchantId": "example_braintree_merchant_ID",
                      "braintree:clientKey": "example_braintree_client_key",
                      "braintree:authorizationFingerprint": "example_braintree_fingerprint"
                    }
                  }
                }
              },
              "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension"
            }
          }
        }
      ]
    }
  }
}

Implémenter l'envoi de commande avec des promotions

Dans le traitement de votre commande, vérifiez si c'est la première fois que l'utilisateur applique un code promotionnel. Lors du traitement de SubmitOrderRequestMessage, vous pouvez vérifier cela à l'aide des détails Contact (tels que l'adresse e-mail de l'utilisateur) de l'objet FoodCartExtension.

Nous vous conseillons également de revérifier l'applicabilité du code promotionnel:

  • Si le code est applicable, confirmez la commande et marquez le bon de réduction utilisé.
  • Si le code n'est plus applicable:refusez la commande avec l'erreur PROMO_NOT_APPLICABLE. Vous pouvez indiquer un motif de refus spécifique en utilisant le même mécanisme que pour FoodOrderUpdateExtension.

Exemples

Voici un exemple de demande de commande avec promotions:

{
  "conversation": {
    "conversationId": "example_conversation_ID"
  },
  "inputs": [
    {
      "intent": "actions.intent.TRANSACTION_DECISION",
      "arguments": [
        {
          "transactionDecisionValue": {
            "order": {
              "finalOrder": {
                "cart": {
                  "merchant": {
                    "id": "https://www.exampleprovider.com/merchant/id1",
                    "name": "Falafel Bite"
                  },
                  "lineItems": [
                    {
                      "name": "Falafel Tray",
                      "type": "REGULAR",
                      "id": "sample_item_offer_id_1",
                      "quantity": 1,
                      "price": {
                        "type": "ESTIMATE",
                        "amount": {
                          "currencyCode": "USD",
                          "units": "9",
                          "nanos": 950000000
                        }
                      },
                      "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id1",
                      "extension": {
                        "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                      }
                    }
                  ],
                  "promotions": [
                    {
                      "coupon": "FOPAACTIVECODE"
                    }
                  ],
                  "extension": {
                    "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
                    "fulfillmentPreference": {
                      "fulfillmentInfo": {
                        "pickup": {
                          "pickupTimeIso8601": "P0M"
                        }
                      }
                    },
                    "contact": {
                      "displayName": "Food Ordering",
                      "email": "example.provider@gmail.com",
                      "phoneNumber": "+19993334444",
                      "firstName": "Food",
                      "lastName": "Ordering"
                    }
                  }
                },
                "otherItems": [
                  {
                    "name": "Delivery Fees",
                    "type": "DELIVERY",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "3",
                        "nanos": 500000000
                      }
                    }
                  },
                  {
                    "name": "Tax",
                    "type": "TAX",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "1",
                        "nanos": 370000000
                      }
                    }
                  },
                  {
                    "name": "Promotion",
                    "type": "DISCOUNT",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "-5"
                      }
                    },
                    "id": "FOPAACTIVECODE"
                  },
                  {
                    "name": "Subtotal",
                    "type": "SUBTOTAL",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD",
                        "units": "9",
                        "nanos": 950000000
                      }
                    }
                  },
                  {
                    "name": "Tip",
                    "type": "GRATUITY",
                    "price": {
                      "type": "ESTIMATE",
                      "amount": {
                        "currencyCode": "USD"
                      }
                    }
                  }
                ],
                "totalPrice": {
                  "type": "ESTIMATE",
                  "amount": {
                    "currencyCode": "USD",
                    "units": "9",
                    "nanos": 820000000
                  }
                },
                "extension": {
                  "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension"
                }
              },
              "googleOrderId": "example_google_order_ID",
              "orderDate": "2018-06-22T19:30:59.502Z",
              "paymentInfo": {
                "displayName": "example_display_name",
                "googleProvidedPaymentInstrument": {
                  "instrumentToken": "example_instrument_token"
                },
                "paymentType": "PAYMENT_CARD"
              },
              "locale": "en"
            }
          }
        }
      ]
    }
  ],
  "directActionOnly": true,
  "isInSandbox": true
}

Voici un exemple de réponse d'envoi de commande correspondante à partir d'un traitement si le code promotionnel est valide:

{
  "expectUserResponse": false,
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "structuredResponse": {
            "orderUpdate": {
              "actionOrderId": "example_action_order_ID",
              "orderState": {
                "state": "CREATED",
                "label": "Order is created with partner."
              },
              "updateTime": "2018-06-22T19:31:01.556Z",
              "orderManagementActions": [
                {
                  "type": "CALL_RESTAURANT",
                  "button": {
                    "title": "Call Us",
                    "openUrlAction": {
                      "url": "tel:+1-111-111-1111"
                    }
                  }
                },
                {
                  "type": "EMAIL",
                  "button": {
                    "title": "Email Us",
                    "openUrlAction": {
                      "url": "mailto:example.provider@gmail.com"
                    }
                  }
                },
                {
                  "type": "CUSTOMER_SERVICE",
                  "button": {
                    "title": "Customer Service",
                    "openUrlAction": {
                      "url": "http://www.google.com"
                    }
                  }
                }
              ]
            }
          }
        }
      ],
      "suggestions": []
    }
  }
}

Voici un exemple de réponse à l'envoi d'une commande lorsque le code promotionnel n'est pas valide:

"orderUpdate": {
  "actionOrderId": "sample_action_order_id",
  "orderState": {
    "state": "REJECTED",
    "label": "Order rejected."
  },
  "updateTime": "2017-05-10T02:30:00.000Z",
  "rejectionInfo": {
    "type": "PROMO_NOT_APPLICABLE",
    "reason": "Sorry, there's something wrong. Try another code?"
  },
  "orderManagementActions": [
    {
      "type": "CUSTOMER_SERVICE",
      "button": {
        "title": "Contact customer service",
        "openUrlAction": {
          "url": "mailto:support@example.com"
        }
      }
    },
    {
      "type": "EMAIL",
      "button": {
        "title": "Email restaurant",
        "openUrlAction": {
          "url": "mailto:example.provider@example.com"
        }
      }
    },
    {
      "type": "CALL_RESTAURANT",
      "button": {
        "title": "Call restaurant",
        "openUrlAction": {
          "url": "tel:+19993334444"
        }
      }
    }
  ],
  "infoExtension": {
    "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
    "foodOrderErrors": [
      {
        "error": "PROMO_USER_INELIGIBLE",
        "description": "Sorry, you can only use this promotion once."
      }
    ]
  }
}