非同步訂單更新

客戶提交餐點訂單後,您可以將訂單更新訊息傳送給「Google 訂餐」服務通知我們。

以下是傳送訂單更新的常見原因:

  • 訂單商品預計出貨時間或變更。
  • 訂單的狀態會隨之變更。
  • 訂單已履行。
  • 訂單中包含的選單項目價格有所變更。
  • 客戶可透過新方式管理訂單,例如客戶服務或餐廳電話號碼。
  • 訂單收據隨即在線上。

下一節將說明如何透過訂單更新,解決這些不同的情況。

轉換訂單狀態

訂單可能會有六個可能的狀態。這些狀態及其可能的轉換作業如下圖所示:

訂單狀態轉換

客戶首次提交訂單時,訂單金額會處於 CREATEDCONFIRMEDREJECTED 的狀態。只要狀態轉換有效,您就可以傳送訂單更新訊息以更新訂單狀態。當合作夥伴的平台無法立即確認或拒絕訂單時,會使用 CREATED 狀態。例如,客戶透過運送匯總器訂購時。放送集結網站會收到 Google 的貨品交付資訊,且集結網站會將資訊傳送給餐廳。餐廳收到並確認訂單供應情形後,狀態可為 CONFIRMED,否則為 REJECTED

CONFIRMED 狀態的訂單會移至 IN_PREPARATION 狀態。視訂單使用的是自取或外送而定,請使用 READY_FOR_PICKUPIN_TRANSIT 狀態。餐點外送或取貨後,訂單會設為 FULFILLED 狀態。

如果您允許客戶取消訂單,則可使用 CANCELLED 狀態。您可以在 CREATEDCONFIRMEDIN_PREPARATIONREADY_FOR_PICKUPIN_TRANSIT 狀態中取消訂單。您的「Google 訂單」服務應根據取消政策和取消時的狀態提供退款。

「Google 訂餐」服務可能不支援所有可用狀態和轉換。不過,訂單的最終狀態必須FULFILLEDREJECTEDCANCELLED

提供預估出貨時間

您可以提供使用者預估可取貨 (或送達) 的預計時間範圍。使用 FoodOrderUpdateExtensionestimatedFulfillmentTimeIso8601 欄位,提供客戶訂單自取或外送時間的預估時間。

在下列時間傳送 estimatedFulfillmentTimeIso8601

  • 如果有預估時間,最好使用 CREATEDCONFIRMED 狀態。
  • 預計時間變更 (例如將預估時間更新為 IN_TRANSIT 時) 以更準確。

為有效管理使用者期望,請謹慎保守預估,並提供日期和時間 (而非固定日期和時間)。您應該盡可能考慮各種因素 (例如路況),舉例來說,假設預估送達時間為下午 1 點,則您可以將預估時間為下午 12 點 45 分至晚上 1 點 15 分。

提供訂單管理動作

傳送訂單更新時,您可以將資源提供給客戶,以 OrderManagementAction 的形式協助客戶管理訂單。客戶下訂單後,他們可能會需要你或餐廳,以便追蹤進度、進行變更或取消訂單。

OrderManagementAction 可讓客戶直接透過裝置傳送電子郵件、通話或連結至網址。請使用傳送至使用者電子郵件確認確認電子郵件中的 OrderManagementAction 相同的資訊。

訂單管理動作包括下列類型:

  • CUSTOMER_SERVICE:向客戶提供與客服聯絡的動作。如要更新訂單,必填這個管理動作類型。
  • EMAIL:為客戶提供操作,將電子郵件傳送至指定的電子郵件地址。
  • CALL:鼓勵客戶致電你提供的電話號碼。
  • VIEW_DETAIL:為客戶提供操作,以便查看訂單詳細資料。

每筆訂單更新都必須含有至少一項訂單管理動作。不過,提供的訂單管理動作會因訂單狀態而異。舉例來說,當訂單處於 CONFIRMED 狀態時,CUSTOMER_SERVICE 動作便可以指向您的客戶服務電話號碼。該訂單的狀態更新為 IN_TRANSIT 時,CUSTOMER_SERVICE 動作可以指向出貨餐廳的電話號碼。

正在傳送訂單動態

您可以使用 AsyncOrderUpdateRequestMessage 訊息類型,將訂單更新傳送至「Google 訂餐」服務。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"
            }
          }
        }
      ]
    }
  }
}
    

意涵

這個範例顯示訂單更新要求範例,讓使用者知道食物目前正在準備中。

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

準備就緒

這個範例顯示訂單更新要求範例,讓使用者知道餐點已可取貨。

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

如需不同用途的訂單更新要求範例,請參閱實作進階訂單更新

產生授權權杖並傳送訊息

訂單更新需要授權權杖,以便「透過 Google 訂餐」服務確認訊息來自「Google 訂餐」網路服務。

如要為專案導入訂單更新,請按照下列步驟操作:

  1. 產生授權權杖的步驟如下:
    1. 使用 Google 驗證程式庫讀取您的服務帳戶檔案中的憑證。
    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

這個程式碼會使用 Node.js 的 Google 驗證程式庫

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

這個程式碼會使用 Python 適用的 Google 驗證程式庫

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

這個程式碼使用 Java 適用的 Google 驗證程式庫

/**
 * 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 就會傳回錯誤。