You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
452 lines
12 KiB
JavaScript
452 lines
12 KiB
JavaScript
const User = require("../models/User.js");
|
|
const Product = require("../models/Product.js");
|
|
const Order = require("../models/Order.js");
|
|
const auth = require("../auth.js");
|
|
const {verify, verifyAdmin} = auth;
|
|
|
|
const multer = require('multer');
|
|
|
|
const storage = multer.diskStorage({
|
|
destination: (req, file, cb) => {
|
|
cb(null, 'public/images/');
|
|
},
|
|
filename: (req, file, cb) => {
|
|
cb(null, file.fieldname + "-" + Date.now() + "-" + file.originalname);
|
|
},
|
|
});
|
|
|
|
|
|
const upload = multer({ storage: storage });
|
|
|
|
// Controllers
|
|
|
|
// create product controller
|
|
module.exports.createProduct = async (req, res) => {
|
|
try {
|
|
const { name, price, description, inventory } = req.body;
|
|
|
|
// console.log(req.file)
|
|
|
|
// Create a new product instance
|
|
const product = new Product({
|
|
name,
|
|
price,
|
|
description,
|
|
inventory,
|
|
image: (req.file != undefined) ? {
|
|
imageName: req.file.originalname,
|
|
}
|
|
:
|
|
null
|
|
});
|
|
|
|
// Save the product to the database
|
|
await product.save();
|
|
|
|
res.status(201).json(true);
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json(false);
|
|
}
|
|
};
|
|
|
|
// Middleware to handle image upload
|
|
module.exports.uploadImage = upload.single('image');
|
|
|
|
module.exports.isProductExisting = async (req, res) => {
|
|
try {
|
|
const { productName } = req.body;
|
|
|
|
|
|
const existingProduct = await Product.findOne({ name: productName });
|
|
|
|
const productExists = !!existingProduct;
|
|
|
|
if (productExists == true) {
|
|
res.json(true);
|
|
} else {
|
|
res.json(false);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json(false);
|
|
}
|
|
};
|
|
|
|
// retrieve all products controller
|
|
module.exports.getAllProducts = async (req, res) => {
|
|
try {
|
|
// Fetch all products from the database
|
|
const products = await Product.find();
|
|
|
|
res.json(products);
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error retrieving products' });
|
|
}
|
|
};
|
|
|
|
// getting product name by id
|
|
exports.getProductName = async (req, res) => {
|
|
try {
|
|
const { productId } = req.body;
|
|
|
|
// Find the product by productId
|
|
const product = await Product.findOne({ _id: productId }).select('name');
|
|
|
|
if (!product) {
|
|
return res.status(404).json({ error: 'Product not found' });
|
|
}
|
|
|
|
// Send the product name in the response
|
|
res.json(product);
|
|
} catch (error) {
|
|
console.error('Error getting product name:', error);
|
|
res.status(500).json({ error: 'Internal Server Error' });
|
|
}
|
|
};
|
|
|
|
// retrieve all active products controller
|
|
exports.getAllActiveProducts = async (req, res) => {
|
|
try {
|
|
const products = await Product.find({ isActive: true });
|
|
|
|
res.json(products);
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error retrieving active products' });
|
|
}
|
|
};
|
|
|
|
|
|
// search products controller
|
|
exports.searchProducts = async (req, res) => {
|
|
try {
|
|
const { productName } = req.body;
|
|
|
|
const products = await Product.find({
|
|
name: { $regex: new RegExp(productName, 'i') },
|
|
isActive: true
|
|
});
|
|
|
|
res.json({products});
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error searching products' });
|
|
}
|
|
};
|
|
|
|
|
|
// Helper function to escape special characters in the search query
|
|
function escapeRegex(text) {
|
|
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
}
|
|
|
|
|
|
// update product controller
|
|
exports.updateProduct = async (req, res) => {
|
|
try {
|
|
const { productId } = req.params;
|
|
const { name, price, description, inventory } = req.body;
|
|
|
|
// Find the product to update
|
|
const product = await Product.findByIdAndUpdate(productId, {
|
|
name,
|
|
price,
|
|
description,
|
|
inventory,
|
|
// image,
|
|
}, { new: true });
|
|
|
|
if (!product) {
|
|
return res.status(404).json(false);
|
|
}
|
|
|
|
res.json(true);
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json(false);
|
|
}
|
|
};
|
|
|
|
// archive product controller
|
|
exports.archiveProduct = async (req, res) => {
|
|
try {
|
|
const { productId } = req.params;
|
|
|
|
// Find the product to archive
|
|
const product = await Product.findById(productId);
|
|
|
|
if (!product) {
|
|
return res.status(404).json({ message: 'Product not found' });
|
|
}else if (product.isActive === false){
|
|
return res.status(404).json({ message: 'Product already archived' });
|
|
}
|
|
|
|
product.isActive = false;
|
|
|
|
await product.save();
|
|
|
|
res.json({ message: 'Product archived successfully' });
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error archiving product' });
|
|
}
|
|
};
|
|
|
|
|
|
// activate product controller
|
|
exports.activateProduct = async (req, res) => {
|
|
try {
|
|
const { productId } = req.params;
|
|
|
|
// Find the product to archive
|
|
const product = await Product.findById(productId);
|
|
|
|
if (!product) {
|
|
return res.status(404).json({ message: 'Product not found' });
|
|
}else if (product.isActive === true){
|
|
return res.status(404).json({ message: 'Product already active' });
|
|
}
|
|
|
|
product.isActive = true;
|
|
|
|
await product.save();
|
|
|
|
res.json({ message: 'Product activated successfully' });
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error activating product' });
|
|
}
|
|
};
|
|
|
|
|
|
// Controller to create an order || check-out
|
|
exports.createOrder = async (req, res, next) => {
|
|
try {
|
|
let cartItems = req.body.orderedItems;
|
|
|
|
// Fetch product prices from the database
|
|
await Product.find({ _id: { $in: cartItems.map(item => item.productId) } }).then( result => {
|
|
for (i = 0 ; i < result.length; i++) {
|
|
cartItems[i].price = result[i].price;
|
|
}
|
|
});
|
|
|
|
// Create the order with retrieved prices
|
|
const newOrder = new Order({
|
|
userId: req.user.id,
|
|
products: cartItems,
|
|
totalAmount: calculateTotalPrice(cartItems)
|
|
});
|
|
|
|
// Save the order and update inventory
|
|
await newOrder.save();
|
|
await updateProductInventory(cartItems);
|
|
|
|
|
|
// Update User orders
|
|
await User.findById(req.user.id).then( result => {
|
|
|
|
const newOrderUserUpdate = {
|
|
products: cartItems,
|
|
totalAmount: calculateTotalPrice(cartItems),
|
|
purchasedOn : new Date()
|
|
}
|
|
|
|
result.orders.push(newOrderUserUpdate);
|
|
|
|
result.save();
|
|
})
|
|
|
|
|
|
|
|
res.status(201).json(true);
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json(false);
|
|
}
|
|
};
|
|
|
|
|
|
// Helper functions for calculating total price and updating inventory
|
|
function calculateTotalPrice(cartItems) {
|
|
return cartItems.reduce((total, item) => {
|
|
const itemPrice = Number(item.price); // Ensure price is a number
|
|
const itemQuantity = Number(item.quantity); // Ensure quantity is a number
|
|
return total + (itemPrice * itemQuantity);
|
|
}, 0);
|
|
}
|
|
|
|
async function updateProductInventory(cartItems) {
|
|
try {
|
|
await Promise.all(
|
|
cartItems.map(async item => {
|
|
const product = await Product.findById(item.productId);
|
|
|
|
if (!product) {
|
|
throw new Error(`Product not found: ${item.productId}`);
|
|
}
|
|
|
|
// Ensure quantity doesn't go below zero
|
|
const newQuantity = Math.max(0, product.inventory - item.quantity);
|
|
|
|
product.inventory = newQuantity;
|
|
await product.save();
|
|
})
|
|
);
|
|
} catch (error) {
|
|
console.error('Error updating product quantities:', error);
|
|
// Handle the error appropriately (e.g., rollback order creation)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// My Cart
|
|
|
|
exports.addProductToCart = async (req, res) => {
|
|
try {
|
|
const { productId, quantity } = req.body;
|
|
|
|
// Find the user
|
|
const user = await User.findById(req.user.id);
|
|
|
|
// Check if the cart array exists
|
|
if (!user.myCart) {
|
|
user.myCart = [];
|
|
}
|
|
|
|
// Check if the product already exists in the cart
|
|
const existingItemIndex = user.myCart.findIndex(item => item.productId === productId);
|
|
|
|
if (existingItemIndex !== -1) {
|
|
// Update quantity of existing item
|
|
await User.findByIdAndUpdate(
|
|
req.user.id,
|
|
{
|
|
$inc: { [`myCart.${existingItemIndex}.quantity`]: quantity } // Increment the quantity field
|
|
},
|
|
{ new: true } // Return the updated user after the operation
|
|
);
|
|
} else {
|
|
if (quantity <= 0) {
|
|
return res.json({ message: 'Provide valid quantity' });
|
|
}
|
|
// Add new item to cart
|
|
const product = await Product.findById(productId);
|
|
user.myCart.push({
|
|
productId,
|
|
name: product.name,
|
|
quantity
|
|
});
|
|
await user.save(); // Save the updated user with cart items
|
|
}
|
|
|
|
res.json({ message: 'Product added to cart successfully' });
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error adding product to cart' });
|
|
}
|
|
};
|
|
|
|
|
|
exports.updateProductQuantity = async (req, res) => {
|
|
try {
|
|
const { productId, quantity } = req.body;
|
|
|
|
// Validate quantity (e.g., must be positive, not exceed available inventory)
|
|
if (quantity <= 0) {
|
|
return res.status(400).json({ message: 'Quantity must be greater than zero' });
|
|
}
|
|
|
|
// Update quantity in the cart using findByIdAndUpdate
|
|
const updatedUser = await User.findByIdAndUpdate(
|
|
req.user.id,
|
|
{ $set: { 'myCart.$[element].quantity': quantity } },
|
|
{
|
|
new: true, // return the updated document
|
|
arrayFilters: [{ 'element.productId': productId }] // update the element where productId matches
|
|
}
|
|
);
|
|
|
|
if (!updatedUser) {
|
|
return res.status(404).json({ message: 'User not found' });
|
|
}
|
|
|
|
if (!updatedUser.myCart) {
|
|
return res.status(400).json({ message: 'Cart is empty' });
|
|
}
|
|
|
|
res.json({ message: 'Product quantity updated successfully', updatedCart: updatedUser.myCart });
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error updating product quantity' });
|
|
}
|
|
};
|
|
|
|
|
|
exports.removeProductsFromCart = async (req, res) => {
|
|
try {
|
|
const productIds = req.body.productIds; // Array of product IDs to remove
|
|
const user = await User.findById(req.user.id);
|
|
|
|
// Update the user's cart by removing the products with the given IDs
|
|
const updatedUser = await User.findByIdAndUpdate(
|
|
req.user.id,
|
|
{
|
|
$pull: { myCart: { productId: { $in: productIds } } }
|
|
},
|
|
{ new: true }
|
|
).exec();
|
|
|
|
// Check if any products were removed from the cart
|
|
if (updatedUser) {
|
|
res.json({ message: 'Products removed from cart successfully' });
|
|
} else {
|
|
res.status(404).json({ message: 'No products removed from cart' });
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error removing products from cart' });
|
|
}
|
|
};
|
|
|
|
|
|
exports.getCartDetails = async (req, res) => {
|
|
try {
|
|
const user = await User.findById(req.user.id);
|
|
|
|
if (!user || !user.myCart || user.myCart.length < 0) {
|
|
return res.json({ cartItems: [], totalPrice: 0 }); // Handle empty cart
|
|
}
|
|
|
|
const cartItems = user.myCart;
|
|
let totalPrice = 0;
|
|
|
|
for (const item of cartItems) {
|
|
const findItemPrice = await Product.findById(item.productId);
|
|
const subtotal = findItemPrice.price * item.quantity;
|
|
totalPrice += subtotal;
|
|
item.price = findItemPrice.price;
|
|
|
|
// Add subtotal to the item object for clarity in response
|
|
item.subtotal = subtotal;
|
|
}
|
|
|
|
res.json({ cartItems, totalPrice });
|
|
} catch (error) {
|
|
console.error(error);
|
|
res.status(500).json({ message: 'Error fetching cart details' });
|
|
}
|
|
};
|
|
|
|
module.exports.getProduct = (request, response) => {
|
|
let reqParams = request.params.productId;
|
|
|
|
Product.findById(reqParams).then(result => response.send(result))
|
|
.catch(error => response.send(error));
|
|
|
|
}
|