Mise à jour de la commande asynchrone

Une fois qu'un client a passé une commande de repas, vous pouvez envoyer un message de mise à jour de la commande au service de commande de bout en bout pour nous en informer.

Voici quelques raisons courantes d'envoyer des informations sur la commande:

  • La date et l'heure d'exécution estimées de la commande sont disponibles ou modifiées.
  • L'état d'une commande change.
  • La commande ne peut plus être traitée.
  • Le prix d'un article du menu inclus dans la commande a changé.
  • Le client dispose d'un nouveau moyen de gérer sa commande, comme un numéro de téléphone du service client ou du restaurant.
  • Le reçu de la commande est disponible.

Les sections suivantes expliquent comment gérer ces différents scénarios à l'aide de mises à jour de commande.

Transitions entre les états des commandes

Une commande peut avoir six états possibles. Ces états et leurs transitions possibles sont décrits dans le diagramme suivant:

Transitions d'état des commandes

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 commande pour modifier l'état d'une commande, à condition que la transition d'état soit valide. L'état CREATED est utilisé lorsque la plate-forme du partenaire ne peut pas confirmer ni refuser immédiatement la commande. Un exemple de cas d'utilisation est lorsqu'un client commande via un agrégateur de livraison. L'agrégateur de livraison reçoit la commande de Google et transmet les informations au restaurant. Une fois que le restaurant a reçu et confirmé la disponibilité de la commande, l'état peut être CONFIRMED, sinon REJECTED.

Une commande à l'état CONFIRMED passe ensuite à l'état IN_PREPARATION. Selon que la commande est à emporter ou livrée, utilisez ensuite l'état READY_FOR_PICKUP ou IN_TRANSIT. Une fois que la nourriture a été livrée ou récupérée, l'état de la commande est défini sur FULFILLED.

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

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

Fournir une estimation du délai d'exécution

Vous pouvez indiquer aux utilisateurs une plage de temps estimée pour que leur commande soit prête à être retirée (ou livrée). Utilisez le champ estimatedFulfillmentTimeIso8601 de FoodOrderUpdateExtension pour indiquer une plage de temps estimée pour le retrait ou la livraison de la commande d'un client.

Envoyez le estimatedFulfillmentTimeIso8601 aux heures suivantes:

  • Lorsque l'heure estimée est disponible, idéalement lorsque la commande est à l'état CREATED ou CONFIRMED.
  • Lorsque l'heure estimée change, par exemple pour la rendre 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 de 12h45 (borne inférieure) à 13h15 (borne supérieure) pour une commande dont l'heure de livraison estimée est 13h00.

Proposer des actions de gestion des commandes

Lorsque vous envoyez une mise à jour de commande, vous pouvez fournir aux clients des ressources qui les aident à gérer leur commande sous la forme d'un OrderManagementAction. Une fois qu'un client a passé une commande, il peut avoir besoin de vous contacter ou de contacter le restaurant qui la traite pour suivre sa progression, apporter des modifications ou annuler sa commande.

Un OrderManagementAction permet aux clients d'envoyer un e-mail, d'appeler ou d'accéder à une URL directement depuis leur appareil. Utilisez les mêmes informations dans OrderManagementAction que dans l'e-mail de confirmation de commande que vous envoyez à l'utilisateur.

Les actions de gestion des commandes incluent les types suivants:

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

Chaque mise à jour d'une 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 est dans l'état CONFIRMED, l'action CUSTOMER_SERVICE peut pointer vers le numéro de téléphone de votre service client. Lorsque cet état de commande est mis à jour en IN_TRANSIT, l'action CUSTOMER_SERVICE peut pointer vers le numéro de téléphone du restaurant chargé de la préparation.

Envoyer des notifications sur les commandes

Vous utilisez le type de message AsyncOrderUpdateRequestMessage pour envoyer une mise à jour de commande au service Ordering End-to-End. Google répond avec un AsyncOrderUpdateResponseMessage. Par exemple, si vous souhaitez informer un client que sa commande est valide et acceptée, vous pouvez envoyer un AsyncOrderUpdateRequestMessage pour définir l'état de la commande sur CONFIRMED avec l'étiquette Accepted by restaurant.

Schéma de mise à jour de la commande

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

Lorsque vous envoyez un 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 commande:

CONFIRMED

Cet exemple montre un exemple de requête de mise à jour de commande qui informe l'utilisateur que la commande est confirmée avec 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 montre une requête de modification de commande qui informe l'utilisateur que la commande est 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."
        }
      ]
      }
    }
  }
}
    

ANNULÉ

Cet exemple montre une requête de modification 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 les plats sont 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 la nourriture est prête à être retirée.

{
  "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 montre un exemple de requête de mise à jour de commande qui informe l'utilisateur que la commande est en transit 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"
      }
    }
  }
}
  

TRAITÉE

Cet exemple montre une requête de mise à jour de commande qui informe l'utilisateur que la commande est récupéré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 obtenir d'autres exemples de requêtes de mise à jour de commande dans différents cas d'utilisation, consultez la section Implémenter des mises à jour de commande avancées.

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

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

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

  1. Pour générer un jeton d'autorisation, procédez comme suit :
    1. Utilisez la bibliothèque Google Auth pour lire les identifiants à partir de votre fichier de compte de service.
    2. Demandez un jeton à l'aide du champ d'application de l'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. Définissez l'en-tête Content-Type sur application/json dans votre requête.

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

Node.js

Ce code utilise la bibliothèque Google Auth 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 Google Auth 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 Google Auth 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 mal formée, Google renvoie une erreur.