Untitled
unknown
plain_text
a year ago
19 kB
6
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' } })
.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 } });
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 } });
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 });
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 });
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 });
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: 'descount' },
];
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