Stripe IntegrationError:在订阅流程中,必须在 stripe.confirmPayment() 之前调用 elements.submit()

问题描述 投票:0回答:1

我在为订阅流程集成 Stripe 时遇到集成错误。我收到的错误消息是:

IntegrationError:elements.submit() 必须在 stripe.confirmPayment() 之前调用。一旦客户按下付款键,在任何异步工作之前,立即调用 elements.submit() 。集成指南:https://stripe.com/docs/ payments/accept-a- payment-deferred

上下文:

SetupIntent:我在服务器上创建一个SetupIntent并将clientSecret传递给客户端。

PaymentIntent:我还创建了一个 PaymentIntent 作为订阅创建过程的一部分,并从最新发票的付款意图中接收 client_secret。

流量:

  1. SetupIntent:在服务器端创建SetupIntent。将 client_secret 传递给客户端。

  2. Setup Elements:使用 clientSecret 创建一个选项对象并将其传递给 Elements 标签。

  3. 订阅生成器:用户构建其订阅详细信息

  4. 表单提交:用户填写并提交付款表单。

  5. 表单验证:我调用 elements.submit() 来验证表单字段。

  6. 确认SetupIntent:我使用SetupIntent中的clientSecret调用stripe.confirmSetup()。

  7. 获取订阅:我调用服务器端并传递用户选择的产品的产品/定价 ID。服务器返回带有 PaymentIntent 的条带订阅对象。

  8. Confirm PaymentIntent:我使用附加到返回的 Stripe Subscription 对象的 PaymentIntent 中的 client_secret 调用 stripe.confirmPayment()。

代码片段:

const handleSubscriptionSubmit = async (e) => {
  e.preventDefault();

  if (!stripe || !elements) {
    toast.error('Error making payment!');
    return;
  }

  //disable loading for now
  //setLoading(true);

  // Validate the form fields
  const { error: submitError } = await elements.submit();
  if (submitError) {
    setLoading(false);
    console.error(submitError);
    return;
  }

  const address = await elements.getElement('address').getValue();
  if (!address.complete || !email.complete) {
    toast.error('Missing required Email or Address field(s)!');
    setLoading(false);
    return;
  }

  // Confirm the SetupIntent
  const { setupError } = await stripe.confirmSetup({
    elements,
    clientSecret: setupIntentOptions.clientSecret,
    redirect: 'if_required',
  });
  if (setupError) {
    toast.error('Error making payment setup!');
    setLoading(false);
    return;
  }

  formik.setFieldValue('phone', address.value.phone);
  formik.setFieldValue('email', email.value.email);
  formik.setFieldValue('payer', address.value.name);
  formik.setFieldValue('address', address.value.address.line1);
  formik.setFieldValue('city', address.value.address.city);
  formik.setFieldValue('state', address.value.address.state);
  formik.setFieldValue('zip', address.value.address.postal_code);

  // Get the subscription intent
  const subscriptionIntent = await getSubscriptionIntent();
  console.log(subscriptionIntent);
  if (!subscriptionIntent) {
    setLoading(false);
    return;
  }

  // Confirm the PaymentIntent
  const secret = subscriptionIntent.latest_invoice.payment_intent.client_secret;
  const { error } = await stripe.confirmPayment({
    elements,
    clientSecret: secret,
    redirect: 'if_required',
  });

  if (error) {
    toast.error(error.message);
    setLoading(false);
    return;
  }

  setTimeout(async () => {
    await submitOrder();
  });
  setLoading(false);
};

问题: 尽管在 stripe.confirmPayment() 之前调用 elements.submit(),我仍然收到 IntegrationError 指示 elements.submit() 必须在 stripe.confirmPayment() 之前调用。这表明我的设置可能会被解释为延迟设置,即使我有一个 SetupIntent。

要求: 您能帮我理解为什么会出现此错误以及如何解决它吗?具体来说,我需要有关我的流程是否正确处理订阅设置中的 SetupIntent 和 PaymentIntent 的指导,以及是否需要任何其他步骤或调整来避免此错误。

reactjs .net stripe-payments
1个回答
0
投票

看起来您在拨打

elements.submit()
后正在确认两个不同的意图。对于 Stripe API 来说这不是必需的,因此
elements.submit()
可能只希望您在提交付款元素后进行一次确认调用。由订阅的第一个发票创建的 PaymentIntent 会将
setup_future_usage
设置为
true
,这将告诉 Stripe 在付款时保存付款方式[1]。如果您删除 SetupIntent 并仅确认订阅的第一次付款意图,则应自动保存 PaymentMethod 并将其附加到订阅的客户。

[1] https://docs.stripe.com/api/ payment_intents/object# payment_intent_object-setup_future_usage

© www.soinside.com 2019 - 2024. All rights reserved.