fixed webhook endpoint
This commit is contained in:
parent
05774ee117
commit
686d20eccf
1 changed files with 65 additions and 64 deletions
|
|
@ -4,6 +4,71 @@ const stripe = require('stripe');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
|
|
||||||
module.exports = (pool, query, authMiddleware) => {
|
module.exports = (pool, query, authMiddleware) => {
|
||||||
|
|
||||||
|
// Webhook to handle events from Stripe
|
||||||
|
router.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
|
||||||
|
// This needs to be called with raw body data
|
||||||
|
const payload = req.body;
|
||||||
|
const sig = req.headers['stripe-signature'];
|
||||||
|
|
||||||
|
let event;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Verify the webhook signature
|
||||||
|
const webhookSecret = config.payment?.stripeWebhookSecret;
|
||||||
|
if (!webhookSecret) {
|
||||||
|
throw new Error('Stripe webhook secret is not configured');
|
||||||
|
}
|
||||||
|
|
||||||
|
event = stripeClient.webhooks.constructEvent(payload, sig, webhookSecret);
|
||||||
|
|
||||||
|
// Handle the event
|
||||||
|
switch (event.type) {
|
||||||
|
case 'checkout.session.completed':
|
||||||
|
const session = event.data.object;
|
||||||
|
|
||||||
|
// Check if payment was successful
|
||||||
|
if (session.payment_status === 'paid') {
|
||||||
|
// Get metadata
|
||||||
|
const { order_id, user_id } = session.metadata;
|
||||||
|
|
||||||
|
if (order_id) {
|
||||||
|
// Update order status in database
|
||||||
|
await query(
|
||||||
|
'UPDATE orders SET status = $1, payment_completed = true, payment_id = $2 WHERE id = $3',
|
||||||
|
['processing', session.id, order_id]
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Payment completed for order ${order_id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'payment_intent.payment_failed':
|
||||||
|
const paymentIntent = event.data.object;
|
||||||
|
console.log(`Payment failed: ${paymentIntent.last_payment_error?.message}`);
|
||||||
|
|
||||||
|
// Handle failed payment
|
||||||
|
if (paymentIntent.metadata?.order_id) {
|
||||||
|
await query(
|
||||||
|
'UPDATE orders SET status = $1, payment_notes = $2 WHERE id = $3',
|
||||||
|
['payment_failed', 'Payment attempt failed', paymentIntent.metadata.order_id]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.log(`Unhandled event type ${event.type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a 200 success response
|
||||||
|
res.status(200).send();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Webhook Error: ${err.message}`);
|
||||||
|
return res.status(400).send(`Webhook Error: ${err.message}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Apply authentication middleware to all routes
|
// Apply authentication middleware to all routes
|
||||||
router.use(authMiddleware);
|
router.use(authMiddleware);
|
||||||
|
|
||||||
|
|
@ -120,70 +185,6 @@ module.exports = (pool, query, authMiddleware) => {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Webhook to handle events from Stripe
|
|
||||||
router.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
|
|
||||||
// This needs to be called with raw body data
|
|
||||||
const payload = req.body;
|
|
||||||
const sig = req.headers['stripe-signature'];
|
|
||||||
|
|
||||||
let event;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Verify the webhook signature
|
|
||||||
const webhookSecret = config.payment?.stripeWebhookSecret;
|
|
||||||
if (!webhookSecret) {
|
|
||||||
throw new Error('Stripe webhook secret is not configured');
|
|
||||||
}
|
|
||||||
|
|
||||||
event = stripeClient.webhooks.constructEvent(payload, sig, webhookSecret);
|
|
||||||
|
|
||||||
// Handle the event
|
|
||||||
switch (event.type) {
|
|
||||||
case 'checkout.session.completed':
|
|
||||||
const session = event.data.object;
|
|
||||||
|
|
||||||
// Check if payment was successful
|
|
||||||
if (session.payment_status === 'paid') {
|
|
||||||
// Get metadata
|
|
||||||
const { order_id, user_id } = session.metadata;
|
|
||||||
|
|
||||||
if (order_id) {
|
|
||||||
// Update order status in database
|
|
||||||
await query(
|
|
||||||
'UPDATE orders SET status = $1, payment_completed = true, payment_id = $2 WHERE id = $3',
|
|
||||||
['processing', session.id, order_id]
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(`Payment completed for order ${order_id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'payment_intent.payment_failed':
|
|
||||||
const paymentIntent = event.data.object;
|
|
||||||
console.log(`Payment failed: ${paymentIntent.last_payment_error?.message}`);
|
|
||||||
|
|
||||||
// Handle failed payment
|
|
||||||
if (paymentIntent.metadata?.order_id) {
|
|
||||||
await query(
|
|
||||||
'UPDATE orders SET status = $1, payment_notes = $2 WHERE id = $3',
|
|
||||||
['payment_failed', 'Payment attempt failed', paymentIntent.metadata.order_id]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
console.log(`Unhandled event type ${event.type}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a 200 success response
|
|
||||||
res.status(200).send();
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Webhook Error: ${err.message}`);
|
|
||||||
return res.status(400).send(`Webhook Error: ${err.message}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
router.get('/config', async (req, res, next) => {
|
router.get('/config', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
res.json({
|
res.json({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue