Cập nhật đơn đặt hàng không đồng bộ

Sau khi khách hàng gửi đơn đặt đồ ăn, bạn có thể gửi thông báo cập nhật đơn đặt hàng đến dịch vụ Toàn diện về việc đặt hàng để thông báo cho chúng tôi về thay đổi đó.

Dưới đây là một số lý do phổ biến khiến bạn gửi thông tin cập nhật về đơn đặt hàng:

  • Thời gian thực hiện ước tính cho đơn đặt hàng có sẵn hoặc thay đổi.
  • Trạng thái của đơn đặt hàng thay đổi.
  • Không thể thực hiện đơn đặt hàng này nữa.
  • Giá của một món ăn trong đơn đặt hàng đã thay đổi.
  • Khách hàng có một cách mới để quản lý đơn đặt hàng, chẳng hạn như số điện thoại của nhà hàng hoặc bộ phận hỗ trợ khách hàng.
  • Biên nhận cho đơn đặt hàng sẽ xuất hiện.

Các phần tiếp theo cung cấp thông tin chi tiết về cách giải quyết các trường hợp này bằng cách sử dụng thông tin cập nhật đơn đặt hàng.

Chuyển đổi trạng thái đơn đặt hàng

Một đơn đặt hàng có thể có 6 trạng thái. Các trạng thái này và các chuyển đổi có thể có của chúng được nêu trong sơ đồ sau:

Chuyển đổi trạng thái đơn đặt hàng

Khi khách hàng gửi đơn đặt hàng lần đầu tiên, đơn đặt hàng sẽ bắt đầu ở trạng thái CREATED, CONFIRMED hoặc REJECTED. Bạn có thể gửi thông báo cập nhật đơn đặt hàng để cập nhật trạng thái của đơn đặt hàng, miễn là quá trình chuyển đổi trạng thái hợp lệ. Trạng thái CREATED được dùng khi nền tảng của đối tác không thể xác nhận hoặc từ chối đơn đặt hàng ngay lập tức. Ví dụ về trường hợp sử dụng là khi khách hàng đặt hàng thông qua một trình tổng hợp đơn hàng giao hàng. Công cụ tổng hợp dịch vụ giao hàng nhận đơn đặt hàng giao từ Google và gửi thông tin đó đến nhà hàng. Sau khi nhà hàng nhận được và xác nhận tình trạng còn hàng của đơn đặt hàng, trạng thái hiện có thể là CONFIRMED, nếu không thì là REJECTED.

Tiếp theo, đơn đặt hàng ở trạng thái CONFIRMED sẽ chuyển sang trạng thái IN_PREPARATION. Tuỳ thuộc vào việc đơn đặt hàng là để đến lấy hàng hay giao hàng, tiếp theo, hãy sử dụng trạng thái READY_FOR_PICKUP hoặc IN_TRANSIT. Khi đồ ăn đã được giao hoặc được đến lấy, đơn đặt hàng sẽ được đặt thành trạng thái FULFILLED.

Nếu cho phép khách hàng huỷ đơn đặt hàng, bạn có thể sử dụng trạng thái CANCELLED. Bạn có thể huỷ đơn đặt hàng khi đơn đặt hàng ở trạng thái CREATED, CONFIRMED, IN_PREPARATION, READY_FOR_PICKUP hoặc IN_TRANSIT. Dịch vụ Đặt hàng toàn diện của bạn sẽ hoàn tiền tuỳ thuộc vào chính sách huỷ và trạng thái thanh toán tại thời điểm huỷ.

Dịch vụ Đặt hàng toàn diện của bạn không nhất thiết phải hỗ trợ tất cả các trạng thái và quá trình chuyển đổi hiện có. Tuy nhiên, trạng thái cuối cùng của đơn đặt hàng phảiFULFILLED, REJECTED hoặc CANCELLED.

Cung cấp thời gian thực hiện đơn hàng ước tính

Bạn có thể cung cấp cho người dùng phạm vi thời gian ước tính để họ đến lấy hàng (hoặc nhận hàng). Sử dụng trường estimatedFulfillmentTimeIso8601 của FoodOrderUpdateExtension để cung cấp phạm vi thời gian ước tính cho thời điểm đơn đặt hàng của khách hàng có thể đến lấy hàng hoặc được giao.

Gửi estimatedFulfillmentTimeIso8601 vào các thời điểm sau:

  • Khi thời gian ước tính có sẵn, tốt nhất là ở trạng thái thứ tự CREATED hoặc CONFIRMED.
  • Khi thời gian ước tính thay đổi, chẳng hạn như cập nhật thời gian ước tính để chính xác hơn khi đơn đặt hàng là IN_TRANSIT.

Để quản lý hiệu quả kỳ vọng của người dùng, hãy ước tính một cách thận trọng và cung cấp phạm vi ngày và giờ thay vì ngày và giờ cố định. Bạn nên tính đến các biến thể như điều kiện giao thông bất cứ khi nào có thể. Ví dụ: bạn có thể gửi thời gian giao hàng dự kiến là 12:45 (giới hạn dưới) đến 13:15 (giới hạn trên) cho một đơn đặt hàng có thời gian giao hàng dự kiến là 13:00.

Cung cấp các hành động quản lý đơn đặt hàng

Khi gửi thông tin cập nhật về đơn đặt hàng, bạn có thể cung cấp cho khách hàng các tài nguyên giúp họ quản lý đơn đặt hàng dưới dạng OrderManagementAction. Sau khi đặt hàng, khách hàng có thể cần liên hệ với bạn hoặc nhà hàng thực hiện đơn đặt hàng để theo dõi tiến trình, thay đổi hoặc huỷ đơn đặt hàng.

OrderManagementAction cho phép khách hàng gửi email, gọi điện hoặc liên kết đến một URL ngay trên thiết bị của họ. Sử dụng cùng một thông tin trong OrderManagementAction như trong email xác nhận đơn đặt hàng mà bạn gửi cho người dùng.

Các hành động quản lý đơn đặt hàng bao gồm các loại sau:

  • CUSTOMER_SERVICE: Cung cấp cho khách hàng một hành động để liên hệ với bộ phận hỗ trợ khách hàng. Bạn bắt buộc phải sử dụng loại hành động quản lý này để cập nhật đơn đặt hàng.
  • EMAIL: Cung cấp cho khách hàng một thao tác để gửi email đến địa chỉ email đã cung cấp.
  • CALL: Cung cấp cho khách hàng một hành động để gọi đến số điện thoại được cung cấp.
  • VIEW_DETAIL: Cung cấp cho khách hàng một hành động để xem thông tin chi tiết về đơn đặt hàng.

Mỗi nội dung cập nhật đơn đặt hàng phải chứa ít nhất một hành động quản lý đơn đặt hàng. Tuy nhiên, các hành động quản lý đơn đặt hàng được cung cấp có thể khác nhau tuỳ theo trạng thái của đơn đặt hàng. Ví dụ: khi một đơn đặt hàng ở trạng thái CONFIRMED, hành động CUSTOMER_SERVICE có thể trỏ đến số điện thoại dịch vụ khách hàng của bạn. Khi trạng thái đơn đặt hàng đó cập nhật thành IN_TRANSIT, thao tác CUSTOMER_SERVICE có thể trỏ đến số điện thoại của nhà hàng thực hiện đơn đặt hàng.

Gửi thông tin cập nhật về đơn đặt hàng

Bạn sử dụng loại thông báo AsyncOrderUpdateRequestMessage để gửi thông tin cập nhật về đơn đặt hàng đến dịch vụ Đặt hàng toàn diện. Google phản hồi bằng một AsyncOrderUpdateResponseMessage. Ví dụ: nếu muốn thông báo cho khách hàng rằng đơn đặt hàng của họ hợp lệ và đã được chấp nhận, bạn có thể gửi AsyncOrderUpdateRequestMessage để thay đổi trạng thái của đơn đặt hàng thành CONFIRMED bằng nhãn Accepted by restaurant.

Sơ đồ cập nhật đơn đặt hàng

Thiết lập thông báo cập nhật đơn đặt hàng

Khi gửi AsyncOrderUpdateRequestMessage cho Google, bạn phải thêm thông tin về trạng thái của đơn đặt hàng bằng cách sử dụng trường OrderUpdate.

Các ví dụ sau đây cho thấy một AsyncOrderUpdateRequestMessage mẫu cho mỗi trạng thái đơn đặt hàng:

ĐÃ XÁC NHẬN

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu thông báo cho người dùng rằng đơn đặt hàng đã được xác nhận kèm theo biên nhận và thời gian giao hàng dự kiến.

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

BỊ TỪ CHỐI

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu thông báo cho người dùng rằng đơn đặt hàng bị từ chối kèm theo lý do từ chối.

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

ĐÃ HỦY

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu thông báo cho người dùng rằng đơn đặt hàng đã bị huỷ kèm theo lý do huỷ.

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

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu thông báo cho người dùng rằng đồ ăn đang được chuẩn bị.

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

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu thông báo cho người dùng rằng đồ ăn đã sẵn sàng để đến lấy.

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

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu thông báo cho người dùng rằng đơn đặt hàng đang được vận chuyển với thời gian giao hàng dự kiến.

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

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu thông báo cho người dùng rằng đơn đặt hàng đã được lấy hoặc giao:

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

Để biết thêm ví dụ về các yêu cầu cập nhật đơn đặt hàng trong nhiều trường hợp sử dụng, hãy đọc bài viết Triển khai tính năng cập nhật đơn đặt hàng nâng cao.

Tạo mã thông báo uỷ quyền và gửi thông báo

Thông tin cập nhật đơn đặt hàng yêu cầu mã thông báo uỷ quyền để dịch vụ Đặt hàng toàn diện có thể xác minh rằng thông báo đó là của dịch vụ web Đặt hàng toàn diện.

Để triển khai nội dung cập nhật đơn đặt hàng cho dự án, hãy làm theo các bước sau:

  1. Tạo mã thông báo uỷ quyền bằng cách làm theo các bước sau:
    1. Sử dụng Thư viện xác thực của Google để đọc thông tin xác thực từ tệp tài khoản dịch vụ.
    2. Yêu cầu mã thông báo bằng phạm vi API sau: https://www.googleapis.com/auth/actions.fulfillment.conversation
  2. Sử dụng mã thông báo này để gửi yêu cầu POST HTTP đã xác thực đến điểm cuối sau: https://actions.googleapis.com/v2/conversations:send
  3. Đặt tiêu đề Content-Type thành application/json trong yêu cầu của bạn.

Các ví dụ sau đây minh hoạ cách triển khai thông tin cập nhật về đơn đặt hàng:

Node.js

Mã này sử dụng thư viện xác thực của Google cho 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

Mã này sử dụng thư viện xác thực của Google cho 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

Mã này sử dụng thư viện xác thực của Google cho 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",);
}
    

Đối với các yêu cầu cập nhật đơn đặt hàng thành công mà không gặp lỗi, Google sẽ trả về một phản hồi HTTP 200 với tải trọng trống. Nếu có vấn đề, chẳng hạn như bản cập nhật có định dạng không chính xác, Google sẽ trả về lỗi.