条带SCA迁移,如何获得PaymentIntent'client_secret'?

时间:2019-09-16 07:49:25

标签: javascript ruby-on-rails ruby stripe-payments

我正在将我的条带集成迁移到新的SCA欧洲法规。我正在将Stripe Billing与Stripe gem(https://github.com/stripe/stripe-ruby),Rails 5.2(ruby 2.6.4)配合使用。我也有turbolinks“开”。

我正在为3D安全身份验证而苦苦挣扎,Stripe.js脚本应该可以平稳地处理此问题,但是我无法提供执行该操作所需的变量。

文档说开票引擎创建了PaymentIntent,所以我不必自己创建它。该对象必须带有client_cecret,我必须将其传递给视图。我将使用gon gem(https://github.com/gazay/gon)完成此操作。要获得这个秘密,根据Stripe docs的介绍,我必须用“ latest_invoice.payment_intent”来“扩展”订阅对象,然后将“ latest_invoice.payment_intent.client_secret”传递给一个变量,此后,JavaScript将用于通过“ .handleCardPayment”以3D安全方式处理付款或2FA。

这是我registration_controller.rb的create_subscription操作(我使用devise):

def create_subscription
    Stripe.api_key = Rails.application.credentials[Rails.env.to_sym][:stripe][:stripe_api_key]

    plan_id = params[:plan_id]
    plan = Stripe::Plan.retrieve(plan_id)
    token = params[:stripeToken]

    customer = if @user.stripe_id?
                 Stripe::Customer.retrieve(@user.stripe_id)
               else
                 Stripe::Customer.create(email: @user.email, source: token)
               end
    subscription = customer.subscriptions.create(
      items: [
        {
          plan: plan_id
        }

      ],
      expand: ['latest_invoice.payment_intent']
    )
    gon.intent = subscription.latest_invoice.payment_intent


    options = {
      stripe_id: customer.id,
      stripe_subscription_id: subscription.id,
      subscribed: true,
      plan: plan_id
    }

    options.merge!(
      card_last4: params[:user][:card_last4],
      card_exp_month: params[:user][:card_exp_month],
      card_exp_year: params[:user][:card_exp_year],
      card_type: params[:user][:card_type]
    ) if params[:user][:card_last4]

    @user.update(options)

    flash[:success] = "¡Se ha creado la suscripción correctamente!"
  end

然后这是我的subscriptions.js脚本:

$(document).on("turbolinks:load", function () {
  const publishableKey = document.querySelector("meta[name='stripe-key']").content;
  const stripe = Stripe(publishableKey);

  const elements = stripe.elements({
    locale: 'es'
  });

  const style = {
    base: {
      color: "#32325d",
      fontWeight: 500,
      fontSize: "16px",
      fontSmoothing: "antialiased",

      "::placeholder": {
        color: "#CFD7DF"
      }
    },
    invalid: {
      color: "#E25950"
    }
  };

  // Create an instance of the card Element.
  const card = elements.create('card', { style });

  // Add an instance of the card Element into the `card-element` <div>.

  card.mount('#card-element');



  card.addEventListener('change', ({ error }) => {

    const displayError = document.getElementById('card-errors');
    if (error) {
      displayError.textContent = error.message;
    } else {
      displayError.textContent = '';
    }
  });

  // Create a token or display an error when the form is submitted.
  const form = document.getElementById('new_user');

  form.addEventListener('submit', async (event) => {
    event.preventDefault();

    const { token, error } = await stripe.createToken(card);

    if (error) {
      // Inform the customer that there was an error.
    const errorElement = document.getElementById('card-errors');
      errorElement.textContent = error.message;
    } else {
      // handle the payment (pass, pyment error or 2FA)
      const clientSecret = gon.intent.client_secret;

      const { paymentIntent, error } =
        await stripe.handleCardPayment(
          clientSecret, card, {
          save_payment_method: true,
          setup_future_usage: 'off_session'
          }
        );
      if (error) {
        const errorElement = document.getElementById('card-errors');
        errorElement.textContent = error.message;
      } else {
      // Send the token to your server.
      // stripeTokenHandler(token);
        const stripeTokenHandler = (token) => {
          // Insert the token ID into the form so it gets submitted to the server
          const form = document.getElementById('new_user');
          const hiddenInput = document.createElement('input');
          hiddenInput.setAttribute('type', 'hidden');
          hiddenInput.setAttribute('name', 'stripeToken');
          hiddenInput.setAttribute('value', token.id);
          form.appendChild(hiddenInput);

          ["type", "last4", "exp_month", "exp_year"].forEach(function (field) {
            addCardField(form, token, field);
          });

          // Submit the form
          form.submit();
        }
      }
    }
  });

  function addCardField(form, token, field) {
    let hiddenInput = document.createElement('input');
    hiddenInput.setAttribute('type', 'hidden');
    hiddenInput.setAttribute('name', "user[card_" + field + "]");
    hiddenInput.setAttribute('value', token.card[field]);
    form.appendChild(hiddenInput);
  }
});

在这种配置下,当我尝试使用条测试卡号获取3D安全模式时,会出现错误:

  

subscriptions.js:61未捕获(已承诺)TypeError:无法读取> HTMLFormElement中未定义的属性“ client_secret”。 (subscriptions.js:61)

我尝试以Stripe Doc的方式(在button标记中为数据秘密)传递变量,但遇到相同的错误(或类似错误)。

似乎很清楚该变量不存在,但是,如何正确传递它?我想念什么?

谢谢!

0 个答案:

没有答案