Aktualizacja zamówienia w tle

Gdy klient złoży zamówienie na jedzenie, możesz wysłać wiadomość z aktualizacją zamówienia do usługi Zamawianie od początku do końca, aby powiadomić nas o zmianie.

Oto kilka najczęstszych przyczyn wysyłania aktualizacji zamówienia:

  • Przewidywany czas realizacji zamówienia staje się dostępny lub zmienia się.
  • Stan zamówienia ulega zmianie.
  • Zamówienia nie można już zrealizować.
  • zmieniła się cena pozycji menu zawartej w zamówieniu;
  • Klient ma nowy sposób zarządzania zamówieniem, np. numer telefonu do obsługi klienta lub restauracji.
  • potwierdzenie zamówienia stanie się dostępne.

W kolejnych sekcjach znajdziesz szczegółowe informacje o tym, jak rozwiązywać te różne scenariusze za pomocą aktualizacji zamówień.

Przechodzenie między stanami zamówienia

Zamówienie może mieć 6 możliwych stanów. Te stany i ich możliwe przejścia przedstawia diagram poniżej:

Przechodzenie do stanu zamówienia

Gdy klient po raz pierwszy przesyła zamówienie, ma ono stan CREATED, CONFIRMED lub REJECTED. Możesz wysłać wiadomość z aktualizacją zamówienia, aby zaktualizować jego stan, o ile zmiana stanu jest prawidłowa. CREATEDStan ten jest używany, gdy platforma partnera nie może od razu potwierdzić ani odrzucić zamówienia. Przykładem takiego przypadku jest sytuacja, gdy klient składa zamówienie za pomocą agregatora dostaw. Agregator dostaw otrzymuje zamówienie od Google, a potem wysyła informacje do restauracji. Gdy restauracja otrzyma i potwierdzi dostępność zamówienia, stan może zostać zmieniony na CONFIRMED. W przeciwnym razie będzie to REJECTED.

Zamówienie w stanie CONFIRMED przechodzi następnie do stanu IN_PREPARATION. W zależności od tego, czy zamówienie jest przeznaczone do odbioru czy dostawy, użyj stanu READY_FOR_PICKUP lub IN_TRANSIT. Po dostarczeniu lub odbiorze jedzenia zamówienie ma stan FULFILLED.

Jeśli zezwalasz klientom na anulowanie zamówień, możesz użyć stanu CANCELLED. Zamówienie można anulować, gdy ma stan CREATED, CONFIRMED, IN_PREPARATION, READY_FOR_PICKUP lub IN_TRANSIT. Usługa kompleksowego zamawiania powinna zwracać środki zgodnie z zasadami anulowania i stanem płatności w momencie anulowania.

Usługa kompleksowego zamawiania nie musi obsługiwać wszystkich dostępnych stanów i przejść. Jednak ostateczny stan zamówienia musi być FULFILLED, REJECTED lub CANCELLED.

Podawanie przewidywanego czasu realizacji

Możesz podać użytkownikom przewidywany czas, kiedy ich zamówienie będzie gotowe do odbioru (lub dostarczone). Użyj pola estimatedFulfillmentTimeIso8601 w FoodOrderUpdateExtension, aby podać przewidywany przedział czasu, w którym zamówienie klienta będzie gotowe do odbioru lub dostawy.

Wysyłaj estimatedFulfillmentTimeIso8601 o tych porach:

  • Gdy przewidywany czas stanie się dostępny, najlepiej w stanie CREATED lub CONFIRMED.
  • Gdy zmieni się szacowany czas, np. gdy zamówienie jest IN_TRANSIT, należy zaktualizować szacowany czas, aby był bardziej dokładny.

Aby skutecznie zarządzać oczekiwaniami użytkowników, podawaj ostrożne szacunki i okres dat i godzin zamiast stałych dat i godzin. O ile to możliwe, należy uwzględnić zmienne czynniki, takie jak warunki na drodze. Na przykład możesz wysłać szacowany czas dostawy 13:45 (wartość dolna) do 13:15 (wartość górna) dla zamówienia, którego przewidywany czas dostawy to 13:00.

Dostępność działań związanych z zarządzaniem zamówieniami

Podczas wysyłania aktualizacji zamówienia możesz udostępnić klientom zasoby, które pomogą im zarządzać zamówieniem w postaci OrderManagementAction. Po złożeniu zamówienia przez klienta może on potrzebować kontaktu z Tobą lub restauracją, aby śledzić postępy, wprowadzić zmiany lub anulować zamówienie.

OrderManagementAction umożliwia klientom wysyłanie e-maili, wykonywanie połączeń telefonicznych i dodawanie linków do adresów URL bezpośrednio z urządzenia. W polu OrderManagementAction podawaj te same informacje co w e-mailu z potwierdzeniem zamówienia wysyłanym do użytkownika.

Działania związane z zarządzaniem zamówieniami obejmują te typy:

  • CUSTOMER_SERVICE: umożliwić klientom skontaktowanie się z zespołem obsługi klienta. Ten typ działania administracyjnego jest wymagany w przypadku aktualizacji zamówień.
  • EMAIL: umożliwić klientom wysyłanie e-maili na podany adres e-mail.
  • CALL: umożliwić klientom wykonanie działania polegającego na wykonaniu połączenia na podany numer telefonu.
  • VIEW_DETAIL: podaj klientom działanie, które umożliwi im wyświetlenie szczegółów zamówienia.

Każda aktualizacja zamówienia musi zawierać co najmniej 1 działanie związane z zarządzaniem zamówieniem. Jednak dostępne działania związane z zarządzaniem zamówieniem mogą się różnić w zależności od jego stanu. Jeśli np. zamówienie ma stan CONFIRMED, działanie CUSTOMER_SERVICE może wskazywać numer telefonu obsługi klienta. Gdy stan zamówienia zmieni się na IN_TRANSIT, działanie CUSTOMER_SERVICE może wskazywać numer telefonu restauracji realizującej zamówienie.

Wysyłanie aktualizacji zamówień

Używasz typu wiadomości AsyncOrderUpdateRequestMessage, aby wysłać do usługi Zamawianie od początku do końca aktualizację zamówienia. Google odpowiada elementem AsyncOrderUpdateResponseMessage. Jeśli na przykład chcesz poinformować klienta, że jego zamówienie zostało przyjęte, możesz wysłać AsyncOrderUpdateRequestMessage, aby zmienić stan zamówienia na CONFIRMED z etykietą Accepted by restaurant.

Diagram aktualizacji zamówienia

Konfigurowanie wiadomości o zaktualizowanym zamówieniu

Wysyłając do Google AsyncOrderUpdateRequestMessage, musisz podać informacje o stanie zamówienia, korzystając z pola OrderUpdate.

Poniższe przykłady pokazują przykładową wartość AsyncOrderUpdateRequestMessage dla każdego stanu zamówienia:

POTWIERDZONO

Ten przykład pokazuje prośbę o zmianę zamówienia, która informuje użytkownika o potwierdzenie zamówienia z potwierdzeniem odbioru i szacowanym czasem dostawy.

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

ODRZUCONE

Ten przykład pokazuje prośbę o zmianę zamówienia, która informuje użytkownika o odrzuceniu zamówienia wraz z odpowiednią przyczyną.

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

ANULOWANO

Ten przykład pokazuje prośbę o zmianę zamówienia, która powiadamia użytkownika o anulowaniu zamówienia wraz z odpowiednim powodem.

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

Ten przykład pokazuje prośbę o zmianę zamówienia, która informuje użytkownika, że posiłek jest obecnie przygotowywany.

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

Ten przykład pokazuje prośbę o zmianę zamówienia, która informuje użytkownika, że posiłek jest gotowy do odbioru.

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

Ten przykład pokazuje prośbę o zmianę zamówienia, która informuje użytkownika, że zamówienie jest w drodze, podając przybliżony czas dostawy.

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

Ten przykład pokazuje prośbę o zmianę zamówienia, która powiadamia użytkownika o odbiorze lub dostawie zamówienia:

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

Więcej przykładów żądań aktualizacji zamówienia w różnych przypadkach użycia znajdziesz w artykule Wdrażanie zaawansowanych aktualizacji zamówienia.

Generowanie tokena autoryzacji i wysyłanie wiadomości

Aktualizacje zamówienia wymagają tokena autoryzacji, aby usługa kompleksowej pomocy w zamawianiu mogła zweryfikować, czy wiadomość pochodzi z Twojej usługi internetowej kompleksowej pomocy w zamawianiu.

Aby wdrożyć aktualizacje zamówień w projekcie:

  1. Aby wygenerować token autoryzacji:
    1. Użyj Google Auth Library, aby odczytać dane logowania z pliku konta usługi.
    2. Poproś o token, używając tego zakresu uprawnień API: https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. Użyj tego tokena, aby wysłać uwierzytelnione żądanie HTTP POST do tego punktu końcowego: https://actions.googleapis.com/v2/conversations:send
  3. W żądaniu ustaw nagłówek Content-Type na application/json.

Te przykłady pokazują, jak wdrażać aktualizacje zamówień:

Node.js

Ten kod używa biblioteki Google do uwierzytelniania w 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

Ten kod korzysta z biblioteki uwierzytelniania Google dla Pythona.

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

Ten kod korzysta z biblioteki Google do uwierzytelniania w Javie.

/**
 * 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",);
}
    

W przypadku pomyślnych aktualizacji zamówień bez błędów Google zwraca odpowiedź HTTP 200 z pustym ładunkiem. Jeśli wystąpił problem, np. nieprawidłowa aktualizacja, Google zwraca błąd.