メニュー フィードとフルフィルメント カート項目のマッピング
ユーザーがメニューフィードのアイテムをカートに追加して購入手続きを行うと、Google はそれらのアイテムをフルフィルメント エンドポイントに送信して、価格と在庫状況を確認します。料金と在庫状況が確認されたら、お客様は注文できます。このセクションでは、メニュー フィード アイテムをフルフィルメント カートのアイテムにマッピングする方法について説明します。
このセクションのサンプルは、メニューフィードとカートスキーマを簡潔にしたものです。メニューフィードと Cart オブジェクト間のマッピングを示すフィールドのみが表示されます。完全なスキーマについては、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 つ以上の AddOnMenuItems を含むメニュー項目が含まれています。
メニュー フィードのメニュー アイテム:
{ "@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
この例には、メニュー項目のオプション、AddOnMenuItems、ネストされた AddOnMenuItems を含むメニュー項目が含まれています。
メニュー フィードのメニュー アイテム:
{ "@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
内の商品アイテムに価格変更があると判断した場合は、correctedProposedOrder
およびpaymentOptions
とともに、エラータイプPRICE_CHANGED
のFoodOrderError
を応答できます。Google はユーザーに変更について通知しますが、ユーザーはcorrectedProposedOrder
を使用して送信できるようになります。ユーザーは、戻って必要に応じてカートを編集することもできます。これにより、新しいCheckoutRequestMessage
またはSubmitOrderRequestMessage
を受け取ります。 - 回復不能なエラー: ユーザーは注文を送信する前にカートを編集する必要があります。たとえば、レストランが閉まっていると判断した場合は、エラータイプ
CLOSED
のFoodOrderError
をレスポンスとして返すことができます。Google がユーザーに通知し、新しいレストランに更新するためのインタラクションを管理します。新しいカートの新しいCheckoutRequestMessage
を受け取ります。
通常は、カートレベルのエラーは回復不能にし、商品アイテムレベルのエラーは回復不能にしてください。エラーの種類とその意味の一覧については、FoodOrderError
をご覧ください。
価格変更の処理
購入手続き中に価格を変更する
顧客の購入手続き リクエストの処理中に価格に関する問題が発生した場合は、次の手順を行います。
- エラーの処理で説明しているように、
FoodErrorExtension
を含むCheckoutResponseMessage
でCheckoutRequestMessage
に応答します。 - エラー レスポンスで、
correctedProposedOrder.cart
を使用して価格を正しい値に更新します。Google は正しい注文を受け取り、新しいCheckoutRequestMessage
を発行します。
購入手続き後、ProposedOrder
が変更されたかどうかにかかわらず、エンドユーザーに対して注文確認ページが表示されます。
ProposedOrder が修正された場合、Google は変更をユーザーに知らせる追加の警告を表示することがあります。ユーザーが注文に同意すると、購入手続きは行われなくなります。フローは注文の送信を続けます。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 を送信する前または後に、そのお支払い方法への請求を試行できます。取引が失敗した場合(価格の差が大きすぎる場合など)、OrderUpdate
で次の設定を指定して AsyncOrderUpdateRequestMessage を送信して 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" } } } ] } } } ] } } }