Thiết lập quy trình thanh toán

Quy trình thanh toán được gọi khi người dùng tạo giỏ hàng. Nội dung trong giỏ hàng của người dùng và thông tin chi tiết về đơn đặt hàng sẽ được gửi đến dịch vụ web Đặt hàng toàn diện của bạn. Dịch vụ web của bạn sẽ xác thực thông tin này, sau đó bạn có thể tiếp tục hoặc điều chỉnh giỏ hàng của họ nếu cần.

Trình xử lý thanh toán cho dịch vụ web của bạn phải phản hồi các yêu cầu POST. Khi khách hàng chọn thanh toán, Google sẽ gửi cho dịch vụ web Toàn diện về việc đặt hàng một nội dung yêu cầu JSON ở dạng CheckoutRequestMessage. Nội dung này chứa thông tin chi tiết về Cart của khách hàng. Sau đó, dịch vụ web của bạn sẽ phản hồi bằng một CheckoutResponseMessage. Sơ đồ sau đây minh hoạ quy trình này.

CheckoutResponseMessage trả về giỏ hàng chưa sửa đổi của khách hàng hoặc một lỗi.

Sau khi nhận được yêu cầu thanh toán, dịch vụ web Toàn diện về việc đặt hàng phải thực hiện những việc sau:

  • Kiểm tra tính hợp lệ của giỏ hàng dựa trên giá hiện tại của mặt hàng, tình trạng còn hàng và dịch vụ của nhà cung cấp.
  • Tính tổng giá (bao gồm mọi khoản chiết khấu, thuế và phí giao hàng).
  • Nếu thành công, hãy phản hồi bằng một giỏ hàng chưa sửa đổi.
  • Nếu không thành công, hãy phản hồi bằng thông báo lỗi và một đơn đặt hàng mới được đề xuất.

Trước khi bắt đầu triển khai quy trình thanh toán, bạn nên xem lại tài liệu Tổng quan về việc thực hiện đơn hàng.

Thông báo yêu cầu thanh toán

Để xác thực giỏ hàng của khách hàng, khi khách hàng chọn thanh toán, Google sẽ gửi một yêu cầu đến dịch vụ web của bạn với nội dung JSON ở dạng CheckoutRequestMessage. Đơn đặt hàng của khách hàng sẽ không được gửi cho đến sau trong quy trình Đặt hàng hoàn chỉnh.

Dữ liệu có trong CheckoutRequestMessage bao gồm:

  • Ý định: Trường inputs[0].intent của mọi nội dung yêu cầu thanh toán chứa giá trị chuỗi actions.foodordering.intent.CHECKOUT.
  • Giỏ hàng: Trường inputs[0].arguments[0].extension của yêu cầu thanh toán chứa đối tượng Cart đại diện cho giỏ hàng của khách hàng.
  • Giao hàng hoặc mang đi: Trường mở rộng của đối tượng Cart chứa một đối tượng FoodCartExtension chỉ định các thuộc tính cho dịch vụ giao hàng hoặc mang đi:
    • Đối với đơn đặt hàng giao tận nơi, đối tượng FoodCartExtension bao gồm cả địa chỉ giao hàng.
    • Đối với đơn đặt hàng mang đi hoặc đến lấy hàng, đối tượng FoodCartExtension không chứa bất kỳ thông tin vị trí nào.
  • Hộp cát: Trường isInSandbox của yêu cầu thanh toán chứa một giá trị boolean cho biết giao dịch có sử dụng phương thức thanh toán trong hộp cát hay không.

Ví dụ về yêu cầu thanh toán

Dưới đây là ví dụ về 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
}

Thông báo phản hồi quy trình thanh toán

Sau khi nhận được yêu cầu từ dịch vụ Đặt hàng toàn diện, dịch vụ web thanh toán của bạn phải xử lý yêu cầu đó và phản hồi bằng CheckoutResponseMessage. CheckoutResponseMessage cần bao gồm một yêu cầu thành công hoặc không thành công.

Yêu cầu thành công

Nếu yêu cầu thanh toán thành công, CheckoutResponseMessage cần bao gồm ProposedOrderPaymentOptions:

  • ProposedOrder

    • cart: Một đối tượng cart giống với giỏ hàng được cung cấp trong CheckoutRequestMessage. Nếu cần thay đổi bất kỳ nội dung nào trong giỏ hàng, CheckoutResponseMessage phải bao gồm FoodErrorExtensionProposedOrder đã sửa.
    • otherItems: Các mục do nhà cung cấp thêm, chẳng hạn như phí giao hàng, thuế và các khoản phí khác. Cũng có thể chứa tiền boa do người dùng thêm.
    • totalPrice: Tổng giá của đơn đặt hàng.
    • extension: FoodOrderExtension xác định thông tin thực hiện đơn đặt hàng, chẳng hạn như thời gian giao hàng.
  • PaymentOptions

    • Phần sau sẽ trình bày cách thiết lập quy trình xử lý thanh toán trong phần Thiết lập Google Pay. Bạn có thể sử dụng JSON phần giữ chỗ trong CheckoutResponseMessage cho đến khi sẵn sàng triển khai quy trình xử lý thanh toán.
    • Để thêm các phương thức thanh toán giữ chỗ trong CheckoutResponseMessage, hãy tham khảo ví dụ bên dưới. Ví dụ này sử dụng một cổng thanh toán mẫu cho PaymentOptions.

Ví dụ về phản hồi thành công

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

Yêu cầu không thành công

Nếu yêu cầu thanh toán không thành công, CheckoutResponseMessage cần bao gồm FoodErrorExtension. FoodErrorExtension chứa danh sách các mục FoodOrderError mô tả mọi lỗi đã xảy ra. Nếu có bất kỳ lỗi nào có thể khôi phục đối với đơn đặt hàng, chẳng hạn như thay đổi giá của một mặt hàng trong giỏ hàng, thì FoodErrorExtension phải bao gồm correctedProposedOrder.

Ví dụ về phản hồi không thành công

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

Triển khai quy trình thanh toán

Bạn nên thực hiện các bước sau khi triển khai quy trình thanh toán.

Xác thực dịch vụ

Trả về FoodOrderError cho điều kiện lỗi dịch vụ đầu tiên được tìm thấy. Bạn không thể khôi phục các lỗi này, vì vậy, lỗi đầu tiên gặp phải sẽ được trả về. Hãy xem phần Xử lý lỗi để biết nội dung mô tả về các lỗi có thể khôi phục.

  1. Đọc thuộc tính FulfillmentOptionInfo trong yêu cầu để xác định xem loại phương thức thực hiện là dành cho delivery hay pickup.
  2. Trả về các loại lỗi sau đây nếu cần:

    Loại lỗi Trường hợp sử dụng
    INVALID Loại phương thức thực hiện là không hợp lệ.
    NOT_FOUND Không tìm thấy loại phương thức thực hiện.
    ĐÃ ĐÓNG
    • Đơn đặt hàng không có khung giờ OperationHours.
    • Đơn đặt hàng này là đơn đặt hàng cần giao hàng ngay và hiện không có ServiceHours nào cho đơn đặt hàng cần giao hàng ngay tại thời điểm hiện tại.
    • Có trường hợp đóng khẩn cấp hoặc dịch vụ isDisabled là đúng.
    Xin lưu ý rằng Cửa sổ đặc biệt được ưu tiên hơn cửa sổ thông thường. Xem ví dụ trong phần xác thực khoảng thời gian đặt hàngtạm thời xoá các thực thể dịch vụ.
    UNAVAILABLE_SLOT Không thể thực hiện đơn đặt hàng trước.
    NO_CAPACITY Nhà hàng đang bận và hiện không nhận đơn đặt hàng.
    OUT_OF_SERVICE_AREA Không thể giao đơn đặt hàng đến địa chỉ của người dùng. Hãy xem phần Xác thực địa chỉ giao hàng để biết ví dụ.
    NO_COURIER_AVAILABLE Không thể giao đơn đặt hàng do thiếu nhân viên giao hàng.

Xác thực và định giá giỏ hàng

  1. Tìm mỗi Giỏ hàng.lineItems và xác thực bằng dữ liệu hiện tại trong hệ thống của bạn hoặc trong hệ thống của người bán. Giá trị MenuItemOffer.sku từ thực thể nguồn cấp dữ liệu được đưa vào dưới dạng LineItem.offerId. Tạo một FoodOrderError cho mỗi mục hàng nếu cần. Tạo tối đa một lỗi cho mỗi mục. Trả về các loại lỗi sau đây nếu cần:

    Loại lỗi Trường hợp sử dụng Có thể khôi phục
    INVALID Dữ liệu mặt hàng hoặc bất kỳ dữ liệu tuỳ chọn nào đều không hợp lệ. Không
    NOT_FOUND Không tìm thấy mặt hàng hoặc bất kỳ tuỳ chọn nào. Không
    PRICE_CHANGED Giá của một mặt hàng hoặc tổ hợp tiện ích bổ sung đã thay đổi. Lỗi này có thể được coi là có thể khôi phục.
    AVAILABILITY_CHANGED Số tiền bạn yêu cầu cho mục hàng hoặc bất kỳ lựa chọn nào không có sẵn.
    REQUIREMENTS_NOT_MET Chưa đạt số lượng đơn đặt hàng tối thiểu hoặc tối đa. Bạn có thể xác định điều này bằng cách kiểm tra xem giá giỏ hàng có thấp hơn Phí.eligibleTransactionVolumeMin hay cao hơn Phí.eligibleTransactionVolumeMax hay không. Xem ví dụ trong phần xác thực giá trị đơn đặt hàng tối thiểu. Không
  2. Trả về danh sách lineItems đã xác thực bằng LineItemType REGULAR. Tổng giá của tất cả các mục hàng trong giỏ hàng là giá giỏ hàng hoặc SUBTOTAL.

Xem ví dụ trong phần xác thực mặt hàng trong giỏ hàng.

Tính phí dịch vụ

  1. Tìm thực thể Phí chính xác cho dịch vụ dựa trên eligibleRegion, validFrom, validThroughpriority.
  2. Tính số tiền phí dựa trên việc thực thể được xác định bằng thuộc tính price, percentageOfCart hoặc pricePerMeter.
  3. Trả về phí dịch vụ giao hàng hoặc mang đi dưới dạng LineItem với LineItemType tương ứng là DELIVERY hoặc FEE. Thêm phí vào danh sách Giỏ hàng.otherItems.

Áp dụng chương trình khuyến mãi

  1. Tìm thực thể Thoả thuận dựa trên việc so khớp giá trị Khuyến mãi.coupon với Thoả thuận.dealCode.
  2. Xác thực ưu đãi và trả về FoodOrderError nếu cần. Những lỗi này có thể được coi là có thể khôi phục. Trả về các loại lỗi sau đây nếu cần:

    Loại lỗi Trường hợp sử dụng
    PROMO_NOT_RECOGNIZED Không nhận dạng được mã giảm giá.
    PROMO_EXPIRED Thời hạn hiệu lực của thoả thuận đã hết.
    PROMO_ORDER_INELIGIBLE Đơn đặt hàng không đủ điều kiện sử dụng phiếu giảm giá.
    PROMO_NOT_APPLICABLE Lý do khác.
  3. Tính số tiền của giá ưu đãi dựa trên Deal.discount hoặc Deal.discountPercentage.

  4. Áp dụng số tiền ưu đãi bằng cách sử dụng tổng giá trị giỏ hàng hoặc tổng phí, tuỳ thuộc vào Ưu đãi.dealType.

  5. Trả về Giỏ hàng.promotions đã áp dụng chương trình khuyến mãi.

  6. Trả về chương trình khuyến mãi dưới dạng LineItem với LineItemType DISCOUNT. Thêm khoản chiết khấu vào danh sách Giỏ hàng.otherItems có giá âm.

Trả về phản hồi

  1. Tạo ProposedOrder.cart, giỏ hàng phản hồi giống với giỏ hàng yêu cầu nếu không gặp lỗi trong quá trình xác thực.
  2. Trả về danh sách ProposedOrder.otherItems bao gồm thuế, phí, tiền boa và chiết khấu nếu áp dụng. Hãy xem phần Tiền boa để biết thêm thông tin chi tiết về cách định cấu hình mặt hàng tiền boa.
  3. Thêm ProposedOrder.totalPrice bằng cách thêm giá, phí, chiết khấu, thuế và tiền boa vào giỏ hàng.
  4. Trả về FoodOrderExtension.availableFulfillmentOptions với FulfillmentOption tương ứng. Cập nhật thời gian lấy hàng hoặc giao hàng dự kiến thành thời gian dự kiến.
  5. Nếu có FoodOrderErrors được tạo từ các lần kiểm tra xác thực trước đó:
    • Thêm StructuredResponse.error và danh sách lỗi vào FoodErrorExtension.foodOrderErrors.
    • Trả về ProposedOrder trong trường correctedProposedOrder nếu tất cả lỗi đều có thể khôi phục.
    • Trả về PaymentOptions trong trường paymentOptions nếu tất cả lỗi đều có thể khôi phục.
    • Bạn có thể thêm additionalPaymentOptions nếu có các phương thức thanh toán khác và tất cả lỗi đều có thể khôi phục.
  6. Nếu không có lỗi xác thực, hãy trả về proposedOrder, paymentOptions trong đối tượng CheckoutResponse. Bạn có thể đưa additionalPaymentOptions vào nếu có các phương thức thanh toán khác.