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 thông báo cập nhật đơn đặt hàng tới dịch vụ Đặt món bằng Google để thông báo cho chúng tôi về thay đổi đó.

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 ước tính cho đơn đặt hàng khả dụng hoặc thay đổi.
  • Trạng thái đơn đặt hàng thay đổi.
  • Đơn đặt hàng không thể thực hiện được nữa.
  • Giá của một món trong thực đơn có 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ư 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 có sẵn.

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 về đơn đặt hàng.

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

Đơn đặt hàng có thể có sáu trạng thái. Các trạng thái này và khả năng chuyển đổi có thể đượ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 bằng 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 ví dụ về trường hợp sử dụng là khi khách hàng đặt hàng thông qua trình tổng hợp phân phối. Đơn vị tổng hợp giao hàng nhận được dịch vụ giao hàng từ Google và tổng hợp sẽ gửi thông tin đến nhà hàng. Sau khi nhà hàng nhận được món ăn và xác nhận tình trạng còn hàng, trạng thái hiện có thể là CONFIRMED, nếu không thì REJECTED.

Tiếp theo, một đơn đặt hàng ở trạng thái CONFIRMED sẽ chuyển sang trạng thái IN_PREPARATION. Tuỳ thuộc vào đơn đặt hàng là tự đến lấy 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 được nhận, đơn đặt hàng được đặt ở trạng thái FULFILLED.

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

Dịch vụ Order with Google của bạn không cần hỗ trợ tất cả các trạng thái và quá trình 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 một khoảng thời gian ước tính về thời điểm đơn đặt hàng của họ sẽ sẵn sàng để nhận (hoặc giao). Sử dụng trường estimatedFulfillmentTimeIso8601 của FoodOrderUpdateExtension để cung cấp khoảng thời gian ước tính khi đơn đặt hàng của khách hàng sẵn sàng để nhận hoặc giao.

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

  • Thời gian ước tính sẽ xuất hiện, lý tưởng là theo 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 dự kiến để chính xác hơn khi đơn hàng là IN_TRANSIT.

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

Cung cấp 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 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 đặt hàng, khách hàng có thể phải liên hệ với bạn hoặc nhà hàng để hoàn thành đơn đặt hàng để theo dõi tiến trình, thực hiện thay đổi hoặc hủy đơn đặt hàng.

OrderManagementAction cho phép khách hàng gửi email, gọi hoặc liên kết đến một URL ngay trên thiết bị của họ. Sử dụng cùng 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.

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 thao tác để liên hệ với dịch vụ khách hàng. Bạn bắt buộc phải thực hiện 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 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 hành động quản lý đơn đặt hàng bạn 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, 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, hành động CUSTOMER_SERVICE có thể trỏ đến số điện thoại của nhà hàng thực hiện đơn 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 qua dịch vụ Đặt món bằng Google. Google sẽ phản hồi lạ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

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

Khi gửi AsyncOrderUpdateRequestMessage đến 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 hiển thị một mẫu AsyncOrderUpdateRequestMessage cho mỗi trạng thái đơn đặt hàng:

ĐÃ XÁC NHẬN

Ví dụ này cho thấy 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 bằng một 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 yêu cầu cập nhật đơn đặt hàng 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 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ị hủy kèm theo lý do hủy.

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

Hàm IN_PREPARATION

Ví dụ này cho thấy 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 thực phẩm 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"
      }
    }
  }
}
    

ĐÃ SẴN SÀNG

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 thực phẩm đã sẵn sàng cho bạn đế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"
      }
    }
  }
}
    

Hàm IN_TRANSIT

Ví dụ này cho thấy 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

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 đã đến lấy hoặc giao hàng:

{
  "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ề 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 ủy quyền và gửi tin nhắn

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

Để triển khai cập nhật đơ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: 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 HTTP POST đã 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 họa cách triển khai cập nhật đơ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",);
}
    

Để 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 phần nội dung trống. Nếu có vấn đề, chẳng hạn như bản cập nhật không đúng định dạng, thì Google sẽ trả về lỗi.