Асинхронное обновление порядка

После того как клиент отправит заказ на еду, вы можете отправить сообщение об обновлении заказа в службу сквозного заказа, чтобы уведомить нас об изменении.

Вот некоторые распространенные причины отправки обновлений заказов:

  • Ориентировочный срок выполнения заказа становится доступным или изменяется.
  • Статус заказа меняется.
  • Заказ больше не может быть выполнен.
  • Изменилась цена позиции меню, включенной в заказ.
  • У клиента появился новый способ управления своим заказом, например, служба поддержки или номер телефона ресторана.
  • Квитанция о заказе становится доступной.

В следующих разделах представлена ​​подробная информация о том, как решать эти различные сценарии с помощью обновлений заказов.

Переходные состояния порядка

Заказ имеет шесть возможных состояний. Эти состояния и их возможные переходы показаны на следующей диаграмме:

Упорядочить переходы между состояниями

Когда клиент впервые отправляет заказ, заказ начинается с состояния CREATED , CONFIRMED или REJECTED . Вы можете отправить сообщение об обновлении заказа, чтобы обновить состояние заказа, если переход состояния действителен. Состояние CREATED используется, когда платформа партнера не может немедленно подтвердить или отклонить заказ. Пример использования: клиент заказывает через агрегатор доставки. Агрегатор доставки получает доставку от Google и отправляет информацию в ресторан. После того, как ресторан получил и подтвердил наличие заказа, состояние теперь может быть CONFIRMED , в противном случае — REJECTED .

Заказ в состоянии CONFIRMED затем переходит в состояние IN_PREPARATION . В зависимости от того, предназначен ли заказ для самовывоза или доставки, затем используйте состояние READY_FOR_PICKUP или IN_TRANSIT . Когда еда доставлена ​​или забрана, заказ переходит в состояние FULFILLED .

Если вы разрешаете клиентам отменять заказы, вы можете использовать состояние CANCELLED . Заказ можно отменить, находясь в состоянии CREATED , CONFIRMED , IN_PREPARATION , READY_FOR_PICKUP или IN_TRANSIT . Служба комплексного оформления заказов должна возвращать средства в зависимости от вашей политики отмены и состояния платежей на момент отмены.

Служба сквозного заказа заказов не обязательно должна поддерживать все доступные состояния и переходы. Однако окончательное состояние заказа должно быть FULFILLED , REJECTED или CANCELLED .

Указание примерного срока выполнения

Вы можете предоставить пользователям приблизительный диапазон времени, когда их заказ будет готов к выдаче (или доставлен). Используйте поле estimatedFulfillmentTimeIso8601 FoodOrderUpdateExtension , чтобы указать предполагаемый диапазон времени, когда заказ клиента будет готов к самовывозу или доставке.

Отправляйте estimatedFulfillmentTimeIso8601 в следующее время:

  • Когда расчетное время станет доступным, в идеале заказ в состоянии CREATED или CONFIRMED .
  • При изменении расчетного времени, например, при обновлении расчетного времени для большей точности при заказе IN_TRANSIT .

Чтобы эффективно управлять ожиданиями пользователей, будьте консервативны в своих оценках и указывайте диапазон дат и времени, а не фиксированную дату и время. По возможности вам следует учитывать такие вариации, как условия дорожного движения. Например, вы можете отправить расчетное время от 12:45 (нижняя граница) до 13:15 (верхняя граница) для заказа, расчетное время доставки которого составляет 13:00.

Обеспечение действий по управлению заказами

Отправляя обновление заказа, вы можете предоставить клиентам ресурсы, которые помогут им управлять своим заказом, в форме OrderManagementAction . После того как клиент разместит заказ, ему может потребоваться связаться с вами или рестораном, выполняющим заказ, чтобы отслеживать ход выполнения, внести изменения или отменить заказ.

OrderManagementAction позволяет клиентам отправлять электронные письма, звонить или ссылаться на URL-адрес непосредственно со своего устройства. Используйте в OrderManagementAction ту же информацию, что и в подтверждении заказа по электронной почте, которое вы отправляете пользователю.

Действия по управлению заказами включают в себя следующие виды:

  • CUSTOMER_SERVICE : предоставить клиентам возможность связаться со службой поддержки. Этот тип действия управления необходим для обновления заказов.
  • EMAIL : Предоставьте клиентам возможность отправить электронное письмо на указанный адрес электронной почты.
  • CALL : Предоставьте клиентам возможность позвонить по указанному номеру телефона.
  • VIEW_DETAIL : Предоставьте клиентам действие для просмотра деталей их заказа.

Каждое обновление заказа должно содержать хотя бы одно действие по управлению заказом. Однако предоставляемые действия по управлению заказами могут различаться в зависимости от состояния заказа. Например, когда заказ находится в состоянии CONFIRMED , действие CUSTOMER_SERVICE может указывать на номер телефона вашей службы поддержки клиентов. Когда состояние заказа обновляется до IN_TRANSIT , действие CUSTOMER_SERVICE может указывать на номер телефона ресторана, где осуществляется выполнение заказов.

Отправка обновлений заказа

Тип сообщения AsyncOrderUpdateRequestMessage используется для отправки обновления заказа в службу сквозного заказа заказов. Google отвечает в ответ AsyncOrderUpdateResponseMessage . Например, если вы хотите сообщить клиенту, что его заказ действителен и принят, вы можете отправить сообщение AsyncOrderUpdateRequestMessage чтобы изменить состояние заказа на CONFIRMED с меткой Accepted by restaurant .

Схема обновления заказа

Настройка сообщения об обновлении заказа

Когда вы отправляете сообщение AsyncOrderUpdateRequestMessage в Google, вы должны включить информацию о состоянии заказа, используя поле OrderUpdate .

В следующих примерах показан образец AsyncOrderUpdateRequestMessage для каждого состояния заказа:

ПОДТВЕРЖДЕННЫЙ

В этом примере показан пример запроса на обновление заказа, который уведомляет пользователя о том, что заказ подтвержден квитанцией и расчетным временем доставки.

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

ОТКЛОНЕННЫЙ

В этом примере показан пример запроса на обновление заказа, который уведомляет пользователя о том, что заказ отклонен с указанием причины отклонения.

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

ОТМЕНЕНО

В этом примере показан пример запроса на обновление заказа, который уведомляет пользователя об отмене заказа с указанием причины отмены.

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

В этом примере показан пример запроса на обновление заказа, который уведомляет пользователя о том, что еда в данный момент готовится.

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

ГОТОВО_FOR_PICKUP

В этом примере показан пример запроса на обновление заказа, который уведомляет пользователя о том, что еда готова к самовывозу.

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

В ПУТИ

В этом примере показан пример запроса на обновление заказа, который уведомляет пользователя о том, что заказ находится в пути, и указывает расчетное время доставки.

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

ВЫПОЛНЕНО

В этом примере показан пример запроса на обновление заказа, который уведомляет пользователя о том, что заказ получен или доставлен:

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

Дополнительные примеры запросов на обновление заказов в различных вариантах использования см. в статье Реализация расширенных обновлений заказов .

Сгенерируйте токен авторизации и отправьте сообщение

Для обновлений заказов требуется токен авторизации, чтобы сквозная служба заказов могла проверить, что сообщение пришло от вашей сквозной веб-службы заказов.

Чтобы реализовать обновления заказов для вашего проекта, выполните следующие действия:

  1. Создайте токен авторизации, выполнив следующие действия:
    1. Используйте библиотеку Google Auth, чтобы прочитать учетные данные из файла вашей учетной записи службы.
    2. Запросите токен, используя следующую область API: https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. Используйте этот токен для отправки аутентифицированного запроса HTTP POST на следующую конечную точку: https://actions.googleapis.com/v2/conversations:send
  3. Установите для заголовка Content-Type значение application/json как часть вашего запроса.

Следующие примеры демонстрируют, как реализовать обновления заказов:

Node.js

Этот код использует библиотеку аутентификации Google для 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)}`)
  })
}
    

Питон

Этот код использует библиотеку аутентификации Google для 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)
    

Ява

Этот код использует библиотеку аутентификации Google для 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",);
}
    

При успешном обновлении заказа без ошибок Google возвращает ответ HTTP 200 с пустой полезной нагрузкой. Если возникла проблема, например неверный формат обновления, Google возвращает ошибку.