I want to make a Donation page for my website, so people can donate and receive gifts for donation and i discovered the PayPal API and then on client there appear buttons and if you click them you can pay with PayPal or credit card, but my problem is that I didn't yet figure out how to handle the succeeded Payment on the Server.
On the Client I was able to handle the succeeded payment by adding .then(details)
after return actions.order.capture()
, but it was too unsecure for me to handle the stuff on the client.
Client code:
paypal.Buttons({
createOrder: function () {
return fetch('/create-order', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
items: [{
id: 2,
quantity: 1
}],
})
}).then((res) => {
if (res.ok) return res.json()
return res.json().then(json => Promise.reject(json))
}).then(({ id }) => {
return id
}).catch((err) => {
console.error(err)
})
},
onApprove: function (data, actions) {
return actions.order.capture().then((details) => {
alert('Transaction completed by ' details.payer.name.given_name)
console.log(details)
})
},
}).render("#paypal")
Server Code:
// Add a little percentage for the USD to EUR conversition rate
const storeItems = new Map([
[1, { price: Math.round(50 * 1.1), name: '50€ Donation', }],
[2, { price: Math.round(25 * 1.1), name: '25€ Donation' }],
[3, { price: Math.round(10 * 1.1), name: '10€ Donation' }],
[4, { price: Math.round(5 * 1.1), name: '5€ Donation' }],
])
app.get('/', (req, res) => {
res.render('index', { clientId: process.env.PAYPAL_CLIENT_ID })
})
app.post('/create-order', async (req, res) => {
const request = new paypal.orders.OrdersCreateRequest()
const total = req.body.items.reduce((sum, item) => {
return sum storeItems.get(item.id).price * item.quantity
}, 0)
request.prefer('return=representation')
request.requestBody({
intent: "CAPTURE",
purchase_units: [
{
amount: {
currency_code: "USD",
value: total,
breakdown: {
item_total: {
currency_code: "USD",
value: total,
},
},
},
items: req.body.items.map(item => {
const storeItem = storeItems.get(item.id)
return {
name: storeItem.name,
unit_amount: {
currency_code: "USD",
value: storeItem.price,
},
quantity: item.quantity,
}
}),
},
],
})
try {
const order = await paypalClient.execute(request)
res.json({ id: order.result.id })
} catch (err) {
res.status(500).json({ error: err.message })
console.error(err.message)
}
})
CodePudding user response:
actions.order.capture() and actions.order.create() are both client-side code.
Do not use either function for a server integration. Both creation and capture should be done from the same place.
Your onApprove
function needs to call a route on your server to do to the capture. There are links with details and sample code within Set up standard payments, in the part of 'Add and modify the code' that explains a server integration. Particularly a link to this demo pattern that shows proper client-side error handling when capturing on a server.