简体   繁体   English

将客户详细信息附加到 Stripe Payment Intent

[英]Attach customer details to Stripe Payment Intent

I am migrating from the 'Card Element' to the 'Payment Element' and have got the payments working successfully.我正在从“卡元素”迁移到“支付元素”,并且付款成功。 I am able to pass in the amount and charge a customer.我能够传递金额并向客户收费。 However, I cannot seem to add any data from my form to the Payment Intent on submission of form.但是,我似乎无法在提交表单时将表单中的任何数据添加到付款意图中。

Once logging the req.body on form submission I realised that the body is empty, although submitting the form with multiple inputs.在表单提交中记录 req.body 后,我意识到主体是空的,尽管提交了具有多个输入的表单。 I have never come across this issue before outside of Stripe, I believe it is the 'checkout.js' file causing this possibly?在 Stripe 之外我从来没有遇到过这个问题,我相信这可能是 'checkout.js' 文件造成的? I am wondering if I will need to split my address inputs into a separate form that needs to be submitted first to be able to extract these values?我想知道我是否需要将我的地址输入拆分成一个单独的表单,需要先提交才能提取这些值?

Server code:服务器代码:

router.post("/create-payment-intent", async (req, res) => {
    if (req.session.cart.products.length > 0) {
        // Create a PaymentIntent with the order amount and currency
        const paymentIntent = await stripe.paymentIntents.create({
        amount: req.session.cart.totalPrice * 100,
        currency: "aud",
        payment_method_types: ['card', 'afterpay_clearpay'],
        receipt_email: req.body.email,
        shipping: {
            address: {
                city: req.body.city,
                line1: req.body.line1,
                line2: req.body.line2,
                postal_code: req.body.postal_code,
                state: req.body.state
            },
            name: req.body.name
        }
        })
        req.session.clientId = paymentIntent.id

        res.send({
        clientSecret: paymentIntent.client_secret
        })
    } else {
        res.redirect('/shop')
    }
})

Frontend JS:前端JS:

// This is your test publishable API key.
const stripe = Stripe("pk_test_123");
// The items the customer wants to buy


let elements;
initialize();
checkStatus();
document
  .querySelector("#payment-form")
  .addEventListener("submit", handleSubmit);
// Fetches a payment intent and captures the client secret
async function initialize() {
  const response = await fetch("/cart/create-payment-intent", {
    method: "POST",
    headers: { "Content-Type": "application/json" }
  });
  console.log(response)
  const { clientSecret } = await response.json();
  const appearance = {
    theme: 'night',
    rules: {
      '.Tab': {
        // border: '1px solid #E0E6EB',
        // boxShadow: '0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02)',
        backgroundColor: '#ccc',
        fontFamily: "'Montserrat', sans-serif"
      },
      '.TabLabel': {
        color: 'black',
        fontFamily: "'Montserrat', sans-serif"
      },
      '.Label': {
        color: '#edf0f1',
        fontFamily: "'Montserrat', sans-serif",
        fontSize: '15px',
      },
      '.Input': {
        backgroundColor: '#edf0f1',
        color: 'black'
      },
      '.Input::placeholder': {
        backgroundColor: '#grey'
      },
      '.Dropdown': {
        color: 'grey',
        backgroundColor: 'red'
      },
      '.DropdownItem  ': {
        color: 'grey',
        backgroundColor: 'red'
      },
      '.DropdownItem:active': {
        color: 'grey',
        backgroundColor: 'red'
      }
    }
  };
  elements = stripe.elements({ appearance, clientSecret });
  const paymentElement = elements.create("payment");
  paymentElement.mount("#payment-element");
}
async function handleSubmit(e) {
  e.preventDefault();
  setLoading(true);
  const { error } = await stripe.confirmPayment({
    elements,
    confirmParams: {
      // Make sure to change this to your payment completion page
      return_url: "http://localhost:3000/cart/success",
      shipping: {

      }
    },
  });
  // This point will only be reached if there is an immediate error when
  // confirming the payment. Otherwise, your customer will be redirected to
  // your `return_url`. For some payment methods like iDEAL, your customer will
  // be redirected to an intermediate site first to authorize the payment, then
  // redirected to the `return_url`.
  if (error.type === "card_error" || error.type === "validation_error") {
    showMessage(error.message);
  } else {
    showMessage("An unexpected error occurred.");
  }
  setLoading(false);
}
// Fetches the payment intent status after payment submission
async function checkStatus() {
  const clientSecret = new URLSearchParams(window.location.search).get(
    "payment_intent_client_secret"
  );
  if (!clientSecret) {
    return;
  }
  const { paymentIntent } = await stripe.retrievePaymentIntent(clientSecret);
  switch (paymentIntent.status) {
    case "succeeded":
      showMessage("Payment succeeded!");
      break;
    case "processing":
      showMessage("Your payment is processing.");
      break;
    case "requires_payment_method":
      showMessage("Your payment was not successful, please try again.");
      break;
    default:
      showMessage("Something went wrong.");
      break;
  }
}
// ------- UI helpers -------
function showMessage(messageText) {
  const messageContainer = document.querySelector("#payment-message");
  messageContainer.classList.remove("hidden");
  messageContainer.textContent = messageText;
  setTimeout(function () {
    messageContainer.classList.add("hidden");
    messageText.textContent = "";
  }, 4000);
}
// Show a spinner on payment submission
function setLoading(isLoading) {
  if (isLoading) {
    // Disable the button and show a spinner
    document.querySelector("#submit").disabled = true;
    document.querySelector("#spinner").classList.remove("hidden");
    document.querySelector("#button-text").classList.add("hidden");
  } else {
    document.querySelector("#submit").disabled = false;
    document.querySelector("#spinner").classList.add("hidden");
    document.querySelector("#button-text").classList.remove("hidden");
  }
}

HTML/HBS: HTML/哈佛商学院:

   <form action="/cart/create-payment-intent" method="POST" id="payment-form">
        <div class="flex_center">
        <h2 class="padded_p bold price_header">Order Total AUD </h2><h2 class="price_header yellow padded_p">${{session.cart.totalPrice}}.00</h2>
        </div>
        <div class="row">
          <div class="col-50">
            <h3>Shipping Address</h3>
            <br>
            <label for="fname"><i class="fa fa-user"></i> Full Name</label>
            <input type="text" id="fname" name="name" placeholder="John M. Doe">

            <label for="email"><i class="fa fa-envelope"></i> Email</label>
            <input type="text" id="email" name="email" placeholder="john@example.com">

            <label for="adr"><i class="fa fa-address-card-o"></i> Address</label>
            <input type="text" id="adr" name="line1" placeholder="542 W. 15th Street">

            <label for="city"><i class="fa fa-institution"></i> City</label>
            <input type="text" id="city" name="city" placeholder="New York">

            <div class="row">
              <div class="col-50">
                <label for="state">State</label>
                <input type="text" id="state" name="state" placeholder="NY">
              </div>
              <div class="col-50">
                <label for="zip">Zip</label>
                <input type="text" id="zip" name="postal_code" placeholder="10001">
              </div>
            </div>
          </div>
          <div class="col-50">
            <h3>Payment</h3>
            <div id="payment-element">
          </div>
          </div>     
        </div>
        <button id="submit">
        <div class="spinner hidden" id="spinner"></div>
        <span id="button-text" class="bold">Pay now</span>
      </button>
      </form>

Any help would be greatly appreciated, thank you in advance.任何帮助将不胜感激,在此先感谢您。

Based on your code, your frontend is calling your backend to create the PaymentIntent here:根据您的代码,您的前端正在调用您的后端在此处创建 PaymentIntent:

const response = await fetch("/cart/create-payment-intent", { method: "POST", headers: { "Content-Type": "application/json" } });

However the user has not filled in the inputs yet (since the page just loaded), and you are not passing any body in your POST request.但是,用户尚未填写输入(因为页面刚刚加载),并且您没有在 POST 请求中传递任何正文。 So it's expected that the req.body is empty.所以预计req.body是空的。

To fix that, should collect the customer information in a separate form with his shipping details And after that you create the payment_intent with these details https://stripe.com/docs/api/payment_intents/create#create_payment_intent-shipping要解决此问题,应使用单独的表格收集客户信息及其运输详细信息,然后使用这些详细信息创建 payment_intent https://stripe.com/docs/api/payment_intents/create#create_payment_intent-shipping

and pass the client_secret to the Payment Element in order to complete the payment并将 client_secret 传递给支付元素以完成支付

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

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