![](/img/trans.png)
[英]Passing extra customer details with Stripe Payment Intent custom payment flow
[英]Attach customer details to Stripe Payment Intent
我正在从“卡元素”迁移到“支付元素”,并且付款成功。 我能够传递金额并向客户收费。 但是,我似乎无法在提交表单时将表单中的任何数据添加到付款意图中。
在表单提交中记录 req.body 后,我意识到主体是空的,尽管提交了具有多个输入的表单。 在 Stripe 之外我从来没有遇到过这个问题,我相信这可能是 'checkout.js' 文件造成的? 我想知道我是否需要将我的地址输入拆分成一个单独的表单,需要先提交才能提取这些值?
服务器代码:
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')
}
})
前端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/哈佛商学院:
<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>
任何帮助将不胜感激,在此先感谢您。
根据您的代码,您的前端正在调用您的后端在此处创建 PaymentIntent:
const response = await fetch("/cart/create-payment-intent", { method: "POST", headers: { "Content-Type": "application/json" } });
但是,用户尚未填写输入(因为页面刚刚加载),并且您没有在 POST 请求中传递任何正文。 所以预计req.body
是空的。
要解决此问题,应使用单独的表格收集客户信息及其运输详细信息,然后使用这些详细信息创建 payment_intent https://stripe.com/docs/api/payment_intents/create#create_payment_intent-shipping
并将 client_secret 传递给支付元素以完成支付
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.