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

Sau khi khách hàng gửi đơn đặt món, bạn có thể gửi tin nhắn cập nhật đơn đặt hàng đến dịch vụ Đặt món hai đầu để thông báo cho chúng tôi về sự thay đổi này.

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

  • Thời gian thực hiện dự kiến cho đơn đặt hàng có sẵn hoặc 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ữa.
  • Đã thay đổi giá của một món trong thực đơn có trong đơn đặt hàng này.
  • Khách hàng có một cách mới để quản lý đơn đặt hàng, chẳng hạn như liên hệ bộ phận hỗ trợ khách hàng hoặc số điện thoại của nhà hàng.
  • Biên nhận cho đơn đặt hàng sẽ có sẵn.

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

Trạng thái đơn đặt hàng chuyển đổi

Một đơn đặt hàng có thể có sáu trạng thái. Các trạng thái này và các quá trình chuyển đổi có thể xảy ra được trình bày trong sơ đồ sau:

Chuyển đổi trạng thái thứ tự

Khi khách hàng gửi đơn đặt hàng lần đầu tiên, đơn đặt hàng sẽ bắt đầu với 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. Một trường hợp sử dụng mẫu là khi khách hàng đặt hàng thông qua một đơn vị tổng hợp hoạt động giao hàng. Đơn vị tập hợp dịch vụ giao đồ ăn sẽ nhận thông tin giao hàng từ Google, sau đó đơn vị tổng hợp sẽ 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, trạng thái bây giờ có thể là CONFIRMED, nếu không 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 sử dụng hình thức đến lấy hàng hay giao hàng, hãy sử dụng trạng thái READY_FOR_PICKUP hoặc IN_TRANSIT. Khi đồ ăn được giao hoặc đến lấy, đơn đặt hàng sẽ được đặt ở 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. Có thể huỷ đơn đặt hàng khi ở trạng thái CREATED, CONFIRMED, IN_PREPARATION, READY_FOR_PICKUP hoặc IN_TRANSIT. Dịch vụ đặt hàng trọn đầu của bạn sẽ tiến hành hoàn tiền tuỳ thuộc vào chính sách huỷ của bạn và trạng thái thanh toán tại thời điểm huỷ.

Dịch vụ Đặt hàng đầu cuối của bạn không cần phải hỗ trợ tất cả các trạng thái và chuyển đổi có sẵn. 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 ước tính

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

Gửi estimatedFulfillmentTimeIso8601 vào những thời điểm sau:

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

Để quản lý kỳ vọng của người dùng một cách hiệu quả, hãy thận trọng trong các ước tính của bạn và cung cấp phạm vi ngày giờ thay vì ngày giờ cố định. Bạn nên tính đến các biến thể, chẳng hạn như điều kiện lưu lượng truy cập 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 từ 12:45 chiều (giới hạn dưới) đến 1:15 chiều (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 chiều.

Cung cấp các thao tác 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 tài nguyên cho khách hàng để giúp họ quản lý đơn đặt hàng dưới dạng OrderManagementAction. Sau khi khách hàng đặt hàng, họ có thể cần phải 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, thực hiện các thay đổi hoặc hủy đơ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.

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

Mỗi 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 thao tác quản lý đơn đặt hàng được cung cấp có thể thay đổi 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, thao tác CUSTOMER_SERVICE có thể trỏ đến số điện thoại của bộ phận dịch vụ khách hàng. 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 hàng.

Đang 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 đối với dịch vụ Đặt hàng hai đầu. Google sẽ phản hồi bằng 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ọ là 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 với nhãn Accepted by restaurant.

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

Thông báo cập nhật về việc đặt đơn đặt hàng

Khi gửi AsyncOrderUpdateRequestMessage đến Google, bạn phải đưa vào 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 minh hoạ một AsyncOrderUpdateRequestMessage mẫu cho từng 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 nhằm thông báo cho người dùng rằng đơn đặt hàng đã được xác nhận bằng 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 nhằm 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."
        }
      ]
      }
    }
  }
}
    

CANCELLED (ĐÃ HUỶ)

Ví dụ này cho thấy một yêu cầu cập nhật đơn đặt hàng mẫu sẽ thông báo cho người dùng rằng đơn đặt hàng bị huỷ vì 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 sẽ thông báo cho người dùng rằng thức ăn hiệ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 sẽ thông báo cho người dùng rằng thức ă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"
      }
    }
  }
}
  

ĐÃ THỰC HIỆN

Dưới đây là ví dụ về 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 đến 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 nội dung cập nhật nâng cao về đơn đặt hàng.

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

Nội dung cập nhật đơn đặt hàng cần có mã uỷ quyền để dịch vụ Đặt hàng hai đầu có thể xác minh tin nhắn đến từ dịch vụ web Đặt hàng hai đầu của bạn.

Để triển khai thông tin cập nhật về đơn đặt hàng cho dự án của bạ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ụ của bạn.
    2. Yêu cầu mã thông báo bằng cách sử dụng phạm vi API sau đây: 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 qua HTTP đã xác thực đến điểm cuối sau: https://actions.googleapis.com/v2/conversations:send
  3. Thiết lập 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 dành 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",);
}
    

Để cập nhật đơn đặt hàng thành công mà không gặp lỗi, Google sẽ trả về 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 không đúng định dạng, Google sẽ trả về lỗi.