Untitled
unknown
plain_text
a year ago
32 kB
5
Indexable
const mongoose = require('mongoose'); const Fuse = require('fuse.js'); const User = require('../Models/userModel.js'); const SubCategory = require('../Models/subcategoryModel.js'); const Group = require('../Models/groupModel.js'); const Brand = require('../Models/brandModel.js'); const Category = require('../Models/categoryModel.js'); const Product = require('../Models/productModel.js'); const AppError = require('../utils/appError.js'); const catchAsync = require('../utils/catchAsync.js'); const { isDecimal } = require('validator'); const Client = require('../Models/clientModel.js'); const Cart = require('../Models/cartModel.js'); const { createAndSendToken } = require('./authController.js'); const Order = require('../Models/orderModel.js'); const { isValidEmail, isValidName, isValidPhoneNumber } = require('./../utils/validationfunctions.js'); const fuseOptions = { threshold: 0.3, keys: ['name.fr', 'name.en', 'categories.category', 'subcategories.subcategory', 'groups.group', 'brand.brand'] }; exports.productFilter = catchAsync(async (req, res, next) => { let { brands, subcategories, groups, id_category, pricing } = req.body; console.log('req.body :', req.body); const page = parseInt(req.query.page); const limit = parseInt(req.query.limit); let arrayOR = new Array(); let arrayAND = new Array(); let obj = {}; if (id_category) { const Id = toObjectId(id_category); let category = await Category.findById(Id); if (category) { arrayAND.push({ categories: Id }); } else { return next(new AppError('invalid categorie value', 400)); } } else { return next(new AppError('category required', 400)); } if (subcategories) { const ids = await checkSubCategories(subcategories, id_category, next); if (ids.length > 0) { arrayOR.push({ subcategories: { $in: ids } }); } } if (groups) { const ids = await checkGroups(groups, id_category, next); if (ids.length > 0) { arrayOR.push({ groups: { $in: ids } }); } } if (brands) { const ids = await checkBrands(brands, next); if (ids.length > 0) { arrayOR.push({ brand: { $in: ids } }); } } if (arrayOR.length) { arrayAND.push({ $or: arrayOR }); } obj.$and = arrayAND; console.log(obj); if (pricing) { console.log(pricing); if (pricing != -1 && pricing != 1) { return next(new AppError('invalid pricing value ', 400)); } } const paths = ['subcategories', 'categories', 'groups', 'brand']; const pathsAndFields = [ { path: 'subcategories', select: 'subcategory' }, { path: 'categories', select: 'category' }, { path: 'groups', select: 'group' }, { path: 'brand', select: 'brand' }, { path: 'offer', select: ['discount','status'] } ]; const count = await Product.find(obj).count(); let countPages = count % limit == 0 ? parseInt(count / limit) : parseInt(count / limit) + 1; let products = []; if (pricing) { products = await Product.find(obj) .sort({ 'pricing.publicPrice': pricing }) .populate(pathsAndFields) .skip((page - 1) * limit) .limit(limit); } else { products = await Product.find(obj) .populate(pathsAndFields) .skip((page - 1) * limit) .limit(limit); } if (products) { res.status(200).json({ products, count }); } else { return next(new AppError('this product no existe', 400)); } }); exports.getAllByCategory = catchAsync(async (req, res, next) => { let { id_category } = req.body; const page = parseInt(req.query.page); const limit = parseInt(req.query.limit); let obj = {}; if (id_category) { const Id = toObjectId(id_category); let category = await Category.findById(Id); if (category) { obj.categories = Id; } else { return next(new AppError('invalid category value', 400)); } } else { return next(new AppError('category required', 400)); } const subcategories = await SubCategory.find({ category: id_category }); let groups = new Array(); if (subcategories?.length > 0) { const ids = new Array(); for (let i = 0; i < subcategories.length; i++) { ids.push(subcategories[i]._id); } groups = await Group.find({ subcategory: { $in: ids } }); } const id_brands = await Product.distinct('brand', { categories: id_category }); const brands = await Brand.find({ _id: { $in: id_brands } }); const paths = ['subcategories', 'categories', 'groups', 'brand']; const pathsAndFields = [ { path: 'subcategories', select: 'subcategory' }, { path: 'categories', select: 'category' }, { path: 'groups', select: 'group' }, { path: 'brand', select: 'brand' } ]; const count = await Product.find(obj).count(); let countPages = count % limit == 0 ? parseInt(count / limit) : parseInt(count / limit) + 1; let products = []; products = await Product.find(obj) .populate(pathsAndFields) .skip((page - 1) * limit) .limit(limit); if (products) { res.status(200).json({ products, subcategories, groups, count, brands }); } else { return next(new AppError('this product no existe', 400)); } }); exports.searchGlobal = catchAsync(async (req, res, next) => { const { filter } = req.query; let { page, limit } = req.query; if (!filter) { return next(new AppError('filter is required', 400)); } page = page ? parseInt(page, 10) : 1; limit = limit ? parseInt(limit, 10) : 10; const skip = (page - 1) * limit; const results = await Product.aggregate([ { $lookup: { from: 'categories', localField: 'categories', foreignField: '_id', as: 'categories' } }, { $lookup: { from: 'subcategories', localField: 'subcategories', foreignField: '_id', as: 'subcategories' } }, { $lookup: { from: 'groups', localField: 'groups', foreignField: '_id', as: 'groups' } }, { $lookup: { from: 'brands', localField: 'brand', foreignField: '_id', as: 'brand' } }, { $lookup: { from: 'offers', localField: 'offer', foreignField: '_id', pipeline:[ {$project : {discount : 1,status:1}}], as: 'offer' } } ]); const array = new Array(); for (let i = 0; i < results.length; i++) { array[i] = { name: { fr: results[i]?.name.fr, en: results[i]?.name.en }, categories: [], subcategories: [], groups: [], brand: [] }; for (let j = 0; j < results[i]?.categories.length; j++) { if (results[i]?.categories[j].category) { array[i].categories.push({ category: results[i]?.categories[j].category }); } } for (let j = 0; j < results[i]?.subcategories.length; j++) { array[i].subcategories[j] = { subcategory: results[i]?.subcategories[j].subcategory }; } for (let j = 0; j < results[i]?.groups.length; j++) { array[i].groups[j] = { group: results[i]?.groups[j].group }; } for (let j = 0; j < results[i]?.brand.length; j++) { array[i].brand[j] = { brand: results[i]?.brand[j].brand }; } } const fuse = new Fuse(array, fuseOptions); const lists = fuse.search(filter); let indexs = new Array(); for (const list of lists) { indexs.push(list.refIndex); } let ProductsList = indexs.map(function (item) { return results[item]; }); let products = ProductsList.slice((page - 1) * limit, page * limit); res.status(200).json({ products, count: products.length }); }); const checkSubCategories = async (subcategories, id_category, next) => { let ids = new Array(); if (subcategories.length > 0) { for (const subcategory of subcategories) { if (!subcategory) { return next(new AppError('id is required', 400)); } let id = toObjectId(subcategory, next); const existingSubCategory = await SubCategory.find({ _id: id, category: id_category }); ids.push(id); if (existingSubCategory?.length < 1) { return next(new AppError('SubCategory not found in this category', 400)); } } } return ids; }; const checkGroups = async (groups, id_category, next) => { let ids = new Array(); if (groups.length > 0) { for (const group of groups) { if (!group) { return next(new AppError('id is required', 400)); } let id = toObjectId(group, next); const subcategories = await SubCategory.find({ category: id_category }); if (subcategories?.length > 0) { const ids_subcat = new Array(); for (let i = 0; i < subcategories.length; i++) { ids_subcat.push(subcategories[i]._id); } const existingGroup = await Group.find({ _id: id, subcategory: { $in: ids_subcat } }); ids.push(id); if (existingGroup?.length < 1) { return next(new AppError('group not found in this category', 400)); } } } } return ids; }; const checkBrands = async (brands, next) => { let ids = new Array(); if (brands.length > 0) { for (const brand of brands) { if (!brand) { return next(new AppError('id is required', 400)); } let id = toObjectId(brand, next); const existingBrand = await Brand.findById(id); ids.push(id); if (!existingBrand) { return next(new AppError('Brand not found', 400)); } } } return ids; }; const toObjectId = (id, next) => { try { return new mongoose.Types.ObjectId(id); } catch (e) { return next(new AppError('Invalid id.', 401)); } }; exports.AddToCart = catchAsync(async (req, res, next) => { // Extracting necessary information from the request body const { productQuantities, userId } = req.body; // Find the user by ID and populate the profile const user = await User.findById(userId); if (!user) { return next(new AppError('User not found', 400)); } // Extract the client profile from the user const client = await Client.findById(user.profile); if (!client) { return next(new AppError('Client profile not found', 400)); } // Get the user's cart from the profile let cart = client.cart; // If the user doesn't have a cart, create a new one if (!cart) { newCart = await Cart.create({ products: [] }); client.cart = newCart._id; await client.save(); cart = newCart._id; } console.log(cart); // Find the user's cart and populate products if (!Array.isArray(productQuantities)) { return next(new AppError('Products is not an array', 400)); } const userCart = await Cart.findById(cart).populate('products.product'); // Check if the product exists for (const { productId, quantity } of productQuantities) { // Check if the product exists const product = await Product.findById(toObjectId(productId)); if (!product) { return next(new AppError(`Product with ID ${productId} not found`, 404)); } console.log(userCart); if (userCart && userCart.products) { // Check if the product is already in the cart const existingProductIndex = userCart.products.findIndex( (item) => item.product && item.product.equals(productId) ); const product = await Product.findById(productId); if (existingProductIndex !== -1) { // If the product is already in the cart, update the quantity userCart.products[existingProductIndex].quantity += parseInt(quantity); userCart.products[existingProductIndex].price = product.pricing.publicPrice * parseInt(userCart.products[existingProductIndex].quantity); if (userCart.products[existingProductIndex].quantity > product.quantity) { return next(new AppError(`Requested quantity of Product ${product.sku} exceeds available stock`, 400)); } } else { // Otherwise, add the product to the cart with the specified quantity userCart.products.push({ product: productId, quantity: quantity, price: parseInt(product.pricing.publicPrice) * parseInt(quantity) }); // Update the total price of the cart userCart.totalPrice = userCart.products.reduce((total, item) => total + item.price, 0); } } else { // Handle the case where userCart or userCart.products is null or undefined return next(new AppError('Error: userCart or userCart.products is null or undefined', 400)); } } await userCart.save(); res.status(200).json({ message: 'Product added to cart successfully', cart: userCart }); // Save the changes to the user's cart // Return success response with updated cart details }); exports.getWishList = catchAsync(async (req, res, next) => { const { userId } = req.body; console.log(userId); const client = await User.aggregate([ { $match: { _id: toObjectId(userId) } }, { $lookup: { from: 'clients', localField: 'profile', foreignField: '_id', as: 'client', pipeline: [ { $lookup: { from: 'products', localField: 'wishlist', foreignField: '_id', pipeline: [{ $lookup: { from: 'offers', localField: 'offer', foreignField: '_id', pipeline: [{$project:{discount:1,status:1}}], as: 'offer' } }], as: 'wishlist' } } ] } } ]); if(!client.length){ return next(new AppError('user not find', 400)); } res.status(200).json({ message: 'wishlist', wishlist: client[0]?.client[0]?.wishlist }); }); exports.RemoveFromCart = catchAsync(async (req, res, next) => { // Extract necessary information from the request body const { productId, userId } = req.body; // Find the user by ID const user = await User.findById(userId); if (!user) { return next(new AppError('User not found', 404)); } // Extract the client profile from the user const client = await Client.findById(user.profile); if (!client) { return next(new AppError('Client profile not found', 404)); } // Get the user's cart from the profile const cart = client.cart; if (!cart) { return next(new AppError('Cart not found', 404)); } // Find the user's cart and populate products const userCart = await Cart.findById(cart).populate('products.product'); // Check if userCart is not null or undefined if (userCart && userCart.products) { // Find the index of the product to remove const indexToRemove = userCart.products.findIndex((item) => item.product && item.product.equals(productId)); if (indexToRemove !== -1) { // Remove the product from the cart userCart.products.splice(indexToRemove, 1); // Save the changes to the user's cart await userCart.save(); // Return success response return res.status(200).json({ message: 'Product removed from cart successfully', cart: userCart.products }); } else { // Product not found in the cart return next(new AppError('Product not found in the cart', 404)); } } else { // Handle the case where userCart or userCart.products is null or undefined console.error('Error: userCart or userCart.products is null or undefined'); return next(new AppError('Error processing request', 500)); } }); exports.decrementQuantity = catchAsync(async (req, res, next) => { // Extract necessary information from the request body const { productId, userId } = req.body; // Find the user by ID const user = await User.findById(userId); if (!user) { return next(new AppError('User not found', 404)); } // Extract the client profile from the user const client = await Client.findById(user.profile); if (!client) { return next(new AppError('Client profile not found', 404)); } // Get the user's cart from the profile const cart = client.cart; if (!cart) { return next(new AppError('Cart not found', 404)); } // Find the user's cart and populate products const userCart = await Cart.findById(cart).populate('products.product'); // Check if userCart is not null or undefined if (userCart && userCart.products) { // Find the index of the product to update const indexToUpdate = userCart.products.findIndex((item) => item.product && item.product.equals(productId)); if (indexToUpdate !== -1) { // Decrement the quantity of the product userCart.products[indexToUpdate].quantity--; // If the quantity becomes zero, remove the product from the cart if (userCart.products[indexToUpdate].quantity === 0) { userCart.products.splice(indexToUpdate, 1); } // Update the price of the product const product = userCart.products[indexToUpdate].product; userCart.products[indexToUpdate].price = product.pricing.publicPrice * userCart.products[indexToUpdate].quantity; // Update the total price of the cart userCart.totalPrice = userCart.products.reduce((total, item) => total + item.price, 0); // Save the changes to the user's cart await userCart.save(); // Return success response return res.status(200).json({ message: 'Product quantity decremented successfully', cart: userCart.products }); } else { // Product not found in the cart return next(new AppError('Product not found in the cart', 404)); } } else { // Handle the case where userCart or userCart.products is null or undefined console.error('Error: userCart or userCart.products is null or undefined'); return next(new AppError('Error processing request', 500)); } }); exports.incrementQuantity = catchAsync(async (req, res, next) => { // Extract necessary information from the request body const { productId, userId } = req.body; // Find the user by ID const user = await User.findById(userId); if (!user) { return next(new AppError('User not found', 404)); } // Extract the client profile from the user const client = await Client.findById(user.profile); if (!client) { return next(new AppError('Client profile not found', 404)); } // Get the user's cart from the profile const cart = client.cart; if (!cart) { return next(new AppError('Cart not found', 404)); } // Find the user's cart and populate products const userCart = await Cart.findById(cart).populate('products.product'); // Check if userCart is not null or undefined if (userCart && userCart.products) { // Find the index of the product to update const indexToUpdate = userCart.products.findIndex((item) => item.product && item.product.equals(productId)); if (indexToUpdate !== -1) { // Increment the quantity of the product userCart.products[indexToUpdate].quantity++; // Update the price of the product const product = userCart.products[indexToUpdate].product; userCart.products[indexToUpdate].price = product.pricing.publicPrice * userCart.products[indexToUpdate].quantity; // Update the total price of the cart userCart.totalPrice = userCart.products.reduce((total, item) => total + item.price, 0); // Save the changes to the user's cart await userCart.save(); } } else { // Handle the case where userCart or userCart.products is null or undefined console.error('Error: userCart or userCart.products is null or undefined'); return next(new AppError('Error processing request', 500)); } }); exports.AddToWishlist = catchAsync(async (req, res, next) => { // Extract necessary information from the request body const { userID, productID } = req.body; // Find the user by ID and check if the client profile and wishlist exist const user = await User.findById(userID); if (!user) { return next(new AppError('User not found', 404)); } const client = await Client.findById(user.profile); if (!client) { return next(new AppError('Client not found', 404)); } // Check if the product exists and is available for wishlisting const product = await Product.findById(productID); if (!product) { return next(new AppError(`Product with ID ${productID} not found`, 404)); } // Check if the product already exists in the client's wishlist const productExistsInWishlist = await Client.findOne({ _id: user.profile, wishlist: { $in: [productID] } }); if (productExistsInWishlist) { return res.status(400).json({ message: 'Product already exists in the wishlist' }); } // Add the product to the wishlist client.wishlist.push(product); await client.save(); // Return success response res.status(200).json({ message: 'Product added to wishlist successfully', wishlist: client.wishlist }); }); exports.RemoveFromWishlist = catchAsync(async (req, res, next) => { // Extract necessary information from the request body const { userID, productID } = req.body; // Find the user by ID and check if the client profile and wishlist exist const user = await User.findById(userID); if (!user) { return next(new AppError('User not found', 404)); } const client = await Client.findById(user.profile); if (!client) { return next(new AppError('Client not found', 404)); } // Check if the product exists in the client's wishlist if (!client.wishlist.includes(productID)) { return res.status(400).json({ message: 'Product does not exist in the wishlist' }); } // Remove the product from the client's wishlist using $pull await Client.findByIdAndUpdate(client._id, { $pull: { wishlist: productID } }); // Return success response res.status(200).json({ message: 'Product removed from wishlist successfully' }); }); exports.getProductDetails = catchAsync(async (req, res, next) => { // Get product details const productId = req.params.productId; const product = await Product.findById(productId); if (!product) { return next(new AppError('Product not found', 404)); } // Check if the product is already in the user's cart let isInCart = false; if (req.user) { const user = await User.findById(req.user.id); const client = await Client.findById(user.profile); const cart = await Cart.findById(client.cart).populate('products.product'); isInCart = cart.products.some((item) => item.product.equals(productId)); } // Find related products (either in category, subcategories, or groups) const relatedProducts = await Product.find({ $or: [ { categories: { $in: product.categories } }, { subcategories: { $in: product.subcategories } }, { groups: { $in: product.groups } } ] }).populate({ path: 'offer', select: ['discount','status'] }) .limit(10); // Limit to 10 related products // Get the number of products sold in the last 7 days const startDate = new Date(); startDate.setDate(startDate.getDate() - 7); // Calculate the date 7 days ago const endDate = new Date(); const productsSoldLast7Days = await Order.aggregate([ { $match: { createdAt: { $gte: startDate, $lte: endDate }, 'products.product': mongoose.Types.ObjectId(productId) } }, { $group: { _id: null, totalSold: { $sum: '$products.quantity' } } } ]); const soldLast7Days = productsSoldLast7Days.length > 0 ? productsSoldLast7Days[0].totalSold : 0; res.status(200).json({ product, isInCart, relatedProducts, soldLast7Days }); }); exports.checkout = async (req, res, next) => { try { // Get the user's cart const cart = await Cart.findOne({ user: req.user.id }).populate('products.product'); if (!cart) { return res.status(404).json({ message: 'Cart not found' }); } // Create order const order = new Order({ user: req.user.id, products: cart.products.map((item) => ({ product: item.product, quantity: item.quantity })), shipping: { method: req.body.shippingMethod, // Assuming the shipping method is passed in the request body cost: req.body.shippingCost // Assuming the shipping cost is passed in the request body }, status: 'pending' // Set the initial status of the order }); // Calculate total price of the order order.totalPrice = cart.products.reduce((total, item) => total + item.price, 0) + order.shipping.cost; // Save the order await order.save(); // Clear user's cart after checkout cart.products = []; cart.totalPrice = 0; await cart.save(); // Return success response res.status(200).json({ message: 'Order placed successfully', order }); } catch (error) { next(error); } }; exports.viewProduct = catchAsync(async (req, res, next) => { const productId = toObjectId(req.query.id); const pathsAndFields = [ { path: 'subcategories', select: 'subcategory' }, { path: 'categories', select: 'category' }, { path: 'groups', select: 'group' }, { path: 'brand', select: 'brand' }, { path: 'offer', select: ['discount','status'] }, ]; const product = await Product.findById(productId).populate({ path: 'offer', select: ['discount','status'] }); if (!product) { return next(new AppError('Product not found', 400)); } const solds = await Order.aggregate([ { $match: { 'products.product': productId } }, { $unwind: '$products' }, { $match: { 'products.product': productId } }, { $group: { _id: null, totalQuantity: { $sum: '$products.quantity' } } } ]); const relatedProducts = await RelatedProducts(productId, next); res.status(200).json({ message: 'Product fetched successfully', product: product, relatedProducts: relatedProducts, sold: solds[0]?.totalQuantity ? solds[0].totalQuantity : 0 }); }); const RelatedProducts = async (id, next) => { let list = new Array(); let ids_list = new Set(); ids_list.add(id.toString()); let prod = await Product.findById(id); if (prod.groups.length > 0) { list.push( ...(await Product.find({ groups: { $in: prod.groups }, _id: { $nin: Array.from(ids_list).map((id) => toObjectId(id)) } }).populate({ path: 'offer', select: ['discount','status'] }) .limit(10)) ); for (const product of list) { ids_list.add(product._id.toString()); } } if (list.length < 10) { if (prod.subcategories.length > 0) { list.push( ...(await Product.find({ subcategories: { $in: prod.subcategories }, _id: { $nin: Array.from(ids_list).map((id) => toObjectId(id)) } }).populate({ path: 'offer', select: ['discount','status'] }) .limit(10 - list.length)) ); } for (const product of list) { ids_list.add(product._id.toString()); } } if (list.length < 10) { if (prod.categories.length > 0) { list.push( ...(await Product.find({ categories: { $in: prod.categories }, _id: { $nin: Array.from(ids_list).map((id) => toObjectId(id)) } }).populate({ path: 'offer', select: ['discount','status'] }) .limit(10 - list.length)) ); } for (const product of list) { ids_list.add(product._id.toString()); } } return list; }; exports.updateClientProfile = catchAsync(async (req, res, next) => { console.log(req.user); const user = await User.findById(req.user.id); // Assuming req.user.id contains the ObjectId of the user if (!user) { return next(new AppError('User not found', 404)); } console.log(req.body); const { firstName, lastName, email, phone, address, gender } = req.body; if (firstName || lastName) { const fullName = [firstName, lastName].filter(Boolean).join(' '); user.name = fullName; } if (email) { user.email = email; } if (phone) { user.phone = phone; } // Update address if provided if (address) { user.fulladdress.address = address?.address; user.fulladdress.zipCode = address?.zipCode; user.fulladdress.city = address?.city; } if (gender) { user.gender = gender; } await user.save(); res.status(200).json({ status: ' the client profile is updated successfully', data: user }); }); exports.getClients = catchAsync(async (req, res, next) => { const {phone} = req.query; const page = parseInt(req.query.page); const limit = parseInt(req.query.limit); console.log(page +" "+limit) let search = {role : "client"} if(phone){ search.phone = { $regex: phone , $options: 'i' } } const count = await User.find(search).count(); console.log(count); let clients = null let countPages = count % limit == 0 ? parseInt(count / limit) : parseInt(count / limit) + 1; // if(count > 10){ clients = await User.find(search) .skip((page - 1) * limit) .limit(limit); /* }else{ clients = await User.find(search) } */ const data = clients.reduce((result, client) => { let obj = {}; obj._id = client._id; obj.name = client.name; obj.joiningDate = client.createdAt; obj.email = client.email; obj.phone = client.phone; obj.profileImage = client.photo; result.push(obj); return result; }, []); res.status(200).json({ status: "success", data: data, count : count }); }) exports.deleteClient = catchAsync(async (req, res, next) => { const clientId = req.params.id; if (!clientId) { return next(new AppError('Please provide the client ID', 400)); } // Start a Mongoose session const session = await mongoose.startSession(); try { // Use the session for transaction await session.withTransaction(async () => { // 1. Get the user document const user = await User.findById(clientId).session(session); // 2. Check if the user exists if (!user) { return next(new AppError('client not found', 404)); } // 3. Determine the type of profile based on the user's role if (user.role !== 'client') { return next(new AppError('Invalid role', 400)); } // 4. Delete the client's profile document await Client.findByIdAndDelete(user.profile).session(session); // Additional Step: Delete the image document if it exists if (user.photo) { await Image.findByIdAndDelete(user.photo).session(session); } // 6. Delete the user document await User.findByIdAndDelete(clientId).session(session); }); // Commit the session if everything went well await session.commitTransaction(); // Respond with a success message res.status(200).json({ status: 'success', message: 'Client deleted successfully' }); } catch (err) { // If any error occurs, abort the session await session.abortTransaction(); // Pass the error to the error handling middleware next(err); } finally { session.endSession(); } });
Editor is loading...
Leave a Comment