Fonctionnalité de commande à l'avance v1

Vous pouvez ajouter une assistance dans votre traitement pour permettre aux utilisateurs de planifier un enlèvement et la livraison de repas à l'avance. Avant d'implémenter cette prise en charge dans le traitement, créez un flux d'inventaire de services spécifiant les horaires pour passer des commandes anticipées, comme décrit dans le schéma du flux d'inventaire (AdvanceServiceDeliveryHoursSpecification).

Emplacements pour commandes avancées

Google propose des créneaux de commande à l'avance par tranches de 15 minutes, pour une durée maximale de 7 jours en 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 d'avance proposés, utilisez les valeurs suivantes de la Champ fulfillmentPreference de l'objet FoodCartExtension lors du règlement:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Implémentez les commandes à l'avance lors du paiement

Le tableau ci-dessous répertorie les différentes manières d'implémenter le code de traitement au moment du paiement, lorsque les utilisateurs tentent de passer des commandes.

Scénario Comportement de traitement
La commande à l'avance peut être honorée pour le créneau demandé. Acceptez les P0M ("dès que possible") ou panier FUTURE_SLOT en créant un ProposedOrder avec le même emplacement. Pour obtenir un exemple de réponse de paiement acceptant un emplacement, consultez cet extrait de code.
La commande à l'avance ne peut pas être honorée pour le créneau demandé. Le fulfillment doit effectuer les opérations suivantes: <ph type="x-smartling-placeholder">
    </ph>
  1. Refuser l'élément P0M ou FUTURE_SLOT demandé panier et indiquez la raison pour laquelle la commande ne peut pas être honorée dans le champ objet FoodErrorExtension.
    • Si la commande ne peut pas être livrée en raison de sa capacité, indiquez une FoodOrderError de type d'erreur NO_CAPACITY.
    • Si la commande ne peut pas être honorée parce que le restaurant est fermé, spécifiez le type d'erreur pour FoodOrderError CLOSED
    • Si la commande ne peut pas être honorée pour une autre raison, spécifiez une FoodOrderError de type d'erreur UNAVAILABLE_SLOT
  2. Si possible, fournissez un autre P0M ou Valeurs FUTURE_SLOT dans correctedProposedOrder. Ces valeurs doivent correspondre à tous les emplacements de traitement valides pour les sept prochains jours à compter de l'heure actuelle. Inclure l'emplacement P0M le cas échéant.

Pour obtenir un exemple de réponse de paiement proposant d'autres emplacements, consultez cet extrait de code.

Emplacements alternatifs pour le traitement des commandes

Lors du règlement, si les créneaux de commande à l'avance proposés par Google ne sont pas adaptés, votre le fulfillment peut suggérer des alternatives à l'aide du CheckoutResponseMessage .

Pour spécifier d'autres créneaux de commande anticipée, répondez à la demande de paiement avec une FoodErrorExtension et définissez les valeurs suivantes:

  1. Dans le paramètre foodOrderErrors, spécifiez le type d'erreur (par exemple, UNAVAILABLE_SLOT, NO_CAPACITY ou CLOSED).
  2. Dans le paramètre correctedProposedOrder, indiquez un autre P0M ou Valeurs FUTURE_SLOT via availableFulfillmentOptions.

Les autres créneaux possibles devraient se situer au cours des sept prochains jours à compter de la date de la commande et inclure tous les emplacements dans lesquels le panier demandé par l'utilisateur peut être satisfaite.

Par exemple, supposons que les plats du jour ne sont disponibles que du lundi au vendredi. entre 11h et 13h. L’utilisateur essaie ensuite d’ajouter des plats du jour à son panier, mais le créneau sélectionné n'est pas disponible. Dans ce cas, votre fulfillment doit Conserver les plats du jour dans le panier et retourner uniquement les créneaux de 11 h à 13 h au cours des 7 prochains jours

Vous devez omettre l'objet correctedProposedOrder.Cart.fulfillmentPreference dans votre réponse.

S'il n'y a pas de créneaux disponibles, ou si le restaurant ou le service n'en propose pas de commandes anticipées, vous n'avez pas à fournir de correctedProposedOrder

Consultez les exemples ci-dessous pour les messages JSON échangés entre votre fulfillment et Google pendant le flux de demande et de réponse lors du règlement pour une commande anticipée, lorsque le un restaurant ou un service peuvent servir des précommandes.

Exemple: Demande de paiement avec créneau de livraison

L'extrait de code ci-dessous illustre un exemple de demande de règlement avec une commande anticipée emplacement de livraison.

{
  "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: La fonction CheckoutResponse accepte le créneau.

L'extrait de code ci-dessous montre un exemple de réponse à un règlement dans laquelle votre traitement accepte les emplacements 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 alternatifs

L'extrait de code ci-dessous montre un exemple de réponse à un règlement dans laquelle votre traitement propose d'autres créneaux pour les commandes à l'avance. 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": {
                ...
              }
            }
          }
        }
      ]
    }
  }
}

Mettre en œuvre les commandes anticipées lors de l'envoi de la commande

Lors de l'envoi de la commande, en cas de problème avec les créneaux de commande anticipée, votre SubmitOrderResponseMessage doit inclure le motif (par exemple, UNAVAILABLE_SLOT ou UNKNOWN) dans l'objet RejectionInfo.

Remplacez l'état de la commande CREATED par CONFIRMED dans la objet OrderState lorsque la commande est acceptée par le fournisseur. Incluez les créneau sélectionné dans l'e-mail de confirmation envoyé à l'utilisateur.

Si votre traitement envoie la commande au restaurant ultérieurement, envoyez un à l'aide de l'action de mise à jour de commande asynchrone.

Dans l'objet OrderUpdate de la réponse à l'envoi de la commande de votre traitement, ou les mises à jour de commandes asynchrones suivantes, incluez un estimatedFulfillmentTimeIso8601 avec la valeur définie comme suit:

  • Si l'état de la commande est CREATED ou CONFIRMED, 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 délai de livraison estimé du restaurant est plus précis ou service, définissez la valeur sur l'heure de livraison ou de retrait estimée.

Exemple: SubmitOrderRequest avec créneau de livraison

L'extrait de code ci-dessous montre un exemple de demande d'envoi de commande indiquant le à un emplacement de commande avancé que l'utilisateur a sélectionné.

{
  "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 accepter la commande

L'extrait de code ci-dessous montre un exemple de réponse d'envoi de commande dans laquelle votre fulfillment confirme qu'il a 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é du créneau

L'extrait de code ci-dessous montre un exemple de réponse d'envoi de commande dans laquelle votre le traitement refuse la commande anticipée d'un utilisateur en raison d'un créneau non disponible.

{
  "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 anticipées

Le type AdvanceServiceDeliveryHoursSpecification peut être utilisé pour spécifier les heures de livraison ou de retrait pour que les utilisateurs planifient leur commande à l'avance.

Remarque : Vous devez spécifier deux périodes distinctes. pour le traitement du service: la période de tri, qui spécifie à quel moment les utilisateurs peuvent placer un commande, et la période de traitement de la commande. La L'objet OpeningHoursSpecification définit quand l'utilisateur peuvent passer la commande. Ses délais de traitement enfant (ServiceDeliveryHoursSpecification) ou AdvanceServiceDeliveryHoursSpecification) définissent quand l'ordre peut être satisfaite.

L'exemple suivant définit les horaires d'un service pour l'acceptation des commandes à l'avance, 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 commandes le jour même le jour de Noël mais fermée pour les commandes à l'avance programmées pour ce jour-là. Cet exemple est compatible avec les scénarios suivants:

  • Les utilisateurs peuvent passer commande le 25 décembre pour une livraison le jour même.
  • Les utilisateurs peuvent passer une commande anticipée le 25 décembre pour une livraison prévue pour 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 commandes le jour même ou les commandes à l'avance planifiées pour le jour de Noël, mais ouvertes pour les commandes avancées planifiées pour un jour ultérieur. Cet exemple est compatible avec scénarios:

  • Les utilisateurs ne peuvent pas passer commande le 25 décembre avec une livraison le jour même.
  • Les utilisateurs peuvent passer une commande anticipée le 25 décembre pour une livraison prévue pour 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 les livre depuis De 10h à 14h59:59 en 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 quotidiennes de 8h à 16h59:59, et les clients peuvent opter pour une livraison dans l'heure qui suit ou choisir l'une des emplacements:

...
{
  "@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 ouvre de 8h à 16h59:59 le en semaine, mais de 8h à 18h59 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"
      }
    }
  ]
}
...