사용자가 음식 주문의 수령 및 배달을 사전에 예약할 수 있도록 처리에 지원을 추가할 수 있습니다. 처리에서 이 지원을 구현하기 전에 인벤토리 피드 스키마(AdvanceServiceDeliveryHoursSpecification
)에 설명된 대로 사용자가 선주문할 수 있는 시간을 지정하는 서비스 인벤토리 피드를 만듭니다.
사전 주문 슬롯
Google은 식당 또는 서비스의 처리 시간 (AdvanceServiceDeliveryHoursSpecification
에 정의됨)을 기준으로 최대 7일 전까지 15분 단위로 사전 주문 시간을 제안합니다.
제안된 사전 주문 시간대를 검색하려면 결제 시 FoodCartExtension
객체의 fulfillmentPreference
필드에서 다음 값을 사용합니다.
PickupInfo.pickupTimeIso8601
DeliveryInfo.deliveryTimeIso8601
결제 시 선주문 구현
아래 표에는 사용자가 주문을 시도할 때 결제 시 처리의 응답을 구현할 수 있는 방법이 나와 있습니다.
시나리오 | 처리 동작 |
---|---|
요청된 슬롯에 대해 선주문을 처리할 수 있습니다. | 동일한 슬롯으로 ProposedOrder 를 만들어 P0M ('최대한 빨리') 또는 FUTURE_SLOT 장바구니를 수락합니다. 슬롯을 수락하는 결제 응답의 예는 이 코드 스니펫을 참고하세요. |
요청된 시간에 대한 선주문을 처리할 수 없습니다. | 처리는 다음을 실행해야 합니다.
대체 시간대를 제안하는 결제 응답의 예는 이 코드 스니펫을 참고하세요. |
주문 처리를 위한 대체 슬롯
결제 시 Google에서 제안한 사전 주문 시간대가 적절하지 않은 경우 처리팀에서 CheckoutResponseMessage
객체를 사용하여 대안을 제안할 수 있습니다.
대체 사전 주문 슬롯을 지정하려면 결제 요청에 FoodErrorExtension
로 응답하고 다음 값을 설정합니다.
foodOrderErrors
매개변수에서 오류 유형 (예:UNAVAILABLE_SLOT
,NO_CAPACITY
,CLOSED
)을 지정합니다.correctedProposedOrder
매개변수에서availableFulfillmentOptions
를 통해 대체P0M
또는FUTURE_SLOT
값을 제공합니다.
대체 슬롯은 주문 시점부터 7일 후까지의 슬롯이어야 하며 사용자의 요청한 장바구니를 처리할 수 있는 모든 슬롯을 포함해야 합니다.
예를 들어 점심 특가는 월요일~금요일 오전 11시~오후 1시에만 제공된다고 가정해 보겠습니다. 그런 다음 사용자가 장바구니에 점심 특가를 추가하려고 하지만 선택한 시간대를 사용할 수 없습니다. 이 경우 처리팀은 장바구니에 있는 점심 특가를 유지하고 다음 7일 동안 오전 11시~오후 1시 시간대만 반환해야 합니다.
응답에서 correctedProposedOrder.Cart.fulfillmentPreference
객체를 생략해야 합니다.
이용 가능한 시간대가 없거나 음식점 또는 서비스에서 사전 주문을 지원하지 않는 경우에는 correctedProposedOrder
를 제공하지 않아도 됩니다.
음식점 또는 서비스에서 선주문을 받을 수 있는 경우 선주문의 결제 요청 및 응답 흐름 중에 처리자와 Google 간에 주고받는 JSON 메시지의 예는 아래를 참고하세요.
배송 슬롯이 있는 CheckoutRequest의 예
아래 스니펫은 선주문 배송 일정이 있는 결제 요청의 예시를 보여줍니다.
{
"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": {
...
}
}
}
}
]
}
]
}
예: 슬롯을 수락하는 CheckoutResponse
아래 스니펫은 판매자가 제안된 선주문 슬롯을 수락하는 결제 응답의 예를 보여줍니다.
{
"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": {
...
}
}
}
}
]
}
}
}
예: 대체 슬롯이 있는 CheckoutResponse
아래 스니펫은 판매자가 대체 선주문 슬롯을 제안하는 결제 응답의 예를 보여줍니다. 응답에서 correctedProposedOrder.Cart.fulfillmentPreference
객체는 생략해야 합니다.
{
"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": {
...
}
}
}
}
]
}
}
}
주문 제출 시 선주문 구현
주문 제출 시 선주문 슬롯에 문제가 있는 경우 SubmitOrderResponseMessage
은 RejectionInfo
객체에 이유 (예: UNAVAILABLE_SLOT
또는 UNKNOWN
)를 포함해야 합니다.
제공업체에서 주문을 수락하면 OrderState
객체에서 주문 상태를 CREATED
에서 CONFIRMED
로 업데이트합니다. 사용자에게 보내는 확인 이메일에 선택한 시간대를 포함합니다.
처리 팀에서 나중에 주문을 음식점에 전송하는 경우 비동기 주문 업데이트 작업을 사용하여 Google에 업데이트를 전송합니다.
처리의 주문 제출 응답 또는 후속 비동기 주문 업데이트의 OrderUpdate
객체에 다음과 같이 값이 설정된 estimatedFulfillmentTimeIso8601
를 포함합니다.
- 주문 상태가
CREATED
또는CONFIRMED
인 경우 사용자가 선주문 시 예약한 배송 또는 수령 시간으로 값을 설정합니다. - 음식점 또는 서비스에서 더 정확한 예상 배송 시간이 있는 경우 값을 예상 배송 시간 또는 수령 시간으로 설정합니다.
배송 슬롯이 있는 SubmitOrderRequest 예시
아래 스니펫은 사용자가 선택한 사전 주문 슬롯을 나타내는 주문 제출 요청의 예를 보여줍니다.
{
"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": {
...
}
}
}
}
]
}
]
}
주문을 수락하는 SubmitOrderResponse 예시
아래 스니펫은 처리팀에서 사용자의 선주문을 수락했음을 확인하는 주문 제출 응답의 예를 보여줍니다.
{
"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"
}
}
}
}
]
}
}
}
예: 슬롯을 사용할 수 없어 주문을 거부하는 SubmitOrderResponse
아래 스니펫은 사용 가능한 슬롯이 없어 처리팀에서 사용자의 사전 주문을 거부하는 주문 제출 응답의 예를 보여줍니다.
{
"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": [
...
]
}
}
}
]
}
}
}
선주문 예시
AdvanceServiceDeliveryHoursSpecification
유형은 사용자가 주문을 미리 예약할 수 있도록 배송 또는 수령 시간을 지정하는 데 사용할 수 있습니다.
참고: 서비스 처리를 위해 지정해야 하는 두 가지 기간이 있습니다. 사용자가 주문할 수 있는 시간을 지정하는 주문 기간과 주문이 처리되는 시간을 지정하는 처리 기간입니다.
객체는 사용자가 주문할 수 있는 시점을 정의합니다. 하위 처리 시간 (OpeningHoursSpecification
또는 ServiceDeliveryHoursSpecification
)은 주문을 처리할 수 있는 시점을 정의합니다.AdvanceServiceDeliveryHoursSpecification
다음 예에서는 15분 간격의 서비스로 사전 주문을 받는 서비스 시간을 정의합니다.
{ "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" } } ] } ] }
다음 예는 크리스마스 당일에 당일 주문의 경우 서비스가 제공되지만 그날로 예약된 사전 주문의 경우 서비스가 제공되지 않도록 지정하는 방법을 보여줍니다. 이 예는 다음 시나리오를 지원합니다.
- 사용자는 12월 25일에 주문하여 당일 배송을 받을 수 있습니다.
- 사용자는 12월 27일 배송 예정인 제품을 12월 25일에 선주문할 수 있습니다.
- 사용자는 12월 25일에 배송될 제품을 12월 22일에 선주문할 수 없습니다.
{ "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" } }
다음 예는 당일 주문 또는 크리스마스에 예정된 선주문의 경우 서비스가 제공되지 않지만 이후에 예정된 선주문의 경우 서비스가 제공된다고 지정하는 방법을 보여줍니다. 이 예는 다음 시나리오를 지원합니다.
- 사용자는 12월 25일에 당일 배송을 위해 주문할 수 없습니다.
- 사용자는 12월 27일 배송 예정인 제품을 12월 25일에 선주문할 수 있습니다.
- 사용자는 12월 25일에 배송될 제품을 12월 22일에 선주문할 수 없습니다.
{ "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" } ] }
다음 샘플 서비스는 연중무휴 주문하고 평일 오전 10시부터 오후 2시 59분 59초까지 배송합니다.
... { "@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" } } } ...
다음 샘플 서비스는 매일 오전 8시부터 오후 4시 59분 59초까지 주문을 받으며 고객은 1시간 이내에 배송되도록 선택하거나 다음 시간 중 하나를 선택할 수 있습니다.
... { "@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" } } ] } ...
다음 샘플은 매장이 평일에는 오전 8시~오후 4시 59분 59초, 주말에는 오전 8시~오후 6시 59분 59초에 영업하는 사례를 보여줍니다. 주문은 연중무휴로 접수되지 않습니다.
... { // 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" } } ] } ...