funzionalità di ordinazione anticipata v1

Puoi aggiungere il supporto nel tuo processo di evasione degli ordini per consentire agli utenti di pianificare in anticipo i ritiri e le consegne di cibo. Prima di implementare questo supporto nell'evasione degli ordini, crea un feed di inventario del servizio che specifichi le ore in cui gli utenti possono effettuare prenotazioni, come descritto nello schema del feed di inventario (AdvanceServiceDeliveryHoursSpecification).

Spazi per prenotazioni in anticipo

Google propone fasce orarie per ordini anticipati con incrementi di 15 minuti, fino a 7 giorni in anticipo, in base ai tempi di evasione di un ristorante o di un servizio (come definito in AdvanceServiceDeliveryHoursSpecification).

Per recuperare gli slot per l'ordine in anticipo proposti, utilizza i seguenti valori del campo fulfillmentPreference dell'oggetto FoodCartExtension al momento del pagamento:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Implementare le prenotazioni al momento del pagamento

La tabella seguente elenca i possibili modi in cui puoi implementare la risposta dell'evasione degli ordini al momento del pagamento quando gli utenti tentano di effettuare ordini.

Scenario Comportamento di evasione
L'ordine anticipato può essere evaso per lo spazio richiesto. Accetta il carrello P0M ("il prima possibile") o FUTURE_SLOT creando un ProposedOrder con lo stesso slot. Per un esempio di risposta al pagamento che accetta uno slot, consulta questo snippet di codice.
Non è possibile soddisfare l'ordine anticipato per lo slot richiesto. Il tuo fornitore di servizi di evasione degli ordini deve:
  1. Rifiuta il carrello P0M o FUTURE_SLOT richiesto e indica il motivo per cui non è possibile evadere l'ordine nell'oggetto FoodErrorExtension.
    • Se l'ordine non può essere evaso a causa della capacità, specifica un FoodOrderError di tipo di errore NO_CAPACITY.
    • Se l'ordine non può essere evaso perché il ristorante è chiuso, specifica un FoodOrderError di tipo di errore CLOSED.
    • Se l'ordine non può essere evaso per qualche altro motivo, specifica un FoodOrderError di tipo di errore UNAVAILABLE_SLOT.
  2. Se possibile, fornisci valori P0M o FUTURE_SLOT alternativi in correctedProposedOrder. Questi valori devono essere tutti gli slot di evasione validi per i prossimi 7 giorni a partire dall'ora corrente. Includi lo slot P0M se applicabile.

Per un esempio di risposta al pagamento che propone fasce orarie alternative, consulta questo snippet di codice.

Slot alternativi per l'evasione degli ordini

Al momento del pagamento, se le fasce orarie proposte da Google per l'ordine anticipato non sono adatte, il tuo Fulfillment può suggerire alternative utilizzando l'oggetto CheckoutResponseMessage.

Per specificare fasce orarie alternative per gli ordini anticipati, rispondi alla richiesta di pagamento con un messaggio FoodErrorExtension e imposta i seguenti valori:

  1. Nel parametro foodOrderErrors, specifica il tipo di errore (ad es. UNAVAILABLE_SLOT, NO_CAPACITY o CLOSED).
  2. Nel parametro correctedProposedOrder, fornisci valori alternativi P0M o FUTURE_SLOT tramite availableFulfillmentOptions.

Gli slot alternativi devono essere per i 7 giorni successivi al momento dell'ordine e devono includere tutti gli slot in cui il carrello richiesto dall'utente può essere evaso.

Ad esempio, supponiamo che le offerte speciali per il pranzo siano disponibili solo dal lunedì al venerdì dalle 11:00 alle 13:00. L'utente prova ad aggiungere al carrello le offerte per il pranzo, ma lo slot selezionato non è disponibile. In questo caso, l'evasione dell'ordine dovrebbe mantenere le specialità per il pranzo nel carrello e restituire solo gli slot dalle 11:00 alle 13:00 per i prossimi 7 giorni

Dovresti omettere l'oggetto correctedProposedOrder.Cart.fulfillmentPreference nella risposta.

Se non sono disponibili fasce orarie o se il ristorante o il servizio non supporta gli ordini anticipati, non è necessario fornire un correctedProposedOrder.

Consulta gli esempi riportati di seguito per i messaggi JSON tra il tuo team di evasione degli ordini e Google durante il flusso di richiesta e risposta di pagamento per un ordine anticipato, quando il ristorante o il servizio è disponibile per le prenotazioni.

Esempio: CheckoutRequest con slot di consegna

Lo snippet riportato di seguito mostra un esempio di richiesta di pagamento con una fascia oraria di consegna per ordini anticipati.

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

Esempio: CheckoutResponse che accetta lo slot

Lo snippet seguente mostra un esempio di risposta al pagamento in cui l'attività di evasione degli ordini accetta le fasce orarie proposte per gli ordini anticipati.

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

Esempio: CheckoutResponse con slot alternativi

Lo snippet riportato di seguito mostra un esempio di risposta al pagamento in cui l'attività di evasione degli ordini propone fasce orarie alternative per gli ordini anticipati. Tieni presente che l'oggetto correctedProposedOrder.Cart.fulfillmentPreference deve essere omesso nella risposta.

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

Implementare le prenotazioni al momento dell'invio dell'ordine

Al momento dell'invio dell'ordine, se si verifica un problema con gli slot per gli ordini anticipati, il valore SubmitOrderResponseMessage deve includere il motivo (ad es. UNAVAILABLE_SLOT o UNKNOWN) nell'oggetto RejectionInfo.

Aggiorna lo stato dell'ordine da CREATED a CONFIRMED nell'oggetto OrderState quando l'ordine viene accettato dal fornitore. Includi la fascia oraria selezionata nell'email di conferma inviata all'utente.

Se il tuo Fulfillment invia l'ordine al ristorante in un secondo momento, invia un update a Google utilizzando l'azione di aggiornamento dell'ordine asincrono.

Nell'oggetto OrderUpdate della risposta all'invio dell'ordine o negli aggiornamenti successivi degli ordini asincroni, includi un estimatedFulfillmentTimeIso8601 con il valore impostato come segue:

  • Quando lo stato dell'ordine è CREATED o CONFIRMED, imposta il valore sull'ora di consegna o ritiro pianificata dall'utente per l'ordine anticipato.
  • Se il ristorante o il servizio fornisce un tempo di consegna stimato più preciso, imposta il valore sul tempo di consegna o di ritiro stimato.

Esempio: SubmitOrderRequest con slot di consegna

Lo snippet riportato di seguito mostra un esempio di richiesta di invio dell'ordine che indica la fascia oraria dell'ordine anticipato selezionata dall'utente.

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

Esempio: SubmitOrderResponse che accetta l'ordine

Lo snippet seguente mostra un esempio di risposta all'invio dell'ordine in cui l'evasione conferma di aver accettato l'ordine anticipato dell'utente.

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

Esempio: SubmitOrderResponse che rifiuta l'ordine a causa della mancata disponibilità dello slot

Lo snippet riportato di seguito mostra un esempio di risposta all'invio dell'ordine in cui l'evasione rifiuta l'ordine anticipato di un utente a causa di uno spazio non disponibile.

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

Esempi di prenotazioni anticipate

Il tipo AdvanceServiceDeliveryHoursSpecification può essere utilizzato per specificare le ore di consegna o ritiro in modo che gli utenti possano pianificare in anticipo il loro ordine.

Nota : per l'evasione del servizio devi specificare due finestre di tempo distinte: la finestra di ordinazione, che specifica quando gli utenti possono effettuare un ordine, e la finestra di evasione, che specifica quando l'ordine deve essere evaso. L'oggetto OpeningHoursSpecification definisce quando l'utente può effettuare l'ordine. I relativi tempi di evasione secondari (ServiceDeliveryHoursSpecification o AdvanceServiceDeliveryHoursSpecification) definiscono quando l'ordine può essere eseguito.

L'esempio seguente definisce l'orario di un servizio per l'accettazione degli ordini anticipati, con intervalli di servizio di 15 minuti.

{
  "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'esempio seguente mostra come puoi specificare che il servizio è aperto per gli ordini in giornata il giorno di Natale, ma chiuso per gli ordini anticipati programmati per quel giorno. Questo esempio supporta i seguenti scenari:

  • Gli utenti possono effettuare un ordine il 25 dicembre per la consegna in giornata.
  • Gli utenti possono effettuare un ordine anticipato il 25 dicembre per la consegna programmata per il 27 dicembre.
  • Gli utenti non possono effettuare un ordine anticipato il 22 dicembre per la consegna programmata il 25 dicembre.
{
  "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'esempio seguente mostra come specificare che il servizio è chiuso per gli ordini in giornata o per gli ordini anticipati programmati per il giorno di Natale, ma è aperto per gli ordini anticipati programmati per un giorno successivo. Questo esempio supporta i seguenti scenari:

  • Gli utenti non possono effettuare un ordine il 25 dicembre per la consegna in giornata.
  • Gli utenti possono effettuare un ordine anticipato il 25 dicembre per la consegna programmata per il 27 dicembre.
  • Gli utenti non possono effettuare un ordine anticipato il 22 dicembre per la consegna programmata il 25 dicembre.
{
  "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"
    }
  ]
}

Il seguente servizio di esempio accetta ordini 24 ore su 24, 7 giorni su 7 e consegna dalle 10:00 alle 02:59:59 nei giorni feriali:

...
{
  "@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"
    }
  }
}
...

Il seguente servizio di esempio accetta ordini ogni giorno dalle 8:00 alle 23:59:59 e i clienti possono scegliere una consegna entro un'ora o uno degli slot:

...
{
  "@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'esempio seguente mostra un caso in cui il negozio è aperto dalle 08:00 alle 23:59:59 nei giorni feriali, ma dalle 08:00 alle 18:59 nei fine settimana. Gli ordini non vengono accettati 24 ore su 24, 7 giorni su 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"
      }
    }
  ]
}
...