教程

按照本教程中的步骤将 Web 应用与 Google Pay API 集成,并将其配置为接受支付卡。

第 1 步:指定您的 Google Pay API 版本

声明您的网站使用的 Google Pay API 版本。该主要版本和次要版本在每个传递的对象的字段中是必需的,并且会包含在响应中。

以下代码示例演示了声明的 API 版本:

const baseRequest = {
  apiVersion: 2,
  apiVersionMinor: 0
};

第 2 步:为您的付款服务机构申请付款令牌

Google 会加密付款人所选卡的相关信息,以便付款服务机构进行安全处理。

const tokenizationSpecification = {
  type: 'PAYMENT_GATEWAY',
  parameters: {
    'gateway': 'example',
    'gatewayMerchantId': 'exampleGatewayMerchantId'
  }
};

exampleexampleGatewayMerchantId 替换为付款服务机构的相应值。请使用下表查找您的付款服务机构的具体 gatewaygatewayMerchantId 值:

网关 参数和文档
ACI

  "gateway": "aciworldwide"
  "gatewayMerchantId": "YOUR_ENTITY_ID"

开发者文档

Adyen

  "gateway": "adyen"
  "gatewayMerchantId": "YOUR_MERCHANT_ACCOUNT_NAME"

开发者文档

Alfa-Bank

  "gateway": "alfabank"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Alfa-Bank Ukraine
  "gateway": "alfabankua"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

APPEX

  "gateway": "epos"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Assist

  "gateway": "assist"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

结算系统

  "gateway": "billingsystems"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Bizzon
  "gateway": "bizzon"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Blue Media

  "gateway": "bluemedia"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

BlueSnap

  "gateway": "bluesnap"
  "gatewayMerchantId": "YOUR_shopToken"

开发者文档

Braintree

  "gateway": "braintree"
  "braintree:apiVersion": "v1"
  "braintree:sdkVersion": "braintree.client.VERSION"
  "braintree:merchantId": "YOUR_BRAINTREE_MERCHANT_ID"
  "braintree:clientKey": "YOUR_BRAINTREE_TOKENIZATION_KEY"

开发者文档

Braspag

  "gateway": "cielo"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

CardConnect

  "gateway": "cardconnect"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Cathay United Bank

  "gateway": "cathaybk"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Chase Merchant Services

  "gateway": "chase"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Checkout.com

  "gateway": "checkoutltd"
  "gatewayMerchantId": "YOUR_PUBLIC_KEY"

开发者文档

CloudPayments

  "gateway": "cloudpayments"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Computop

  "gateway": "computop"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

ConcordPay

  "gateway": "concordpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Credorax
"gateway": "credorax"
"gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Cybersource

  "gateway": "cybersource"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Datatrans

  "gateway": "datatrans"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

dLocal

  "gateway": "dlocal"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Dotpay

  "gateway": "dotpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

e-SiTef - Software Express

  "gateway": "softwareexpress"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

EasyPay

  "gateway": "easypay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

EBANX

  "gateway": "ebanx"
  "gatewayMerchantId": "YOUR_PUBLIC_INTEGRATION_KEY"

开发者文档

eCard

  "gateway": "ecard"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

ECPay

  "gateway": "ecpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

eGHL

  "gateway": "eghl"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

eSafe

  "gateway": "esafe"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Evo Payment Gateway

  "gateway": "evopaymentgateway"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Fat Zebra

  "gateway": "fatzebra"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

First Data (Payeezy)

  "gateway": "firstdata"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

FreedomPay

  "gateway": "freedompay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Gestpay

  "gateway": "gestpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Global One Pay

  "gateway": "globalonepay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Global Payments

  "gateway": "globalpayments"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

GMO Payment Gateway

  "gateway": "gmopg"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

GoPay

  "gateway": "gopay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

GP Webpay

  "gateway": "gpwebpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

HiTrust

  "gateway": "hitrustpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

InPlat
  "gateway": "inplat"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

IntellectMoney
"gateway": "intellectmoney"
"gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

iPay88

  "gateway": "ipay88"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

iQmetrix

  "gateway": "iqmetrixpaymentservicesgateway"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

IXOPAY

  "gateway": "ixopay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

JudoPay

  "gateway": "judopay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Kassa

  "gateway": "kassacom"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Kineox

  "gateway": "kineox"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

LogPay

  "gateway": "logpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Lyra

  "gateway": "lyra"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Mastercard Payment Gateway Services

  "gateway": "mpgs"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

MOBI.Money

  "gateway": "mobimoney"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Molpay

  "gateway": "molpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Moneris

  "gateway": "moneris"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Moneta

  "gateway": "moneta"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Monext

  "gateway": "monext"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Money.Mail.Ru

  "gateway": "moneymailru"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Multicarta

  "gateway": "mulitcarta"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Mundipagg

  "gateway": "mundipagg"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

MyCheck

  "gateway": "mycheck"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

MyPay

  "gateway": "mypay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Newebpay(原名 STPath、Pay2Go)

  "gateway": "newebpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Nexi

  "gateway": "nexi"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

NMI

  "gateway": "gatewayservices"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Nuvei

  "gateway": "nuvei"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Payfacto

  "gateway": "payfacto"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

paygent

  "gateway": "paygent"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

PayLane

  "gateway": "paylane"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Payler

  "gateway": "payler"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Payload
"gateway": "payload"
"gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Paymark

  "gateway": "paymark"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Paymentwall

  "gateway": "paymentwall"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Paymo

  "gateway": "paymo"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

PayOnline

  "gateway": "payonline"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Paysafe

  "gateway": "paysafe"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Payture

  "gateway": "payture"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

PayU

  "gateway": "payu"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Payway

  "gateway": "payway"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Platon

  "gateway": "platon"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Portmone

  "gateway": "portmonecom"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Przelewy24

  "gateway": "przelewy24"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Radial

  "gateway": "radial"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

RBK.money

  "gateway": "rbkmoney"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Rebilly

  "gateway": "Rebilly"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Redsys

  "gateway": "redsys"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Sberbank

  "gateway": "sberbank"
  "gatewayMerchantId": "YOUR_ORGANIZATION_NAME"

开发者文档

Sipay

  "gateway": "sipay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Softbank Payment Service

  "gateway": "sbps"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Solid

  "gateway": "solid"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Sony Payment Services

  "gateway": "sonypaymentservices"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Spreedly

  "gateway": "spreedly"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Square

  "gateway": "square"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Stripe

  "gateway": "stripe"
  "stripe:version": "2018-10-31"
  "stripe:publishableKey": "YOUR_PUBLIC_STRIPE_KEY"

开发者文档

TapPay (Cherri Tech)

  "gateway": "tappay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

TAS Link

  "gateway": "taslink"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

Developer docs

Tatra banka (CardPay)

  "gateway": "tatrabanka"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

没有开发者文档

Tinkoff

  "gateway": "tinkoff"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

theMAP

  "gateway": "themap"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

TPay.com

  "gateway": "tpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Tranzzo

  "gateway": "tranzzo"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Uniteller

  "gateway": "uniteller"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Vantiv

  "gateway": "vantiv"
  "vantiv:merchantPayPageId": "YOUR_PAY_PAGE_ID"
  "vantiv:merchantOrderId": "YOUR_ORDER_ID"
  "vantiv:merchantTransactionId": "YOUR_TRANSACTION_ID"
  "vantiv:merchantReportGroup": "*web"

开发者文档

Veritrans

  "gateway": "veritrans"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Vindicia

  "gateway": "vindicia"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

WayForPay

  "gateway": "wayforpay"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Windcave

  "gateway": "windcave"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Wirecard

  "gateway": "wirecard"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Worldnet

  "gateway": "worldnet"
  "gatewayMerchantId": "YOUR_GATEWAY_MERCHANT_ID"

开发者文档

Worldpay

  "gateway": "worldpay"
  "gatewayMerchantId": "YOUR_WORLDPAY_MERCHANT_ID"

开发者文档

Yandex.Checkout

  "gateway": "yandexcheckout"
  "gatewayMerchantId": "YOUR_SHOP_ID"

开发者文档

PAYMENT_GATEWAY 令牌化类型是 Google Pay API 中为商家实现卡付款方式的最常见类型。如果您的付款服务机构不受支持,您也许可以通过直接集成来接受 Google Pay。如需了解详情,请参阅直接令牌化文档

第 3 步:指定支持的支付卡网络

指定您的网站接受的支付卡网络。请参阅以下代码示例:

const allowedCardNetworks = ["AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"];

Google Pay API 可能返回 Google 记录在案的支付卡 (PAN_ONLY) 和/或在 Android 设备上以 3D 安全密文进行身份验证的设备令牌 (CRYPTOGRAM_3DS)。请参阅以下代码示例:

const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];

如需了解详情,请参阅我们的对象参考文档中的 CardParameters。此外,请与您的网关或处理方联系,了解所支持的支付卡网络以及对 Android 设备令牌的支持情况。

第 4 步:说明您允许的付款方式

要说明您允许的付款方式,请完成以下步骤:

  1. 将您支持的身份验证方法和支持的支付卡网络结合使用,以说明您的网站对 CARD 付款方式的支持情况。请参阅以下代码示例:
    const baseCardPaymentMethod = {
      type: 'CARD',
      parameters: {
        allowedAuthMethods: allowedCardAuthMethods,
        allowedCardNetworks: allowedCardNetworks
      }
    };
    
  2. 扩展基本的卡付款方式对象,以说明您预计会返回给您的应用的信息。添加令牌化的付款数据的说明。请参阅以下代码示例:
    const cardPaymentMethod = Object.assign(
      {tokenizationSpecification: tokenizationSpecification},
      baseCardPaymentMethod
    );
    
  3. 如需详细了解所支持的 parameters,请参阅 CardParameters

    Google Pay 还支持 CARD 类型和 PAYPAL 类型的付款方式。如需详细了解如何将 PAYPAL 类型添加为 Google Pay 的付款方式,请参阅 PayPal 的开发者文档

第 5 步:加载 Google Pay API JavaScript 库

要加载 Google Pay API JavaScript 库,请完成以下步骤:

  1. 在您的网页上添加 Google 托管的 JavaScript。请参阅以下代码示例:
    <script
      async
      src="https://pay.google.com/gp/p/js/pay.js"
      onload="console.log('TODO: add onload function')">
    </script>
  2. 加载 Google Pay API JavaScript 库后,初始化 PaymentsClient 对象。初始开发使用 TEST 环境,该环境会返回适合引用付款响应结构的虚拟付款方式。在此环境中,选定的付款方式无法进行交易。请参阅以下代码示例:
    const paymentsClient =
        new google.payments.api.PaymentsClient({environment: 'TEST'});

    如需详细了解会返回可扣款付款方式的 PRODUCTION 环境的要求,请参阅集成核对清单

第 6 步:确定是否能使用 Google Pay API 进行付款

要确定是否已准备好使用 Google Pay API 付款,请完成以下步骤:

  1. 将您允许的付款方式添加到基本请求对象中。请参阅以下代码示例:
    const isReadyToPayRequest = Object.assign({}, baseRequest);
    isReadyToPayRequest.allowedPaymentMethods = [baseCardPaymentMethod];
  2. 对于您的指定付款方式,请调用 isReadyToPay(),以确定当前设备和/或浏览器是否支持 Google Pay API。请参阅以下代码示例:
    paymentsClient.isReadyToPay(isReadyToPayRequest)
        .then(function(response) {
          if (response.result) {
            // add a Google Pay payment button
          }
        })
        .catch(function(err) {
          // show error in developer console for debugging
          console.error(err);
        });

第 7 步:添加 Google Pay 付款按钮

向您的网页添加 Google Pay 付款按钮,以鼓励买家使用 Google Pay API 和您的网站支持的付款方式结算。如需详细了解可用的按钮类型、颜色和显示要求,请参阅品牌推广指南

请参阅以下付款按钮代码示例:

const button =
    paymentsClient.createButton({onClick: () => console.log('TODO: click handler')});
document.getElementById('container').appendChild(button);

第 8 步:创建 PaymentDataRequest 对象

要创建 PaymentDataRequest 对象,请完成以下步骤:

  1. 构建一个 JavaScript 对象来说明您的网站对 Google Pay API 的支持情况。如需查看受支持属性的完整列表,请参阅 PaymentDataRequest。请参阅以下代码示例:
    const paymentDataRequest = Object.assign({}, baseRequest);
  2. 添加您的应用所支持的付款方式,例如响应中应该会包含的任何其他数据的配置。请参阅以下代码示例:
    paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
    
  3. 指定买家授权的总价和币种。请参阅以下代码示例:
    paymentDataRequest.transactionInfo = {
      totalPriceStatus: 'FINAL',
      totalPrice: '123.45',
      currencyCode: 'USD',
      countryCode: 'US'
    };
  4. 提供用户可见的商家名称,并在 TEST 中使用我们的 TEST merchantId 值。如需了解详情以及了解何时替换 TEST merchantId值,请参阅 MerchantInfo。请参阅以下代码示例,了解用户可见的商家名称:
    paymentDataRequest.merchantInfo = {
      merchantName: 'Example Merchant'
      merchantId: '12345678901234567890'
    };
    

第 9 步:为用户手势注册事件处理程序

要为用户手势注册事件处理程序,请完成以下步骤:

  1. 为购买按钮注册 Click 事件处理程序。该事件处理程序会在与 Google Pay 付款按钮互动后立即调用 loadPaymentData()
  2. 在 Google 用户授权您的网站接收与用户所选付款方式和可选联系数据相关的信息后,处理来自 Google Pay API 的响应。
  3. 请从 paymentData 响应中提取付款令牌。如果您实现了网关集成,请将此令牌传递给您的网关,无需进行任何修改。
    paymentsClient.loadPaymentData(paymentDataRequest).then(function(paymentData){
      // if using gateway tokenization, pass this token without modification
      paymentToken = paymentData.paymentMethodData.tokenizationData.token;
    }).catch(function(err){
      // show error in developer console for debugging
      console.error(err);
    });

第 10 步(可选):在用户互动之前预取付款数据

要缩短执行时间,请先从 Google Pay API 预取您网站的付款配置,然后再调用 loadPaymentData()。请参阅以下示例:

paymentsClient.prefetchPaymentData(paymentDataRequest);

第 11 步(可选):设置授权付款

“授权付款”用于启动付款流程并确认付款的授权状态。要设置授权付款,请按以下步骤操作:

  1. PaymentOptions 中注册 onPaymentAuthorized() 回调。
  2. 使用 PAYMENT_AUTHORIZATION 回调 Intent 时,可调用 loadPaymentData() 函数。
  3. 实现 onPaymentAuthorized()

注册 onPaymentAuthorized 回调

以下代码示例演示了如何注册 onPaymentAuthorized 回调:

{
  environment: "TEST",
  merchantInfo: {
    merchantName: "Example Merchant",
    merchantId: "12345678901234567890"
  },
  paymentDataCallbacks: {
    onPaymentAuthorized: onPaymentAuthorized
  }
}

使用回调 intent 加载付款数据

以下代码示例演示了如何使用“授权付款”来初始化付款表格:

const paymentDataRequest = Object.assign({}, baseRequest);
paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
paymentDataRequest.transactionInfo = getGoogleTransactionInfo();
paymentDataRequest.merchantInfo = {
  merchantName: 'Example Merchant'
  merchantId: '12345678901234567890',
};

paymentDataRequest.callbackIntents = ["PAYMENT_AUTHORIZATION"];

处理 onPaymentAuthorized 回调

付款人通过用户手势批准付款(例如,点击付款)后,Google 会使用 PaymentData 对象调用 onPaymentAuthorized() 回调。

该回调会返回一个 Promise<PaymentAuthorizationResult> 值。PaymentAuthorizationResult 对象具有 SUCCESSERROR 交易状态。成功后,付款表格将成功关闭。如果您遇到错误,则付款表格会显示系统处理完付款后返回的错误详情。用户可以更改付款表格的付款数据并再次授权付款。请参阅以下代码示例:

function onPaymentAuthorized(paymentData) {
  return new Promise(function(resolve, reject){
    // handle the response
    processPayment(paymentData)
    .then(function() {
      resolve({transactionState: 'SUCCESS'});
    })
    .catch(function() {
      resolve({
        transactionState: 'ERROR',
        error: {
          intent: 'PAYMENT_AUTHORIZATION',
          message: 'Insufficient funds',
          reason: 'PAYMENT_DATA_INVALID'
        }
      });
    });
  });
}

第 12 步(启用运费时为可选):设置动态价格更新

动态价格更新允许商家根据所选的送货地址动态地更新运费选项和交易信息。此外,您还可以根据所选的运费选项动态地更新交易信息。

要设置动态价格更新,请按以下步骤操作:

  1. PaymentOptions 中注册 onPaymentAuthorizedonPaymentDataChanged 回调。
  2. 使用回调 Intent 调用 loadPaymentData() 函数。如需了解详情,请参阅相应的示例
  3. 实现 onPaymentAuthorizedonPaymentDataChanged

注册 PaymentData 回调

以下代码示例显示动态价格更新需要在 PaymentsClient paymentOptions 对象中注册回调函数。

{
  environment: "TEST",
  merchantInfo: {
    merchantName: "Example Merchant",
    merchantId: "12345678901234567890"
  },
  paymentDataCallbacks: {
    onPaymentAuthorized: onPaymentAuthorized,
    onPaymentDataChanged: onPaymentDataChanged
  }
}

使用回调 intent 加载付款数据

以下代码示例演示了如何使用所需的送货地址和运费选项配置来初始化付款表格:

const paymentDataRequest = Object.assign({}, baseRequest);
paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
paymentDataRequest.transactionInfo = getGoogleTransactionInfo();
paymentDataRequest.merchantInfo = {
  merchantId: '12345678901234567890',
  merchantName: 'Example Merchant'
};

paymentDataRequest.callbackIntents = ["SHIPPING_ADDRESS",  "SHIPPING_OPTION", "PAYMENT_AUTHORIZATION"];

paymentDataRequest.shippingAddressRequired = true;
paymentDataRequest.shippingAddressParameters = getGoogleShippingAddressParameters();
paymentDataRequest.shippingOptionRequired = true;

处理 onPaymentDataChanged 回调

onPaymentDataChanged 回调是使用 IntermediatePaymentData 对象调用的,该对象中包含在付款表格中选择的送货地址和运费选项。

该回调会返回一个 Promise<PaymentDataRequestUpdate> 值。PaymentDataRequestUpdate 对象包含新的交易信息、运费选项和付款数据错误,这些数据用于更新付款表格。

直接在付款表格中处理所有例外情况,例如无用的送货地址或无效的运费选项。设置 PaymentDataError 对象以突出显示错误原因,并向用户显示错误消息。请务必在消息中添加相关 intent。如需详细了解如何设置对象和消息,请参阅以下代码示例:

function onPaymentDataChanged(intermediatePaymentData) {
  return new Promise(function(resolve, reject) {

    let shippingAddress = intermediatePaymentData.shippingAddress;
    let shippingOptionData = intermediatePaymentData.shippingOptionData;
    let paymentDataRequestUpdate = {};

    if (intermediatePaymentData.callbackTrigger == "INITIALIZE" || intermediatePaymentData.callbackTrigger == "SHIPPING_ADDRESS") {
      if(shippingAddress.administrativeArea == "NJ")  {
        paymentDataRequestUpdate.error = getGoogleUnserviceableAddressError();
      }
      else {
        paymentDataRequestUpdate.newShippingOptionParameters = getGoogleDefaultShippingOptions();
        let selectedShippingOptionId = paymentDataRequestUpdate.newShippingOptionParameters.defaultSelectedOptionId;
        paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(selectedShippingOptionId);
      }
    }
    else if (intermediatePaymentData.callbackTrigger == "SHIPPING_OPTION") {
      paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(shippingOptionData.id);
    }

    resolve(paymentDataRequestUpdate);
  });
}

总结

此部分中的示例代码块演示了 Google Pay API JavaScript 库教程、授权付款和动态价格更新的完整端到端示例。

教程

<div id="container"></div>

<script>
/**
 * Define the version of the Google Pay API referenced when creating your
 * configuration
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|apiVersion in PaymentDataRequest}
 */
const baseRequest = {
  apiVersion: 2,
  apiVersionMinor: 0
};

/**
 * Card networks supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 * @todo confirm card networks supported by your site and gateway
 */
const allowedCardNetworks = ["AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"];

/**
 * Card authentication methods supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 * @todo confirm your processor supports Android device tokens for your
 * supported card networks
 */
const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];

/**
 * Identify your gateway and your site's gateway merchant identifier
 *
 * The Google Pay API response will return an encrypted payment method capable
 * of being charged by a supported gateway after payer authorization
 *
 * @todo check with your gateway on the parameters to pass
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#gateway|PaymentMethodTokenizationSpecification}
 */
const tokenizationSpecification = {
  type: 'PAYMENT_GATEWAY',
  parameters: {
    'gateway': 'example',
    'gatewayMerchantId': 'exampleGatewayMerchantId'
  }
};

/**
 * Describe your site's support for the CARD payment method and its required
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 */
const baseCardPaymentMethod = {
  type: 'CARD',
  parameters: {
    allowedAuthMethods: allowedCardAuthMethods,
    allowedCardNetworks: allowedCardNetworks
  }
};

/**
 * Describe your site's support for the CARD payment method including optional
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 */
const cardPaymentMethod = Object.assign(
  {},
  baseCardPaymentMethod,
  {
    tokenizationSpecification: tokenizationSpecification
  }
);

/**
 * An initialized google.payments.api.PaymentsClient object or null if not yet set
 *
 * @see {@link getGooglePaymentsClient}
 */
let paymentsClient = null;

/**
 * Configure your site's support for payment methods supported by the Google Pay
 * API.
 *
 * Each member of allowedPaymentMethods should contain only the required fields,
 * allowing reuse of this base request when determining a viewer's ability
 * to pay and later requesting a supported payment method
 *
 * @returns {object} Google Pay API version, payment methods supported by the site
 */
function getGoogleIsReadyToPayRequest() {
  return Object.assign(
      {},
      baseRequest,
      {
        allowedPaymentMethods: [baseCardPaymentMethod]
      }
  );
}

/**
 * Configure support for the Google Pay API
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|PaymentDataRequest}
 * @returns {object} PaymentDataRequest fields
 */
function getGooglePaymentDataRequest() {
  const paymentDataRequest = Object.assign({}, baseRequest);
  paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();
  paymentDataRequest.merchantInfo = {
    // @todo a merchant ID is available for a production environment after approval by Google
    // See {@link https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist|Integration checklist}
    // merchantId: '12345678901234567890',
    merchantName: 'Example Merchant'
  };
  return paymentDataRequest;
}

/**
 * Return an active PaymentsClient or initialize
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/client#PaymentsClient|PaymentsClient constructor}
 * @returns {google.payments.api.PaymentsClient} Google Pay API client
 */
function getGooglePaymentsClient() {
  if ( paymentsClient === null ) {
    paymentsClient = new google.payments.api.PaymentsClient({environment: 'TEST'});
  }
  return paymentsClient;
}

/**
 * Initialize Google PaymentsClient after Google-hosted JavaScript has loaded
 *
 * Display a Google Pay payment button after confirmation of the viewer's
 * ability to pay.
 */
function onGooglePayLoaded() {
  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest())
      .then(function(response) {
        if (response.result) {
          addGooglePayButton();
          // @todo prefetch payment data to improve performance after confirming site functionality
          // prefetchGooglePaymentData();
        }
      })
      .catch(function(err) {
        // show error in developer console for debugging
        console.error(err);
      });
}

/**
 * Add a Google Pay purchase button alongside an existing checkout button
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#ButtonOptions|Button options}
 * @see {@link https://developers.google.com/pay/api/web/guides/brand-guidelines|Google Pay brand guidelines}
 */
function addGooglePayButton() {
  const paymentsClient = getGooglePaymentsClient();
  const button =
      paymentsClient.createButton({onClick: onGooglePaymentButtonClicked});
  document.getElementById('container').appendChild(button);
}

/**
 * Provide Google Pay API with a payment amount, currency, and amount status
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#TransactionInfo|TransactionInfo}
 * @returns {object} transaction info, suitable for use as transactionInfo property of PaymentDataRequest
 */
function getGoogleTransactionInfo() {
  return {
    countryCode: 'US',
    currencyCode: 'USD',
    totalPriceStatus: 'FINAL',
    // set to cart total
    totalPrice: '1.00'
  };
}

/**
 * Prefetch payment data to improve performance
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/client#prefetchPaymentData|prefetchPaymentData()}
 */
function prefetchGooglePaymentData() {
  const paymentDataRequest = getGooglePaymentDataRequest();
  // transactionInfo must be set but does not affect cache
  paymentDataRequest.transactionInfo = {
    totalPriceStatus: 'NOT_CURRENTLY_KNOWN',
    currencyCode: 'USD'
  };
  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.prefetchPaymentData(paymentDataRequest);
}

/**
 * Show Google Pay payment sheet when Google Pay payment button is clicked
 */
function onGooglePaymentButtonClicked() {
  const paymentDataRequest = getGooglePaymentDataRequest();
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();

  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.loadPaymentData(paymentDataRequest)
      .then(function(paymentData) {
        // handle the response
        processPayment(paymentData);
      })
      .catch(function(err) {
        // show error in developer console for debugging
        console.error(err);
      });
}
/**
 * Process payment data returned by the Google Pay API
 *
 * @param {object} paymentData response from Google Pay API after user approves payment
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentData|PaymentData object reference}
 */
function processPayment(paymentData) {
  // show returned data in developer console for debugging
    console.log(paymentData);
  // @todo pass payment token to your gateway to process payment
  paymentToken = paymentData.paymentMethodData.tokenizationData.token;
}</script>
<script async
  src="https://pay.google.com/gp/p/js/pay.js"
  onload="onGooglePayLoaded()"></script>

授权付款

<div id="container"></div>

<script>
/**
 * Define the version of the Google Pay API referenced when creating your
 * configuration
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|apiVersion in PaymentDataRequest}
 */
const baseRequest = {
  apiVersion: 2,
  apiVersionMinor: 0
};

/**
 * Card networks supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 * @todo confirm card networks supported by your site and gateway
 */
const allowedCardNetworks = ["AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"];

/**
 * Card authentication methods supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 * @todo confirm your processor supports Android device tokens for your
 * supported card networks
 */
const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];

/**
 * Identify your gateway and your site's gateway merchant identifier
 *
 * The Google Pay API response will return an encrypted payment method capable
 * of being charged by a supported gateway after payer authorization
 *
 * @todo check with your gateway on the parameters to pass
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#gateway|PaymentMethodTokenizationSpecification}
 */
const tokenizationSpecification = {
  type: 'PAYMENT_GATEWAY',
  parameters: {
    'gateway': 'example',
    'gatewayMerchantId': 'exampleGatewayMerchantId'
  }
};

/**
 * Describe your site's support for the CARD payment method and its required
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 */
const baseCardPaymentMethod = {
  type: 'CARD',
  parameters: {
    allowedAuthMethods: allowedCardAuthMethods,
    allowedCardNetworks: allowedCardNetworks
  }
};

/**
 * Describe your site's support for the CARD payment method including optional
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 */
const cardPaymentMethod = Object.assign(
  {},
  baseCardPaymentMethod,
  {
    tokenizationSpecification: tokenizationSpecification
  }
);

/**
 * An initialized google.payments.api.PaymentsClient object or null if not yet set
 *
 * @see {@link getGooglePaymentsClient}
 */
let paymentsClient = null;

/**
 * Configure your site's support for payment methods supported by the Google Pay
 * API.
 *
 * Each member of allowedPaymentMethods should contain only the required fields,
 * allowing reuse of this base request when determining a viewer's ability
 * to pay and later requesting a supported payment method
 *
 * @returns {object} Google Pay API version, payment methods supported by the site
 */
function getGoogleIsReadyToPayRequest() {
  return Object.assign(
      {},
      baseRequest,
      {
        allowedPaymentMethods: [baseCardPaymentMethod]
      }
  );
}

/**
 * Configure support for the Google Pay API
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|PaymentDataRequest}
 * @returns {object} PaymentDataRequest fields
 */
function getGooglePaymentDataRequest() {
  const paymentDataRequest = Object.assign({}, baseRequest);
  paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();
  paymentDataRequest.merchantInfo = {
    // @todo a merchant ID is available for a production environment after approval by Google
    // See {@link https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist|Integration checklist}
    // merchantId: '12345678901234567890',
    merchantName: 'Example Merchant'
  };

  paymentDataRequest.callbackIntents = ["PAYMENT_AUTHORIZATION"];

  return paymentDataRequest;
}

/**
 * Return an active PaymentsClient or initialize
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/client#PaymentsClient|PaymentsClient constructor}
 * @returns {google.payments.api.PaymentsClient} Google Pay API client
 */
function getGooglePaymentsClient() {
  if ( paymentsClient === null ) {
    paymentsClient = new google.payments.api.PaymentsClient({
    	environment: 'TEST',
      paymentDataCallbacks: {
      	onPaymentAuthorized: onPaymentAuthorized
      }
    });
  }
  return paymentsClient;
}

/**
 * Handles authorize payments callback intents.
 *
 * @param {object} paymentData response from Google Pay API after a payer approves payment through user gesture.
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentData object reference}
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentAuthorizationResult}
 * @returns Promise<{object}> Promise of PaymentAuthorizationResult object to acknowledge the payment authorization status.
 */
function onPaymentAuthorized(paymentData) {
	return new Promise(function(resolve, reject){
    // handle the response
    processPayment(paymentData)
    .then(function() {
      resolve({transactionState: 'SUCCESS'});
    })
    .catch(function() {
      resolve({
        transactionState: 'ERROR',
        error: {
          intent: 'PAYMENT_AUTHORIZATION',
          message: 'Insufficient funds',
          reason: 'PAYMENT_DATA_INVALID'
        }
      });
  	});
  });
}

/**
 * Initialize Google PaymentsClient after Google-hosted JavaScript has loaded
 *
 * Display a Google Pay payment button after confirmation of the viewer's
 * ability to pay.
 */
function onGooglePayLoaded() {
  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest())
      .then(function(response) {
        if (response.result) {
          addGooglePayButton();
        }
      })
      .catch(function(err) {
        // show error in developer console for debugging
        console.error(err);
      });
}

/**
 * Add a Google Pay purchase button alongside an existing checkout button
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#ButtonOptions|Button options}
 * @see {@link https://developers.google.com/pay/api/web/guides/brand-guidelines|Google Pay brand guidelines}
 */
function addGooglePayButton() {
  const paymentsClient = getGooglePaymentsClient();
  const button =
      paymentsClient.createButton({onClick: onGooglePaymentButtonClicked});
  document.getElementById('container').appendChild(button);
}

/**
 * Provide Google Pay API with a payment amount, currency, and amount status
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#TransactionInfo|TransactionInfo}
 * @returns {object} transaction info, suitable for use as transactionInfo property of PaymentDataRequest
 */
function getGoogleTransactionInfo() {
  return {
        displayItems: [
        {
          label: "Subtotal",
          type: "SUBTOTAL",
          price: "11.00",
        },
      {
          label: "Tax",
          type: "TAX",
          price: "1.00",
        }
    ],
    countryCode: 'US',
    currencyCode: "USD",
    totalPriceStatus: "FINAL",
    totalPrice: "12.00",
    totalPriceLabel: "Total"
  };
}

/**
 * Show Google Pay payment sheet when Google Pay payment button is clicked
 */
function onGooglePaymentButtonClicked() {
  const paymentDataRequest = getGooglePaymentDataRequest();
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();

  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.loadPaymentData(paymentDataRequest);
}

/**
 * Process payment data returned by the Google Pay API
 *
 * @param {object} paymentData response from Google Pay API after user approves payment
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentData|PaymentData object reference}
 */
function processPayment(paymentData) {
	return new Promise(function(resolve, reject) {
  	setTimeout(function() {
  		// @todo pass payment token to your gateway to process payment
  		paymentToken = paymentData.paymentMethodData.tokenizationData.token;

    	resolve({});
    }, 3000);
  });
}</script>
<script async
  src="https://pay.google.com/gp/p/js/pay.js"
  onload="onGooglePayLoaded()"></script>

动态价格更新

<div id="container"></div>

<script>
/**
 * Define the version of the Google Pay API referenced when creating your
 * configuration
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|apiVersion in PaymentDataRequest}
 */
const baseRequest = {
  apiVersion: 2,
  apiVersionMinor: 0
};

/**
 * Card networks supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 * @todo confirm card networks supported by your site and gateway
 */
const allowedCardNetworks = ["AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"];

/**
 * Card authentication methods supported by your site and your gateway
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 * @todo confirm your processor supports Android device tokens for your
 * supported card networks
 */
const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];

/**
 * Identify your gateway and your site's gateway merchant identifier
 *
 * The Google Pay API response will return an encrypted payment method capable
 * of being charged by a supported gateway after payer authorization
 *
 * @todo check with your gateway on the parameters to pass
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#gateway|PaymentMethodTokenizationSpecification}
 */
const tokenizationSpecification = {
  type: 'PAYMENT_GATEWAY',
  parameters: {
    'gateway': 'example',
    'gatewayMerchantId': 'exampleGatewayMerchantId'
  }
};

/**
 * Describe your site's support for the CARD payment method and its required
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 */
const baseCardPaymentMethod = {
  type: 'CARD',
  parameters: {
    allowedAuthMethods: allowedCardAuthMethods,
    allowedCardNetworks: allowedCardNetworks
  }
};

/**
 * Describe your site's support for the CARD payment method including optional
 * fields
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
 */
const cardPaymentMethod = Object.assign(
  {},
  baseCardPaymentMethod,
  {
    tokenizationSpecification: tokenizationSpecification
  }
);

/**
 * An initialized google.payments.api.PaymentsClient object or null if not yet set
 *
 * @see {@link getGooglePaymentsClient}
 */
let paymentsClient = null;

/**
 * Configure your site's support for payment methods supported by the Google Pay
 * API.
 *
 * Each member of allowedPaymentMethods should contain only the required fields,
 * allowing reuse of this base request when determining a viewer's ability
 * to pay and later requesting a supported payment method
 *
 * @returns {object} Google Pay API version, payment methods supported by the site
 */
function getGoogleIsReadyToPayRequest() {
  return Object.assign(
      {},
      baseRequest,
      {
        allowedPaymentMethods: [baseCardPaymentMethod]
      }
  );
}

/**
 * Configure support for the Google Pay API
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|PaymentDataRequest}
 * @returns {object} PaymentDataRequest fields
 */
function getGooglePaymentDataRequest() {
  const paymentDataRequest = Object.assign({}, baseRequest);
  paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();
  paymentDataRequest.merchantInfo = {
    // @todo a merchant ID is available for a production environment after approval by Google
    // See {@link https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist|Integration checklist}
    // merchantId: '12345678901234567890',
    merchantName: 'Example Merchant'
  };

  paymentDataRequest.callbackIntents = ["SHIPPING_ADDRESS",  "SHIPPING_OPTION", "PAYMENT_AUTHORIZATION"];
  paymentDataRequest.shippingAddressRequired = true;
  paymentDataRequest.shippingAddressParameters = getGoogleShippingAddressParameters();
  paymentDataRequest.shippingOptionRequired = true;

  return paymentDataRequest;
}

/**
 * Return an active PaymentsClient or initialize
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/client#PaymentsClient|PaymentsClient constructor}
 * @returns {google.payments.api.PaymentsClient} Google Pay API client
 */
function getGooglePaymentsClient() {
  if ( paymentsClient === null ) {
    paymentsClient = new google.payments.api.PaymentsClient({
      environment: "TEST",
      merchantInfo: {
        merchantName: "Example Merchant",
        merchantId: "01234567890123456789"
      },
      paymentDataCallbacks: {
      	onPaymentAuthorized: onPaymentAuthorized,
        onPaymentDataChanged: onPaymentDataChanged
      }
    });
  }
  return paymentsClient;
}

function onPaymentAuthorized(paymentData) {
	return new Promise(function(resolve, reject){

  // handle the response
  processPayment(paymentData)
    .then(function() {
      resolve({transactionState: 'SUCCESS'});
    })
    .catch(function() {
    	resolve({
        transactionState: 'ERROR',
        error: {
          intent: 'PAYMENT_AUTHORIZATION',
          message: 'Insufficient funds',
          reason: 'PAYMENT_DATA_INVALID'
        }
      });
    });

  });
}

/**
 * Handles dynamic buy flow shipping address and shipping options callback intents.
 *
 * @param {object} itermediatePaymentData response from Google Pay API a shipping address or shipping option is selected in the payment sheet.
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#IntermediatePaymentData|IntermediatePaymentData object reference}
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentDataRequestUpdate|PaymentDataRequestUpdate}
 * @returns Promise<{object}> Promise of PaymentDataRequestUpdate object to update the payment sheet.
 */
function onPaymentDataChanged(intermediatePaymentData) {
  return new Promise(function(resolve, reject) {

   	let shippingAddress = intermediatePaymentData.shippingAddress;
    let shippingOptionData = intermediatePaymentData.shippingOptionData;
    let paymentDataRequestUpdate = {};

    if (intermediatePaymentData.callbackTrigger == "INITIALIZE" || intermediatePaymentData.callbackTrigger == "SHIPPING_ADDRESS") {
      if(shippingAddress.administrativeArea == "NJ")  {
        paymentDataRequestUpdate.error = getGoogleUnserviceableAddressError();
      }
      else {
        paymentDataRequestUpdate.newShippingOptionParameters = getGoogleDefaultShippingOptions();
        let selectedShippingOptionId = paymentDataRequestUpdate.newShippingOptionParameters.defaultSelectedOptionId;
        paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(selectedShippingOptionId);
      }
    }
    else if (intermediatePaymentData.callbackTrigger == "SHIPPING_OPTION") {
      paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(shippingOptionData.id);
    }

    resolve(paymentDataRequestUpdate);
  });
}

/**
 * Helper function to create a new TransactionInfo object.

 * @param string shippingOptionId respresenting the selected shipping option in the payment sheet.
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#TransactionInfo|TransactionInfo}
 * @returns {object} transaction info, suitable for use as transactionInfo property of PaymentDataRequest
 */
function calculateNewTransactionInfo(shippingOptionId) {
        let newTransactionInfo = getGoogleTransactionInfo();

  let shippingCost = getShippingCosts()[shippingOptionId];
  newTransactionInfo.displayItems.push({
    type: "LINE_ITEM",
    label: "Shipping cost",
    price: shippingCost,
    status: "FINAL"
  });

  let totalPrice = 0.00;
  newTransactionInfo.displayItems.forEach(displayItem => totalPrice += parseFloat(displayItem.price));
  newTransactionInfo.totalPrice = totalPrice.toString();

  return newTransactionInfo;
}

/**
 * Initialize Google PaymentsClient after Google-hosted JavaScript has loaded
 *
 * Display a Google Pay payment button after confirmation of the viewer's
 * ability to pay.
 */
function onGooglePayLoaded() {
  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest())
      .then(function(response) {
        if (response.result) {
          addGooglePayButton();
          // @todo prefetch payment data to improve performance after confirming site functionality
          // prefetchGooglePaymentData();
        }
      })
      .catch(function(err) {
        // show error in developer console for debugging
        console.error(err);
      });
}

/**
 * Add a Google Pay purchase button alongside an existing checkout button
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#ButtonOptions|Button options}
 * @see {@link https://developers.google.com/pay/api/web/guides/brand-guidelines|Google Pay brand guidelines}
 */
function addGooglePayButton() {
  const paymentsClient = getGooglePaymentsClient();
  const button =
      paymentsClient.createButton({onClick: onGooglePaymentButtonClicked});
  document.getElementById('container').appendChild(button);
}

/**
 * Provide Google Pay API with a payment amount, currency, and amount status
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#TransactionInfo|TransactionInfo}
 * @returns {object} transaction info, suitable for use as transactionInfo property of PaymentDataRequest
 */
function getGoogleTransactionInfo() {
  return {
        displayItems: [
        {
          label: "Subtotal",
          type: "SUBTOTAL",
          price: "11.00",
        },
      {
          label: "Tax",
          type: "TAX",
          price: "1.00",
        }
    ],
    countryCode: 'US',
    currencyCode: "USD",
    totalPriceStatus: "FINAL",
    totalPrice: "12.00",
    totalPriceLabel: "Total"
  };
}

/**
 * Provide a key value store for shippping options.
 */
function getShippingCosts() {
        return {
    "shipping-001": "0.00",
    "shipping-002": "1.99",
    "shipping-003": "10.00"
  }
}

/**
 * Provide Google Pay API with shipping address parameters when using dynamic buy flow.
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#ShippingAddressParameters|ShippingAddressParameters}
 * @returns {object} shipping address details, suitable for use as shippingAddressParameters property of PaymentDataRequest
 */
function getGoogleShippingAddressParameters() {
        return  {
        allowedCountryCodes: ['US'],
    phoneNumberRequired: true
  };
}

/**
 * Provide Google Pay API with shipping options and a default selected shipping option.
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/request-objects#ShippingOptionParameters|ShippingOptionParameters}
 * @returns {object} shipping option parameters, suitable for use as shippingOptionParameters property of PaymentDataRequest
 */
function getGoogleDefaultShippingOptions() {
        return {
      defaultSelectedOptionId: "shipping-001",
      shippingOptions: [
        {
          "id": "shipping-001",
          "label": "Free: Standard shipping",
          "description": "Free Shipping delivered in 5 business days."
        },
        {
          "id": "shipping-002",
          "label": "$1.99: Standard shipping",
          "description": "Standard shipping delivered in 3 business days."
        },
        {
          "id": "shipping-003",
          "label": "$10: Express shipping",
          "description": "Express shipping delivered in 1 business day."
        },
      ]
  };
}

/**
 * Provide Google Pay API with a payment data error.
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentDataError|PaymentDataError}
 * @returns {object} payment data error, suitable for use as error property of PaymentDataRequestUpdate
 */
function getGoogleUnserviceableAddressError() {
        return {
    reason: "SHIPPING_ADDRESS_UNSERVICEABLE",
    message: "Cannot ship to the selected address",
    intent: "SHIPPING_ADDRESS"
        };
}

/**
 * Prefetch payment data to improve performance
 *
 * @see {@link https://developers.google.com/pay/api/web/reference/client#prefetchPaymentData|prefetchPaymentData()}
 */
function prefetchGooglePaymentData() {
  const paymentDataRequest = getGooglePaymentDataRequest();
  // transactionInfo must be set but does not affect cache
  paymentDataRequest.transactionInfo = {
    totalPriceStatus: 'NOT_CURRENTLY_KNOWN',
    currencyCode: 'USD'
  };
  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.prefetchPaymentData(paymentDataRequest);
}

/**
 * Show Google Pay payment sheet when Google Pay payment button is clicked
 */
function onGooglePaymentButtonClicked() {
  const paymentDataRequest = getGooglePaymentDataRequest();
  paymentDataRequest.transactionInfo = getGoogleTransactionInfo();

  const paymentsClient = getGooglePaymentsClient();
  paymentsClient.loadPaymentData(paymentDataRequest);
}

/**
 * Process payment data returned by the Google Pay API
 *
 * @param {object} paymentData response from Google Pay API after user approves payment
 * @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentData|PaymentData object reference}
 */
function processPayment(paymentData) {
	return new Promise(function(resolve, reject) {
  	setTimeout(function() {
    	// show returned data in developer console for debugging
   	 console.log(paymentData);
  		// @todo pass payment token to your gateway to process payment
  		paymentToken = paymentData.paymentMethodData.tokenizationData.token;

    	resolve({});
    }, 3000);
  });
}</script>
<script async
  src="https://pay.google.com/gp/p/js/pay.js"
  onload="onGooglePayLoaded()"></script>