Подписка Stripe billing без взимания последующих сборов после первоначального успешного платежа

Я следил за этой документацией, чтобы реализовать Stripe Recurring Payments, которая отлично работает для обоих карты без 3D-Secure и карты с поддержкой 3D-Secure. Для первоначальных платежей я получаю от Stripe модальную аутентификацию 3d-Secure Payment для аутентификации платежей с использованием тестовых карт 3D-Secure.

Подписка создается вместе со счетами, которые Stripe генерирует для меня. Кажется, все в порядке, НО для 3D-Secure Enabled (Stripe Testing Cards) первый платеж проходит успешно, но последующие платежи, для которых я установил интервал в 1 день (для тестирования), Stripe "проваливает". Насколько я понимаю, Stripe снова требует аутентификации клиента для продолжения подписки.


В this говорится

При обнаружении 3D Secure настройте параметры выставления счетов, чтобы отправить размещенную ссылку вашему клиенту для завершения процесса.

Это совершенно нормально, но почему они даже снова требуют шаг аутентификации, если первый платеж прошел успешно и подписка запущена? Я просмотрел все связанные документы, но не нашел ничего, что могло бы предотвратить это.

Что делать, если Клиент не проверяет свою электронную почту, чтобы вернуться в мое Приложение для аутентификации платежей? ИЛИ

Что-то не так с кодом? Под этим я подразумеваю, что Stripe должен был сохранить способ оплаты, то есть номер карты, чтобы он не требовал аутентификации клиента при последующих платежах каждый раз, когда начинается новый платежный цикл (ежемесячно / раз в два года).

Я поискал в Интернете и нашел и ответил, что

Вы используете stripe.createToken, который не поддерживает аутентификацию 3ds. Вам необходимо перенести свой клиентский код на 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" => "[email protected]",
    "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']);
    }
}

person Haroon Khan    schedule 16.09.2019    source источник
comment
Я пробовал использовать stripe.createPaymentMethod (), но получаю сообщение об ошибке: у этого клиента нет прикрепленного источника оплаты. означает, что \ Stripe \ Customer :: create не получает требуемый исходный параметр, который был предоставлен token_id.   -  person Haroon Khan    schedule 16.09.2019
comment
Если вы используете тестовые карты 3DS, они всегда будут требовать аутентификации, потому что они не настроены для проверки исключений SCA. Можете ли вы попробовать нормативные тестовые карты на странице stripe.com/docs/payments/cards/ протестируйте # нормативные карты и посмотрите, дадут ли они вам то, что вы ищете?   -  person taintedzodiac    schedule 16.09.2019
comment
Моя реализация в основном охватывает как карты, не относящиеся к 3DS, так и карты 3DS. Поэтому наше требование протестировать оба типа карт. Как я уже упоминал, платежи по картам, не относящимся к 3DS, взимаются без каких-либо проблем.   -  person Haroon Khan    schedule 19.09.2019
comment
@taintedzodiac в любом случае я попробую использовать нормативные карты, как вы упомянули   -  person Haroon Khan    schedule 19.09.2019


Ответы (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

person KAUSHIK JANI    schedule 17.09.2019
comment
Проблема с картой 4242 в том, что она вообще не проверяет правила SCA (она никогда не запрашивает аутентификацию, потому что не поддерживает ее). Карты для тестирования SCA находятся по адресу stripe.com/docs/payments/cards/ testing # Regulation-cards Вы также не должны использовать тестовые карты 3DS для тестирования SCA, потому что все они не поддерживают исключения SCA для повторяющихся платежей (или любые другие исключения). - person taintedzodiac; 20.09.2019