고급 처리 작업 구현

메뉴 피드 및 처리 장바구니 항목 매핑

고객이 메뉴 피드의 상품을 장바구니에 추가하고 결제하면 Google에서 해당 상품을 처리 엔드포인트로 전송하여 가격과 재고를 확인합니다. 가격 및 재고가 확인되면 고객이 주문할 수 있습니다. 이 섹션에서는 메뉴 피드 항목을 처리 장바구니 항목에 매핑하는 방법을 보여줍니다.

이 섹션의 샘플은 메뉴 피드 및 장바구니 스키마의 축소된 버전입니다. 메뉴 피드와 장바구니 객체 간의 매핑을 보여주는 데 관련된 필드만 표시됩니다. 전체 스키마는 MenuCart를 참고하세요.

장바구니에 추가된 Menu 피드의 상품은 결제 및 주문 제출 모두에 대해 Cart 객체로 전송됩니다.

  • 단순한 MenuItemlineItems 배열에서 LineItem로 표시되며 offerId는 메뉴 피드에서 선택된 메뉴 항목의 offer.id입니다.
  • 필수 MenuItemOption가 있는 MenuItemlineItems 배열에서 LineItem로 표시되며 offerId는 메뉴 피드에서 선택된 메뉴 항목 옵션의 offer.id입니다.
  • LineItemAddOnMenuItemFoodItemExtensionoptions 배열에서 FoodItemOption로 표시됩니다. 각 옵션에는 메뉴 피드에서 선택한 부가기능 메뉴 항목의 offer.id에 해당하는 offerId가 있습니다. AddOnMenuItem에는 각 옵션 내에 subOptions로 표시되는 중첩된 AddOnMenuItem이 있을 수도 있습니다.

다음 예에서는 메뉴 피드와 처리 장바구니 간에 메뉴 항목을 매핑합니다.

JSONJSONJSON

이 예에는 간단한 메뉴 항목 목록이 포함되어 있습니다.

메뉴 피드의 메뉴 항목:

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

이 예에는 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"
    }
  ]
}

이 예에는 메뉴 항목 옵션, 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로 응답할 수 있습니다. 이 응답을 사용하여 처리 중에 발생한 하나 이상의 오류를 식별할 수 있습니다.

오류를 처리하는 방법에는 두 가지가 있습니다.

  • 복구 가능한 오류: 사용자가 장바구니를 수정하지 않고도 주문을 제출할 수 있습니다. 예를 들어 Cart의 상품에 가격 변경이 있다고 판단되면 correctedProposedOrderpaymentOptions과 함께 오류 유형 PRICE_CHANGEDFoodOrderError로 응답할 수 있습니다. Google은 사용자에게 변경사항을 알리지만 사용자가 correctedProposedOrder를 사용하여 제출하도록 허용합니다. 원하는 경우 사용자는 돌아가 장바구니를 수정할 수도 있습니다. 새 CheckoutRequestMessage 또는 SubmitOrderRequestMessage를 받게 됩니다.
  • 복구 불가능한 오류: 사용자가 주문을 제출하기 전에 장바구니를 수정해야 합니다. 예를 들어 레스토랑이 문을 닫았다고 판단되면 오류 유형 CLOSEDFoodOrderError로 응답할 수 있습니다. Google은 사용자에게 알리고 상호작용을 관리하여 새 식당으로 업데이트합니다. 새 장바구니에 대한 새 CheckoutRequestMessage가 표시됩니다.

일반적으로 장바구니 수준 오류는 복구할 수 없게 하고 상품 수준 오류는 복구할 수 있도록 합니다. 오류 유형 및 의미의 전체 목록은 FoodOrderError을 참고하세요.

가격 변경 처리

결제 중 가격 변경

고객의 결제 요청을 처리하는 중에 가격 문제가 발생하면 다음 단계를 따르세요.

  1. 오류 처리에 설명된 대로 CheckoutRequestMessageFoodErrorExtension가 포함된 CheckoutResponseMessage로 응답합니다.
  2. 오류 응답에서 correctedProposedOrder.cart를 사용하여 가격을 올바른 값으로 업데이트합니다. Google에서 수정된 주문을 수신하고 새 CheckoutRequestMessage를 발행할 수 있습니다.

결제 후 Google에서는 ProposedOrder가 변경되었는지 여부와 관계없이 최종 사용자에게 주문 확인 페이지를 표시합니다.

ProposedOrder가 수정된 경우 Google은 사용자에게 변경사항을 알리기 위해 추가 경고를 표시할 수 있습니다. 사용자가 주문에 동의하면 더 이상 결제 요청이 표시되지 않습니다. 수정된 ProposedOrder를 사용하여 주문 제출 절차가 계속됩니다.

하지만 사용자는 언제든지 마음을 바꿔 장바구니를 다시 수정할 수 있습니다. 이렇게 장바구니가 업데이트되면 Google에서 새 CheckoutRequestMessage를 전송합니다.

주문 제출 중 가격 변경

주문 제출을 처리하는 중에 가격 문제가 발생하면(actions.intent.TRANSACTION_DECISION 인텐트가 트리거됨) 오류로 응답하거나 응답에서 가격을 업데이트하지 마세요. SubmitOrderRequestMessage의 가격, 수량 또는 기타 세부정보가 데이터와 일치하지 않으면 orderStateREJECTED로 설정하여 요청한 대로 주문을 처리할 수 없음을 나타냅니다.

그런 다음 주문 및 결제 세부정보가 유효하면 orderStateCREATED 또는 CONFIRMED로 설정합니다. 또한 시스템에서 주문 ID를 나타내는 actionOrderId를 포함합니다. 후속 업데이트를 전송할 때 이 ID를 사용해야 합니다.

결제를 처리할 수 없고 이미 SubmitOrderRequestMessage를 보낸 경우 orderStateREJECTED로 설정하여 AsyncOrderUpdateRequestMessage를 보내 사용자에게 주문이 처리되지 않음을 알릴 수 있습니다.

주문 제출 후 가격 변경

고객이 주문을 제출할 때 사용된 가격에서 가격이 변경되었다고 판단되면 비동기 주문 업데이트 구현에 설명된 대로 새 가격으로 AsyncOrderUpdateRequestMessage를 발행할 수 있습니다.

비동기 주문 업데이트를 사용하여 가격을 업데이트하려면 다음 단계를 따르세요.

  1. lineItemUpdates[x].price에서 가격을 변경합니다. 이 값은 부가기능을 포함한 상품의 총비용에 수량을 곱한 값입니다. 자세한 내용은 LineItemprice 필드 설명을 참고하세요.
  2. lineItemUpdates[x].reason에 설명을 입력합니다.
  3. lineItemUpdates[x].orderStateCONFIRMED로 설정합니다.

개발자는 재량에 따라 AsyncOrderUpdateRequestMessage를 전송하기 전이나 후에 결제 수단에 청구를 시도할 수 있습니다. 가격 차이가 너무 커서 트랜잭션이 실패한 경우 OrderUpdate에 다음 설정을 사용하여 AsyncOrderUpdateRequestMessage를 전송하여 Google에 실패를 알립니다.

  • orderStateREJECTED로 설정합니다.
  • label 필드에 오류를 설명합니다.

결제 유효성 검사

4단계: 결제 구현에서 설명한 대로 처리 엔드포인트는 들어오는 모든 CheckoutRequestMessage에 대해 유효성 검사를 실행하고 CheckoutResponseMessage으로 응답해야 합니다.

다음은 유효성 검사에 성공한 CheckoutResponseMessage의 예입니다.

사용 사례 구현 방법
사용 사례 1: 검증 성공 CheckoutResponse를 반환합니다. ProposedOrderPaymentOptions가 있어야 합니다. 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_AREAFoodOrderError이 있는 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_METFoodOrderError이 포함되어야 합니다.

사용 사례 구현 방법
사용 사례 1: 최소 주문 금액이 충족되지 않아 유효성 검사가 실패함 오류 유형 REQUIREMENTS_NOT_METFoodOrderError이 있는 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_CAPACITYFoodOrderError가 포함되어야 합니다.

사용 사례 구현 방법
사용 사례 1: 음식점이 폐쇄되었거나 더 이상 지원되지 않아 유효성 검사가 실패함 오류 유형 CLOSEDFoodOrderError이 있는 FoodErrorExtension를 반환합니다.
사용 사례 2: 음식점이 바빠서 현재 주문을 받지 않고 있어 유효성 검사가 실패함 오류 유형 NO_CAPACITYFoodOrderError이 있는 FoodErrorExtension를 반환합니다.
JSONJSON
{
  "expectUserResponse": false,
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "structuredResponse": {
            "error": {
              "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
              "foodOrderErrors": [
                {
                  "error": "CLOSED",
                  "description": "The restaurant is closed."
                }
              ]
            }
          }
        }
      ]
    }
  }
}
{
  "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_CHANGEDFoodOrderError가 포함되어야 합니다.

사용 사례 구현 방법
사용 사례 1: 일부 메뉴 항목 또는 맞춤설정이 유효하지 않거나 재고가 없어 검증에 실패함 오류 유형 AVAILABILITY_CHANGEDcorrectedProposedOrder, PaymentOptions, FoodOrderError가 포함된 FoodErrorExtension를 반환합니다. 잘못된 항목은 CorrectedProposedOrder에서 삭제해야 합니다.
사용 사례 2: 일부 메뉴 항목 또는 맞춤설정이 유효하지 않거나 재고가 없어서 유효성 검사가 실패했습니다. 수정된 장바구니가 더 이상 최소 주문 금액 요구사항을 충족하지 않습니다. 오류 유형 AVAILABILITY_CHANGEDREQUIREMENTS_NOT_METFoodOrderError가 있는 FoodErrorExtension를 반환합니다.
사용 사례 3: 일부 메뉴 항목 또는 맞춤설정 가격이 변경되어 검증에 실패함 오류 유형 PRICE_CHANGEDcorrectedProposedOrder, PaymentOptions, FoodOrderError가 포함된 FoodErrorExtension를 반환합니다. 오래된 가격은 CorrectedProposedOrder에서 업데이트해야 합니다.
사용 사례 4: 일부 메뉴 항목 또는 맞춤설정 가격이 변경되어 유효성 검사가 실패했습니다. 수정된 장바구니가 더 이상 최소 주문 금액 요구사항을 충족하지 않음 오류 유형 PRICE_CHANGEDREQUIREMENTS_NOT_METFoodOrderError가 있는 FoodErrorExtension를 반환합니다.
JSONJSONJSONJSON
{
  "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
                }
              }
            }
          }
        }
      ]
    }
  }
}
{
  "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."
                }
              ]
            }
          }
        }
      ]
    }
  }
}
{
  "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
                }
              }
            }
          }
        }
      ]
    }
  }
}
{
  "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가 있어야 합니다.
{
  "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"
                    }
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}
{
  "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"
                    }
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}
{
  "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"
                    }
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}
{
  "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"
                    }
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}
{
  "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"
                    }
                  }
                }
              ]
            }
          }
        }
      ]
    }
  }
}