Bạn có thể hỗ trợ thêm trong phương thức thực hiện của mình để người dùng lên lịch trước cho các đơn đặt hàng tự đến lấy và giao đồ ăn. Trước khi triển khai tính năng hỗ trợ này trong phương thức thực hiện, hãy tạo một 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 hàng (AdvanceServiceDeliveryHoursSpecification
).
Khung giờ đặt hàng trước
Google đề xuất khung giờ đặt hàng trước theo mức tăng 15 phút (tối đa 7 ngày trước đó) dựa trên thời gian thực hiện đơn hàng của một nhà hàng hoặc dịch vụ (như xác định trong AdvanceServiceDeliveryHoursSpecification
).
Để truy xuất thời điểm đề xuất cho đơn đặt hàng trước, hãy sử dụng các giá trị sau từ trường fulfillmentPreference
của đối tượng FoodCartExtension
ở bước thanh toán:
PickupInfo.pickupTimeIso8601
DeliveryInfo.deliveryTimeIso8601
Triển khai đơn đặt hàng trước khi thanh toán
Bảng dưới đây liệt kê các cách mà bạn có thể 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 |
---|---|
Đơn đặt hàng trước có thể được thực hiện cho vị trí đượ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 ô. Để biết ví dụ về phản hồi thanh toán chấp nhận vị trí, hãy xem đoạn mã này. |
Không thể thực hiện đơn đặt hàng trước cho vị trí được yêu cầu. | Phương thức thực hiện 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 vị trí thay thế, hãy xem đoạn mã này. |
Vị trí thay thế để thực hiện đơn đặt hàng
Khi thanh toán, nếu các vị trí đặt hàng trước do Google đề xuất không phù hợp, thì phương thức thực hiện của bạn có thể đề xuất các lựa chọn thay thế bằng cách sử dụng đối tượng CheckoutResponseMessage
.
Để chỉ định khung giờ cho đơn đặ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 vị trí thay thế nên là trong 7 ngày tiếp theo kể từ thời điểm đặt hàng và bao gồm tất cả các vị trí mà giỏ hàng mà người dùng yêu cầu có thể được thực hiện.
Ví dụ: giả sử giá đặc biệt cho bữa trưa chỉ có từ thứ Hai đến thứ Sáu, từ 11 giờ sáng đến 1 giờ chiều. Sau đó, người dùng thử thêm các món ăn trưa đặc biệt vào giỏ hàng nhưng không gian họ đã chọn không có sẵn. Trong trường hợp này, phương thức thực hiện của bạn sẽ giữ lại các món ăn trưa đặc biệt trong giỏ hàng và chỉ trả lại khung giờ 11 giờ sáng đến 1 giờ chiều 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òn suất trống hoặc nếu nhà hàng hoặc dịch vụ không hỗ trợ đặt hàng trước, thì bạn không cần cung cấp correctedProposedOrder
.
Hãy xem ví dụ dưới đây về thông báo JSON giữa phương thức thực hiện đơn hàng của bạn và Google trong quá trình yêu cầu thanh toán và phản hồi cho một đơn đặt hàng trước, khi nhà hàng hoặc dịch vụ cho phép nhận đơn đặt hàng trước.
Ví dụ: CheckoutRequest có vị trí phân phối
Đoạn mã dưới đây cho thấy ví dụ về yêu cầu thanh toán có khung giao hàng trước.
{
"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 vị trí
Đ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 của bạn chấp nhận các vị trí đặ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 với các khung giờ thay thế
Đoạn mã dưới đây cho thấy ví dụ về một phản hồi thanh toán, trong đó phương thức thực hiện của bạn đề xuất các khung giờ cho đơn đặ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ề thời điểm đặt hàng trước, SubmitOrderResponseMessage
của bạn 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 phương thức thực hiện 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 đơn đặt hàng gửi của phương thức thực hiện hoặc các lần cập nhật đơn đặt hàng không đồng bộ tiếp theo, hãy thêm 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 đến lấy hàng mà người dùng đã lên lịch cho đơn đặt hàng trước. - Khi có thời gian giao hàng dự kiến của nhà hàng hoặc dịch vụ chính xác hơn, hãy đặt giá trị thành thời gian dự kiến cho thời gian giao hàng hoặc lấy hàng.
Ví dụ: SubmitOrderRequest có vùng phân phối
Đoạn mã dưới đây cho thấy ví dụ về một yêu cầu gửi đơn đặt hàng cho biết vị trí đặ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ề một phản hồi gửi đơn đặt hàng, trong đó việc thực hiện đơn hàng xác nhận rằng họ đã 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 vì không có vị trí
Đoạn mã dưới đây cho thấy ví dụ về một phản hồi gửi đơn đặt hàng, trong đó việc thực hiện đơn hàng của bạn từ chối đơn đặt hàng trước của người dùng vì không còn một suất nữa.
{
"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 trước cho đơn đặt hàng.
Lưu ý: Có hai khoảng thời gian riêng biệt mà bạn phải chỉ định cho việc thực hiện đơn hàng: thời hạn đặt hàng chỉ định thời điểm người dùng có thể đặt hàng và thời lượng thực hiện đơn hàng 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 đặt hàng.AdvanceServiceDeliveryHoursSpecification
Ví dụ sau đây xác định giờ của một dịch vụ để chấp nhận đơn đặt hàng trước, với khoảng thời gian dịch vụ 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 cho thấy cách bạn có thể chỉ định rằng dịch vụ mở cửa cho các đơn đặt hàng trong cùng ngày vào ngày Giáng sinh nhưng đóng cửa đối với các đơn đặt hàng nâng cao được lên lịch cho 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 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": "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 cho thấy cách bạn có thể chỉ định rằng dịch vụ đóng cửa đối với các đơn đặt hàng cùng ngày hoặc các đơn đặt hàng đặt trước được lên lịch vào ngày Giáng sinh, nhưng vẫn mở đối với các đơn đặt hàng nâng cao đượ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 trong 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 24x7 và giao hàng từ 10:00 đến 2: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 giờ sáng đến 4:59:59 tối, 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 giờ sáng đến 4:59:59 tối vào các ngày trong tuần nhưng từ 8 giờ sáng đến 6:59 tối vào cuối tuần. Không chấp nhận đơn đặt hàng 24x7.
... { // 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" } } ] } ...