メニューフィードとフルフィルメント カート商品アイテムのマッピング
ユーザーがメニューフィードから商品をカートに追加して購入手続きを行うと、Google はこれらの商品をフルフィルメント エンドポイントに送信し、価格と在庫状況を確認します。料金と在庫状況が確認できたら、お客様は注文できます。このセクションでは、メニューフィード アイテムをフルフィルメント カート アイテムにマッピングする方法について説明します。
このセクションのサンプルは、メニューフィードとカート スキーマの簡素化されたバージョンです。メニューフィードとカート オブジェクトのマッピングを示すのに関連するフィールドのみが表示されます。完全なスキーマについては、Menu
と Cart
をご覧ください。
カートに追加された Menu
フィード内のアイテムは、購入手続きと注文送信の両方で Cart
オブジェクトで送信されます。
- 単純な
MenuItem
は、lineItems
配列内のLineItem
として表されます。offerId
は、メニューフィードで選択したメニュー項目のoffer.id
です。 - 必須の
MenuItemOption
を含むMenuItem
は、lineItems
配列内のLineItem
として表されます。ここで、offerId
は、メニューフィードから選択されたメニュー項目オプションのoffer.id
です。 LineItem
のAddOnMenuItem
は、FoodItemExtension
のoptions
配列内のFoodItemOption
として表されます。各オプションには、メニューフィードから選択したアドオン メニュー アイテムのoffer.id
に対応するofferId
があります。AddOnMenuItem には、各オプション内にsubOptions
として表されるネストされた AddOnMenuItem を含めることもできます。
次の例では、メニューフィードとフルフィルメント カートの間にメニュー アイテムをマッピングしています。
JSON
この例には、シンプルなメニュー項目のリストが含まれています。
メニュー フィードのメニュー項目:
{ "@type": "Menu", "@id": "menu_id", "hasMenuItem": [ { "@type": "MenuItem", "@id": "menuitem_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_1", "price": "p_1", "priceCurrency": "USD" } ] }, { "@type": "MenuItem", "@id": "menuitem_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_2", "price": "p_2", "priceCurrency": "USD" } ] } ] }
フルフィルメント カートにマッピングされたメニュー アイテム:
{ "@type": "Cart", "lineItems": [ { "offerId": "menuitem_offer_id_1", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_1*p_1)", "nanos": "cent(q_1*p_1)" } }, "quantity": "q_1" }, { "offerId": "menuitem_offer_id_2", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_2*p_2)", "nanos": "cent(q_2*p_2)" } }, "quantity": "q_2" } ] }
JSON
この例には、1 つ以上の AddOnMenuItem を含むメニュー アイテムが含まれています。
メニュー フィードのメニュー項目:
{ "@type": "Menu", "@id": "menu_id", "hasMenuItem": [ { "@type": "MenuItem", "@id": "menuitem_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_1", "price": "p_1", "priceCurrency": "USD" } ], "menuAddOn": [ { "@type": "MenuAddOnSection", "@id": "menuaddon_section_id_1", "hasMenuItem": [ { "@type": "AddOnMenuItem", "@id": "menuitem_addon_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_addon_offer_id_1", "price": "addon_p_1", "priceCurrency": "USD" } ] }, { "@type": "AddOnMenuItem", "@id": "menuitem_addon_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_addon_offer_id_2", "price": "addon_p_2", "priceCurrency": "USD" } ] } ] } ] }, { "@type": "MenuItem", "@id": "menuitem_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_offer_id_2", "price": "p_2", "priceCurrency": "USD" } ] } ] }
フルフィルメント カートにマッピングされたメニュー アイテム:
{ "@type": "Cart", "lineItems": [ { "offerId": "menuitem_offer_id_1", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*addon_p_2))", "nanos": "cent(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*addon_p_2))" } }, "quantity": "q_1", "extension": { "@type": "FoodItemExtension", "options": [ { "offerId": "menuitem_addon_offer_id_1", "price": { "currencyCode": "USD", "units": "dollar(addon_q_1*addon_p_1)", "nanos": "cent(addon_q_1*addon_p_1)" }, "quantity": "addon_q_1" }, { "offerId": "menuitem_addon_offer_id_2", "price": { "currencyCode": "USD", "units": "dollar(addon_q_2*addon_p_2)", "nanos": "cent(addon_q_2*addon_p_2)" }, "quantity": "addon_q_2" } ] } }, { "offerId": "menuitem_offer_id_2", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_2*p_2)", "nanos": "cent(q_2*p_2)" } }, "quantity": "q_2" } ] }
JSON
この例には、メニュー アイテム オプション、AddOnMenuItem、ネストされた AddOnMenuItem を含むメニュー アイテムが含まれています。
メニュー フィードのメニュー項目:
{ "@type": "MenuItem", "@id": "menuitem_id_1", "hasMenuItemOptions": [ { "@type": "MenuItemOption", "value": { "@type": "PropertyValue", "name": "OPTION", "value": "Large", "offers": [ { "@type": "Offer", "@id": "menuitem_option_offer_id_1", "price": "p_1", "priceCurrency": "USD" } ], "menuAddOn": [ { "@type": "AddOnMenuSection", "@id": "menuitem_option_addon_section_id_1", "hasMenuItem": [ { "@type": "AddOnMenuItem", "@id": "menuitem_option_addon_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_option_addon_offer_id_1", "price": "addon_p_1", "priceCurrency": "USD" } ] }, { "@type": "AddOnMenuItem", "@id": "menuitem_option_addon_id_2", "offers": [ { "@type": "Offer", "@id": "menuitem_option_addon_offer_id_2", "price": "addon_p_2", "priceCurrency": "USD" } ], "menuAddOn": [ { "@type": "AddOnMenuSection", "@id": "menuitem_option_subaddon_section_id_1", "hasMenuItem": [ { "@type": "AddOnMenuItem", "@id": "menuitem_option_subaddon_id_1", "offers": [ { "@type": "Offer", "@id": "menuitem_option_subaddon_offer_id_1", "price": "subaddon_p_1", "priceCurrency": "USD" } ] } ] } ] } ] } ] } } ] }
フルフィルメント カートにマッピングされたメニュー アイテム:
{ "@type": "Cart", "lineItems": [ { "offerId": "menuitem_option_offer_id_1", "price": { "amount": { "currencyCode": "USD", "units": "dollar(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1)))", "nanos": "cent(q_1*(p_1 + addon_q_1*addon_p_1 + addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1)))" } }, "quantity": "q_1", "extension": { "@type": "FoodItemExtension", "options": [ { "offerId": "menuitem_option_addon_offer_id_1", "price": { "currencyCode": "USD", "units": "dollar(addon_q_1*addon_p_1)", "nanos": "cent(addon_q_1*addon_p_1)" }, "quantity": "addon_q_1" }, { "offerId": "menuitem_option_addon_offer_id_2", "price": { "currencyCode": "USD", "units": "dollar(addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1))", "nanos": "cent(addon_q_2*(addon_p_2 + subaddon_q_1*subaddon_p_1))" }, "quantity": "addon_q_2", "subOptions": [ { "offerId": "menuitem_option_subaddon_offer_id_1", "price": { "currencyCode": "USD", "units": "dollar(subaddon_q_1*subaddon_p_1)", "nanos": "cent(subaddon_q_1*subaddon_p_1)" }, "quantity": "subaddon_q_1" } ] } ] } } ] }
エラー処理
CheckoutRequestMessage
の処理中に問題が発生した場合は、CheckoutResponse ではなく、FoodErrorExtension
を含む CheckoutResponseMessage
で応答できます。このレスポンスを使用して、処理中に発生した 1 つ以上のエラーを特定できます。
エラーを処理する方法は 2 つあります。
- 復元可能なエラー: ユーザーはカートを編集して注文を送信する必要はありません。たとえば、
Cart
内のアイテムの価格が変更されていると判断した場合は、エラータイプPRICE_CHANGED
のFoodOrderError
をcorrectedProposedOrder
とpaymentOptions
とともに返すことができます。Google はユーザーに変更を通知しますが、ユーザーはcorrectedProposedOrder
を使用して送信できます。必要に応じて、カートに戻って編集することもできます。新しいCheckoutRequestMessage
またはSubmitOrderRequestMessage
が届きます。 - 回復不能なエラー: ユーザーは注文を送信する前にカートを編集する必要があります。たとえば、レストランが閉店していると判断した場合は、エラータイプ
CLOSED
のFoodOrderError
で応答できます。Google はユーザーに通知し、新しいレストランに更新するための操作を管理します。新しいカートには新しいCheckoutRequestMessage
が割り当てられます。
一般的に、カートレベルのエラーは復元不可とし、商品アイテム単位のエラーは復元可能にします。エラーの種類とその意味の一覧については、FoodOrderError
をご覧ください。
価格変更の処理
購入手続き中の価格変更
お客様の購入手続きリクエストの処理中に価格に関する問題が発生した場合は、次のように対応します。
- エラーの処理で説明されているように、
CheckoutRequestMessage
にFoodErrorExtension
を含むCheckoutResponseMessage
で応答します。 - エラー レスポンスで、
correctedProposedOrder.cart
を使用して価格を正しい値に更新します。Google は修正された注文を受け取り、新しいCheckoutRequestMessage
を発行する場合があります。
ご購入手続きが完了すると、ProposedOrder
が変更されたかどうかにかかわらず、エンドユーザーに注文確認ページが表示されます。
ProposedOrder が修正された場合は、変更内容をユーザーに通知するために、追加の警告が表示されることがあります。お客様が注文に同意した場合、購入手続きのリクエストは行われなくなります。修正された ProposedOrder
とともに、フローは注文の送信に進みます。
ただし、ユーザーはいつでも気が変わった場合にカートを再度編集できます。このようにカート情報が更新されると、Google は新しい CheckoutRequestMessage
を送信します。
注文の送信中に価格が変更された
注文の送信の処理中に料金に関する問題が発生した場合(actions.intent.TRANSACTION_DECISION
インテントのトリガー)、エラーで応答したり、レスポンスで料金を更新したりしないでください。SubmitOrderRequestMessage
の価格、数量、その他の詳細がデータと一致しない場合は、orderState
を REJECTED
に設定してレスポンスを返します。これは、リクエストされたとおりに注文できないことを示します。
注文と支払い情報が有効な場合は、orderState
を CREATED
または CONFIRMED
に設定します。また、システム内の注文 ID を表す actionOrderId
を含めます。この ID は、後続の更新を送信する際に使用する必要があります。
支払いを処理できず、すでに SubmitOrderRequestMessage
を送信している場合は、orderState
を REJECTED
に設定して AsyncOrderUpdateRequestMessage
を送信し、注文が処理されないことをお客様に知らせることができます。
注文の送信後に価格が変更された
お客様が注文を送信したときと価格が変更されたと判断した場合は、非同期注文の更新の実装で説明されているように、新しい価格で AsyncOrderUpdateRequestMessage
を発行できます。
非同期注文更新を使用して料金を更新するには:
lineItemUpdates[x].price
の価格を変更します。この値には、アドオンを含む商品の合計費用が反映され、数量が掛けられます。(詳細については、LineItem
のprice
フィールドの説明をご覧ください)。lineItemUpdates[x].reason
に説明を入力します。lineItemUpdates[x].orderState
をCONFIRMED
に設定します。
AsyncOrderUpdateRequestMessage の送信の前後に、お支払い方法の請求を試行できます。取引が失敗した場合(価格差が大きすぎることが原因である可能性があります)、AsyncOrderUpdateRequestMessage を送信し、OrderUpdate
で次の設定を行い、Google に失敗を通知します。
orderState
をREJECTED
に設定する。label
フィールドに障害の説明を入力します。
購入手続きの検証
ステップ 4: 購入手続きを実装するで説明したように、フルフィルメント エンドポイントは、受信したすべての CheckoutRequestMessage
に対して検証を行い、CheckoutResponseMessage
で応答する必要があります。
検証が成功した CheckoutResponseMessage
の例を次に示します。
ユースケース | 導入方法 |
---|---|
ユースケース 1: 検証が成功する | CheckoutResponse を返します。ProposedOrder と PaymentOptions が必要です。ProposedOrder には、税金、手数料、カートの合計金額が含まれます。 |
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "checkoutResponse": { "proposedOrder": { "id": "sample_proposed_order_id_1", "otherItems": [ { "name":"New customer discount", "price": { "type":"ESTIMATE", "amount": { "currencyCode":"USD", "units":"-5", "nanos": -500000000 } }, "type": "DISCOUNT" }, { "name": "Delivery fee", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "3", "nanos": 500000000 } }, "type": "DELIVERY" }, { "name": "Tax", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "1", "nanos": 500000000 } }, "type": "TAX" } ], "cart": { "merchant": { "id": "https://www.exampleprovider.com/merchant/id1", "name": "Falafel Bite" }, "lineItems": [ { "name": "Pita Chips", "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": "2", "nanos": 750000000 } }, "subLines": [ { "note": "Notes for this item." } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension", "options": [ { "id": "sample_addon_offer_id_1", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id1", "name": "Honey Mustard", "price": { "currencyCode": "USD" }, "quantity": 1 }, { "id": "sample_addon_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id2", "name": "BBQ Sauce", "price": { "currencyCode": "USD", "nanos": 500000000 }, "quantity": 1 } ] } }, { "name": "Chicken Shwarma Wrap", "type": "REGULAR", "id": "sample_item_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/offer/id2", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "8" } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Greek Salad", "type": "REGULAR", "id": "sample_item_offer_id_3", "offerId": "https://www.exampleprovider.com/menu/item/offer/id3", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "9", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Prawns Biryani", "type": "REGULAR", "id": "sample_item_offer_id_4", "offerId": "https://www.exampleprovider.com/menu/item/offer/id4", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "15", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension", "fulfillmentPreference": { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } } }, "location": { "coordinates": { "latitude": 37.788783, "longitude": -122.41384 }, "formattedAddress": "1350 CHARLESTON ROAD, MOUNTAIN VIEW, CA, United States", "zipCode": "94043", "city": "Mountain View", "postalAddress": { "regionCode": "US", "postalCode": "94043", "administrativeArea": "CA", "locality": "Mountain View", "addressLines": [ "1350 Charleston Road" ] }, "notes": "Gate code is #111" } } }, "totalPrice": { "type": "ESTIMATE", "amount": { // Represents $36.73 "currencyCode": "USD", "units": "36", "nanos": 730000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension", "availableFulfillmentOptions": [ { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } }, "expiresAt": "2017-07-17T12:30:00Z" } ] } }, "paymentOptions": { "googleProvidedOptions": { "tokenizationParameters": { "tokenizationType": "PAYMENT_GATEWAY", "parameters": { "gateway": "stripe", "stripe:publishableKey": "pk_live_stripe_client_key", "stripe:version": "2017-04-06" } }, "supportedCardNetworks": [ "AMEX", "DISCOVER", "MASTERCARD", "JCB", "VISA" ], "prepaidCardDisallowed": true } } } } } ] } } }
配送先住所の検証
フルフィルメント エンドポイントは、各 CheckoutRequestMessage
に含まれる配送先住所を検証する必要があります。
配送先住所に問題がある場合(配送サービスの範囲外など)は、フルフィルメントから返された CheckoutResponseMessage
に、適切なタイプの FoodOrderError
が含まれている必要があります。
ユースケース | 導入方法 |
---|---|
ユースケース 1: 配送先住所が範囲外であるか、配送先住所に問題があるため、検証に失敗した | エラータイプ OUT_OF_SERVICE_AREA の FoodOrderError を持つ FoodErrorExtension を返します。 |
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "OUT_OF_SERVICE_AREA", "description": "Sorry, the restaurant cannot deliver to your address." } ] } } } ] } } }
最低注文額の検証
フルフィルメント エンドポイントは、各 CheckoutRequestMessage
の最低注文額を検証する必要があります。
最低注文額が満たされていない場合、フルフィルメントから返される CheckoutResponseMessage
には、エラータイプ REQUIREMENTS_NOT_MET
の FoodOrderError
が含まれている必要があります。
ユースケース | 導入方法 |
---|---|
ユースケース 1: 最低注文額を満たしていないため、検証に失敗しました | エラータイプ REQUIREMENTS_NOT_MET の FoodOrderError を持つ FoodErrorExtension を返します。 |
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "REQUIREMENTS_NOT_MET", "description": "The cart subtotal must be over $20." } ] } } } ] } } }
注文可能期間の検証
フルフィルメント エンドポイントは、各 CheckoutRequestMessage
の注文可能期間に影響する可能性のある要素を検証する必要があります。
たとえば、レストランが閉店している場合や、現在注文を受け付けていない場合は、フルフィルメントから返される CheckoutResponseMessage
に、それぞれエラータイプ CLOSED
または NO_CAPACITY
の FoodOrderError
が含まれている必要があります。
ユースケース | 導入方法 |
---|---|
ユースケース 1: レストランが閉店しているか、サポートが終了しているため、検証に失敗しました | エラータイプ CLOSED の FoodOrderError を持つ FoodErrorExtension を返します。 |
ユースケース 2: レストランが混み合っていて現在注文を受け付けていないため、検証に失敗しました | エラータイプ NO_CAPACITY の FoodOrderError を持つ FoodErrorExtension を返します。 |
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "CLOSED", "description": "The restaurant is closed." } ] } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "NO_CAPACITY", "description": "Sorry, the restaurant is busy at the moment." } ] } } } ] } } }
カート内の商品の検証
フルフィルメント エンドポイントは、CheckoutRequestMessage
に含まれる各カートアイテムの価格と在庫状況を検証する必要があります。
在庫状況または価格が変更された場合は、フルフィルメントから返される CheckoutResponseMessage
に、エラータイプがそれぞれ AVAILABILITY_CHANGED
または PRICE_CHANGED
の FoodOrderError
が含まれている必要があります。
ユースケース | 導入方法 |
---|---|
ユースケース 1: 一部のメニュー アイテムやそのカスタマイズが無効であるか、在庫切れであるため、検証に失敗しました | エラータイプ AVAILABILITY_CHANGED の correctedProposedOrder 、PaymentOptions 、FoodOrderError を含む FoodErrorExtension を返します。無効なアイテムは CorrectedProposedOrder から削除する必要があります。 |
ユースケース 2: 一部のメニュー アイテムやそのカスタマイズが有効でないか、在庫切れであるため、検証に失敗しました。修正されたカートでは、最低注文額の要件を満たさなくなった。 | エラータイプ AVAILABILITY_CHANGED と REQUIREMENTS_NOT_MET の FoodOrderError を使用して FoodErrorExtension を返します。 |
ユースケース 3: 一部のメニュー項目やカスタマイズの料金が変更されたため、検証に失敗した | エラータイプ PRICE_CHANGED の correctedProposedOrder 、PaymentOptions 、FoodOrderError を含む FoodErrorExtension を返します。古い価格は CorrectedProposedOrder で更新する必要があります。 |
ユースケース 4: 一部のメニュー項目やカスタマイズの料金が変更されたため、検証が失敗しました。修正したカートでは最低注文額の要件を満たさなくなった | エラータイプ PRICE_CHANGED と REQUIREMENTS_NOT_MET の FoodOrderError を使用して FoodErrorExtension を返します。 |
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "AVAILABILITY_CHANGED", "id": "sample_item_offer_id_1", "description": "The item is no longer available." }, { "error": "AVAILABILITY_CHANGED", "id": "sample_item_offer_id_2", "description": "The item is no longer available." } ], "correctedProposedOrder": { "id": "sample_corrected_proposed_order_id_1", "otherItems": [ { "name":"New customer discount", "price": { "type":"ESTIMATE", "amount": { "currencyCode":"USD", "units":"-5", "nanos": -500000000 } }, "type": "DISCOUNT" }, { "name": "Delivery fee", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "3", "nanos": 500000000 } }, "type": "DELIVERY" }, { "name": "Tax", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "1", "nanos": 500000000 } }, "type": "TAX" } ], "cart": { "merchant": { "id": "https://www.exampleprovider.com/merchant/id1", "name": "Falafel Bite" }, "lineItems": [ { "name": "Greek Salad", "type": "REGULAR", "id": "sample_item_offer_id_3", "offerId": "https://www.exampleprovider.com/menu/item/offer/id3", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "9", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Prawns Biryani", "type": "REGULAR", "id": "sample_item_offer_id_4", "offerId": "https://www.exampleprovider.com/menu/item/offer/id4", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "15", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension", "fulfillmentPreference": { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } } }, "location": { "coordinates": { "latitude": 37.788783, "longitude": -122.41384 }, "formattedAddress": "1350 CHARLESTON ROAD, MOUNTAIN VIEW, CA, United States", "zipCode": "94043", "city": "Mountain View", "postalAddress": { "regionCode": "US", "postalCode": "94043", "administrativeArea": "CA", "locality": "Mountain View", "addressLines": [ "1350 Charleston Road" ] }, "notes": "Gate code is #111" } } }, "totalPrice": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "36", "nanos": 730000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension", "availableFulfillmentOptions": [ { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } }, "expiresAt": "2017-07-17T12:30:00Z" } ] } }, "paymentOptions": { "googleProvidedOptions": { "tokenizationParameters": { "tokenizationType": "PAYMENT_GATEWAY", "parameters": { "gateway": "stripe", "stripe:publishableKey": "pk_live_stripe_client_key", "stripe:version": "2017-04-06" } }, "supportedCardNetworks": [ "AMEX", "DISCOVER", "MASTERCARD", "JCB", "VISA" ], "prepaidCardDisallowed": true } } } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "REQUIREMENTS_NOT_MET", "description": "The cart subtotal must be over $20." }, { "error": "AVAILABILITY_CHANGED", "id": "cart_lineitem_id" "description": "cart_lineitem_id is no longer available." } ] } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "PRICE_CHANGED", "id": "sample_item_offer_id_1", "description": "The price has changed.", "updatedPrice": { "currencyCode": "USD", "units": "2", "nanos": 750000000 } }, { "error": "PRICE_CHANGED", "id": "sample_item_offer_id_2", "description": "The price has changed.", "updatedPrice": { "currencyCode": "USD", "units": "8" } } ], "correctedProposedOrder": { "id": "sample_corrected_proposed_order_id_1", "otherItems": [ { "name":"New customer discount", "price": { "type":"ESTIMATE", "amount": { "currencyCode":"USD", "units":"-5", "nanos": -500000000 } }, "type": "DISCOUNT" }, { "name": "Delivery fee", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "3", "nanos": 500000000 } }, "type": "DELIVERY" }, { "name": "Tax", "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "1", "nanos": 500000000 } }, "type": "TAX" } ], "cart": { "merchant": { "id": "https://www.exampleprovider.com/merchant/id1", "name": "Falafel Bite" }, "lineItems": [ { "name": "Pita Chips", "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": "2", "nanos": 750000000 } }, "subLines": [ { "note": "Notes for this item." } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension", "options": [ { "id": "sample_addon_offer_id_1", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id1", "name": "Honey Mustard", "price": { "currencyCode": "USD" }, "quantity": 1 }, { "id": "sample_addon_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/addon/offer/id2", "name": "BBQ Sauce", "price": { "currencyCode": "USD", "nanos": 500000000 }, "quantity": 1 } ] } }, { "name": "Chicken Shwarma Wrap", "type": "REGULAR", "id": "sample_item_offer_id_2", "offerId": "https://www.exampleprovider.com/menu/item/offer/id2", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "8" } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Greek Salad", "type": "REGULAR", "id": "sample_item_offer_id_3", "offerId": "https://www.exampleprovider.com/menu/item/offer/id3", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "9", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } }, { "name": "Prawns Biryani", "type": "REGULAR", "id": "sample_item_offer_id_4", "offerId": "https://www.exampleprovider.com/menu/item/offer/id4", "quantity": 1, "price": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "15", "nanos": 990000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension" } } ], "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension", "fulfillmentPreference": { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } } }, "location": { "coordinates": { "latitude": 37.788783, "longitude": -122.41384 }, "formattedAddress": "1350 CHARLESTON ROAD, MOUNTAIN VIEW, CA, United States", "zipCode": "94043", "city": "Mountain View", "postalAddress": { "regionCode": "US", "postalCode": "94043", "administrativeArea": "CA", "locality": "Mountain View", "addressLines": [ "1350 Charleston Road" ] }, "notes": "Gate code is #111" } } }, "totalPrice": { "type": "ESTIMATE", "amount": { "currencyCode": "USD", "units": "36", "nanos": 730000000 } }, "extension": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension", "availableFulfillmentOptions": [ { "fulfillmentInfo": { "delivery": { "deliveryTimeIso8601": "P90M" } }, "expiresAt": "2017-07-17T12:30:00Z" } ] } }, "paymentOptions": { "googleProvidedOptions": { "tokenizationParameters": { "tokenizationType": "PAYMENT_GATEWAY", "parameters": { "gateway": "stripe", "stripe:publishableKey": "pk_live_stripe_client_key", "stripe:version": "2017-04-06" } }, "supportedCardNetworks": [ "AMEX", "DISCOVER", "MASTERCARD", "JCB", "VISA" ], "prepaidCardDisallowed": true } } } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "error": { "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension", "foodOrderErrors": [ { "error": "REQUIREMENTS_NOT_MET", "description": "The cart subtotal must be over $20." }, { "error": "PRICE_CHANGED", "id": "cart_lineitem_id" "description": "cart_lineitem_id price has been updated." "updatedPrice": { "currencyCode": "USD", "units": "2", "nanos": 750000000 } } ] } } } ] } } }
注文の確認を送信する
ステップ 7: 注文の送信を実装するで説明したように、フルフィルメント エンドポイントは、受信したすべての SubmitOrderRequestMessage
に対して検証を行い、SubmitOrderResponseMessage
で応答する必要があります。
検証が成功した SubmitOrderResponseMessage
の例を次に示します。
ユースケース | 導入方法 |
---|---|
ユースケース 1: 注文が正常に作成される | CREATED 注文ステータスの SubmitOrderResponseMessage 。actionOrderId 、userVisibleId 、orderManagementActions 、estimatedFulfillmentTime が必要です。 |
ユースケース 2: お支払いに関する問題により注文が不承認となった | REJECTED 注文ステータスの SubmitOrderResponseMessage 。PAYMENT_DECLINED タイプの actionOrderId 、userVisibleId 、orderManagementActions 、rejectionInfo が必要です。 |
ユースケース 3: ユーザーが禁止されているとして報告されているため、注文が拒否される | REJECTED 注文ステータスの SubmitOrderResponseMessage 。INELIGIBLE タイプの actionOrderId 、userVisibleId 、orderManagementActions 、rejectionInfo が必要です。 |
ユースケース 4: ユーザー情報が不完全または無効なため、注文が拒否される | REJECTED 注文ステータスの SubmitOrderResponseMessage 。INELIGIBLE タイプの actionOrderId 、userVisibleId 、orderManagementActions 、rejectionInfo が必要です。 |
ユースケース 5: 不明な理由で注文が拒否される | REJECTED 注文ステータスの SubmitOrderResponseMessage 。UNKNOWN タイプの actionOrderId 、userVisibleId 、orderManagementActions 、rejectionInfo が必要です。 |
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "CREATED", "label": "Order received" }, "updateTime": "2017-05-10T02:30:00.000Z", "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "PAYMENT_DECLINED", "reason": "Insufficient funds" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "INELIGIBLE", "reason": "Sorry, we are not able to take orders from this user" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "INELIGIBLE", "reason": "Sorry, the phone number must not be blank" }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }
JSON
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "structuredResponse": { "orderUpdate": { "actionOrderId": "sample_action_order_id", "orderState": { "state": "REJECTED", "label": "Order rejected" }, "updateTime": "2017-05-10T02:30:00.000Z", "rejectionInfo": { "type": "UNKNOWN", "reason": "Sorry, there is something wrong with this order." }, "orderManagementActions": [ { "type": "CUSTOMER_SERVICE", "button": { "title": "Contact customer service", "openUrlAction": { "url": "mailto:support@example.com" } } }, { "type": "EMAIL", "button": { "title": "Email restaurant", "openUrlAction": { "url": "mailto:person@example.com" } } }, { "type": "CALL", "button": { "title": "Call restaurant", "openUrlAction": { "url": "tel:+16505554679" } } }, { "type": "VIEW_DETAILS", "button": { "title": "View order", "openUrlAction": { "url": "https://orderview.partner.com?orderid=sample_action_order_id" } } } ] } } } ] } } }