简体   繁体   English

分条订阅-计费返回返回subscription_payment_intent_requires_action的3D安全卡号

[英]Stripe Subscriptions - Charing a 3D Secure card number returning subscription_payment_intent_requires_action

We are integrating 3D secure checkout with our current subscription billing solution. 我们正在将3D安全结帐与我们当前的订阅计费解决方案集成在一起。 We offer a monthly plan with a 7 day free trial. 我们提供7个月免费试用的月度计划。 For the integration, we are using a SetupIntent to determine if the customer's card information requires 3D secure authorization. 对于集成,我们使用SetupIntent确定客户的卡信息是否需要3D安全授权。 Using Stripe's test card that requires 3D secure, we are calling the handleCardSetup() function in our javascript on our checkout page. 使用需要3D安全的Stripe测试卡,我们在结帐页面上的javascript中调用handleCardSetup()函数。 Then after successful authorization, attaching the customer's payment method to the customer. 然后,在成功授权之后,将客户的付款方式附加到客户。 Then continuing checkout, we create the subscription. 然后继续结帐,我们创建订阅。 We expand the latest_invoice.payment_intent on the subscription. 我们在订阅中扩展了latest_invoice.payment_intent

According to Stripe's documentation: 根据Stripe的文档:

"SetupIntents are automatically created for subscriptions that don't require an initial payment. If authentication and authorization are required, they're executed as well. If both succeed, or if they aren't needed, no action is required, and the subscription.pending_setup_intent field is null." “ SetupIntents是自动为不需要初始付款的订阅创建的。如果需要身份验证和授权,则也会执行它们。如果成功或不需要,则不需要任何操作,并且订阅.pending_setup_intent字段为空。”

When I look at the response from calling Subscription.create(params) , I see that the pending_setup_intent field is equal to null . 当我查看来自调用Subscription.create(params)的响应时,我看到pending_setup_intent字段等于null However, when viewing the subscription on Stripe's dashboard, I see that the attempt to charge the card returned a 402 error with the following response: 但是,当在Stripe的仪表板上查看订阅时,我看到尝试对卡进行充电的尝试返回了402错误,并显示以下响应:

{
  "error": {
    "code": "subscription_payment_intent_requires_action",
    "message": "Payment for this subscription requires additional user action before it can be completed successfully. Please refer to the use of the `enable_incomplete_payments` parameter here: https://stripe.com/docs/billing/lifecycle#incomplete-opt-in",
    "type": "card_error"
  }
}

What gives? 是什么赋予了? Did I miss a step somewhere? 我在某个地方错过了一步吗? We are currently on the latest version of Stripe's API: 2019-05-16 . 我们当前正在使用Stripe API的最新版本: 2019-05-16 I've attached the code we use for creating the SetupIntent , attaching the PaymentMethod to the Customer , and creating the Subscription . 我已经附加了用于创建SetupIntent ,将PaymentMethod附加到Customer以及创建Subscription Please let me know if there are any errors in my code. 如果我的代码中有任何错误,请告诉我。

SetupIntent: SetupIntent:

public static String createSetupIntent() {
    try {
        Map<String, Object> setupIntentParams = new HashMap<>();
        ArrayList<String> paymentMethodTypes = new ArrayList<>();
        paymentMethodTypes.add("card");
        setupIntentParams.put("payment_method_types", paymentMethodTypes);
        SetupIntent setupIntent = SetupIntent.create(setupIntentParams);
        return setupIntent.getClientSecret();
    } catch (AuthenticationException | InvalidRequestException | ApiConnectionException | ApiException ex) {
        throw new Error("Unable to create SetupIntent", ex);
    } catch (StripeException ex) {
        throw new Error("Unable to create SetupIntent", ex);
    }
}

Javascript: Javascript:

var customerInfo = {
  payment_method_data: {
    billing_details: {
      name: document.getElementById('cardholder_name').value,
      address: {
        postal_code: document.getElementById('cardholder_zip').value
      }
    }
  }
};

stripe.handleCardSetup(clientSecret, card, customerInfo).then(function (result) {
    if (result.error) {
        setStripeError(result.error);
        hideLoading('hosted_content');
    } else {
        var paymentMethodId = result.setupIntent.payment_method;

        $.post({
            url: backendURL + 'attachpaymentmethod',
            data: {payment_id: paymentMethodId},
            success: function (response) {
                document.getElementById('payment-form').submit(); //sends a post to endpoint that handles creating subscription
            },
            error: function (response) {
                hideLoading('hosted_content');
                setStripeError(response.responseJSON.error);
            }
        });

    }
});

PaymentMethod: 付款方法:

public static void updatePaymentMethod(User user, String paymentMethodId) throws CardException {
    Customer customer = getCustomer(user); //Retrieves customer if user has stripeId, otherwise create a new customer
    try {
        PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodId);
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("customer", customer.getId());
        paymentMethod.attach(params);
    } catch (AuthenticationException | InvalidRequestException | ApiConnectionException | ApiException ex) {
        throw new Error("Unable to update Stripe payment method", ex);
    } catch (StripeException ex) {
        throw new Error("Unable to update Stripe payment method", ex);
    }
}

Subscription: 订阅:

Map<String, Object> planItem = new HashMap<>();
planItem.put("plan", planId);
Map<String, Object> items = new HashMap<>();
items.put("0", planItem);

List<String> expandList = new LinkedList<String>();
expandList.add("latest_invoice.payment_intent");

Map<String, Object> subscriptionOptions = new HashMap<>();
subscriptionOptions.put("customer", user.getStripeId());
subscriptionOptions.put("trial_period_days", trialDays);
subscriptionOptions.put("items", items);
subscriptionOptions.put("expand", expandList);
try {
    Subscription subscription = Subscription.create(subscriptionOptions);
    System.out.println(subscription); //pending_setup_intent is equal to null
} catch (AuthenticationException | InvalidRequestException | ApiConnectionException | ApiException ex) {
    throw new Error("Unable to create Stripe subscription", ex);
} catch (StripeException ex) {
    throw new Error("Unable to create Stripe subscription", ex);
}

I got in touch with Stripe support. 我联系了Stripe支持。 They told the that the purpose of the test card I was using is to require 3DS authentication for every single transaction. 他们告诉我,我使用的测试卡的目的是要求每笔交易都具有3DS身份验证。 That means that even thought I saved the card after authenticating it, the card will be declined on every single use unless it's authenticated. 这意味着即使我在对卡进行身份验证之后也保存了它,除非经过身份验证,否则每次使用该卡都会被拒绝。 So my solution was to use a different test card, one that only requires authentication one time and that will be approved on each use afterwards. 因此,我的解决方案是使用另一种测试卡,该测试卡只需要进行一次身份验证,然后将在每次使用后获得批准。

Furthermore, according to some documentation on SCA that I read here , recurring transactions on SCA required cards are exempt and will only require authentication once. 此外,根据我在此处阅读的有关SCA的一些文档,在SCA要求的卡上进行的重复交易是免税的,只需要进行一次身份验证。 Thus, using a test card that only requires authentication once is advised as its behavior is closer to what will be expected when SCA starts being enforced. 因此,建议使用只需要认证一次的测试卡,因为它的行为更接近于开始执行SCA时所期望的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM