Untitled
unknown
plain_text
9 months ago
20 kB
2
Indexable
// controllers/productController.js const mongoose = require('mongoose'); const Product = require('../Models/productModel.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 User = require('../Models/userModel.js'); const Image = require('../Models/imageModel.js'); const catchAsync = require('../utils/catchAsync.js'); const AppError = require('../utils/appError.js'); const multer = require('multer'); const { isValidObjectId } = require('mongoose'); const defaultImage = '/img/products/default-product-image.png'; // Chemin vers l'image par défaut const upload = multer(); exports.uploadImages = upload.array('images'); const isImage = (image) => { if (image == 'image/png' || image == 'image/jpeg' || image == 'image/jpg') { return true; } return false; }; exports.addProduct = catchAsync(async (req, res, next) => { let { sku, quantity, name, description, categories, subcategories = [], groups = [], brand, tags, pricing, visibility } = req.body; quantity = parseInt(quantity); const skuRegex = /^[a-zA-Z0-9_-]{4,16}$/; visibility = visibility === 'true'; // Validation checks if (!sku || !skuRegex.test(sku)) { return next(new AppError('Invalid SKU format', 400)); } if (!quantity || typeof quantity !== 'number' || quantity < 0) { return next(new AppError('Invalid quantity format', 400)); } if (!categories || !Array.isArray(categories) || !categories.length) { return next(new AppError('Categories array cannot be empty', 400)); } const existingProduct = await Product.findOne({ sku }); if (existingProduct) { return next(new AppError('Product with the same SKU already exists', 400)); } // Processing images const imageDocuments = req.body.images.map((base64Str) => ({ image: new Buffer.from(base64Str, 'base64') })); const imageInsertionResults = await Image.insertMany(imageDocuments); const imgs = imageInsertionResults.map((doc) => doc._id); // Filter out any invalid ObjectIds from subcategories and groups const validSubcategories = subcategories.filter((subcatId) => isValidObjectId(subcatId)); const validGroups = groups.filter((groupId) => isValidObjectId(groupId)); // Validate brand if provided let validBrand; if (brand && isValidObjectId(brand)) { const existingBrand = await Brand.findById(brand); if (!existingBrand) { return next(new AppError('Brand not found', 404)); } validBrand = brand; } // Create and save the new product const product = new Product({ sku, quantity, name, description, images: imgs, categories, subcategories: validSubcategories, groups: validGroups, brand: validBrand, tags, pricing, visibility }); await product.save(); res.status(201).json({ success: true, message: 'The product has been successfully added', product }); }); exports.updateProduct = catchAsync(async (req, res, next) => { let body = JSON.parse(JSON.stringify(req.body)); const productId = req.params.id; console.log(productId); const session = await mongoose.startSession(); session.startTransaction(); try { if (!isValidObjectId(productId)) { return next(new AppError('Invalid product ID', 400)); } const product = await Product.findById(productId); if (!product) { return next(new AppError('Product not found', 400)); } let { sku, quantity, name, description, categories, subcategories, groups, brand, pricing, images } = body; // Update SKU if provided and unique if (sku && sku !== product.sku) { const existingProduct = await Product.findOne({ sku }); if (existingProduct && existingProduct._id.toString() !== productId) { return next(new AppError('Product with the same SKU already exists', 400)); } product.sku = sku; } if (quantity) { product.quantity = parseInt(quantity); } if (name) { product.name = name; } if (description) { product.description = description; } if (categories) { const ids = await checkCategories(categories, next); console.log(ids); product.categories = ids; } if (subcategories) { const ids = await checkSubCategories(subcategories, categories, next); product.subcategories = ids; } if (groups) { const ids = await checkGroups(groups, subcategories, next); product.groups = ids; } if (pricing) { product.pricing = pricing; // Make sure to validate or adjust pricing structure as needed } // Update brand if valid ObjectId if (brand && isValidObjectId(brand)) { const existingBrand = await Brand.findById(brand); if (!existingBrand) { return next(new AppError('Brand not found', 404)); } product.brand = brand; } // Process images if provided if (images && images.length) { const imageDocuments = images.map((base64Str) => ({ image: new Buffer.from(base64Str, 'base64') })); await Image.deleteMany({ _id: { $in: product.images } }, { session }); const imageInsertionResults = await Image.insertMany(imageDocuments, { session }); product.images = imageInsertionResults.map((doc) => doc._id); } await product.save(); await session.commitTransaction(); session.endSession(); res.status(200).json({ message: 'Product updated successfully', product }); } catch (error) { await session.abortTransaction(); session.endSession(); return next(error); } }); exports.viewProduct = catchAsync(async (req, res, next) => { const productId = req.params.id; // Validate the productId if (!isValidObjectId(productId)) { return res.status(400).json({ message: 'Invalid product ID' }); } const pathsAndFields = [ { path: 'subcategories', select: 'subcategory' }, { path: 'categories', select: 'category' }, { path: 'groups', select: 'group' }, { path: 'brand', select: 'brand' }, { path: 'offer', select: 'discount' }, ]; const product = await Product.findById(productId).populate(pathsAndFields).exec(); if (!product) { return res.status(404).json({ message: 'Product not found' }); } res.status(200).json({ message: 'Product fetched successfully', product: product }); }); exports.deleteProduct = catchAsync(async (req, res, next) => { const productId = req.params.id; // First, find the product to get the image IDs const productToDelete = await Product.findById(productId); if (!productToDelete) { return res.status(404).json({ message: 'Product not found' }); } // Delete the product await Product.findByIdAndDelete(productId); // Now delete each associated image if (productToDelete.images && productToDelete.images.length > 0) { for (const imageId of productToDelete.images) { // Assuming imageId is the actual ID, if it's a reference to an image object, you might need to adjust await Image.findByIdAndDelete(imageId); } } res.status(200).json({ message: 'Product and associated images deleted successfully' }); }); exports.getProducts = catchAsync(async (req, res, next) => { const requestedPage = parseInt(req.query.page) || 1; // Requested page number const productsPerPage = parseInt(req.query.limit) || 10; // Requested page number // Count total number of products const count = await Product.countDocuments(); // Get products for the requested page const products = await Product.find().populate({ path: 'offer', select: 'discount' }) .skip((requestedPage - 1) * productsPerPage) .limit(productsPerPage) .select('-_v'); // Exclude the '_v' field from the JSON response res.status(200).json({ count, currentPage: requestedPage, productsPerPage, products }); }); // Route pour la recherche SKU exports.searchbySku = async (req, res) => { try { // Extract SKU and pagination parameters from query parameters const { sku } = req.query; let { page, limit } = req.query; // Check if SKU is provided if (!sku) { return res.status(400).json({ error: 'SKU is required' }); } // Default to page 1 if not provided or invalid and limit to 10 if not provided or invalid page = page ? parseInt(page, 10) : 1; limit = limit ? parseInt(limit, 10) : 10; // Calculate the skip value const skip = (page - 1) * limit; // Search for products in the database based on SKU with pagination const products = await Product.find({ sku: { $regex: '^' + sku, $options: 'i' } }) .populate({ path: 'offer', select: 'discount' }) .skip(skip) .limit(limit); // Find total number of products to calculate total pages const totalProducts = await Product.countDocuments({ sku: { $regex: '^' + sku, $options: 'i' } }); const totalPages = Math.ceil(totalProducts / limit); // Handle case where no products are found with the specified SKU if (products.length === 0) { return res.status(404).json({ message: 'No products found with the specified SKU' }); } // Return the found products along with pagination data res.json({ products, pagination: { totalProducts, totalPages, currentPage: page, limit } }); } catch (error) { console.error(error); res.status(500).json({ error: 'Internal Server Error' }); } }; exports.productInStock = catchAsync(async (req, res, next) => { if (req.body.stock == 1) { let products = await Product.find({ quantity: { $gt: 0 } }) .populate({ path: 'offer', select: 'discount' }); if (products) { res.status(200).json({ products }); } else { return next(new AppError('There are no products with this filter', 400)); } } else if (req.body.stock == 0) { let products = await Product.find({ quantity: { $eq: 0 } }) .populate({ path: 'offer', select: 'discount' }); if (products) { res.status(200).json({ products }); } else { return next(new AppError('There are no products with this filter', 400)); } } else { return next(new AppError('invalad value', 400)); } }); exports.productVisibility = catchAsync(async (req, res, next) => { if (req.body.visibility == 1) { let products = await Product.find({ visibility: true }) .populate({ path: 'offer', select: 'discount' });; if (products) { res.status(200).json({ products }); } else { return next(new AppError('There are no products with this filter', 400)); } } if (req.body.visibility == 0) { let products = await Product.find({ visibility: false }) .populate({ path: 'offer', select: 'discount' }); if (products) { res.status(200).json({ products }); } else { return next(new AppError('There are no products with this filter', 400)); } } }); exports.productByCategory = catchAsync(async (req, res, next) => { let category = await Category.findById(req.body.id_category); if (category) { const products = await Product.find({ categories: req.body.id_category }) .populate({ path: 'offer', select: 'discount' }); if (products) { res.status(200).json({ products }); } else { return next(new AppError('this product no existe', 400)); } } else { return next(new AppError('this category no existe', 400)); } }); exports.deleteProducts = catchAsync(async (req, res, next) => { const productIds = req.body.products; if (!Array.isArray(productIds) || productIds.length === 0) { return next(new AppError('Invalid or empty product IDs array', 400)); } // Convert string IDs to mongoose ObjectId const ids = productIds.map((id) => mongoose.Types.ObjectId(id)); // Find products to retrieve their images before deletion const products = await Product.find({ _id: { $in: ids } }); if (products.length === 0) { return next(new AppError('No products found for deletion', 404)); } // Collect all image IDs to delete const imagesToDelete = products.reduce((acc, product) => { if (product.images && product.images.length) { acc.push(...product.images.map((imageId) => mongoose.Types.ObjectId(imageId))); } return acc; }, []); // Delete images if there are any to delete if (imagesToDelete.length > 0) { await Image.deleteMany({ _id: { $in: imagesToDelete } }); } // Finally, delete the products await Product.deleteMany({ _id: { $in: ids } }); res.status(200).json({ message: 'Products and associated images deleted successfully', deletedCount: products.length }); }); exports.productsVisibilityChange = catchAsync(async (req, res, next) => { const productIds = req.body.products; let visibility = req.body.visibility; let obj = {}; if (visibility) { if (visibility == 'true') { obj.visibility = true; } else if (visibility == 'false') { obj.visibility = false; } else { return next(new AppError('invalid visibility value', 400)); } } else { return next(new AppError('visiility required', 400)); } if (productIds) { if (Array.isArray(productIds)) { let ids = new Array(); for (let j = 0; j < productIds.length; j++) { try { ids.push(new mongoose.Types.ObjectId(productIds[j])); } catch (e) { return next(new AppError('Invalid id.', 401)); } } const productsapdated = await Product.updateMany({ _id: { $in: ids } }, obj); if (productsapdated) { res.status(200).json({ message: 'Product visibility updated successfully', productsapdated }); } else { return next(new AppError('no products', 400)); } } else { return next(new AppError('invalid format for products array', 400)); } } }); exports.productsStockStatusChange = catchAsync(async (req, res, next) => { const productIds = req.body.products; let status = req.body.stockstatus; let obj = {}; if (status) { if (status == true) { obj.quantity = 0; } else { return next(new AppError('invalid status value', 400)); } } else { return next(new AppError('status required', 400)); } console.log(productIds); if (productIds) { if (Array.isArray(productIds)) { let ids = new Array(); for (let j = 0; j < productIds.length; j++) { try { ids.push(new mongoose.Types.ObjectId(productIds[j])); } catch (e) { return next(new AppError('Invalid id.', 401)); } } const productsapdated = await Product.updateMany({ _id: { $in: ids } }, obj); if (productsapdated) { res.status(200).json({ message: 'Products stockstatus changed successfully', productsapdated }); } else { return next(new AppError('no products', 400)); } } else { return next(new AppError('invalid format for products array', 400)); } } }); exports.productFilter = catchAsync(async (req, res, next) => { let { visibility, status, id_category } = req.body; const page = parseInt(req.query.page); const limit = parseInt(req.query.limit); try { var Id = new mongoose.Types.ObjectId(id_category); } catch (e) { return next(new AppError('Invalid id.', 401)); } let obj = {}; if (visibility) { if (visibility == 'true') { obj.visibility = true; } else if (visibility == 'false') { obj.visibility = false; } else { return next(new AppError('invalid visibility value', 400)); } } if (status) { if (status == 'true') { obj.quantity = { $gt: 0 }; } else if (status == 'false') { obj.quantity = 0; } else { return next(new AppError('invalid visibility value', 400)); } } if (id_category) { let category = await Category.findById(Id); if (category) { obj.categories = Id; } else { return next(new AppError('invalid categorie 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' }, ]; const count = await Product.find(obj).count(); console.log(count); let countPages = count % limit == 0 ? parseInt(count / limit) : parseInt(count / limit) + 1; const products = await Product.find(obj) .populate(pathsAndFields) .skip((page - 1) * limit) .limit(limit); if (products) { res.status(200).json({ products }); } else { return next(new AppError('this product no existe', 400)); } }); const checkCategories = async (categories, next) => { let ids = new Array(); if (categories.length > 0) { for (const category of categories) { if (!category) { return next(new AppError('id is required', 400)); } let id = toObjectId(category, next); const existingCategory = await Category.find({ _id: id }); ids.push(id); if (existingCategory?.length < 1) { return next(new AppError('Category not found', 400)); } } } return ids; }; const checkSubCategories = async (subcategories, categories, 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: { $in: categories } }); ids.push(id); if (existingSubCategory?.length < 1) { return next(new AppError('SubCategory not found in this category', 400)); } } } return ids; }; const checkGroups = async (groups, subcategories, 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 existingGroup = await Group.find({ _id: id, subcategory: { $in: subcategories } }); ids.push(id); if (existingGroup?.length < 1) { return next(new AppError('group not found in this category', 400)); } } } return ids; }; const toObjectId = (id, next) => { try { return new mongoose.Types.ObjectId(id); } catch (e) { return next(new AppError('Invalid id.', 401)); } };
Editor is loading...
Leave a Comment