Apple Pay - 定期付款

问题描述 投票:0回答:1

我正在尝试利用通过 Apple Pay 进行定期付款。看来付款会话设置正确。出现正确的弹出窗口,指示立即收费和定期付款,付款已成功提交给 NMI 并将响应发送回客户端。

前端代码:

function subscribe() {
        var request = {
          countryCode: 'US',
          currencyCode: 'USD',
          supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
          merchantCapabilities: ['supports3DS'],
          total: { label: 'Budmember', amount: packages?.Package_Amount__c.toFixed(2).toString()},
          recurringPaymentRequest: {
            managementURL:"https://7d50e9ae5e20.ngrok.io/billing",
            tokenNotificationURL:"https://webhook.site/8bb38a60-be08-47f5-82ba-2bdccc7ec4cf/",
            paymentDescription: "VIP Membership",
            regularBilling: {
              label: {amount: packages?.Package_Amount__c.toFixed(2).toString(), type: "final"},
              amount: packages?.Package_Amount__c.toFixed(2).toString(), 
              paymentTiming: "recurring", 
              recurringPaymentIntervalUnit: "month",
              recurringPaymentStartDate: moment().format("YYYY-MM-DD"),
            }},      
          }
        
        //start apple Pay session
        var session = new window.ApplePaySession(3, request);
        session.begin()
        session.onvalidatemerchant = async (event) => {
            const res = await applePaySessionRequest(event.validationURL)
            console.log(res.data)
            session.completeMerchantValidation(res.data)     
        }

        //submit payment to backend
        session.onpaymentauthorized = async (event) => {
          const dataPackage= {
          onboardingStep: '7',
          salesForceId: cognitoUser.salesForceId,
          packageId: packages?.Id,
            billingPackage: {
              first_name: currentUser.firstName,
              last_name:  currentUser.lastName,
              company: "",
              address1: "",
              address2: "",
              city: "",
              state: "",
              zip: "",
              country:"USA",
              phone: "",
              fax: "",
              email: currentUser.email,
          }
        }
        
            const res = await applePayInitialSub(event.payment, dataPackage )
            
            if (res?.data?.success) {
              //update token for new field in the token
              setOnboardingStep("7");
              localStorage.setItem("token", res.data.token || localStorage.getItem("token"));
              notification("Membership Payment Received","success","Payment Success");
              handleBillingAddress()
             
            } else {
              notification(res.data.msg || "Card Declined" , "danger" , "Error");
              setLoading(false)
        
            }
            session.completePayment({status: res.data.applePayMsg})
         
        }
      }

后端代码(Apple Pay 会话):

async function applePaySession(req, res, next) {
const sessionURL = req.body.sessionURL
let response = {};
try {
function promisifyRequest(options) {
    return new Promise((resolve, reject) => {
      request(options, (error, response, body) => {
        if (body) {
          return resolve(res.send(body));
        }
        if (error) {
          return reject(error);
        }
      });
    });
}
  const options = {
    url: sessionURL,
    agentOptions: {
      pfx: fs.readFileSync("./merchant_id.p12"),
      passphrase: "SECRET",
    },
    method: 'post',
    body: {
        merchantIdentifier: "merchant.com.some.app",
        displayName: "NAME",
        initiative: "web",
        initiativeContext: "some.url" // Frontend url as registered
    },
    json: true,
  };
  response = await promisifyRequest(options);
  console.log(response)
} catch (error) {
  console.log(error)
}
return response;

}

后端代码(支付和订阅):

async function appleSubProcessor(req, res, next) {
    try {
      const conn = sfConn();
      const { cognitoUserId, accessToken, email } = req.user.data
      const {billingPackage} = req.body
      const {onboardingStep, salesForceId, packageId} = billingPackage
      const member = await conn.sobject("Contact").find({"Email": email})
      const response = await NMI.getSubscriptionById(member[0].Subscription_ID__c) 

      // PROCESSING CODE!!!!!
      //encodes data object to buffer
      const data = req.body.paymentObject.token.paymentData
      var buf = Buffer.from(JSON.stringify(data))
      //encodes buffer to hex string
      const hexCode = buf.toString("hex")
      
      //if subscription is present on NMI only charge
      if(response?.nm_response?.subscription?.subscription_id) {
        await applePaymentOnly(member, hexCode, billingPackage, email, res)
      } else {
        await applePayInitialSub(req, member, hexCode, res, cognitoUserId, accessToken, email, billingPackage)
      }
    } catch(err) {
      console.log(err)
    }
  }

async function applePayInitialSub(req, member, paymentToken, res, cognitoUserId, accessToken, email, billingPackage) {

try {
  const conn = sfConn()
  // const { cognitoUserId, accessToken, email } = req.user.data
  // const {billingPackage} = req.body
  const {onboardingStep, salesForceId, packageId} = billingPackage
  const subsc_data = await conn.sobject("Packages__c").find({"Id": packageId})
  const dueNow = subsc_data[0].Package_Amount__c.toFixed(2).toString()
  

  //Error handling - no package available
  if(!subsc_data || !subsc_data.length){  
    console.log("Error")   
    Sentry.withScope((scope) => {
      scope.setLevel("fatal");
      Sentry.captureException("Internal Error, Unable to get subscription data");
    })
    return res.json({
      success: false,
      message:"Internal Error. Unable to get subscription data"
    })
  }

  
 
  //sends request
  const response = await NMI.applePayInitialSubscription(billingPackage.billingPackage, paymentToken, dueNow, email, billingPackage.billingPackage.email)
  console.log(response) 

onboarding logic ...
    }

到目前为止我尝试过的:

  1. 充值初始代币。 NMI 返回“不尊重”。这表明 Apple Pay 阻止了交易。该卡没有任何欺诈警报,我可以使用新令牌为其充电。

  2. 将 Apple Pay 的订阅间隔设置为“分钟”,并在 60 秒后尝试重新充值令牌。再次强调“不要尊重”。

  3. 我将 tokenNotificationURL 设置为服务器上的端点。我通过 NGROK 通过 https 隧道连接到我的本地主机。我能够通过邮递员调用端点。 我遵循了 Apple 开发人员文档。但没有收到来自 Apple 的任何挂钩调用。

  4. 我使用我的 webhook.site pro 订阅完成了第 3 步。 Postman 呼叫成功,没有来自 Apple 的呼叫。

  5. 我在 StackOverflow 中搜索答案并找到了关于 Stripe 的这篇文章。这里描述了(使用 Stripe SDK) paymentRequest 带有一个“ paymentmethod ”监听器,它应该返回 paymentMethod.id 。我尝试利用 AppleJS 的 on paymentmethodselected 来访问 id,但我只得到 paymentMethod: {type: "Credit"} 作为响应:

    session.on paymentmethodselected =异步(事件)=> { session.completePaymentMethodSelection({newTotal: { amount:"49.00", label:'VIP会员'}}) }

  6. 我在后端解密了支付令牌。我按照 this 指南创建了证书和密钥 (.pem) 文件。他的包使用了过时的依赖项,该依赖项不适用于较新版本的 Node。我使用 this package 来解密令牌。但是,我无法向 applicationPrimaryAccountNumber 收费。 AVS 似乎不被允许,因此提供邮政编码也不会产生成功的交易。以下是解密的令牌以及 NMI 响应:

我在 SO 和 Apple 开发者论坛中进行了搜索,但没有找到任何结果。过去三天我一直在研究这个问题。非常感谢任何帮助!

payment-gateway applepay apple-wallet nmi-payments
1个回答
0
投票

我很久以前就知道了,但我也有同样的问题

您解决这个问题了吗?你怎么解决的?

我想使用带有解密令牌的 mpgs 进行重复,但没有成功

© www.soinside.com 2019 - 2024. All rights reserved.