funzionalità v1 per ordinazione

Puoi aggiungere il supporto nell'evasione degli ordini per consentire agli utenti di programmare in anticipo gli ordini di cibo da asporto e con consegna a domicilio. Prima di implementare questo supporto nell'evasione degli ordini, crea un feed di inventario dei servizi che specifichi gli orari a cui gli utenti possono effettuare ordini in anticipo, come descritto nello schema del feed di inventario (AdvanceServiceDeliveryHoursSpecification).

Slot ordine anticipato

Google propone slot per ordini anticipati con incrementi di 15 minuti, fino a un massimo di 7 giorni in base ai tempi di evasione degli ordini di un ristorante o di un servizio (come definiti nei AdvanceServiceDeliveryHoursSpecification).

Per recuperare gli slot con ordine proposto, utilizza i seguenti valori dal campo fulfillmentPreference dell'oggetto FoodCartExtension al momento del pagamento:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Implementare gli ordini anticipati al momento del pagamento

La tabella riportata di seguito elenca i possibili modi in cui puoi implementare la risposta dell'evasione dell'ordine al momento del pagamento, quando gli utenti provano a effettuare ordini.

Scenario Comportamento dell'evasione degli ordini
È possibile completare l'ordine anticipato per lo slot richiesto. Accetta il carrello P0M ("il prima possibile") o FUTURE_SLOT creando una ProposedOrder con la stessa area annuncio. Per un esempio di risposta al pagamento che accetta un'area annuncio, consulta questo snippet di codice.
Impossibile completare l'ordine anticipato per lo slot richiesto. Il fulfillment 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 completato a causa della capacità, specifica un FoodOrderError di tipo di errore NO_CAPACITY.
    • Se l'ordine non può essere completato perché il ristorante è chiuso, specifica un valore FoodOrderError di tipo CLOSED.
    • Se l'ordine non può essere completato per altri motivi, specifica un valore FoodOrderError di tipo di errore UNAVAILABLE_SLOT.
  2. Se possibile, fornisci valori P0M o FUTURE_SLOT alternativi in correctedProposedOrder. Questi valori devono corrispondere a tutti gli slot di evasione degli ordini validi per i 7 giorni successivi a partire dall'ora attuale. Se applicabile, includi lo slot P0M.

Per un esempio di risposta al pagamento che propone slot alternativi, consulta questo snippet di codice.

Slot alternativi per l'evasione degli ordini

Al momento del pagamento, se gli slot con ordine in anticipo proposto da Google non sono adatti, il tuo evasione può suggerire alternative utilizzando l'oggetto CheckoutResponseMessage.

Per specificare slot alternativi per gli ordini anticipati, rispondi alla richiesta di pagamento con un 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 P0M o FUTURE_SLOT alternativi tramite availableFulfillmentOptions.

Gli slot alternativi devono riguardare i 7 giorni successivi al momento del posizionamento dell'ordine e includere tutti gli slot in cui è possibile evadere il carrello richiesto dall'utente.

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

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

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

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

Esempio: CheckoutRequest con area di consegna

Lo snippet riportato di seguito mostra un esempio di richiesta di pagamento con un'area di consegna dell'ordine anticipato.

{
  "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 accetta l'area annuncio

Lo snippet riportato di seguito mostra un esempio di risposta al pagamento in cui l'evasione degli ordini accetta gli slot dell'ordine anticipato proposti.

{
  "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 aree alternative

Lo snippet riportato di seguito mostra un esempio di risposta al pagamento in cui l'evasione degli ordini propone slot alternativi 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 gli ordini anticipati al momento dell'invio dell'ordine

Al momento dell'invio dell'ordine, se si verifica un problema con gli slot dell'ordine anticipato, SubmitOrderResponseMessage deve includere il motivo (ad esempio 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 fulfillment invia l'ordine al ristorante in un secondo momento, invia a Google un aggiornamento utilizzando l'Azione di aggiornamento dell'ordine asincrono.

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

  • Quando lo stato dell'ordine è CREATED o CONFIRMED, imposta il valore sull'orario di consegna o ritiro programmato dall'utente per l'ordine anticipato.
  • Quando i tempi di consegna stimati dal ristorante o dal servizio sono più precisi, imposta il valore sull'orario stimato per la consegna o il ritiro.

Esempio: SubmitOrderRequest con area di consegna

Lo snippet riportato di seguito mostra un esempio di richiesta di invio di un ordine che indica l'area annuncio di avanzamento 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 accetta l'ordine

Lo snippet riportato di seguito mostra un esempio di risposta relativa all'invio di un ordine in cui l'evasione degli ordini conferma che ha 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 ha rifiutato l'ordine a causa dell'indisponibilità dell'area annuncio

Lo snippet riportato di seguito mostra un esempio di risposta a "Invia ordine" in cui l'evasione dell'ordine rifiuta l'ordine anticipato di un utente a causa di un'area 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 ordini anticipati

Il tipo AdvanceServiceDeliveryHoursSpecification può essere utilizzato per specificare gli orari di consegna o di ritiro in cui gli utenti possono pianificare in anticipo l'ordine.

Nota : esistono due periodi di tempo distinti che devi specificare per l'evasione dell'ordine: la finestra di ordinazione, che specifica quando gli utenti possono effettuare un ordine, e la finestra di evasione degli ordini, che specifica quando l'ordine deve essere evaso. L'oggetto OpeningHoursSpecification definisce quando l'utente può effettuare l'ordine. I relativi tempi di evasione degli ordini secondari (ServiceDeliveryHoursSpecification o AdvanceServiceDeliveryHoursSpecification) definiscono quando è possibile evadere l'ordine.

L'esempio seguente definisce le ore di un servizio per l'accettazione di 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 specificare che il servizio è aperto per gli ordini dello stesso giorno il giorno di Natale, ma chiuso per gli ordini anticipati pianificati per quel giorno. Questo esempio supporta i seguenti scenari:

  • Gli utenti possono effettuare un ordine il 25 dicembre con la consegna in giornata.
  • Gli utenti possono effettuare un ordine anticipato il 25 dicembre per la consegna prevista per il 27 dicembre.
  • Gli utenti non possono effettuare un ordine anticipato il 22 dicembre con consegna prevista 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 sia chiuso per gli ordini lo stesso giorno o per gli ordini anticipati pianificati per il giorno di Natale, ma aperto per gli ordini avanzati pianificati per un giorno successivo. Questo esempio supporta i seguenti scenari:

  • Gli utenti non possono effettuare un ordine il 25 dicembre con consegna in giornata.
  • Gli utenti possono effettuare un ordine anticipato il 25 dicembre per la consegna prevista per il 27 dicembre.
  • Gli utenti non possono effettuare un ordine anticipato il 22 dicembre con consegna prevista 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 14: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 tutti i giorni dalle 8:00 alle 16:59:59 e i clienti possono scegliere di ricevere la consegna entro un'ora o scegliere 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 apre dalle 08:00 alle 16:59:59 nei giorni feriali, ma dalle 08:00 alle 18:59 nei fine settimana. Gli ordini non sono 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"
      }
    }
  ]
}
...