非同步訂單更新

客戶提交訂餐後,您可以傳送訂單更新訊息給 「訂單端對端服務」回報變更。

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

  • 訂單的預估出貨時間有現貨或變更。
  • 訂單狀態會變更。
  • 訂單已無法履行。
  • 訂單中包含的菜單品項價格已變更。
  • 客戶可透過新的方式管理訂單,例如客戶服務人員 或餐廳的電話號碼
  • 訂單收據可供查看。

以下各節將詳細說明如何因應這些不同情況 來更新訂單內容

轉換訂單狀態

訂單有六種可能的狀態。這些狀態及其可能的轉換 ,如下圖所示:

訂單狀態轉換

當客戶初次提交訂單時,訂單會從 CREATEDCONFIRMEDREJECTED。你可以傳送訂單更新訊息給 只要狀態轉換有效,系統就會更新訂單狀態。CREATED 狀態是合作夥伴平台無法確認或拒絕訂單時使用 立即生效應用情境範例是指客戶下單訂購的商品 。配送集結網站收到 Google 傳送的影片內容, 集結網站將資訊傳送給餐廳。餐廳收到 並確認訂單供應情形,狀態現在可能是 CONFIRMED,否則 REJECTED

CONFIRMED 狀態中的訂單接下來會移至 IN_PREPARATION 狀態。接著根據訂單是自取或外送,接著使用 READY_FOR_PICKUPIN_TRANSIT 狀態。餐點外送或取貨後,訂單會設為 FULFILLED 狀態,

如果您允許客戶取消訂單,您就能使用 CANCELLED 狀態。您可以在 CREATEDCONFIRMEDIN_PREPARATIONREADY_FOR_PICKUPIN_TRANSIT 狀態下取消訂單。 您的訂購端對端服務應會根據您的 取消政策以及取消時付款的狀態。

您的端對端訂購服務不需要支援所有可用狀態 和轉場效果不過,訂單的最終狀態「必須」FULFILLEDREJECTEDCANCELLED

提供預估出貨時間

您可以為使用者設定訂單預計送達的時間範圍 可供取貨 (或已送達) 取貨。使用 estimatedFulfillmentTimeIso8601 欄位 的 FoodOrderUpdateExtension,以便系統預估接下來 顧客的訂單即可取貨或配送到貨。

在以下時間傳送 estimatedFulfillmentTimeIso8601

  • 預估時間可供使用時,最好以 CREATEDCONFIRMED 狀態。
  • 預估時間發生變化時,例如:更新預計為 訂單金額為 IN_TRANSIT 時則提供更準確。

如要有效管理使用者期望,請謹慎進行估算, 提供日期和時間範圍,而非固定的日期和時間。請 會將路況等變化因素納入考量。適用對象 例如,你可以將估計為晚上 12:45 (下限) 傳送至晚上 1:15 (上下限) 規定)。

提供訂單管理動作

傳送訂單最新狀態時,你可以為客戶提供實用資源 他們可以使用 OrderManagementAction 格式管理訂單執行 客戶下訂單後,可能要聯絡你或餐廳 履行訂單以便追蹤進度、變更或取消訂單。

OrderManagementAction 能讓客戶透過電子郵件、電話或連結 直接透過自己的裝置存取網址。在 OrderManagementAction,必須與您傳送給 內容。

訂單管理動作如下:

  • CUSTOMER_SERVICE:為客戶提供聯絡客戶的動作 課程中也會快速介紹 Memorystore 這是 Google Cloud 的全代管 Redis 服務這個管理動作類型是更新訂單的必要項目。
  • EMAIL:讓客戶採取行動,傳送電子郵件至提供的 建立一個 Fitbit 帳戶。
  • CALL:請鼓勵客戶撥打提供的電話號碼。
  • VIEW_DETAIL:提供動作,以便客戶查看 順序。

每筆訂單更新都必須包含至少一個訂單管理動作。不過 提供的訂單管理動作可能因訂單狀態而異。 舉例來說,如果訂單處於 CONFIRMED 狀態,CUSTOMER_SERVICE 動作指向您的客戶服務電話號碼。訂單狀態的時候 更新為 IN_TRANSITCUSTOMER_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"
      }
    }
  }
}
    

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

IN_TRANSIT

本例顯示會通知使用者的訂單更新要求範例 訂單商品正在運送途中,以及預計送達時間。

{
  "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 驗證程式庫讀取服務的憑證
    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 會傳回錯誤。