Vous pouvez ajouter une fonctionnalité dans votre traitement permettant aux utilisateurs de planifier à l'avance la livraison et le retrait de leurs commandes de repas. Avant d'implémenter cette fonctionnalité dans l'exécution, créez un flux d'inventaire de services qui spécifie les heures auxquelles les utilisateurs peuvent passer des commandes à l'avance, comme décrit dans le schéma du flux d'inventaire (AdvanceServiceDeliveryHoursSpecification
).
Créneaux horaires de commande anticipée
Google propose des créneaux de commande à l'avance par tranche de 15 minutes, jusqu'à sept jours à l'avance, en fonction des délais de traitement d'un restaurant ou d'un service (tels que définis dans AdvanceServiceDeliveryHoursSpecification
).
Pour récupérer les créneaux proposés pour la commande à l'avance, utilisez les valeurs suivantes du champ fulfillmentPreference
de l'objet FoodCartExtension
au moment du règlement:
PickupInfo.pickupTimeIso8601
DeliveryInfo.deliveryTimeIso8601
Implémenter les commandes anticipées lors du paiement
Le tableau ci-dessous présente les différentes façons d'implémenter la réponse de votre traitement au moment du règlement lorsque les utilisateurs tentent de passer commande.
Scénario | Comportement de traitement |
---|---|
La commande anticipée peut être traitée pour l'emplacement demandé. | Acceptez le panier P0M ("dès que possible") ou FUTURE_SLOT en créant un ProposedOrder avec le même emplacement. Pour obtenir un exemple de réponse de règlement acceptant un créneau horaire, consultez cet extrait de code. |
La commande anticipée ne peut pas être traitée pour le créneau horaire demandé. | Votre prestataire de traitement doit effectuer les opérations suivantes :
Pour voir un exemple de réponse de règlement proposant d'autres créneaux, consultez cet extrait de code. |
Autres créneaux horaires pour le traitement des commandes
Lors du règlement, si les créneaux proposés par Google pour la commande à l'avance ne conviennent pas, votre service de traitement peut suggérer d'autres créneaux à l'aide de l'objet CheckoutResponseMessage
.
Pour spécifier d'autres créneaux de commande anticipée, répondez à la requête de paiement avec un FoodErrorExtension
et définissez les valeurs suivantes:
- Dans le paramètre
foodOrderErrors
, spécifiez le type d'erreur (par exemple,UNAVAILABLE_SLOT
,NO_CAPACITY
ouCLOSED
). - Dans le paramètre
correctedProposedOrder
, indiquez d'autres valeursP0M
ouFUTURE_SLOT
viaavailableFulfillmentOptions
.
Les créneaux alternatifs doivent concerner les sept prochains jours à compter de la date de passation de la commande et inclure tous les créneaux au cours desquels le panier demandé par l'utilisateur peut être expédié.
Par exemple, imaginons que les plats du jour ne sont disponibles que du lundi au vendredi de 11h à 13h. L'utilisateur tente ensuite d'ajouter des plats du jour à son panier, mais l'heure sélectionnée n'est pas disponible. Dans ce cas, votre traitement doit conserver les plats du jour dans le panier et ne renvoyer que les créneaux de 11h à 13h pour les sept prochains jours.
Vous devez omettre l'objet correctedProposedOrder.Cart.fulfillmentPreference
dans votre réponse.
Si aucun créneau n'est disponible ou si le restaurant ou le service n'accepte pas les commandes à l'avance, vous n'avez pas besoin de fournir de correctedProposedOrder
.
Consultez les exemples ci-dessous pour les messages JSON échangés entre votre prestataire de traitement et Google lors du flux de requête et de réponse de paiement pour une commande anticipée, lorsque le restaurant ou le service est disponible pour les précommandes.
Exemple: CheckoutRequest avec créneau de livraison
L'extrait de code ci-dessous montre un exemple de requête de paiement avec un créneau de livraison de commande anticipée.
{
"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": "Cucina Venti"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
// Deliver at 6:30PM.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
},
"location": {
...
}
}
}
}
]
}
]
}
Exemple: CheckoutResponse acceptant l'emplacement
L'extrait de code ci-dessous montre un exemple de réponse de règlement dans lequel votre chaîne d'exécution accepte les créneaux de commande anticipée proposés.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"checkoutResponse": {
"proposedOrder": {
"id": "sample_proposed_order_id_1",
"cart": {
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Falafel Bite"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
// Same as the time in the request.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
},
"location": {
...
}
}
},
"totalPrice": {
"type": "ESTIMATE",
"amount": {
// Represents $16.75
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
// Send whole proposed order back.
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
// Same as the time in the request.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
]
}
},
"paymentOptions": {
...
}
}
}
}
]
}
}
}
Exemple: CheckoutResponse avec des emplacements de remplacement
L'extrait de code ci-dessous montre un exemple de réponse de règlement dans lequel votre chaîne d'exécution propose d'autres créneaux de commande anticipée. Notez que l'objet correctedProposedOrder.Cart.fulfillmentPreference
doit être omis dans votre réponse.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"error": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
"foodOrderErrors": [
{
"error": "UNAVAILABLE_SLOT", // Cart level error
"description": "The restaurant is closed."
}
],
"correctedProposedOrder": {
// Send whole original cart back,
// without the fulfillmentPreference.
"cart": {
...
},
"otherItems": {
...
},
"totalPrice": {
...
},
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T19:00:00-07:00"
}
},
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T19:30:00-07:00"
}
},
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T20:00:00-07:00"
}
}
]
}
},
"paymentOptions": {
...
}
}
}
}
]
}
}
}
Implémenter les commandes anticipées au moment de l'envoi de la commande
Lors de l'envoi de la commande, si un problème survient avec les créneaux de commande anticipée, votre SubmitOrderResponseMessage
doit inclure le motif (par exemple, UNAVAILABLE_SLOT
ou UNKNOWN
) dans l'objet RejectionInfo
.
Passez l'état de la commande de CREATED
à CONFIRMED
dans l'objet OrderState
lorsque la commande est acceptée par le fournisseur. Incluez la plage horaire sélectionnée dans l'e-mail de confirmation envoyé à l'utilisateur.
Si votre système de traitement envoie la commande au restaurant plus tard, envoyez une mise à jour à Google à l'aide de l'action de mise à jour de commande asynchrone.
Dans l'objet OrderUpdate
de la réponse d'envoi de commande de votre chaîne d'exécution ou des mises à jour de commande asynchrones ultérieures, incluez un estimatedFulfillmentTimeIso8601
dont la valeur est définie comme suit:
- Lorsque l'état de la commande est
CREATED
ouCONFIRMED
, définissez la valeur sur l'heure de livraison ou de retrait que l'utilisateur a planifiée pour sa commande anticipée. - Lorsque le restaurant ou le service indique un délai de livraison estimé plus précis, définissez la valeur sur le délai de livraison ou de retrait estimé.
Exemple: SubmitOrderRequest avec créneau de livraison
L'extrait de code ci-dessous montre un exemple de requête d'envoi de commande indiquant l'heure de commande anticipée sélectionnée par l'utilisateur.
{
"inputs": [
{
"intent": "actions.intent.TRANSACTION_DECISION",
"arguments": [
{
"transactionDecisionValue": {
"order": {
"finalOrder": {
"cart": {
"notes": "Guest prefers their food to be hot when it is delivered.",
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Cucina Venti"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
}
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
}
"contact": {
...
}
}
},
"totalPrice": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
"id": "sample_final_order_id",
"extension": {
// Send whole proposed order back.
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
]
}
},
"googleOrderId": "sample_google_order_id",
"orderDate": "2017-07-17T12:00:00Z",
"paymentInfo": {
...
}
}
}
}
]
}
]
}
Exemple: SubmitOrderResponse acceptant la commande
L'extrait de code ci-dessous montre un exemple de réponse d'envoi de commande dans laquelle votre traitement confirme avoir accepté la commande anticipée de l'utilisateur.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"orderUpdate": {
"actionOrderId": "sample_action_order_id",
"orderState": {
"state": "CREATED",
"label": "Order placed"
},
"receipt": {
"userVisibleOrderId": "userVisibleId1234"
},
"updateTime": "2017-07-17T12:00:00Z",
"orderManagementActions": [
...
],
"infoExtension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
// Same as the user selected time.
"estimatedFulfillmentTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
}
}
]
}
}
}
Exemple: SubmitOrderResponse refusant la commande en raison de l'indisponibilité d'un créneau
L'extrait de code ci-dessous montre un exemple de réponse d'envoi de commande dans laquelle votre traitement refuse la commande anticipée d'un utilisateur en raison d'un créneau horaire indisponible.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"orderUpdate": {
"actionOrderId": "sample_action_order_id",
"orderState": {
"state": "REJECTED",
"label": "Unavailable slot"
},
"rejectionInfo": {
// Note that this UNAVAILABLE_SLOT is different from the enum
// with the same name proposed for FoodOrderError.
"state": "UNAVAILABLE_SLOT",
"label": "Unavailable slot"
},
"updateTime": "2017-07-17T12:00:00Z",
"orderManagementActions": [
...
]
}
}
}
]
}
}
}
Exemples de commandes avancées
Le type AdvanceServiceDeliveryHoursSpecification
permet de spécifier les heures de livraison ou de retrait pour que les utilisateurs puissent planifier leur commande à l'avance.
Remarque : Vous devez spécifier deux périodes distinctes pour le traitement du service: la période de commande, qui indique quand les utilisateurs peuvent passer une commande, et la période de traitement, qui indique quand la commande doit être traitée. L'objet
définit le moment où l'utilisateur peut passer la commande. Les délais de traitement de ses enfants (OpeningHoursSpecification
ou ServiceDeliveryHoursSpecification
) définissent quand la commande peut être traitée.AdvanceServiceDeliveryHoursSpecification
L'exemple suivant définit les heures d'acceptation des commandes à l'avance d'un service, avec des intervalles de service de 15 minutes.
{ "hoursAvailable": [ { "@type": "OpeningHoursSpecification", "opens": "T00:00:00", // Ordering available 24 hours "closes": "T23:59:59", "deliveryHours": [ { "@type": "ServiceDeliveryHoursSpecification", "opens": "T09:00:00", // ASAP orders b/w 9am and 8:59:59pm "closes": "T21:00:00", "deliveryLeadTime": { "value": "60", "unitCode": "MIN" } }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T10:00:00", // Delivery between 10AM and 7:59:59PM "closes": "T20:00:00", "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart (ISO8601) "advanceBookingRequirement": { "minValue": 60, // The slot should be at least 60 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } ] } ] }
L'exemple suivant montre comment spécifier que le service est ouvert pour les commandes du même jour le jour de Noël, mais fermé pour les commandes avancées planifiées pour ce jour. Cet exemple est compatible avec les scénarios suivants:
- Les utilisateurs peuvent passer commande le 25 décembre pour une livraison le même jour.
- Les utilisateurs peuvent passer une commande anticipée le 25 décembre pour une livraison prévue le 27 décembre.
- Les utilisateurs ne peuvent pas passer de commande anticipée le 22 décembre pour une livraison prévue le 25 décembre.
{ "specialOpeningHoursSpecification": { "@type": "AdvanceServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // No advance ordering "closes": "T00:00:00" } }
L'exemple suivant montre comment spécifier que le service est fermé pour les commandes le même jour ou les commandes à l'avance planifiées pour le jour de Noël, mais ouvert pour les commandes à l'avance planifiées pour un autre jour. Cet exemple est compatible avec les scénarios suivants:
- Les utilisateurs ne peuvent pas passer de commande le 25 décembre pour une livraison le même jour.
- Les utilisateurs peuvent passer une commande anticipée le 25 décembre pour une livraison prévue le 27 décembre.
- Les utilisateurs ne peuvent pas passer de commande anticipée le 22 décembre pour une livraison prévue le 25 décembre.
{ "specialOpeningHoursSpecification": [ { "@type": "ServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // No ASAP ordering on Christmas "closes": "T00:00:00" }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // Orders cannot be scheduled for Christmas "closes": "T00:00:00" } ] }
L'exemple de service suivant accepte les commandes 24h/24, 7j/7 et livre les commandes entre 10h et 14h59 les jours de la semaine :
... { "@type": "OpeningHoursSpecification", "opens": "T00:00:00", "closes": "T23:59:59", "deliveryHours": { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T10:00:00", // Delivery starts at 10:00AM "closes": "T15:00:00", // Delivery ends at 3:00PM. Delivery from 10AM-2:59:59PM. "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart "advanceBookingRequirement": { "minValue": 60, // The slot should be at least 60 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } } ...
L'exemple de service suivant accepte les commandes tous les jours de 8h à 16h59:59. Les clients peuvent choisir une livraison dans l'heure ou l'un des créneaux horaires suivants :
... { "@type": "OpeningHoursSpecification", "opens": "T08:00:00", // Ordering opens at 8:00AM "closes": "T17:00:00", // Ordering closes at 5:00PM, last order at 4:59:59PM "deliveryHours": [ { "@type": "ServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "deliveryLeadTime": { "@type": "QuantitativeValue", "value": "60", // If no exact deliveryLeadTime, put a maximum time "unitCode": "MIN" } }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart "advanceBookingRequirement": { "minValue": 90, // The slot should be at least 90 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } ] } ...
L'exemple suivant montre un cas où le magasin est ouvert de 8h à 16h59:59 en semaine, mais de 8h à 18h30 le week-end. Les commandes ne sont pas acceptées 24h/24, 7j/7.
... { // On weekdays, ordering open from 8AM-4:59:59PM. "@type": "OpeningHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "deliveryHours": [ { // Fulfillment between 8AM-4:59:59PM on weekdays. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } }, { // Fulfillment between 8AM-6:59:59PM on weekends (even for orders placed on a // weekday). "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } } ] }, { // On weekends, one can place orders upto 6:59:59PM. "@type": "OpeningHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "deliveryHours": [ { // But fulfillment on weekdays is only till 4:59:59PM. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } }, { // Fulfillment on weekends is till 6:59:59PM. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } } ] } ...