v1 預訂餐點功能

您可以在執行階段新增支援功能,讓使用者提前安排外送和外帶餐點訂單。在履行中實作這項支援功能前,請建立服務目錄動態饋給,指定使用者可下預訂單的時間,如目錄動態饋給結構定義 (AdvanceServiceDeliveryHoursSpecification) 所述。

預訂時段

Google 會根據餐廳或服務的履行時間 (如 AdvanceServiceDeliveryHoursSpecification 所定義),提前 15 分鐘為單位,最多提前 7 天,提出預訂時段。

如要擷取建議的提前訂單時段,請在結帳時使用 FoodCartExtension 物件的 fulfillmentPreference 欄位中的下列值:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

在結帳時實作預購功能

下表列出在使用者嘗試下單時,可在結帳時實作訂單履行回應的可能方式。

情境 執行行為
系統可以為要求的時間段執行預先訂購的訂單。 建立具有相同時段的 ProposedOrder,接受 P0MFUTURE_SLOT 購物車 (「盡快」)。如需接受時段的結帳回應範例,請參閱這個程式碼片段
無法為要求的時段安排提前預約。 你的服務應執行以下操作:
  1. 拒絕要求的 P0MFUTURE_SLOT 購物車,並在 FoodErrorExtension 物件中指出無法執行訂單的原因。
    • 如果因產能而無法完成訂單,請指定錯誤類型 NO_CAPACITYFoodOrderError
    • 如果餐廳已關閉,無法完成訂單,請指定錯誤類型 CLOSEDFoodOrderError
    • 如果因其他原因無法完成訂單,請指定錯誤類型 UNAVAILABLE_SLOTFoodOrderError
  2. 盡可能在 correctedProposedOrder 中提供替代 P0MFUTURE_SLOT 值。這些值應為從目前時間開始,未來 7 天內的所有有效執行時段。在適用情況下加入 P0M 時段。

如需建議其他時段的結帳回應範例,請參閱這個程式碼片段

訂單履行作業的其他時段

如果 Google 建議的提前訂房時段不合適,訂房服務可以使用 CheckoutResponseMessage 物件建議其他時段。

如要指定其他預訂時段,請使用 FoodErrorExtension 回應結帳要求,並設定下列值:

  1. foodOrderErrors 參數中,指定錯誤類型 (例如 UNAVAILABLE_SLOTNO_CAPACITYCLOSED)。
  2. correctedProposedOrder 參數中,透過 availableFulfillmentOptions 提供替代 P0MFUTURE_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_SLOTUNKNOWN)。

當訂單獲得供應商接受時,請在 OrderState 物件中,將訂單狀態從 CREATED 更新為 CONFIRMED。在寄給使用者的確認電子郵件中,附上所選的時間時段。

如果你的訂單執行服務稍後才將訂單傳送至餐廳,請使用非同步訂單更新動作傳送更新內容給 Google。

在履行服務的提交訂單回應或後續的非同步訂單更新的 OrderUpdate 物件中,請加入 estimatedFulfillmentTimeIso8601,並將值設為以下設定:

  • 如果訂單狀態為 CREATEDCONFIRMED,請將值設為使用者預訂時程訂單的送達或取貨時間。
  • 如果餐廳或服務提供更準確的預估送達時間,請將值設為預估送達時間或取貨時間。

範例:含有運送時段的 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 物件會定義使用者何時可以下單。其子項履行時間 (ServiceDeliveryHoursSpecificationAdvanceServiceDeliveryHoursSpecification) 會定義訂單何時可履行。

以下範例定義服務接受預訂單的營業時間,服務間隔為 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 月 25 日提前下單,並安排在 12 月 27 日出貨。
  • 使用者無法在 12 月 22 日提前訂購 12 月 25 日的預定送達日期。
{
  "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 月 25 日提前下單,並安排在 12 月 27 日出貨。
  • 使用者無法在 12 月 22 日提前訂購 12 月 25 日的預定送達日期。
{
  "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"
    }
  ]
}

以下範例服務會在 24 小時全天候接受訂單,並在週一至週五上午 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 分。我們並非 24 小時全年無休。

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