【问题标题】:Stripe Subscriptions - Charing a 3D Secure card number returning subscription_payment_intent_requires_actionStripe Subscriptions - Charing 一个 3D 安全卡号返回 subscription_payment_intent_requires_action
【发布时间】:2019-12-10 14:09:43
【问题描述】:

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

根据 Stripe 的文档:

“SetupIntents 是为不需要初始付款的订阅自动创建的。如果需要身份验证和授权,它们也会被执行。如果两者都成功,或者不需要它们,则不需要任何操作,并且 subscription.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 的代码。如果我的代码有任何错误,请告诉我。

设置意图:

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

【问题讨论】:

  • 我也有同样的问题,你找到解决办法了吗?

标签: javascript java stripe-payments 3d-secure


【解决方案1】:

我与 Stripe 支持人员取得了联系。他们告诉我,我使用的测试卡的目的是要求对每笔交易进行 3DS 身份验证。这意味着即使我在验证后保存了卡,除非经过验证,否则每次使用都会拒绝该卡。所以我的解决方案是使用不同的测试卡,一张只需要验证一次,之后每次使用都会获得批准。

此外,根据我阅读过的有关 SCA 的一些文档here,SCA 所需卡上的重复交易是免税的,并且只需要一次身份验证。因此,建议使用只需要验证一次的测试卡,因为它的行为更接近 SCA 开始实施时的预期。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-03
    • 2021-01-08
    • 2017-10-19
    • 2019-12-11
    • 2012-04-28
    • 2018-07-24
    • 2021-10-11
    • 2021-04-11
    相关资源
    最近更新 更多