v1 預訂功能功能

您可以在執行要求中加入支援,讓使用者預先安排自取和外送餐點訂單。在執行要求導入這項支援功能之前,請先建立服務商品目錄動態饋給,指定使用者的提前訂購時數,如商品目錄動態饋給結構定義 (AdvanceServiceDeliveryHoursSpecification) 所述。

提前訂購運算單元

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

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

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

在結帳時導入提前訂單功能

下表列出了當使用者嘗試下單時,在結帳時間實作執行要求回應的方法。

情境 出貨行為
可針對要求的時段提前完成訂單。 使用同一個版位建立 ProposedOrder,接受 P0M (「越快越好」) 或 FUTURE_SLOT 購物車。如需接受運算單元的結帳回應範例,請參閱這個程式碼片段
系統無法針對要求的時段完成提前訂單。 執行要求應執行以下操作:
  1. 拒絕要求的 P0MFUTURE_SLOT 購物車,並在 FoodErrorExtension 物件中說明訂單無法履行的原因。
    • 如果因容量不足而無法完成訂單,請指定錯誤類型的 NO_CAPACITY FoodOrderError
    • 如果因餐廳歇業而無法履行訂單,請指定錯誤類型的 CLOSED FoodOrderError
    • 如果訂單因其他原因而無法完成,請指定錯誤類型 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 訊息。

範例:包含放送時段的「CheckRequest」要求

下方程式碼片段是含提前訂單送達時段的結帳要求範例。

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

範例:CheckResponse 接受版位

以下程式碼片段是結帳回應範例,您的執行要求接受建議的提前訂購時段。

{
  "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 分的訂單,客戶可以選擇在一小時內送達,或是選擇其中一個時段:

...
{
  "@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 分。我們不提供全年無休的訂單。

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