设置结账

当用户创建购物车时,系统会调用结账流程。用户购物车中的内容和订单详情会发送到您的端到端订购 Web 服务。您的网站服务会验证这些信息,然后您可以根据需要继续操作或调整其购物车。

Web 服务的结账处理脚本必须响应 POST 请求。当客户选择结账时,Google 会向订购端到端 Web 服务发送 JSON 请求正文,该正文采用 CheckoutRequestMessage 的形式,其中包含客户 Cart 的详细信息。然后,您的 Web 服务会使用 CheckoutResponseMessage 进行响应。下图演示了该流程。

CheckoutResponseMessage 会返回客户未经修改的购物车或错误。

收到结账请求后,您的端到端订购 Web 服务必须执行以下操作:

  • 根据当前商品价格、库存状况和提供商服务,检查购物车的有效性。
  • 计算总价(包括所有折扣、税费和运费)。
  • 如果成功,请响应未修改的购物车。
  • 如果失败,请返回错误消息和新的建议顺序。

在开始实现结账功能之前,我们建议您先查看履单概览文档。

结账请求消息

为了验证客户的购物车,当客户选择结账时,Google 会向您的 Web 服务发送请求,其中包含采用 CheckoutRequestMessage 格式的 JSON 正文。只有在端到端订餐流程的后续阶段,系统才会提交客户订单。

CheckoutRequestMessage 中包含的数据包括:

  • 意图:每个结账请求正文的 inputs[0].intent 字段都包含 actions.foodordering.intent.CHECKOUT 字符串值。
  • 购物车:结账请求的 inputs[0].arguments[0].extension 字段包含一个 Cart 对象,该对象代表客户的购物车。
  • 外卖或自提:Cart 对象的扩展字段包含一个 FoodCartExtension 对象,用于指定外卖或自提的属性:
    • 对于送货订单,FoodCartExtension 对象包含送货地址。
    • 对于自提或外卖订单,FoodCartExtension 对象不包含任何位置信息。
  • 沙盒:结账请求的 isInSandbox 字段包含一个布尔值,用于指示交易是否使用沙盒付款。

结账请求示例

下面是一个 CheckoutRequestMessage 示例:

{
    "user": {},
    "conversation": {
        "conversationId": "CTZbZfUlHCybEdcz_5PB3Ttf"
    },
    "inputs": [
        {
            "intent": "actions.foodordering.intent.CHECKOUT",
            "arguments": [
                {
                    "extension": {
                        "@type": "type.googleapis.com/google.actions.v2.orders.Cart",
                        "merchant": {
                            "id": "restaurant/Restaurant/QWERTY",
                            "name": "Tep Tep Chicken Club"
                        },
                        "lineItems": [
                            {
                                "name": "Spicy Fried Chicken",
                                "type": "REGULAR",
                                "id": "299977679",
                                "quantity": 2,
                                "price": {
                                    "type": "ESTIMATE",
                                    "amount": {
                                        "currencyCode": "AUD",
                                        "units": "39",
                                        "nanos": 600000000
                                    }
                                },
                                "offerId": "MenuItemOffer/QWERTY/scheduleId/496/itemId/143",
                                "extension": {
                                    "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                                }
                            }
                        ],
                        "extension": {
                            "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
                            "fulfillmentPreference": {
                                "fulfillmentInfo": {
                                    "delivery": {
                                        "deliveryTimeIso8601": "P0M"
                                    }
                                }
                            },
                            "location": {
                                "coordinates": {
                                    "latitude": -33.8376441,
                                    "longitude": 151.0868736
                                },
                                "formattedAddress": "Killoola St, 1, Concord West NSW 2138",
                                "zipCode": "2138",
                                "city": "Concord West",
                                "postalAddress": {
                                    "regionCode": "AU",
                                    "postalCode": "2138",
                                    "administrativeArea": "NSW",
                                    "locality": "Concord West",
                                    "addressLines": [
                                        "Killoola St",
                                        "1"
                                    ]
                                }
                            }
                        }
                    }
                }
            ]
        }
    ],
    "directActionOnly": true,
    "isInSandbox": true
}

结账响应消息

收到来自端到端订购服务的请求后,您的结账 Web 服务必须对其进行处理,并以 CheckoutResponseMessage 进行响应。CheckoutResponseMessage 需要涵盖成功或失败的请求。

成功请求

如果结账请求成功,CheckoutResponseMessage 需要包含 ProposedOrderPaymentOptions

  • ProposedOrder

    • cart:与 CheckoutRequestMessage 中提供的购物车相同的 cart 对象。如果购物车中的任何内容都需要更改,CheckoutResponseMessage 应改为包含具有更正的 ProposedOrderFoodErrorExtension
    • otherItems:提供商添加的项目,例如运费、税费和其他费用。还可能包含用户添加的小费。
    • totalPrice:订单的总金额。
    • extension:用于定义订单履单信息(例如送货时间)的 FoodOrderExtension
  • PaymentOptions

    • 如需了解如何设置付款处理,请参阅下文中的设置 Google Pay。在准备好实现付款处理之前,您可以在 CheckoutResponseMessage 中使用占位符 JSON。
    • 如需在 CheckoutResponseMessage 中添加占位符付款选项,请参阅下面的示例,其中使用了 PaymentOptions 的示例付款网关。

成功响应示例

{
    "finalResponse": {
        "richResponse": {
            "items": [
                {
                    "structuredResponse": {
                        "checkoutResponse": {
                            "proposedOrder": {
                                "cart": {
                                    "merchant": {
                                        "id": "restaurant/Restaurant/QWERTY",
                                        "name": "Tep Tep Chicken Club"
                                    },
                                    "lineItems": [
                                        {
                                            "name": "Spicy Fried Chicken",
                                            "type": "REGULAR",
                                            "id": "299977679",
                                            "quantity": 2,
                                            "price": {
                                                "type": "ESTIMATE",
                                                "amount": {
                                                    "currencyCode": "AUD",
                                                    "units": "39",
                                                    "nanos": 600000000
                                                }
                                            },
                                            "offerId": "MenuItemOffer/QWERTY/scheduleId/496/itemId/143",
                                            "extension": {
                                                "@type": "type.googleapis.com/google.actions.v2.orders.FoodItemExtension"
                                            }
                                        }
                                    ],
                                    "extension": {
                                        "@type": "type.googleapis.com/google.actions.v2.orders.FoodCartExtension",
                                        "fulfillmentPreference": {
                                            "fulfillmentInfo": {
                                                "delivery": {
                                                    "deliveryTimeIso8601": "P0M"
                                                }
                                            }
                                        },
                                        "location": {
                                            "coordinates": {
                                                "latitude": -33.8376441,
                                                "longitude": 151.0868736
                                            },
                                            "formattedAddress": "Killoola St, 1, Concord West NSW 2138",
                                            "zipCode": "2138",
                                            "city": "Concord West",
                                            "postalAddress": {
                                                "regionCode": "AU",
                                                "postalCode": "2138",
                                                "administrativeArea": "NSW",
                                                "locality": "Concord West",
                                                "addressLines": [
                                                    "Killoola St",
                                                    "1"
                                                ]
                                            }
                                        }
                                    }
                                },
                                "totalPrice": {
                                    "type": "ESTIMATE",
                                    "amount": {
                                        "currencyCode": "AUD",
                                        "units": "43",
                                        "nanos": 100000000
                                    }
                                },
                                "extension": {
                                    "@type": "type.googleapis.com/google.actions.v2.orders.FoodOrderExtension",
                                    "availableFulfillmentOptions": [
                                        {
                                            "fulfillmentInfo": {
                                                "delivery": {
                                                    "deliveryTimeIso8601": "P0M"
                                                }
                                            }
                                        }
                                    ]
                                },
                                "otherItems": [
                                    {
                                        "name": "Delivery fee",
                                        "price": {
                                            "type": "ESTIMATE",
                                            "amount": {
                                                "currencyCode": "AUD",
                                                "units": "3",
                                                "nanos": 500000000
                                            }
                                        },
                                        "type": "DELIVERY"
                                    }
                                ]
                            },
                            "paymentOptions": {
                                "googleProvidedOptions": {
                                    "facilitationSpecification": "{\"apiVersion\":2,\"apiVersionMinor\":0,\"merchantInfo\":{\"merchantName\":\"merchantName\"},\"allowedPaymentMethods\":[{\"type\":\"CARD\",\"parameters\":{\"allowedAuthMethods\":[\"PAN_ONLY\"],\"allowedCardNetworks\":[\"VISA\",\"MASTERCARD\"],\"billingAddressRequired\":true,\"cvcRequired\":false},\"tokenizationSpecification\":{\"type\":\"PAYMENT_GATEWAY\",\"parameters\":{\"gatewayMerchantId\":\"YOUR_MERCHANT_ID\",\"gateway\":\"cybersource\"}}}],\"transactionInfo\":{\"currencyCode\":\"AUD\",\"totalPriceStatus\":\"ESTIMATED\",\"totalPrice\":\"43.1\"}} "
                                }
                            },
                            "additionalPaymentOptions": [
                                {
                                    "actionProvidedOptions": {
                                        "paymentType": "ON_FULFILLMENT",
                                        "displayName": "Pay when you get your food.",
                                        "onFulfillmentPaymentData": {
                                            "supportedPaymentOptions": []
                                        }
                                    }
                                }
                            ]
                        }
                    }
                }
            ]
        }
    }
}

请求失败

如果结账请求失败,CheckoutResponseMessage 需要包含 FoodErrorExtension,其中包含用于描述发生的任何错误的 FoodOrderError 项列表。如果订单存在任何可恢复的错误(例如购物车中商品的价格发生变化),FoodErrorExtension 必须包含 correctedProposedOrder

失败响应示例

{
  "expectUserResponse": false,
  "finalResponse": {
    "richResponse": {
      "items": [
        {
          "structuredResponse": {
            "error": {
              "@type": "type.googleapis.com/google.actions.v2.orders.FoodErrorExtension",
              "foodOrderErrors": [
                {
                  "error": "CLOSED",
                  "description": "The restaurant is closed."
                }
              ]
            }
          }
        }
      ]
    }
  }
}

结账流程实现

实现结账时,应执行以下步骤。

验证服务

针对找到的第一个服务错误条件返回 FoodOrderError。这些错误无法恢复,因此应返回遇到的第一个错误。如需了解可恢复的错误,请参阅处理错误

  1. 读取请求中的 FulfillmentOptionInfo 属性,以确定执行方式类型是 delivery 还是 pickup
  2. 请根据需要返回以下错误类型:

    错误类型 使用场景
    INVALID 执行方式类型无效。
    NOT_FOUND 找不到履单类型。
    已解决
    • 订单没有 OperationHours 时间范围。
    • 该订单是“尽快”订单,目前没有任何“尽快”ServiceHours可用。
    • 发生紧急关闭或服务 isDisabled 为 true。
    请注意,特殊窗口优先于普通窗口。请参阅有序时间范围验证暂时移除服务实体中的示例。
    UNAVAILABLE_SLOT 无法执行提前下单。
    NO_CAPACITY 餐厅很忙,目前不接受订单。
    OUT_OF_SERVICE_AREA 订单无法配送到用户的地址。如需查看示例,请参阅送货地址验证
    NO_COURIER_AVAILABLE 由于配送人员有限,订单无法配送。

验证购物车并为其定价

  1. 查询每个购物车lineItems并使用您系统或商家系统中的当前数据进行验证。Feed 实体中的 MenuItemOffer.sku 值会作为 LineItem.offerId 包含在内。根据需要,为每个订单项创建 FoodOrderError。每个项最多只能创建一个错误。如有需要,返回以下错误类型:

    错误类型 使用场景 可恢复
    INVALID 商品数据或任何选项数据无效。
    NOT_FOUND 找不到相应内容或任何选项。
    PRICE_CHANGED 商品或附加内容组合的价格发生了变化。此错误可视为可恢复的错误。
    AVAILABILITY_CHANGED 系统无法提供为订单项或任何选项请求的金额。
    REQUIREMENTS_NOT_MET 未达到最低或最高订单金额要求。您可以通过检查购物车价格是否低于 Fee.eligibleTransactionVolumeMin 或高于 Fee.eligibleTransactionVolumeMax 来确定这一点。请参阅最低订单金额验证中的示例。
  2. 返回包含 LineItemType REGULAR 且已通过验证的 LineItem 列表。购物车中所有商品订单项价格的总和即为购物车价格或 SUBTOTAL

请参阅购物车商品验证中的示例。

计算服务费

  1. 根据 eligibleRegionvalidFromvalidThroughpriority 为服务查找正确的费用实体。
  2. 根据实体是使用 pricepercentageOfCart 还是 pricePerMeter 属性定义的来计算费用金额。
  3. 将外卖或外带服务费作为 LineItem 返回,其 LineItemType 分别为 DELIVERYFEE。将费用添加到购物车otherItems列表中。

使用促销优惠

  1. 根据将 Promotion.coupon 值与 Deal.dealCode 进行匹配,找到 Deal 实体。
  2. 验证交易,并根据需要返回 FoodOrderError。 这些错误可以视为可恢复的错误。根据需要返回以下错误类型:

    错误类型 使用场景
    PROMO_NOT_RECOGNIZED 系统无法识别优惠券代码。
    PROMO_EXPIRED 特惠已过期。
    PROMO_ORDER_INELIGIBLE 订单不符合优惠券使用条件。
    PROMO_NOT_APPLICABLE 任何其他原因。
  3. 根据 Deal.discountDeal.discountPercentage 计算交易价格金额。

  4. 根据特惠,使用购物车总金额或费用总金额应用特惠价格金额。dealType

  5. 返回包含已应用促销的 Cart.promotions

  6. 将促销活动作为 LineItem 返回,其 LineItemTypeDISCOUNT。将折扣添加到价格为负的 Cart.otherItems 列表中。

返回响应

  1. 创建 ProposedOrdercart如果验证期间未遇到错误,则响应购物车与请求购物车相同。
  2. 返回 ProposedOrder.otherItems 列表,其中包含税费、费用、小费和折扣(如果适用)。如需详细了解如何配置小费项,请参阅小费
  3. 添加购物车价格、费用、折扣、税费和小费,以包含 ProposedOrdertotalPrice
  4. 返回 FoodOrderExtension.availableFulfillmentOptions 及其相应的 FulfillmentOption。将预计取件时间或送货时间更新为预计时间。
  5. 如果之前的验证检查生成了 FoodOrderError:
    • FoodErrorExtension.foodOrderErrors 中添加 StructuredResponse.error 和错误列表。
    • 如果所有错误均可恢复,则在 correctedProposedOrder 字段中返回 ProposedOrder
    • 如果所有错误均可恢复,请在 paymentOptions 字段中返回 PaymentOptions
    • 如果有其他付款方式可用且所有错误均可恢复,可以选择添加 additionalPaymentOptions
  6. 如果没有验证错误,请在 CheckoutResponse 对象中返回 proposedOrderpaymentOptions。(可选)如果有其他付款方式可用,请添加 additionalPaymentOptions