Fitur pesan di muka v1

Anda dapat menambahkan dukungan dalam fulfillment untuk pengguna guna menjadwalkan pesanan makanan untuk diambil dan dikirimkan terlebih dahulu. Sebelum menerapkan dukungan ini dalam fulfillment, buat feed inventaris layanan yang menentukan jam bagi pengguna untuk melakukan pemesanan awal, seperti yang dijelaskan dalam skema feed inventaris (AdvanceServiceDeliveryHoursSpecification).

Slot praorder

Google mengusulkan slot pemesanan awal dengan penambahan 15 menit, hingga 7 hari mendatang, berdasarkan waktu pemenuhan untuk restoran atau layanan (seperti yang ditentukan dalam AdvanceServiceDeliveryHoursSpecification).

Untuk mengambil slot pemesanan di muka yang diusulkan, gunakan nilai berikut dari kolom fulfillmentPreference objek FoodCartExtension saat checkout:

  • PickupInfo.pickupTimeIso8601
  • DeliveryInfo.deliveryTimeIso8601

Menerapkan praorder saat checkout

Tabel di bawah ini mencantumkan kemungkinan cara untuk menerapkan respons fulfillment pada waktu checkout saat pengguna mencoba melakukan pemesanan.

Skenario Perilaku fulfillment
Pesanan di muka dapat dipenuhi untuk slot yang diminta. Terima keranjang P0M ("sesegera mungkin") atau FUTURE_SLOT dengan membuat ProposedOrder dengan slot yang sama. Untuk contoh respons checkout yang menerima slot, lihat cuplikan kode ini.
Pesanan awal tidak dapat dipenuhi untuk slot yang diminta. Fulfillment Anda harus melakukan hal berikut:
  1. Tolak keranjang P0M atau FUTURE_SLOT yang diminta, dan tunjukkan alasan pesanan tidak dapat dipenuhi di objek FoodErrorExtension.
    • Jika pesanan tidak dapat dipenuhi karena kapasitas, tentukan FoodOrderError dari jenis error NO_CAPACITY.
    • Jika pesanan tidak dapat dipenuhi karena restoran tutup, tentukan FoodOrderError dari jenis error CLOSED.
    • Jika pesanan tidak dapat dipenuhi karena alasan lain, tentukan FoodOrderError dari jenis error UNAVAILABLE_SLOT.
  2. Jika memungkinkan, berikan nilai P0M atau FUTURE_SLOT alternatif di correctedProposedOrder. Nilai ini harus berupa semua slot fulfillment yang valid selama 7 hari ke depan mulai dari waktu saat ini. Sertakan slot P0M jika berlaku.

Untuk contoh respons checkout yang mengusulkan slot alternatif, lihat cuplikan kode ini.

Slot alternatif untuk pemenuhan pesanan

Saat checkout, jika slot pemesanan di muka yang diusulkan oleh Google tidak sesuai, fulfillment Anda dapat menyarankan alternatif menggunakan objek CheckoutResponseMessage.

Untuk menentukan slot pemesanan awal alternatif, respons permintaan checkout dengan FoodErrorExtension dan tetapkan nilai berikut:

  1. Pada parameter foodOrderErrors, tentukan jenis error (seperti UNAVAILABLE_SLOT, NO_CAPACITY, atau CLOSED).
  2. Di parameter correctedProposedOrder, berikan nilai P0M atau FUTURE_SLOT alternatif melalui availableFulfillmentOptions.

Slot alternatif harus berlaku selama 7 hari ke depan sejak waktu penempatan pesanan, dan menyertakan semua slot tempat keranjang yang diminta pengguna dapat dipenuhi.

Misalnya, menu spesial makan siang hanya tersedia dari Senin hingga Jumat dari pukul 11.00 hingga 13.00. Kemudian, pengguna mencoba menambahkan menu spesial makan siang ke keranjang, tetapi slot yang dipilih tidak tersedia. Dalam hal ini, fulfillment Anda harus mempertahankan menu spesial makan siang di keranjang, dan hanya menampilkan slot pukul 11.00 hingga 13.00 untuk 7 hari ke depan

Anda harus menghapus objek correctedProposedOrder.Cart.fulfillmentPreference dalam respons.

Jika tidak ada slot yang tersedia, atau jika restoran atau layanan tidak mendukung pemesanan di muka, Anda tidak perlu memberikan correctedProposedOrder.

Lihat contoh di bawah untuk pesan JSON antara fulfillment Anda dan Google selama alur permintaan dan respons checkout untuk pesanan di muka, saat restoran atau layanan tersedia untuk menerima praorder.

Contoh: CheckoutRequest dengan slot pengiriman

Cuplikan di bawah menunjukkan contoh permintaan checkout dengan slot pengiriman pesanan di muka.

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

Contoh: CheckoutResponse yang menerima slot

Cuplikan di bawah menunjukkan contoh respons checkout tempat fulfillment Anda menerima slot pemesanan awal yang diusulkan.

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

Contoh: CheckoutResponse dengan slot alternatif

Cuplikan di bawah menunjukkan contoh respons checkout tempat fulfillment Anda mengusulkan slot pemesanan awal alternatif. Perhatikan bahwa objek correctedProposedOrder.Cart.fulfillmentPreference harus dihilangkan dalam respons Anda.

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

Mengimplementasikan praorder saat mengirimkan pesanan

Saat pengiriman pesanan, jika ada masalah dengan slot pesanan awal, SubmitOrderResponseMessage Anda harus menyertakan alasannya (seperti UNAVAILABLE_SLOT atau UNKNOWN) dalam objek RejectionInfo.

Perbarui status pesanan dari CREATED menjadi CONFIRMED di objek OrderState saat pesanan disetujui oleh penyedia. Sertakan slot waktu yang dipilih dalam email konfirmasi Anda kepada pengguna.

Jika fulfillment Anda mengirimkan pesanan ke restoran nanti, kirimkan update ke Google menggunakan Tindakan Pembaruan Pesanan Asinkron.

Dalam objek OrderUpdate dari respons kirim pesanan fulfillment atau update pesanan asinkron berikutnya, sertakan estimatedFulfillmentTimeIso8601 dengan nilai yang ditetapkan sebagai berikut:

  • Jika status pesanan adalah CREATED atau CONFIRMED, tetapkan nilai ke waktu pengiriman atau pengambilan yang dijadwalkan pengguna untuk pesanan di muka.
  • Jika ada perkiraan waktu pengiriman yang lebih akurat dari restoran atau layanan, tetapkan nilai ke perkiraan waktu pengiriman atau waktu pengambilan.

Contoh: SubmitOrderRequest dengan slot pengiriman

Cuplikan di bawah menunjukkan contoh permintaan kirim pesanan yang menunjukkan slot pesanan awal yang dipilih pengguna.

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

Contoh: SubmitOrderResponse yang menyetujui pesanan

Cuplikan di bawah menunjukkan contoh respons kirim pesanan saat fulfillment Anda mengonfirmasi bahwa pesanan awal pengguna telah diterima.

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

Contoh: SubmitOrderResponse menolak pesanan karena slot tidak tersedia

Cuplikan di bawah menunjukkan contoh respons pengiriman pesanan saat fulfillment Anda menolak pesanan awal pengguna karena slot tidak tersedia.

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

Contoh pemesanan awal

Jenis AdvanceServiceDeliveryHoursSpecification dapat digunakan untuk menentukan jam pengiriman atau pengambilan bagi pengguna untuk menjadwalkan pesanan mereka terlebih dahulu.

Catatan: Ada dua periode waktu terpisah yang harus Anda tentukan untuk fulfillment layanan: periode pemesanan yang menentukan kapan pengguna dapat melakukan pesanan, dan periode fulfillment yang menentukan kapan pesanan akan dipenuhi. Objek OpeningHoursSpecification menentukan kapan pengguna dapat melakukan pemesanan. Waktu fulfillment turunannya (ServiceDeliveryHoursSpecification atau AdvanceServiceDeliveryHoursSpecification) menentukan kapan pesanan dapat dipenuhi.

Contoh berikut menentukan jam layanan untuk menerima pesanan awal, dengan interval layanan 15 menit.

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

Contoh berikut menunjukkan cara menentukan bahwa layanan buka untuk pesanan pada hari yang sama pada hari Natal, tetapi tutup untuk pesanan awal yang dijadwalkan untuk hari itu. Contoh ini mendukung skenario berikut:

  • Pengguna dapat melakukan pemesanan pada 25 Desember untuk pengiriman pada hari yang sama.
  • Pengguna dapat melakukan pemesanan di muka pada 25 Desember untuk pengiriman yang dijadwalkan pada 27 Desember.
  • Pengguna tidak dapat melakukan pemesanan di muka pada 22 Desember untuk pengiriman yang dijadwalkan pada 25 Desember.
{
  "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"
  }
}

Contoh berikut menunjukkan cara menentukan bahwa layanan ditutup untuk pesanan pada hari yang sama atau pesanan awal yang dijadwalkan untuk hari Natal, tetapi buka untuk pesanan awal yang dijadwalkan untuk hari berikutnya. Contoh ini mendukung skenario berikut:

  • Pengguna tidak dapat melakukan pemesanan pada 25 Desember untuk pengiriman pada hari yang sama.
  • Pengguna dapat melakukan pemesanan di muka pada 25 Desember untuk pengiriman yang dijadwalkan pada 27 Desember.
  • Pengguna tidak dapat melakukan pemesanan di muka pada 22 Desember untuk pengiriman yang dijadwalkan pada 25 Desember.
{
  "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"
    }
  ]
}

Contoh Layanan berikut menerima pesanan 24x7 dan mengirimkan dari pukul 10.00-23.59 pada hari kerja:

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

Contoh Layanan berikut menerima pesanan setiap hari mulai pukul 08.00-23.59, dan pelanggan dapat memilih pengiriman dalam waktu satu jam, atau memilih salah satu slot:

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

Contoh berikut menunjukkan kasus saat toko buka pukul 08.00-20.59.59 pada hari kerja, tetapi pukul 08.00-18.59 pada akhir pekan. Pesanan tidak diterima 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"
      }
    }
  ]
}
...