E-Commerce-Module/backend/src/routes/cart.js

363 lines
No EOL
9.9 KiB
JavaScript

const express = require('express');
const { v4: uuidv4 } = require('uuid');
const router = express.Router();
module.exports = (pool, query, authMiddleware) => {
router.use(authMiddleware);
// Get user's cart
router.get('/:userId', async (req, res, next) => {
try {
const { userId } = req.params;
if (req.user.id !== userId) {
return res.status(403).json({
error: true,
message: 'You can only access your own cart'
});
}
// Get cart
let cartResult = await query(
'SELECT * FROM carts WHERE user_id = $1',
[userId]
);
// If no cart exists, create one
if (cartResult.rows.length === 0) {
cartResult = await query(
'INSERT INTO carts (id, user_id) VALUES ($1, $2) RETURNING *',
[uuidv4(), userId]
);
}
const cartId = cartResult.rows[0].id;
// Get cart items with product details
const cartItemsResult = await query(
`SELECT ci.id, ci.quantity, ci.added_at,
p.id AS product_id, p.name, p.description, p.price,
p.category_id, pc.name AS category_name
FROM cart_items ci
JOIN products p ON ci.product_id = p.id
JOIN product_categories pc ON p.category_id = pc.id
WHERE ci.cart_id = $1`,
[cartId]
);
// Calculate total
const total = cartItemsResult.rows.reduce((sum, item) => {
return sum + (parseFloat(item.price) * item.quantity);
}, 0);
res.json({
id: cartId,
userId,
items: cartItemsResult.rows,
itemCount: cartItemsResult.rows.length,
total
});
} catch (error) {
next(error);
}
});
// Add item to cart
router.post('/add', async (req, res, next) => {
try {
const { userId, productId, quantity = 1 } = req.body;
if (req.user.id !== userId) {
return res.status(403).json({
error: true,
message: 'You can only modify your own cart' + req.user.id + " "+ userId
});
}
// Check if product exists
const productResult = await query(
'SELECT * FROM products WHERE id = $1',
[productId]
);
if (productResult.rows.length === 0) {
return res.status(404).json({
error: true,
message: 'Product not found'
});
}
// Get or create cart
let cartResult = await query(
'SELECT * FROM carts WHERE user_id = $1',
[userId]
);
if (cartResult.rows.length === 0) {
cartResult = await query(
'INSERT INTO carts (id, user_id) VALUES ($1, $2) RETURNING *',
[uuidv4(), userId]
);
}
const cartId = cartResult.rows[0].id;
// Check if item already in cart
const existingItemResult = await query(
'SELECT * FROM cart_items WHERE cart_id = $1 AND product_id = $2',
[cartId, productId]
);
if (existingItemResult.rows.length > 0) {
// Update quantity
const newQuantity = existingItemResult.rows[0].quantity + quantity;
await query(
'UPDATE cart_items SET quantity = $1 WHERE id = $2',
[newQuantity, existingItemResult.rows[0].id]
);
} else {
// Add new item
await query(
'INSERT INTO cart_items (id, cart_id, product_id, quantity) VALUES ($1, $2, $3, $4)',
[uuidv4(), cartId, productId, quantity]
);
}
// Get updated cart
const updatedCartItems = await query(
`SELECT ci.id, ci.quantity, ci.added_at,
p.id AS product_id, p.name, p.description, p.price,
p.category_id, pc.name AS category_name
FROM cart_items ci
JOIN products p ON ci.product_id = p.id
JOIN product_categories pc ON p.category_id = pc.id
WHERE ci.cart_id = $1`,
[cartId]
);
// Calculate total
const total = updatedCartItems.rows.reduce((sum, item) => {
return sum + (parseFloat(item.price) * item.quantity);
}, 0);
res.json({
id: cartId,
userId,
items: updatedCartItems.rows,
itemCount: updatedCartItems.rows.length,
total
});
} catch (error) {
next(error);
}
});
// Update cart item quantity
router.put('/update', async (req, res, next) => {
try {
const { userId, productId, quantity } = req.body;
if (req.user.id !== userId) {
return res.status(403).json({
error: true,
message: 'You can only modify your own cart' + req.user.id + " "+ userId
});
}
// Get cart
const cartResult = await query(
'SELECT * FROM carts WHERE user_id = $1',
[userId]
);
if (cartResult.rows.length === 0) {
return res.status(404).json({
error: true,
message: 'Cart not found'
});
}
const cartId = cartResult.rows[0].id;
if (quantity <= 0) {
// Remove item
await query(
'DELETE FROM cart_items WHERE cart_id = $1 AND product_id = $2',
[cartId, productId]
);
} else {
// Update quantity
await query(
'UPDATE cart_items SET quantity = $1 WHERE cart_id = $2 AND product_id = $3',
[quantity, cartId, productId]
);
}
// Get updated cart
const updatedCartItems = await query(
`SELECT ci.id, ci.quantity, ci.added_at,
p.id AS product_id, p.name, p.description, p.price,
p.category_id, pc.name AS category_name
FROM cart_items ci
JOIN products p ON ci.product_id = p.id
JOIN product_categories pc ON p.category_id = pc.id
WHERE ci.cart_id = $1`,
[cartId]
);
// Calculate total
const total = updatedCartItems.rows.reduce((sum, item) => {
return sum + (parseFloat(item.price) * item.quantity);
}, 0);
res.json({
id: cartId,
userId,
items: updatedCartItems.rows,
itemCount: updatedCartItems.rows.length,
total
});
} catch (error) {
next(error);
}
});
// Clear cart
router.delete('/clear/:userId', async (req, res, next) => {
try {
const { userId } = req.params;
if (req.user.id !== userId) {
return res.status(403).json({
error: true,
message: 'You can only modify your own cart' + req.user.id + " "+ userId
});
}
// Get cart
const cartResult = await query(
'SELECT * FROM carts WHERE user_id = $1',
[userId]
);
if (cartResult.rows.length === 0) {
return res.status(404).json({
error: true,
message: 'Cart not found'
});
}
const cartId = cartResult.rows[0].id;
// Delete all items
await query(
'DELETE FROM cart_items WHERE cart_id = $1',
[cartId]
);
res.json({
id: cartId,
userId,
items: [],
itemCount: 0,
total: 0
});
} catch (error) {
next(error);
}
});
// Checkout (create order from cart)
router.post('/checkout', async (req, res, next) => {
try {
const { userId, shippingAddress } = req.body;
if (req.user.id !== userId) {
return res.status(403).json({
error: true,
message: 'You can only checkout your own cart'
});
}
// Get cart
const cartResult = await query(
'SELECT * FROM carts WHERE user_id = $1',
[userId]
);
if (cartResult.rows.length === 0) {
return res.status(404).json({
error: true,
message: 'Cart not found'
});
}
const cartId = cartResult.rows[0].id;
// Get cart items
const cartItemsResult = await query(
`SELECT ci.*, p.price
FROM cart_items ci
JOIN products p ON ci.product_id = p.id
WHERE ci.cart_id = $1`,
[cartId]
);
if (cartItemsResult.rows.length === 0) {
return res.status(400).json({
error: true,
message: 'Cart is empty'
});
}
// Calculate total
const total = cartItemsResult.rows.reduce((sum, item) => {
return sum + (parseFloat(item.price) * item.quantity);
}, 0);
// Begin transaction
const client = await pool.connect();
try {
await client.query('BEGIN');
// Create order
const orderId = uuidv4();
await client.query(
'INSERT INTO orders (id, user_id, status, total_amount, shipping_address) VALUES ($1, $2, $3, $4, $5)',
[orderId, userId, 'pending', total, shippingAddress]
);
// Create order items
for (const item of cartItemsResult.rows) {
await client.query(
'INSERT INTO order_items (id, order_id, product_id, quantity, price_at_purchase) VALUES ($1, $2, $3, $4, $5)',
[uuidv4(), orderId, item.product_id, item.quantity, item.price]
);
// Update product stock
await client.query(
'UPDATE products SET stock_quantity = stock_quantity - $1 WHERE id = $2',
[item.quantity, item.product_id]
);
}
// Clear cart
await client.query(
'DELETE FROM cart_items WHERE cart_id = $1',
[cartId]
);
await client.query('COMMIT');
res.status(201).json({
success: true,
message: 'Order created successfully',
orderId
});
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}
} catch (error) {
next(error);
}
});
return router;
};