英文:
How to correctly pass email and name to created customers in Stripe?
问题
以下是您的代码的翻译:
服务器端(Node.js):
app.post("/create-payment-intent", async (req, res) => {
const { email, name } = req.body;
const customer = await stripe.customers.create({ email, name });
const paymentIntent = await stripe.paymentIntents.create({
customer: customer.id,
setup_future_usage: "off_session",
amount: 2499,
currency: "usd",
automatic_payment_methods: { enabled: true }
});
res.send({ clientSecret: paymentIntent.client_secret });
});
客户端:
<body>
<form id="payment-form">
<input type="email" id="email" placeholder="输入电子邮件地址" required/>
<input type="text" id="name" placeholder="全名" required/>
<div id="payment-element"></div>
<button class="str" id="submit">
<div class="spinner hidden" id="spinner"></div>
<span id="button-text">提交</span>
</button>
<div id="payment-message" class="hidden"></div>
</form>
<script>
document.addEventListener('DOMContentLoaded', async () => {
const { publicKey, endPoint } = await fetch('/config').then((r) => r.json())
const stripe = Stripe(publicKey)
const endpoint = endPoint
const email = document.getElementById('email').value;
const name = document.getElementById('name').value;
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, name })
})
const { clientSecret } = await response.json();
const appearance = { theme: 'flat' };
const elements = stripe.elements({ clientSecret, appearance });
const paymentElement = elements.create('payment')
paymentElement.mount('#payment-element')
const form = document.getElementById("payment-form")
form.addEventListener('submit', async (e) => {
e.preventDefault();
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: endpoint
}
})
if (error) {
const message = document.getElementById("payment-message")
message.innerText = error.message;
}
setLoading(false);
})
})
</script>
</body>
7.17.23 更新:
好的,我终于成功了,但是只有在 DOM 加载之前填写了电子邮件和姓名字段才有效(就像我输入了我的电子邮件和姓名,重新加载页面,我的数据仍然填写)。因此,我尝试将电子邮件和姓名移到提交事件内部,但它没有起作用。问题仍然是一样的 - 如何将电子邮件和姓名传递给已创建的客户,但是我猜测我需要在提交事件内传递它,它应该更新客户(因为当表单加载时,它已经从这些字段传递数据了)?
英文:
My current code is:
server (Node js)
app.post("/create-payment-intent", async (req, res) => {
const { email, name } = req.body;
const customer = await stripe.customers.create({ email, name });
const paymentIntent = await stripe.paymentIntents.create({
customer: customer.id,
setup_future_usage: "off_session",
amount: 2499,
currency: "usd",
automatic_payment_methods: { enabled: true }
});
res.send({ clientSecret: paymentIntent.client_secret });
});
client
<body>
<form id="payment-form">
<input type="email" id="email" placeholder="Enter email address" required/>
<input type="text" id="name" placeholder="Full Name" required/>
<div id="payment-element"></div>
<button class="str" id="submit">
<div class="spinner hidden" id="spinner"></div>
<span id="button-text">Submit</span>
</button>
<div id="payment-message" class="hidden"></div>
</form>
<script>
document.addEventListener('DOMContentLoaded', async () => {
const {publicKey, endPoint} = await fetch('/config').then((r) => r.json())
const stripe = Stripe(publicKey)
const endpoint = (endPoint)
const email = document.getElementById('email').value;
const name = document.getElementById('name').value;
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({email, name})
})
const { clientSecret } = await response.json();
const appearance = { theme: 'flat' };
const elements = stripe.elements({ clientSecret, appearance });
const paymentElement = elements.create('payment')
paymentElement.mount('#payment-element')
const form = document.getElementById("payment-form")
form.addEventListener('submit', async (e) => {
e.preventDefault();
setLoading(true);
const {error} = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: (endpoint)
}
})
if(error) {
const message = document.getElementById("payment-message")
message.innerText = error.message;
}
setLoading(false);
})
})
</script>
</body>
7.17.23 UPDATE:
Well, I finally did it BUT - it only works if email and name fields are already filled before DOM loads (like I enter my email and name, reload page and my data still filled). So I tried to move the email and name inside the submit but it didn't work. Question is the same - how to pass email and name to already created customer but as I may guess I need to pass it inside the submit event and it should update the customer (because when form is loaded it already passes data from these fields)?
答案1
得分: 1
我认为你只是有点混淆了你的条带方法顺序。在大多数情况下,您可以按照以下顺序操作:
- 创建一个客户
- 为您的客户创建付款
- 确认您刚刚为客户创建的付款
因此,您的服务器代码应该类似于这样:
app.post("/create-payment-intent", async (req, res) => {
const { email, name } = req.body;
// 步骤 1)创建客户
const customer = await stripe.customers.create({
email: email,
name: name,
});
// 步骤 2)为您的客户创建付款
const paymentIntent = await stripe.paymentIntents.create({
customer: customer.id,
setup_future_usage: "off_session",
amount: 2499,
currency: "usd",
automatic_payment_methods: { enabled: true },
});
// 将 client_secret 发送到前端以便我们可以确认付款
res.send({ clientSecret: paymentIntent.client_secret });
});
而您的前端代码应该类似于这样:
<form id="payment-form">
...
<button class="str" id="submit">提交</button>
...
</form>
<script>
document.addEventListener('DOMContentLoaded', async () => {
...
const form = document.getElementById("payment-form")
form.addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const name = document.getElementById("name").value;
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email: email, name: name })
})
const { clientSecret } = await response.json()
// 步骤 3)确认您刚刚为客户创建的付款
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
client_secret: clientSecret, // <--- 这是您从服务器获得的客户机密
return_url: (endpoint)
}
})
if(error) {
const message = document.getElementById("payment-message")
message.innerText = error.message;
}
})
})
</script>
英文:
I think you just have your stripe method order a bit mixed up is all. In most cases you can follow this order:
- Create a customer
- Create a payment for your customer
- Confirm the payment that you just made for your customer
So you server code would look something like this:
app.post("/create-payment-intent", async (req, res) => {
const { email, name } = req.body;
// Step 1) Create a customer
const customer = await stripe.customers.create({
email: email,
name: name,
});
// Step 2) Create a payment for your customer
const paymentIntent = await stripe.paymentIntents.create({
customer: customer.id,
setup_future_usage: "off_session",
amount: 2499,
currency: "usd",
automatic_payment_methods: { enabled: true },
});
// Send the client_secret to the frontend so we can confirm the payment
res.send({ clientSecret: paymentIntent.client_secret });
});
And your frontend code would look something like this:
<form id="payment-form">
...
<button class="str" id="submit">Submit</button>
...
</form>
<script>
document.addEventListener('DOMContentLoaded', async () => {
...
const form = document.getElementById("payment-form")
form.addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const name = document.getElementById("name").value;
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email: email, name: name })
})
const { clientSecret } = await response.json()
// Step 3) Confirm the payment that you just made for your customer
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
client_secret: clientSecret, // <--- This is the client secret that you got from the server
return_url: (endpoint)
}
})
if(error) {
const message = document.getElementById("payment-message")
message.innerText = error.message;
}
})
})
</script>
答案2
得分: 0
根据您的描述和您分享的代码,看起来email
和name
变量是在DOMContentLoaded
事件发生时被赋值的。这意味着输入字段的值会在文档完全加载后立即获取,这解释了为什么需要预填字段才能使代码正常工作。
相反,您希望在表单提交时获取输入字段的值,也就是在submit
事件处理程序内部获取。
尝试将这些行移动到submit
事件处理程序内,如下所示:
const email = document.getElementById('email').value;
const name = document.getElementById('name').value;
在submit
事件处理程序内部,像这样:
document.addEventListener('DOMContentLoaded', async () => {
const { publicKey, endPoint } = await fetch('/config').then((r) => r.json())
const stripe = Stripe(publicKey)
const endpoint = (endPoint)
const form = document.getElementById("payment-form")
form.addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const name = document.getElementById('name').value;
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, name })
})
const { clientSecret } = await response.json();
const appearance = { theme: 'flat' };
const elements = stripe.elements({ clientSecret, appearance });
const paymentElement = elements.create('payment')
paymentElement.mount('#payment-element')
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: (endpoint)
}
})
if (error) {
const message = document.getElementById("payment-message")
message.innerText = error.message;
}
setLoading(false);
})
})
这样,email
和name
变量将在表单提交时被赋予输入字段的值。之后,将使用来自该请求的响应来创建付款元素并确认付款。
英文:
Answer to your question after update (7.17.23 UPDATE)
Based on your description and the code you've shared, it appears the email
and name
variables are being assigned at the time of the DOMContentLoaded
event. This means that the input fields' values are fetched as soon as the document has been completely loaded, which explains why the fields need to be prefilled for the code to work.
Instead, you want to fetch the input field values at the time the form is submitted, i.e., inside the submit
event handler.
Try moving these lines:
const email = document.getElementById('email').value;
const name = document.getElementById('name').value;
inside the submit
event handler, like so:
document.addEventListener('DOMContentLoaded', async () => {
const {publicKey, endPoint} = await fetch('/config').then((r) => r.json())
const stripe = Stripe(publicKey)
const endpoint = (endPoint)
const form = document.getElementById("payment-form")
form.addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const name = document.getElementById('name').value;
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({email, name})
})
const { clientSecret } = await response.json();
const appearance = { theme: 'flat' };
const elements = stripe.elements({ clientSecret, appearance });
const paymentElement = elements.create('payment')
paymentElement.mount('#payment-element')
setLoading(true);
const {error} = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: (endpoint)
}
})
if(error) {
const message = document.getElementById("payment-message")
message.innerText = error.message;
}
setLoading(false);
})
})
This way, the email
and name
variables will be assigned the values from the input fields at the time the form is submitted. After that, a fetch request is made to the /create-payment-intent
endpoint with the entered email and name. The response from this request is then used to create the payment element and confirm the payment.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论