初次成功付款后,条带计费订阅不收取“后续费用”

Posted

技术标签:

【中文标题】初次成功付款后,条带计费订阅不收取“后续费用”【英文标题】:Stripe billing Subscription not charging the "subsequent charges" after initial successful Payment 【发布时间】:2020-01-17 09:56:21 【问题描述】:

我已按照this 文档实施 Stripe Recurring Payments,它适用于非 3d-Secure 卡和启用 3d-Secure 的卡。对于初始付款,我从 Stripe 获得了 3d-Secure Payment 身份验证模式,以使用 3D-Secure Test 卡对付款进行身份验证。

订阅是与 Stripe 为我生成的发票一起创建的。一切似乎都很好,但是对于启用 3D-Secure 的(条纹测试卡),第一次付款成功完成,但我设置的 1 天间隔(用于测试)的后续付款被条纹“失败”。据我了解,Stripe 需要再次进行客户身份验证才能继续订阅。


在this 他们说

遇到 3D Secure 时,配置您的结算设置以发送 一个指向您的客户的托管链接以完成流程。

这完全没问题,但是如果第一次付款成功并开始订阅,为什么他们还要再次进行身份验证?我已经浏览了所有相关的文档,但没有发现任何可以防止这种情况发生的情况。

如果客户没有检查他/她的电子邮件以返回我的应用程序以验证付款怎么办? 或

代码有什么问题吗?我的意思是说,Stripe 应该保存付款方式,即卡号,这样每次新的计费周期开始(每月/每半年)时,它就不需要对后续费用进行客户身份验证。

我在网上搜索并找到并回答说

您正在使用不支持 3ds 的 stripe.createToken 验证。您需要将客户端代码迁移到 stripe.createPaymentMethod 确实支持它

是这样吗?任何回应表示赞赏

我的 Payment.js

// set your stripe publishable key
var stripe = Stripe('pk_test_key');
var elements = stripe.elements();
var style = 
    base: 
        color: '#32325d',
        lineHeight: '18px',
        fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
        fontSmoothing: 'antialiased',
        fontSize: '16px',
        '::placeholder': 
            color: '#aab7c4'
        
    ,
    invalid: 
        color: '#fa755a',
        iconColor: '#fa755a'
    
;

var cardNumber = elements.create('cardNumber', 
    style: style
);
cardNumber.mount('#cardNumber');
var cardExpiry = elements.create('cardExpiry', 
    style: style
);
cardExpiry.mount('#cardExpiry');
var cardCvc = elements.create('cardCvc', 
    style: style
);
cardCvc.mount('#cardCVC');

var cardholderName = $('#custName').val();
var amount = $('#amount').val();

var cardButton = document.getElementById('makePayment');
cardButton.addEventListener('click', function(ev) 
     // alert();
    ev.preventDefault();




    stripe.createToken(cardNumber).then(function(result) 

    if (result.error) 


     else 
      //$body.addClass("loading");
      fetch('process.php', 
        method: 'POST',
        headers:  'Content-Type': 'application/json' ,
        body: JSON.stringify( 
            token_id: result.token.id          
            )
      ).then(function(result) 


        // Handle server response (see Step 3)
        result.json().then(function(json) 
          handleServerResponse(json);
          //alert();
        )
      );
    
  );
);
function handleServerResponse(response) 
            if (response.error) 
                // Show error from server on payment form
             else if (response.requires_action) 
                // Use Stripe.js to handle required card action
                var action = response.next_action;
                if (action && action.type == 'redirect_to_url') 
                    window.location = action.redirect_to_url.url;
                

                handleAction(response);

             else 
                console.log("3D" + response);
            


        function handleAction(response) 
           var paymentIntentSecret = response.payment_intent_client_secret;
            stripe.handleCardPayment(paymentIntentSecret).then(function(result) 
              if (result.error) 
                // Display error.message in your UI.
               else 
                // The payment has succeeded. Display a success message.
                alert('Payment succeeded!');
              
);



Process.php

<?php 

require_once('stripe-php/init.php');   
\Stripe\Stripe::setApiKey('sk_test_key');

$json_str = file_get_contents('php://input');

$json_obj = json_decode($json_str);
 //print_r($json_obj->token_id);die;

  //$intent = null;
try 
    if (isset($json_obj->token_id)) 
     //Create Customer   
    $customer = \Stripe\Customer::create([
    "email" => "test@gmail.com",
    "name" => "Haroon",  
    "source" => $json_obj->token_id,
]);
    //create product
    $product = \Stripe\Product::create([
    'name' => 'Water',
    'type' => 'service',
]);
    //create a plan
    $plan = \Stripe\Plan::create([
      'product' => $product->id,
      'nickname' => 'Water',
      'interval' => 'day',
      'currency' => 'eur',
      'amount' => 1200.00,
    ]);   

    //add subscription to stripe
    $subscription = \Stripe\Subscription::create([

        'customer' => $customer->id,
        'items' => [[
        "plan" => $plan->id],],
        'expand' => ['latest_invoice.payment_intent'],
]);    


      $intent = \Stripe\PaymentIntent::retrieve($subscription->latest_invoice->payment_intent->id);

      $subscription = \Stripe\Subscription::retrieve($subscription->id);
    //   $intent->confirm();
    // 
    generatePaymentResponse($intent,$subscription);
  catch (\Stripe\Error\Base $e) 
    # Display error on client
    echo json_encode([
      'error' => $e->getMessage()
    ]);
    

   function generatePaymentResponse($intent,$subscription) 
    if ($intent->status == 'requires_action' && $subscription->status == 'incomplete' &&
        $intent->next_action->type == 'use_stripe_sdk' ) 
        # Tell the client to handle the action

        echo json_encode([
            'requires_action' => true,
            'payment_intent_client_secret' => $intent->client_secret
        ]);
     else if ($intent->status == 'succeeded' && $subscription->status == 'active') 

        # The payment didn’t need any additional actions and completed!
        # Handle post-payment fulfillment
        echo json_encode([
            'success' => true
        ]);
     else if ($intent->status == 'requires_payment_method' && $subscription->status == 'incomplete') 
        echo "Subscription failed";

     else 
        # Invalid status
        http_response_code(500);
        echo json_encode(['error' => 'Invalid PaymentIntent status']);
    

【问题讨论】:

我尝试使用 stripe.createPaymentMethod() 但我收到错误消息“错误”:“此客户没有附加付款来源”。表示 \Stripe\Customer::create 没有获得由 token_id 提供的所需“源”参数。 如果您使用的是“3DS”测试卡,这些卡将始终需要身份验证,因为它们未设置为测试 SCA 豁免。您可以试试stripe.com/docs/payments/cards/testing#regulatory-cards 的监管测试卡,看看它们是否能满足您的需求? 我的实现基本上涵盖了非3DS卡和3DS卡。因此,我们要求对这两种类型的卡进行测试。正如我在问题中提到的那样,非 3DS 卡的付款被收取没有任何问题 @taintedzodiac 不管怎样,我会尝试使用您提到的监管卡 【参考方案1】:

如果您是为已经存在的卡执行此操作,那么我已经在某天之前完成了此操作。请参阅此文档https://stripe.com/docs/payments/3d-secure。

这提示你需要创建 paymentIntent 并且需要确认这个支付意图。并且在 3ds 中还有测试卡 4242 4242 4242 4242 这张卡不需要对 3ds 进行任何身份验证。提供以下测试卡链接

https://stripe.com/docs/payments/3d-secure/web#three-ds-cards

【讨论】:

4242 卡的问题是它根本不会测试 SCA 规则(它从不要求验证,因为它不支持它)。用于测试 SCA 的卡位于 stripe.com/docs/payments/cards/testing#regulatory-cards 您也不应该使用“3DS”测试卡来测试 SCA,因为它们都不支持 SCA 的定期付款豁免(或任何其他豁免)。

以上是关于初次成功付款后,条带计费订阅不收取“后续费用”的主要内容,如果未能解决你的问题,请参考以下文章

年度订阅的条带费用每月更改一次

条带订阅现在和每月的第一天付款

以编程方式向 PayPal 收取定期付款的费用

付款成功后迅速获取条带费用ID

Authorize.net - 延迟付款和重复

Paypal + PHP 订阅计费?