繁体   English   中英

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

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

我们正在将3D安全结帐与我们当前的订阅计费解决方案集成在一起。 我们提供7个月免费试用的月度计划。 对于集成,我们使用SetupIntent确定客户的卡信息是否需要3D安全授权。 使用需要3D安全的Stripe测试卡,我们在结帐页面上的javascript中调用handleCardSetup()函数。 然后,在成功授权之后,将客户的付款方式附加到客户。 然后继续结帐,我们创建订阅。 我们在订阅中扩展了latest_invoice.payment_intent

根据Stripe的文档:

“ SetupIntents是自动为不需要初始付款的订阅创建的。如果需要身份验证和授权,则也会执行它们。如果成功或不需要,则不需要任何操作,并且订阅.pending_setup_intent字段为空。”

当我查看来自调用Subscription.create(params)的响应时,我看到pending_setup_intent字段等于null 但是,当在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"
  }
}

是什么赋予了? 我在某个地方错过了一步吗? 我们当前正在使用Stripe API的最新版本: 2019-05-16 我已经附加了用于创建SetupIntent ,将PaymentMethod附加到Customer以及创建Subscription 如果我的代码中有任何错误,请告诉我。

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:

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);
            }
        });

    }
});

付款方法:

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);
    }
}

订阅:

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);
}

我联系了Stripe支持。 他们告诉我,我使用的测试卡的目的是要求每笔交易都具有3DS身份验证。 这意味着即使我在对卡进行身份验证之后也保存了它,除非经过身份验证,否则每次使用该卡都会被拒绝。 因此,我的解决方案是使用另一种测试卡,该测试卡只需要进行一次身份验证,然后将在每次使用后获得批准。

此外,根据我在此处阅读的有关SCA的一些文档,在SCA要求的卡上进行的重复交易是免税的,只需要进行一次身份验证。 因此,建议使用只需要认证一次的测试卡,因为它的行为更接近于开始执行SCA时所期望的行为。

暂无
暂无

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

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