Dopo che un cliente ha inviato un ordine di cibo, puoi inviare un messaggio di aggiornamento dell'ordine al servizio Ordering End-to-End per informarci della modifica.
Di seguito sono riportati alcuni motivi comuni per l'invio di aggiornamenti sugli ordini:
- Il tempo di evasione stimato per l'ordine diventa disponibile o cambia.
- Lo stato di un ordine cambia.
- Non è più possibile evadere l'ordine.
- Il prezzo di un articolo del menu incluso nell'ordine è cambiato.
- Il cliente ha un nuovo modo per gestire il proprio ordine, ad esempio un numero di telefono dell'assistenza clienti o del ristorante.
- La ricevuta dell'ordine diventa disponibile.
Le sezioni seguenti forniscono dettagli su come gestire questi diversi scenari utilizzando gli aggiornamenti degli ordini.
Stati di transizione degli ordini
Un ordine può avere sei possibili stati. Questi stati e le relative possibili transizioni sono descritti nel seguente diagramma:
Quando un cliente invia per la prima volta un ordine, questo inizia con uno stato di
CREATED
, CONFIRMED
o REJECTED
. Puoi inviare un messaggio di aggiornamento dell'ordine per aggiornarne lo stato, a condizione che la transizione di stato sia valida. Lo stato CREATED
viene utilizzato quando la piattaforma del partner non può confermare o rifiutare l'ordine
immediatamente. Un esempio di caso d'uso è quando un cliente effettua un ordine tramite un aggregatore di servizi di consegna. L'aggregatore di servizi di consegna riceve l'ordine da Google e invia le informazioni al ristorante. Una volta che il ristorante ha ricevuto e confermato la disponibilità dell'ordine, lo stato può essere CONFIRMED
, altrimenti REJECTED
.
Un ordine nello stato CONFIRMED
passa allo stato IN_PREPARATION
. A seconda che l'ordine sia per il ritiro o la consegna, utilizza lo stato READY_FOR_PICKUP
o IN_TRANSIT
. Quando il cibo è stato consegnato o ritirato, l'ordine viene impostato sullo stato FULFILLED
.
Se consenti ai clienti di annullare gli ordini, puoi utilizzare lo stato CANCELLED
. Un ordine può essere annullato se è nello stato CREATED
, CONFIRMED
, IN_PREPARATION
, READY_FOR_PICKUP
o IN_TRANSIT
.
Il servizio Ordering End-to-End deve emettere i rimborsi in base alle tue norme sull'annullamento e allo stato dei pagamenti al momento dell'annullamento.
Il servizio Ordering End-to-End non deve supportare tutti gli stati e le transizioni disponibili. Tuttavia, lo stato finale dell'ordine deve essere FULFILLED
,
REJECTED
o CANCELLED
.
Fornire un tempo di evasione stimato
Puoi fornire agli utenti un intervallo di tempo stimato per quando il loro ordine sarà pronto per il ritiro (o la consegna). Utilizza il campo estimatedFulfillmentTimeIso8601
di FoodOrderUpdateExtension
per fornire un intervallo di tempo stimato per il ritiro o la consegna dell'ordine di un cliente.
Invia il estimatedFulfillmentTimeIso8601
nei seguenti orari:
- Quando l'ora stimata diventa disponibile, idealmente nello stato dell'ordine
CREATED
oCONFIRMED
. - Quando l'orario stimato cambia, ad esempio quando viene aggiornato per essere più preciso quando l'ordine è
IN_TRANSIT
.
Per gestire efficacemente le aspettative degli utenti, fai delle stime conservative e fornisci un intervallo di date e ore anziché una data e un'ora fisse. Se possibile, tieni conto di variazioni come le condizioni del traffico. Ad esempio, puoi inviare una stima tra le 12:45 (limite inferiore) e le 13:15 (limite superiore) per un ordine in cui l'orario di consegna stimato è le 13:00.
Fornire azioni di gestione degli ordini
Quando invii un aggiornamento dell'ordine, puoi fornire ai clienti risorse che li aiutino a gestire l'ordine sotto forma di OrderManagementAction
. Dopo che un cliente ha effettuato un ordine, potrebbe dover contattare te o il ristorante che lo soddisfa per monitorarne l'avanzamento, apportare modifiche o annullarlo.
Un OrderManagementAction
consente ai clienti di inviare email, effettuare chiamate o creare un link a un URL direttamente dal proprio dispositivo. Utilizza le stesse informazioni in
OrderManagementAction
come nell'email di conferma dell'ordine inviata all'
utente.
Le azioni di gestione degli ordini includono i seguenti tipi:
CUSTOMER_SERVICE
: offri ai clienti un'azione per contattare l'assistenza clienti. Questo tipo di azione di gestione è obbligatorio per gli aggiornamenti degli ordini.EMAIL
: offri ai clienti un'azione per inviare un'email all'indirizzo fornito.CALL
: invita i clienti a chiamare il numero di telefono fornito.VIEW_DETAIL
: offri ai clienti un'azione per visualizzare i dettagli del loro ordine.
Ogni aggiornamento dell'ordine deve contenere almeno un'azione di gestione dell'ordine. Tuttavia,
le azioni di gestione degli ordini fornite possono variare in base allo stato dell'ordine.
Ad esempio, quando un ordine è nello stato CONFIRMED
, l'azione CUSTOMER_SERVICE
può indirizzare al numero di telefono dell'assistenza clienti. Quando lo stato dell'ordine viene aggiornato in IN_TRANSIT
, l'azione CUSTOMER_SERVICE
può indicare il numero di telefono del ristorante di evasione.
Invio di aggiornamenti sugli ordini
Utilizza il tipo di messaggio AsyncOrderUpdateRequestMessage
per inviare un aggiornamento dell'ordine al servizio Ordering End-to-End. Google risponde con un messaggio AsyncOrderUpdateResponseMessage
. Ad esempio, se vuoi informare un cliente che il suo ordine è valido e accettato, puoi inviare un messaggio AsyncOrderUpdateRequestMessage
per modificare lo stato dell'ordine in CONFIRMED
con l'etichetta Accepted by restaurant
.
Impostazione del messaggio di aggiornamento dell'ordine
Quando invii un AsyncOrderUpdateRequestMessage
a Google, devi includere informazioni sullo stato dell'ordine utilizzando il campo OrderUpdate
.
Gli esempi riportati di seguito mostrano un AsyncOrderUpdateRequestMessage
di esempio per ogni stato dell'ordine:
CONFERMATA
Questo esempio mostra una richiesta di aggiornamento dell'ordine di esempio che comunica all'utente che l'ordine è stato confermato con una ricevuta e un'ora di consegna stimata.
{ "isInSandbox": true, "customPushMessage": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "CONFIRMED", "label": "Provider confirmed" }, "receipt": { "userVisibleOrderId": "userVisibleId1234" }, "updateTime": "2017-07-17T12:00:00Z", "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL_RESTAURANT", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "CALL_DRIVER", "button": { "title": "Call driver", "openUrlAction": { "url": "tel:+16505554681" } } } ], "infoExtension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension", "estimatedFulfillmentTimeIso8601": "2017-07-17T13:00:00Z/2017-07-17T13:30:00Z" } } } }
RIFIUTATA
Questo esempio mostra una richiesta di aggiornamento dell'ordine di esempio che comunica all'utente che l'ordine è stato rifiutato con un motivo del rifiuto.
{ "isInSandbox": true, "customPushMessage": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "UNKNOWN", "reason": "Sorry, the restaurant cannot take your order right now." }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL_RESTAURANT", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "CALL_DRIVER", "button": { "title": "Call driver", "openUrlAction": { "url": "tel:+16505554681" } } } ], "infoExtension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension", "foodOrderErrors": [ { "error": "NO_CAPACITY", "description": "Sorry, the restaurant cannot take your order right now." } ] } } } }
CANCELLATO
Questo esempio mostra una richiesta di aggiornamento dell'ordine di esempio che comunica all'utente che l'ordine è stato annullato con un motivo dell'annullamento.
{ "isInSandbox": true, "customPushMessage": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "CANCELLED", "label": "Order cancelled" }, "updateTime": "2017-05-10T02:30:00.000Z", "cancellationInfo": { "reason": "Customer requested" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL_RESTAURANT", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "CALL_DRIVER", "button": { "title": "Call driver", "openUrlAction": { "url": "tel:+16505554681" } } } ] } } }
IN_PREPARATION
Questo esempio mostra una richiesta di aggiornamento dell'ordine di esempio che comunica all'utente che il cibo è in fase di preparazione.
{ "isInSandbox":true, "customPushMessage":{ "orderUpdate":{ "actionOrderId":"sample_action_order_id", "orderState":{ "state":"IN_PREPARATION", "label":"Order is being prepared" }, "receipt": { "userVisibleOrderId": "userVisibleId1234" }, "updateTime":"2018-04-15T11:30:00Z", "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL_RESTAURANT", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "CALL_DRIVER", "button": { "title": "Call driver", "openUrlAction": { "url": "tel:+16505554681" } } } ], "infoExtension":{ "@type":"type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension", "estimatedFulfillmentTimeIso8601":"PT20M" } } } }
READY_FOR_PICKUP
Questo esempio mostra una richiesta di aggiornamento dell'ordine di esempio che comunica all'utente che il cibo è pronto per il ritiro.
{ "isInSandbox": true, "customPushMessage": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "READY_FOR_PICKUP", "label": "Order is ready for pickup" }, "receipt": { "userVisibleOrderId": "userVisibleId1234" }, "updateTime": "2018-04-15T12:00:00Z", "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL_RESTAURANT", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "CALL_DRIVER", "button": { "title": "Call driver", "openUrlAction": { "url": "tel:+16505554681" } } } ], "infoExtension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension", "estimatedFulfillmentTimeIso8601": "PT20M" } } } }
IN_TRANSIT
Questo esempio mostra una richiesta di aggiornamento dell'ordine di esempio che comunica all'utente che l'ordine è in transito con un tempo di consegna stimato.
{ "isInSandbox": true, "customPushMessage": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "IN_TRANSIT", "label": "Order is on the way" }, "inTransitInfo": { "updatedTime": "2017-07-17T12:00:00Z" }, "updateTime": "2017-07-17T12:00:00Z", "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL_RESTAURANT", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "CALL_DRIVER", "button": { "title": "Call driver", "openUrlAction": { "url": "tel:+16505554681" } } } ], "infoExtension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension", "estimatedFulfillmentTimeIso8601": "PT20M" } } } }
FULFILLED
Questo esempio mostra una richiesta di aggiornamento dell'ordine di esempio che comunica all'utente che l'ordine è stato ritirato o consegnato:
{ "isInSandbox": true, "customPushMessage": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "FULFILLED", "label": "Order delivered" }, "updateTime": "2017-05-10T02:30:00.000Z", "fulfillmentInfo": { "deliveryTime": "2017-05-10T02:30:00.000Z" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL_RESTAURANT", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "CALL_DRIVER", "button": { "title": "Call driver", "openUrlAction": { "url": "tel:+16505554681" } } } ] } } }
Per altri esempi di richieste di aggiornamento degli ordini in diversi casi d'uso, consulta Implementare aggiornamenti degli ordini avanzati.
Genera il token di autorizzazione e invia il messaggio
Gli aggiornamenti degli ordini richiedono un token di autorizzazione in modo che il servizio Ordering End-to-End possa verificare che il messaggio provenga dal tuo servizio web Ordering End-to-End.
Per implementare gli aggiornamenti degli ordini per il tuo progetto:
- Per generare un token di autorizzazione:
- Utilizza la libreria di autenticazione Google per leggere le credenziali dal file del tuo account di servizio.
- Richiedi il token utilizzando il seguente ambito API:
https://www.googleapis.com/auth/actions.fulfillment.conversation
- Utilizza questo token per inviare una richiesta POST HTTP autenticata al seguente endpoint:
https://actions.googleapis.com/v2/conversations:send
- Imposta l'intestazione
Content-Type
suapplication/json
all'interno della richiesta.
Gli esempi riportati di seguito mostrano come implementare gli aggiornamenti degli ordini:
Node.js
Questo codice utilizza la libreria di autenticazione di Google per Node.js.
const {auth} = require('google-auth-library') const request = require('request'); // The service account client secret file downloaded from the Google Cloud Console const serviceAccountJson = require('./service-account.json') // order-update.json is a file that contains the payload const jsonBody = require('./order-update.json') /** * Get the authorization token using a service account. */ async function getAuthToken() { let client = auth.fromJSON(serviceAccountJson) client.scopes = ['https://www.googleapis.com/auth/actions.fulfillment.conversation'] const tokens = await client.authorize() return tokens.access_token; } /** * Send an order update request */ async function sendOrderUpdate() { const token = await getAuthToken() request.post({ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, url: 'https://actions.googleapis.com/v2/conversations:send', body: jsonBody, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) }
Python
Questo codice utilizza la libreria di autenticazione di Google per Python.
from google.oauth2 import service_account from google.auth.transport.requests import AuthorizedSession import json # service-account.json is the service account client secret file downloaded from the # Google Cloud Console credentials = service_account.Credentials.from_service_account_file( 'service-account.json') scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/actions.fulfillment.conversation']) authed_session = AuthorizedSession(scoped_credentials) # order-update.json is a file that contains the payload json_payload=json.load(open('order-update.json')) response = authed_session.post( 'https://actions.googleapis.com/v2/conversations:send', json=json_payload)
Java
Questo codice utilizza la libreria di autenticazione di Google per Java.
/** * Get the authorization token using a service account. */ private static String getAuthToken() { InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json"); ServiceAccountCredentials.Builder credentialsSimpleBuilder = ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder(); credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/actions.fulfillment.conversation")); AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken(); return accessToken.getTokenValue(); } /** * Send an order update request */ public void sendOrderUpdate() { String authToken = getAuthToken(); // Execute POST request executePostRequest("https://actions.googleapis.com/v2/conversations:send", authToken, "update_order_example.json",); }
Per gli aggiornamenti degli ordini andati a buon fine senza errori, Google restituisce una risposta HTTP 200 con un payload vuoto. Se si è verificato un problema, ad esempio l'aggiornamento è stato formato in modo errato, Google restituisce un errore.