Mise à jour de la commande asynchrone

Lorsqu'un client passe une commande de repas, vous pouvez envoyer un message de mise à jour de la commande au service de bout en bout pour nous informer de la modification.

Vous trouverez ci-dessous quelques raisons courantes pouvant expliquer pourquoi vous envoyez des mises à jour de commande:

  • Le délai de traitement estimé de la commande devient disponible ou change.
  • L'état d'une commande change.
  • Il n'est plus possible de traiter la commande.
  • Le prix d'un plat inclus dans la commande a été modifié.
  • Le client dispose d'une nouvelle façon de gérer sa commande, par exemple via le service client ou le numéro de téléphone du restaurant.
  • Le reçu de la commande devient disponible.

Les sections suivantes expliquent comment résoudre ces différents scénarios à l'aide de mises à jour de commandes.

Migrer les états des campagnes

Un ordre possède six états possibles. Ces états et leurs transitions possibles sont décrits dans le schéma suivant:

Ordonner les transitions d'état

Lorsqu'un client passe une commande pour la première fois, celle-ci commence par l'état CREATED, CONFIRMED ou REJECTED. Vous pouvez envoyer un message de mise à jour de la commande pour mettre à jour l'état d'une commande, tant que la transition d'état est valide. L'état CREATED est utilisé lorsque la plate-forme du partenaire ne peut pas confirmer ou refuser la commande immédiatement. Exemple de cas d'utilisation : lorsqu'un client passe commande via un agrégateur de livraison. L'agrégateur de livraison reçoit la livraison de Google, et l'agrégateur envoie les informations au restaurant. Une fois que le restaurant a reçu et confirmé la disponibilité de la commande, l'état peut désormais être CONFIRMED. Sinon, l'état peut être REJECTED.

Une commande à l'état CONFIRMED passe ensuite à l'état IN_PREPARATION. Selon que la commande est en retrait ou en livraison, utilisez ensuite l'état READY_FOR_PICKUP ou IN_TRANSIT. Lorsque les plats ont été livrés ou retirés, la commande est définie sur l'état FULFILLED.

Si vous autorisez les clients à annuler des commandes, vous pouvez utiliser l'état CANCELLED. Une commande peut être annulée lorsqu'elle possède l'état CREATED, CONFIRMED, IN_PREPARATION, READY_FOR_PICKUP ou IN_TRANSIT. Votre service de bout en bout des commandes doit émettre des remboursements en fonction de vos modalités d'annulation et de l'état des paiements au moment de l'annulation.

Votre service de commande de bout en bout ne doit pas nécessairement prendre en charge tous les états et transitions disponibles. Cependant, l'état final de la commande doit être FULFILLED, REJECTED ou CANCELLED.

Fournir une estimation du délai de traitement

Vous pouvez indiquer aux utilisateurs une période estimée pendant laquelle leur commande sera prête à être retirée (ou livrée). Utilisez le champ estimatedFulfillmentTimeIso8601 de FoodOrderUpdateExtension pour fournir une estimation de la période pendant laquelle la commande d'un client sera prête à être retirée ou livrée.

Envoyez le estimatedFulfillmentTimeIso8601 aux heures suivantes:

  • Lorsque le délai estimé devient disponible, idéalement à l'état CREATED ou CONFIRMED.
  • Lorsque l'heure estimée change (par exemple, en mettant à jour l'heure estimée pour qu'elle soit plus précise lorsque la commande est IN_TRANSIT).

Pour gérer efficacement les attentes des utilisateurs, soyez prudent dans vos estimations et fournissez une plage de dates et d'heures plutôt qu'une date et une heure fixes. Dans la mesure du possible, vous devez tenir compte des variations telles que les conditions de circulation. Par exemple, vous pouvez envoyer une estimation comprise entre 12h45 (limite inférieure) et 13h15 (limite supérieure) pour une commande dont le délai de livraison estimé est 13h.

Fournir des actions de gestion des commandes

Lorsque vous envoyez une mise à jour de commande, vous pouvez fournir aux clients des ressources pour les aider à gérer leur commande sous la forme d'un OrderManagementAction. Lorsqu'un client passe une commande, il peut avoir besoin de vous contacter ou de contacter le restaurant qui la traite pour suivre la progression, la modifier ou l'annuler.

Un OrderManagementAction permet aux clients d'envoyer des e-mails, d'appeler ou de créer un lien vers une URL directement depuis leur appareil. Utilisez les mêmes informations dans OrderManagementAction que dans la confirmation de commande par e-mail que vous envoyez à l'utilisateur.

Les actions de gestion des commandes sont les suivantes:

  • CUSTOMER_SERVICE: indiquez aux clients une action permettant de contacter le service client. Ce type d'action de gestion est obligatoire pour les mises à jour des commandes.
  • EMAIL: indiquer aux clients une action permettant d'envoyer un e-mail à l'adresse e-mail fournie.
  • CALL: proposez aux clients d'appeler le numéro de téléphone indiqué.
  • VIEW_DETAIL: proposez aux clients une action permettant d'afficher les détails de leur commande.

Chaque mise à jour de commande doit contenir au moins une action de gestion des commandes. Toutefois, les actions de gestion des commandes fournies peuvent varier en fonction de l'état de la commande. Par exemple, lorsqu'une commande possède l'état CONFIRMED, l'action CUSTOMER_SERVICE peut pointer vers le numéro de téléphone de votre service client. Lorsque l'état de cette commande est mis à jour vers IN_TRANSIT, l'action CUSTOMER_SERVICE peut pointer vers le numéro de téléphone du restaurant de traitement.

Envoyer des mises à jour de commande

Utilisez le type de message AsyncOrderUpdateRequestMessage pour envoyer une mise à jour de commande au service de commande de bout en bout. Google répond par un AsyncOrderUpdateResponseMessage. Par exemple, si vous souhaitez informer un client que sa commande est valide et acceptée, vous pouvez lui envoyer un AsyncOrderUpdateRequestMessage pour définir l'état de la commande sur CONFIRMED avec le libellé Accepted by restaurant.

Schéma de mise à jour d'une commande

Définir le message de mise à jour de la commande

Lorsque vous envoyez une AsyncOrderUpdateRequestMessage à Google, vous devez inclure des informations sur l'état de la commande à l'aide du champ OrderUpdate.

Les exemples suivants présentent un exemple de AsyncOrderUpdateRequestMessage pour chaque état de la commande:

CONFIRMÉ

Cet exemple présente un exemple de requête de mise à jour de commande qui informe l'utilisateur que la commande est confirmée par un reçu et un délai de livraison estimé.

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

REFUSÉE

Cet exemple présente un exemple de requête de mise à jour de commande qui informe l'utilisateur que la commande a été refusée avec un motif de refus.

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

CANCELLED

Voici un exemple de requête de mise à jour de commande qui informe l'utilisateur que la commande est annulée avec un motif d'annulation.

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

Cet exemple montre un exemple de requête de mise à jour de commande qui informe l'utilisateur que le plat est en cours de préparation.

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

Cet exemple montre un exemple de requête de mise à jour de commande qui informe l'utilisateur que le plat est prêt à être retiré.

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

Cet exemple présente un exemple de requête de mise à jour de commande qui informe l'utilisateur que la commande est en cours d'acheminement avec un délai de livraison estimé.

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

TERMINÉ

Voici un exemple de requête de mise à jour de commande qui informe l'utilisateur que la commande est retirée ou livrée:

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

Pour plus d'exemples de demandes de mise à jour de commande dans différents cas d'utilisation, consultez Implémenter des mises à jour avancées des commandes.

Générer un jeton d'autorisation et envoyer le message

Les mises à jour de commandes nécessitent un jeton d'autorisation pour que le service de commande de bout en bout puisse vérifier que le message provient bien de votre service Web de commande de bout en bout.

Pour implémenter les mises à jour des commandes pour votre projet, procédez comme suit:

  1. Générez un jeton d'autorisation en procédant comme suit :
    1. Utilisez la bibliothèque Google Auth pour lire les identifiants à partir du fichier de votre compte de service.
    2. Jeton de requête utilisant le champ d'application d'API suivant : https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. Utilisez ce jeton pour envoyer une requête HTTP POST authentifiée au point de terminaison suivant: https://actions.googleapis.com/v2/conversations:send
  3. Dans le cadre de votre requête, définissez l'en-tête Content-Type sur application/json.

Les exemples suivants montrent comment implémenter des mises à jour de commandes:

Node.js

Ce code utilise la bibliothèque d'authentification Google pour 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

Ce code utilise la bibliothèque d'authentification Google pour 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

Ce code utilise la bibliothèque d'authentification Google pour 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",);
}
    

Pour les mises à jour de commande réussies sans erreur, Google renvoie une réponse HTTP 200 avec une charge utile vide. En cas de problème, par exemple si la mise à jour est incorrecte, Google renvoie une erreur.