Bạn có thể thêm tính năng hỗ trợ trong quy trình thực hiện đơn hàng để người dùng lên lịch trước việc đến lấy hàng và giao đồ ăn. Trước khi triển khai tính năng hỗ trợ này trong quá trình thực hiện đơn hàng, hãy tạo nguồn cấp dữ liệu khoảng không quảng cáo dịch vụ chỉ định giờ để người dùng đặt hàng trước, như mô tả trong giản đồ nguồn cấp dữ liệu khoảng không quảng cáo (AdvanceServiceDeliveryHoursSpecification
).
Khung giờ đặt hàng trước
Google đề xuất các khung giờ đặt hàng trước, tăng dần 15 phút, trong tối đa 7 ngày tới, dựa trên thời gian thực hiện đơn hàng của nhà hàng hoặc dịch vụ (như được xác định trong AdvanceServiceDeliveryHoursSpecification
).
Để truy xuất các khung giờ đặt trước được đề xuất, hãy sử dụng các giá trị sau đây trong trường fulfillmentPreference
của đối tượng FoodCartExtension
tại bước thanh toán:
PickupInfo.pickupTimeIso8601
DeliveryInfo.deliveryTimeIso8601
Triển khai đơn đặt hàng trước ở bước thanh toán
Bảng bên dưới liệt kê các cách có thể để bạn triển khai phản hồi của phương thức thực hiện đơn hàng tại thời điểm thanh toán khi người dùng cố gắng đặt hàng.
Trường hợp | Hành vi thực hiện đơn hàng |
---|---|
Có thể thực hiện đơn đặt hàng trước cho khung giờ được yêu cầu. | Chấp nhận giỏ hàng P0M ("càng sớm càng tốt") hoặc
FUTURE_SLOT bằng cách tạo một ProposedOrder có
cùng một vị trí. Để biết ví dụ về phản hồi thanh toán chấp nhận một khung giờ, hãy xem đoạn mã này. |
Không thể thực hiện đơn đặt hàng trước cho khung giờ đã yêu cầu. | Phương thức thực hiện đơn hàng của bạn phải thực hiện những việc sau:
Để biết ví dụ về phản hồi thanh toán đề xuất các khung giờ thay thế, hãy xem đoạn mã này. |
Khung giờ thay thế để thực hiện đơn hàng
Tại bước thanh toán, nếu các khung giờ đặt hàng trước do Google đề xuất không phù hợp, thì phương thức thực hiện đơn hàng của bạn có thể đề xuất các khung giờ thay thế bằng cách sử dụng đối tượng CheckoutResponseMessage
.
Để chỉ định các khung giờ đặt hàng trước thay thế, hãy phản hồi yêu cầu thanh toán bằng FoodErrorExtension
và đặt các giá trị sau:
- Trong tham số
foodOrderErrors
, hãy chỉ định loại lỗi (chẳng hạn nhưUNAVAILABLE_SLOT
,NO_CAPACITY
hoặcCLOSED
). - Trong tham số
correctedProposedOrder
, hãy cung cấp các giá trịP0M
hoặcFUTURE_SLOT
thay thế thông quaavailableFulfillmentOptions
.
Các khung giờ thay thế phải là trong vòng 7 ngày tiếp theo kể từ thời điểm đặt hàng và bao gồm tất cả khung giờ mà bạn có thể thực hiện đơn đặt hàng mà người dùng yêu cầu.
Ví dụ: giả sử bạn chỉ phục vụ bữa trưa đặc biệt từ thứ Hai đến thứ Sáu, từ 11:00 đến 13:00. Sau đó, người dùng cố gắng thêm bữa trưa đặc biệt vào giỏ hàng nhưng không có khung giờ mà họ chọn. Trong trường hợp này, quy trình thực hiện đơn hàng của bạn sẽ giữ lại bữa trưa đặc biệt trong giỏ hàng và chỉ trả về khung giờ từ 11:00 đến 13:00 trong 7 ngày tới
Bạn nên bỏ qua đối tượng correctedProposedOrder.Cart.fulfillmentPreference
trong phản hồi.
Nếu không có khung giờ nào trống hoặc nếu nhà hàng hoặc dịch vụ không hỗ trợ đặt trước, thì bạn không cần cung cấp correctedProposedOrder
.
Hãy xem các ví dụ bên dưới về thông điệp JSON giữa đơn vị thực hiện đơn hàng và Google trong quy trình yêu cầu thanh toán và phản hồi cho đơn đặt hàng trước, khi nhà hàng hoặc dịch vụ có thể nhận đơn đặt hàng trước.
Ví dụ: CheckoutRequest có khung giờ giao hàng
Đoạn mã dưới đây cho thấy ví dụ về một yêu cầu thanh toán có khung giờ giao hàng trước cho đơn đặt hàng.
{
"inputs": [
{
"intent": "actions.foodordering.intent.CHECKOUT",
"arguments": [
{
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.Cart",
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Cucina Venti"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
// Deliver at 6:30PM.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
},
"location": {
...
}
}
}
}
]
}
]
}
Ví dụ: CheckoutResponse chấp nhận khung giờ
Đoạn mã dưới đây cho thấy ví dụ về phản hồi thanh toán, trong đó phương thức thực hiện đơn hàng chấp nhận các khung giờ đặt hàng trước được đề xuất.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"checkoutResponse": {
"proposedOrder": {
"id": "sample_proposed_order_id_1",
"cart": {
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Falafel Bite"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
// Same as the time in the request.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
},
"location": {
...
}
}
},
"totalPrice": {
"type": "ESTIMATE",
"amount": {
// Represents $16.75
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
// Send whole proposed order back.
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
// Same as the time in the request.
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
]
}
},
"paymentOptions": {
...
}
}
}
}
]
}
}
}
Ví dụ: CheckoutResponse có các khung giờ thay thế
Đoạn mã dưới đây cho thấy ví dụ về phản hồi thanh toán, trong đó phương thức thực hiện đơn đặt hàng đề xuất các khung giờ đặt hàng trước thay thế. Xin lưu ý rằng bạn nên bỏ qua đối tượng correctedProposedOrder.Cart.fulfillmentPreference
trong phản hồi.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"error": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
"foodOrderErrors": [
{
"error": "UNAVAILABLE_SLOT", // Cart level error
"description": "The restaurant is closed."
}
],
"correctedProposedOrder": {
// Send whole original cart back,
// without the fulfillmentPreference.
"cart": {
...
},
"otherItems": {
...
},
"totalPrice": {
...
},
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T19:00:00-07:00"
}
},
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T19:30:00-07:00"
}
},
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T20:00:00-07:00"
}
}
]
}
},
"paymentOptions": {
...
}
}
}
}
]
}
}
}
Triển khai đơn đặt hàng trước khi gửi đơn đặt hàng
Khi gửi đơn đặt hàng, nếu có vấn đề với khung giờ đặt hàng trước, thì SubmitOrderResponseMessage
phải bao gồm lý do (chẳng hạn như UNAVAILABLE_SLOT
hoặc UNKNOWN
) trong đối tượng RejectionInfo
.
Cập nhật trạng thái của đơn đặt hàng từ CREATED
thành CONFIRMED
trong đối tượng OrderState
khi nhà cung cấp chấp nhận đơn đặt hàng. Đưa khung giờ đã chọn vào email xác nhận gửi cho người dùng.
Nếu quy trình thực hiện đơn đặt hàng của bạn gửi đơn đặt hàng đến nhà hàng sau, hãy gửi cho Google thông tin cập nhật bằng cách sử dụng Thao tác cập nhật đơn đặt hàng không đồng bộ.
Trong đối tượng OrderUpdate
của phản hồi gửi đơn đặt hàng của phương thức thực hiện hoặc các bản cập nhật đơn đặt hàng không đồng bộ tiếp theo, hãy thêm một estimatedFulfillmentTimeIso8601
có giá trị được đặt như sau:
- Khi trạng thái đơn đặt hàng là
CREATED
hoặcCONFIRMED
, hãy đặt giá trị thành thời gian giao hàng hoặc thời gian đến lấy hàng mà người dùng đã lên lịch cho đơn đặt hàng trước. - Khi nhà hàng hoặc dịch vụ cung cấp thời gian giao hàng dự kiến chính xác hơn, hãy đặt giá trị này thành thời gian giao hàng hoặc thời gian đến lấy hàng dự kiến.
Ví dụ: SubmitOrderRequest có khung giờ giao hàng
Đoạn mã dưới đây cho thấy ví dụ về yêu cầu gửi đơn đặt hàng cho biết khung giờ đặt hàng trước mà người dùng đã chọn.
{
"inputs": [
{
"intent": "actions.intent.TRANSACTION_DECISION",
"arguments": [
{
"transactionDecisionValue": {
"order": {
"finalOrder": {
"cart": {
"notes": "Guest prefers their food to be hot when it is delivered.",
"merchant": {
"id": "https://www.exampleprovider.com/merchant/id1",
"name": "Cucina Venti"
},
"lineItems": [
{
"name": "Sizzling Prawns Dinner",
"type": "REGULAR",
"id": "sample_item_offer_id_1",
"offerId": "https://www.exampleprovider.com/menu/item/offer/id1",
"quantity": 1,
"price": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
}
}
],
"extension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
"fulfillmentPreference": {
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
}
"contact": {
...
}
}
},
"totalPrice": {
"type": "ESTIMATE",
"amount": {
"currencyCode": "USD",
"units": "16",
"nanos": 750000000
}
},
"id": "sample_final_order_id",
"extension": {
// Send whole proposed order back.
"availableFulfillmentOptions": [
"fulfillmentInfo": {
"delivery": {
"deliveryTimeIso8601": "2017-12-14T18:30:00-07:00"
}
]
}
},
"googleOrderId": "sample_google_order_id",
"orderDate": "2017-07-17T12:00:00Z",
"paymentInfo": {
...
}
}
}
}
]
}
]
}
Ví dụ: SubmitOrderResponse chấp nhận đơn đặt hàng
Đoạn mã dưới đây cho thấy ví dụ về phản hồi gửi đơn đặt hàng, trong đó dịch vụ thực hiện đơn đặt hàng xác nhận rằng đã chấp nhận đơn đặt hàng trước của người dùng.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"orderUpdate": {
"actionOrderId": "sample_action_order_id",
"orderState": {
"state": "CREATED",
"label": "Order placed"
},
"receipt": {
"userVisibleOrderId": "userVisibleId1234"
},
"updateTime": "2017-07-17T12:00:00Z",
"orderManagementActions": [
...
],
"infoExtension": {
"@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderUpdateExtension",
// Same as the user selected time.
"estimatedFulfillmentTimeIso8601": "2017-12-14T18:30:00-07:00"
}
}
}
}
]
}
}
}
Ví dụ: SubmitOrderResponse từ chối đơn đặt hàng do không có khung giờ
Đoạn mã dưới đây cho thấy ví dụ về phản hồi gửi đơn đặt hàng, trong đó phương thức thực hiện đơn đặt hàng từ chối đơn đặt hàng trước của người dùng do không có khung giờ phù hợp.
{
"expectUserResponse": false,
"finalResponse": {
"richResponse": {
"items": [
{
"structuredResponse": {
"orderUpdate": {
"actionOrderId": "sample_action_order_id",
"orderState": {
"state": "REJECTED",
"label": "Unavailable slot"
},
"rejectionInfo": {
// Note that this UNAVAILABLE_SLOT is different from the enum
// with the same name proposed for FoodOrderError.
"state": "UNAVAILABLE_SLOT",
"label": "Unavailable slot"
},
"updateTime": "2017-07-17T12:00:00Z",
"orderManagementActions": [
...
]
}
}
}
]
}
}
}
Ví dụ về đơn đặt hàng trước
Bạn có thể sử dụng loại AdvanceServiceDeliveryHoursSpecification
để chỉ định giờ giao hàng hoặc giờ đến lấy hàng để người dùng lên lịch đặt hàng trước.
Lưu ý: Bạn phải chỉ định hai khoảng thời gian riêng biệt để thực hiện dịch vụ: khoảng thời gian đặt hàng chỉ định thời điểm người dùng có thể đặt hàng và khoảng thời gian thực hiện chỉ định thời điểm thực hiện đơn đặt hàng. Đối tượng
xác định thời điểm người dùng có thể đặt hàng. Thời gian thực hiện đơn hàng con (OpeningHoursSpecification
hoặc ServiceDeliveryHoursSpecification
) xác định thời điểm có thể thực hiện đơn hàng.AdvanceServiceDeliveryHoursSpecification
Ví dụ sau đây xác định giờ hoạt động của dịch vụ để chấp nhận đơn đặt hàng trước, với khoảng thời gian bảo dưỡng là 15 phút.
{ "hoursAvailable": [ { "@type": "OpeningHoursSpecification", "opens": "T00:00:00", // Ordering available 24 hours "closes": "T23:59:59", "deliveryHours": [ { "@type": "ServiceDeliveryHoursSpecification", "opens": "T09:00:00", // ASAP orders b/w 9am and 8:59:59pm "closes": "T21:00:00", "deliveryLeadTime": { "value": "60", "unitCode": "MIN" } }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T10:00:00", // Delivery between 10AM and 7:59:59PM "closes": "T20:00:00", "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart (ISO8601) "advanceBookingRequirement": { "minValue": 60, // The slot should be at least 60 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } ] } ] }
Ví dụ sau đây cho thấy cách bạn có thể chỉ định rằng dịch vụ này sẽ mở cửa cho các đơn đặt hàng cùng ngày vào ngày Giáng sinh nhưng sẽ đóng cửa cho các đơn đặt hàng trước được lên lịch vào ngày đó. Ví dụ này hỗ trợ các trường hợp sau:
- Người dùng có thể đặt hàng vào ngày 25 tháng 12 để được giao hàng trong ngày.
- Người dùng có thể đặt hàng trước vào ngày 25 tháng 12 để giao hàng theo lịch vào ngày 27 tháng 12.
- Người dùng không thể đặt hàng trước vào ngày 22 tháng 12 để giao hàng theo lịch vào ngày 25 tháng 12.
{ "specialOpeningHoursSpecification": { "@type": "AdvanceServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // No advance ordering "closes": "T00:00:00" } }
Ví dụ sau đây cho biết cách bạn có thể chỉ định rằng dịch vụ này sẽ đóng cửa đối với các đơn đặt hàng cùng ngày hoặc đơn đặt hàng trước được lên lịch vào ngày Giáng sinh, nhưng sẽ mở cửa đối với các đơn đặt hàng trước được lên lịch vào một ngày sau đó. Ví dụ này hỗ trợ các trường hợp sau:
- Người dùng không thể đặt hàng vào ngày 25 tháng 12 để giao hàng cùng ngày.
- Người dùng có thể đặt hàng trước vào ngày 25 tháng 12 để giao hàng theo lịch vào ngày 27 tháng 12.
- Người dùng không thể đặt hàng trước vào ngày 22 tháng 12 để giao hàng theo lịch vào ngày 25 tháng 12.
{ "specialOpeningHoursSpecification": [ { "@type": "ServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // No ASAP ordering on Christmas "closes": "T00:00:00" }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "validFrom": "2018-12-25T00:00:00-07:00", "validThrough": "2018-12-26T00:00:00-07:00", "opens": "T00:00:00", // Orders cannot be scheduled for Christmas "closes": "T00:00:00" } ] }
Dịch vụ mẫu sau đây chấp nhận đơn đặt hàng 24/7 và giao hàng từ 10:00 đến 23:59:59 vào các ngày trong tuần:
... { "@type": "OpeningHoursSpecification", "opens": "T00:00:00", "closes": "T23:59:59", "deliveryHours": { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T10:00:00", // Delivery starts at 10:00AM "closes": "T15:00:00", // Delivery ends at 3:00PM. Delivery from 10AM-2:59:59PM. "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart "advanceBookingRequirement": { "minValue": 60, // The slot should be at least 60 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } } ...
Dịch vụ mẫu sau đây chấp nhận đơn đặt hàng mỗi ngày từ 8:00 đến 16:59:59 và khách hàng có thể chọn giao hàng trong vòng một giờ hoặc chọn một trong các khung giờ:
... { "@type": "OpeningHoursSpecification", "opens": "T08:00:00", // Ordering opens at 8:00AM "closes": "T17:00:00", // Ordering closes at 5:00PM, last order at 4:59:59PM "deliveryHours": [ { "@type": "ServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "deliveryLeadTime": { "@type": "QuantitativeValue", "value": "60", // If no exact deliveryLeadTime, put a maximum time "unitCode": "MIN" } }, { "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "serviceTimeInterval": "PT15M", // in slots spaced 15 minutes apart "advanceBookingRequirement": { "minValue": 90, // The slot should be at least 90 mins away "maxValue": 8640, // but not more than 6 days away "unitCode": "MIN" } } ] } ...
Mẫu sau đây cho thấy trường hợp cửa hàng mở cửa từ 8:00 đến 20:59:59 vào các ngày trong tuần, nhưng mở cửa từ 8:00 đến 18:59 vào cuối tuần. Chúng tôi không nhận đơn đặt hàng 24/7.
... { // On weekdays, ordering open from 8AM-4:59:59PM. "@type": "OpeningHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "deliveryHours": [ { // Fulfillment between 8AM-4:59:59PM on weekdays. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } }, { // Fulfillment between 8AM-6:59:59PM on weekends (even for orders placed on a // weekday). "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } } ] }, { // On weekends, one can place orders upto 6:59:59PM. "@type": "OpeningHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "deliveryHours": [ { // But fulfillment on weekdays is only till 4:59:59PM. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T17:00:00", "dayOfWeek": [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } }, { // Fulfillment on weekends is till 6:59:59PM. "@type": "AdvanceServiceDeliveryHoursSpecification", "opens": "T08:00:00", "closes": "T19:00:00", "dayOfWeek": [ "Saturday", "Sunday" ], "serviceTimeInterval": "PT15M", "advanceBookingRequirement": { "minValue": 60, "maxValue": 8640, "unitCode": "MIN" } } ] } ...