Actualización de orden asíncrona

Después de que un cliente envía un pedido de comida, puedes enviar un mensaje de actualización del pedido al servicio de Order with Google para notificarnos el cambio.

Estos son algunos de los motivos comunes por los que se envían actualizaciones del pedido:

  • El tiempo de entrega estimado para el pedido pasa a estar disponible o cambia.
  • El estado de un pedido cambia.
  • Ya no se puede completar el pedido.
  • Cambió el precio de un elemento del menú incluido en el pedido.
  • El cliente tiene una nueva forma de administrar su pedido, como la asistencia al cliente o el número de teléfono de un restaurante.
  • El recibo del pedido estará disponible.

En las siguientes secciones, se proporcionan detalles sobre cómo abordar estas diferentes situaciones con actualizaciones del pedido.

Estados de transición de pedidos

Un pedido tiene seis estados posibles. Estos estados y sus transiciones posibles se describen en el siguiente diagrama:

Transiciones del estado de los pedidos

Cuando un cliente envía un pedido por primera vez, este comienza con el estado CREATED, CONFIRMED o REJECTED. Puedes enviar un mensaje de actualización del pedido para actualizar el estado de un pedido, siempre que la transición de estado sea válida. El estado CREATED se usa cuando la plataforma del socio no puede confirmar o rechazar el pedido de inmediato. Un caso de uso de ejemplo es cuando un cliente realiza un pedido a través de un agregador de entrega. El agregador de entregas recibe la entrega de Google y el agregador envía la información al restaurante. Una vez que el restaurante recibe y confirma la disponibilidad del pedido, el estado ahora puede ser CONFIRMED; de lo contrario, es REJECTED.

A continuación, un pedido en el estado CONFIRMED pasa al estado IN_PREPARATION. Según si el pedido es para retiro o entrega, a continuación, usa el estado READY_FOR_PICKUP o IN_TRANSIT. Una vez que la comida se entregó o se retiró, el pedido se establece en el estado FULFILLED.

Si permites que los clientes cancelen pedidos, puedes usar el estado CANCELLED. Se puede cancelar un pedido en el estado CREATED, CONFIRMED, IN_PREPARATION, READY_FOR_PICKUP o IN_TRANSIT. Tu servicio de Order with Google debe emitir reembolsos según tu política de cancelación y el estado de los pagos en el momento de la cancelación.

Tu servicio de Order with Google no necesita admitir todos los estados y transiciones disponibles. Sin embargo, el estado final del pedido debe ser FULFILLED, REJECTED o CANCELLED.

Proporciona un tiempo de entrega estimado

Puedes proporcionarles a los usuarios un intervalo de tiempo estimado en el que su pedido estará listo para retirarse (o entregarse). Usa el campo estimatedFulfillmentTimeIso8601 de FoodOrderUpdateExtension a fin de proporcionar un intervalo de tiempo estimado en el que el pedido de un cliente esté listo para ser recogido o entregado.

Envía la estimatedFulfillmentTimeIso8601 en los siguientes horarios:

  • Cuando el tiempo estimado esté disponible, idealmente, estará en el estado CREATED o CONFIRMED.
  • Cuando cambia la hora estimada, por ejemplo, actualizando la hora estimada para que sea más precisa cuando el pedido sea IN_TRANSIT

Para administrar las expectativas de los usuarios de forma eficaz, sé conservador en tus estimaciones y proporciona una fecha y hora en lugar de una fecha y hora fijas. Siempre que sea posible, debes considerar variaciones como las condiciones de tráfico. Por ejemplo, puedes enviar una estimación de 12:45 p.m. (límite inferior) a 1:15 p.m. (límite superior) para un pedido en el que la hora de entrega estimada es 1:00 p.m.

Cómo proporcionar acciones de administración de pedidos

Cuando envías una actualización de pedido, puedes proporcionar recursos a los clientes que los ayuden a administrar su pedido en forma de OrderManagementAction. Después de que un cliente realiza un pedido, es posible que deba comunicarse contigo o el restaurante que entrega el pedido para realizar el seguimiento del progreso, realizar cambios o cancelar el pedido.

Un OrderManagementAction permite a los clientes enviar correos electrónicos, llamar o vincular una URL directamente desde sus dispositivos. Usa la misma información en OrderManagementAction que en la confirmación del pedido por correo electrónico que envías al usuario.

Las acciones de administración de pedidos incluyen los siguientes tipos:

  • CUSTOMER_SERVICE: Ofrece a los clientes una acción para comunicarse con el servicio de atención al cliente. Este tipo de acción de administración es obligatoria para las actualizaciones de pedidos.
  • EMAIL: Proporciona a los clientes una acción para enviar un correo electrónico a la dirección proporcionada.
  • CALL: Proporcione a los clientes una acción para llamar al número de teléfono proporcionado.
  • VIEW_DETAIL: Proporciona a los clientes una acción para ver los detalles de su pedido.

Cada actualización de pedido debe contener al menos una acción de administración de pedidos. Sin embargo, las acciones proporcionadas para la administración de pedidos pueden variar según el estado del pedido. Por ejemplo, cuando un pedido se encuentra en el estado CONFIRMED, la acción CUSTOMER_SERVICE puede apuntar a tu número de teléfono de atención al cliente. Cuando el estado de ese pedido se actualiza a IN_TRANSIT, la acción CUSTOMER_SERVICE puede apuntar al número de teléfono del restaurante de entrega.

Enviando actualizaciones del pedido

Usas el tipo de mensaje AsyncOrderUpdateRequestMessage para enviar una actualización del pedido al servicio de Order with Google. Google responde con AsyncOrderUpdateResponseMessage. Por ejemplo, si quieres informar a un cliente que su pedido es válido y se acepta, puedes enviar un AsyncOrderUpdateRequestMessage para cambiar el estado del pedido a CONFIRMED con la etiqueta Accepted by restaurant.

Diagrama de actualización del pedido

Cómo configurar el mensaje de actualización del pedido

Cuando envías una AsyncOrderUpdateRequestMessage a Google, debes incluir información sobre el estado del pedido mediante el campo OrderUpdate.

En los siguientes ejemplos, se muestra un AsyncOrderUpdateRequestMessage de muestra para cada estado del pedido:

CONFIRMED

En este ejemplo, se muestra una solicitud de actualización de pedido de muestra que notifica al usuario que el pedido se confirmó con un recibo y una hora de entrega estimada.

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

RECHAZADA

En este ejemplo, se muestra una solicitud de actualización de pedido de muestra que notifica al usuario que el pedido se rechazó por el motivo del rechazo.

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

CANCELADA

En este ejemplo, se muestra una solicitud de actualización de pedido de muestra que notifica al usuario que el pedido se canceló con un motivo de cancelación.

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

EN PREPARACIÓN

En este ejemplo, se muestra una solicitud de actualización del pedido de muestra que notifica al usuario que la comida se está preparando en ese momento.

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

LISTO_PARA_RETIRO

En este ejemplo, se muestra una solicitud de actualización del pedido de muestra que notifica al usuario que la comida está lista para retirarse.

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

EN TRANSPORTE PÚBLICO

En este ejemplo, se muestra una solicitud de actualización de pedido de muestra que notifica al usuario que el pedido está en tránsito con un tiempo de entrega estimado.

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

CUMPLIMIENTO

En este ejemplo, se muestra una solicitud de actualización de pedido de muestra que notifica al usuario que se retiró o entregó el pedido:

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

Para ver más ejemplos de solicitudes de actualización de pedidos en diferentes casos de uso, consulta Cómo implementar actualizaciones avanzadas de pedidos.

Generar un token de autorización y enviar el mensaje

Las actualizaciones de pedidos requieren un token de autorización para que el servicio de Order with Google pueda verificar que el mensaje proviene de tu servicio web de Order with Google.

Para implementar actualizaciones de pedidos en tu proyecto, sigue estos pasos:

  1. Sigue estos pasos para generar un token de autorización:
    1. Usa la biblioteca de Google Auth para leer las credenciales del archivo de tu cuenta de servicio.
    2. Token de solicitud con el siguiente alcance de API: https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. Usa este token para enviar una solicitud HTTP POST autenticada al siguiente extremo: https://actions.googleapis.com/v2/conversations:send
  3. Configura el encabezado Content-Type como application/json como parte de tu solicitud.

En los siguientes ejemplos, se muestra cómo implementar actualizaciones de pedidos:

Node.js

Este código usa la biblioteca de autenticación de Google para 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

Este código usa la biblioteca de autenticación de Google para 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

Este código usa la biblioteca de autenticación de Google para 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",);
}
    

Para que las actualizaciones de pedidos se realicen sin errores, Google muestra una respuesta HTTP 200 con una carga útil vacía. Si hubo un problema, por ejemplo, si la actualización tiene un formato incorrecto, Google muestra un error.