category and product updated and brand created

This commit is contained in:
Sibunnayak 2024-08-22 16:40:00 +05:30
parent b8e525e774
commit 69dc2cb1b4
11 changed files with 631 additions and 218 deletions

3
app.js
View File

@ -151,6 +151,7 @@ import SalesCoOrdinatorRoute from "./resources/SalesCoOrdinators/SalesCoOrdinato
import TerritoryManagerRoute from "./resources/TerritoryManagers/TerritoryManagerRoute.js";
// category Route
import categoryRoute from "./resources/Category/categoryRoutes.js";
import brandroute from "./resources/Brands/BrandsRoutes.js";
import RegistrationImageRoute from "./resources/RegistrationImage/RegistrationImageRoute.js";
import loginImageRoute from "./resources/LoginImage/LoginImageRoute.js";
import shopImageRoute from "./resources/ShopPageImage/ShopPageImageRoute.js";
@ -199,6 +200,8 @@ app.use("/api", ProductRouter);
// Category
app.use("/api/category", categoryRoute);
//Brand
app.use("/api/brand", brandroute);
// registration image
app.use("/api/registerImage", RegistrationImageRoute);
app.use("/api/loginImage", loginImageRoute);

Binary file not shown.

View File

@ -0,0 +1,111 @@
import mongoose from "mongoose";
import { BrandModel } from "./BrandsModel.js";
// Add new Brand
export const addBrand = async (req, res) => {
const { brandName } = req.body;
if (!req?.user) {
return res.status(400).json({ message: "Please login!" });
}
try {
if (!mongoose.Types.ObjectId.isValid(req.user._id)) {
return res.status(400).json({ message: "Please login again." });
}
if (!brandName) {
return res.status(400).json({ message: "Please provide a brand name" });
}
const brand = await BrandModel.create({
brandName,
addedBy: req.user._id,
});
return res.status(201).json({ success: true, brand, message: "Brand added successfully" });
} catch (error) {
res.status(500).json({
success: false,
message: error.message || "Something went wrong",
});
}
};
// Get all Brands
export const getBrands = async (req, res) => {
try {
const brands = await BrandModel.find().sort({ createdAt: -1 });
if (!brands.length) {
return res.status(404).json({ message: "No brands found" });
}
res.status(200).json({ success: true, brands });
} catch (error) {
res.status(500).json({
success: false,
message: error.message || "Something went wrong",
});
}
};
// Update Brand
export const updateBrand = async (req, res) => {
const { _id } = req.params;
const { brandName } = req.body;
if (!req?.user) {
return res.status(400).json({ message: "Please login!" });
}
if (!mongoose.Types.ObjectId.isValid(_id)) {
return res.status(404).json({ message: "Invalid brand ID" });
}
try {
const updatedBrand = await BrandModel.findByIdAndUpdate(
_id,
{ brandName },
{ new: true, runValidators: true }
);
if (!updatedBrand) {
return res.status(404).json({ message: "Brand not found" });
}
res.status(200).json({ success: true, updatedBrand, message: "Brand updated successfully" });
} catch (error) {
res.status(500).json({
success: false,
message: error.message || "Something went wrong",
});
}
};
// Delete Brand
export const deleteBrand = async (req, res) => {
const { _id } = req.params;
if (!req?.user) {
return res.status(400).json({ message: "Please login!" });
}
if (!mongoose.Types.ObjectId.isValid(_id)) {
return res.status(404).json({ message: "Invalid brand ID" });
}
try {
const deletedBrand = await BrandModel.findByIdAndDelete(_id);
if (!deletedBrand) {
return res.status(404).json({ message: "Brand not found" });
}
res.status(200).json({ success: true, deletedBrand, message: "Brand deleted successfully" });
} catch (error) {
res.status(500).json({
success: false,
message: error.message || "Something went wrong",
});
}
};

View File

@ -0,0 +1,18 @@
import mongoose from "mongoose";
const BrandSchema = new mongoose.Schema(
{
brandName: {
type: String,
required: [true, "Name of brand required"],
},
addedBy: {
type: mongoose.Schema.ObjectId,
ref: "User",
required: true,
},
},
{ timestamps: true }
);
export const BrandModel = mongoose.model("BrandModel", BrandSchema);

View File

@ -0,0 +1,26 @@
import express from "express";
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
import {
addBrand,
deleteBrand,
getBrands,
updateBrand,
} from "./BrandsController.js";
const router = express.Router();
router
.route("/add")
.post(isAuthenticatedUser, authorizeRoles("admin"), addBrand);
router.route("/getBrands").get(getBrands);
router
.route("/update/:_id")
.patch(isAuthenticatedUser, authorizeRoles("admin"), updateBrand);
router
.route("/delete/:_id")
.delete(isAuthenticatedUser, authorizeRoles("admin"), deleteBrand);
export default router;

View File

@ -6,7 +6,6 @@ const CategorySchema = new mongoose.Schema(
type: String,
required: [true, "Name of category required "],
},
categoryImage: {},
addedBy: {
type: mongoose.Schema.ObjectId,
ref: "User",

View File

@ -1,53 +1,43 @@
import mongoose from "mongoose";
import { CategoryModel } from "./CategoryModel.js";
import cloudinary from "../../Utils/cloudinary.js";
// Add new Category
export const addCategory = async (req, res) => {
const { categoryName } = req.body;
const { categoryImage } = req.files;
// console.log(categoryName, categoryImage);
if (!req?.user) return res.status(400).json({ message: "please login !" });
if (!req?.user) {
return res.status(400).json({ message: "Please login!" });
}
try {
if (!mongoose.Types.ObjectId.isValid(req.user._id)) {
return res.status(400).json({ message: "please login again " });
return res.status(400).json({ message: "Please login again." });
}
const result = await cloudinary.v2.uploader.upload(
categoryImage.tempFilePath,
{
folder: "GetSygnal/category",
}
);
if (result) {
const category = await CategoryModel.create({
categoryName,
categoryImage: result,
addedBy: req.user._id,
});
if (category) {
return res
.status(201)
.json({ success: true, category, message: "category Added" });
}
if (!categoryName) {
return res.status(400).json({ message: "Please provide a category name" });
}
const category = await CategoryModel.create({
categoryName,
addedBy: req.user._id,
});
return res.status(201).json({ success: true, category, message: "Category added successfully" });
} catch (error) {
res.status(500).json({
success: false,
message: error.message ? error.message : "Something went Wrong",
message: error.message || "Something went wrong",
});
}
};
// Get all Categories
export const getCategories = async (req, res) => {
try {
// if (!req?.user) return res.status(400).json({ message: "please login !" });
const categories = await CategoryModel.find().sort({
createdAt: -1,
});
const categories = await CategoryModel.find().sort({ createdAt: -1 });
if (!categories) {
if (!categories.length) {
return res.status(404).json({ message: "No categories found" });
}
@ -55,96 +45,68 @@ export const getCategories = async (req, res) => {
} catch (error) {
res.status(500).json({
success: false,
message: error.message ? error.message : "Something went wrong",
message: error.message || "Something went wrong",
});
}
};
// Update Category
export const updateCategory = async (req, res) => {
try {
if (!req?.user) return res.status(400).json({ message: "please login !" });
const { _id } = req.params;
const { categoryName } = req.body;
const olderImage = req.body?.olderImage;
const categoryImag = req.files?.categoryImage;
const { _id } = req.params;
const { categoryName } = req.body;
if (!mongoose.Types.ObjectId.isValid(_id)) {
return res.status(404).json({ error: "Can not find the document " });
}
// find the document with the id to delete the image from cloudinary
if (JSON.parse(olderImage).length == 0) {
const deletefromCloudinary = await CategoryModel.findOne({ _id: _id });
const deleteresponse = await cloudinary.v2.uploader.destroy(
deletefromCloudinary.categoryImage.public_id
);
if (deleteresponse) {
const result = await cloudinary.v2.uploader.upload(
categoryImag.tempFilePath,
{
folder: "GetSygnal/category",
}
);
const update = await CategoryModel.findOneAndUpdate(
{ _id: _id },
{ categoryName: categoryName, categoryImage: result }, // Provide the updated categoryName
{ new: true } // To return the updated document
);
if (!update) {
return res
.status(404)
.json({ message: "Can not update document, something went wrong" });
} else {
return res.status(200).json({ success: true, update });
}
}
} else {
const update = await CategoryModel.findOneAndUpdate(
{ _id: _id },
{ categoryName: categoryName, categoryImage: JSON.parse(olderImage) }, // Provide the updated categoryName
{ new: true } // To return the updated document
);
if (update) {
return res.status(200).json({ success: true, update });
}
}
} catch (error) {
res.status(500).json({
success: false,
message: error.message ? error.message : "Something went wrong",
});
if (!req?.user) {
return res.status(400).json({ message: "Please login!" });
}
if (!mongoose.Types.ObjectId.isValid(_id)) {
return res.status(404).json({ message: "Invalid category ID" });
}
};
export const deleteCategory = async (req, res) => {
try {
if (!req?.user) return res.status(400).json({ message: "please login !" });
const { _id } = req.params;
if (!mongoose.Types.ObjectId.isValid(_id)) {
return res.status(404).json({ error: "Can not find the document " });
}
const deletefromCloudinary = await CategoryModel.findOne({ _id: _id });
const deleteresponse = await cloudinary.v2.uploader.destroy(
deletefromCloudinary.categoryImage.public_id
const updatedCategory = await CategoryModel.findByIdAndUpdate(
_id,
{ categoryName },
{ new: true, runValidators: true }
);
if (deleteresponse) {
const deleteCategory = await CategoryModel.findOneAndDelete({ _id: _id });
if (!deleteCategory) {
return res.status(404).json({
error: "Can not find the document with the provided id to delete ",
});
}
res.status(200).json({ success: true, deleteCategory });
} else {
return res.status(404).json({ error: "can not delete the category " });
if (!updatedCategory) {
return res.status(404).json({ message: "Category not found" });
}
res.status(200).json({ success: true, updatedCategory, message: "Category updated successfully" });
} catch (error) {
res.status(500).json({
success: false,
message: error.message ? error.message : "Something went wrong",
message: error.message || "Something went wrong",
});
}
};
// Delete Category
export const deleteCategory = async (req, res) => {
const { _id } = req.params;
if (!req?.user) {
return res.status(400).json({ message: "Please login!" });
}
if (!mongoose.Types.ObjectId.isValid(_id)) {
return res.status(404).json({ message: "Invalid category ID" });
}
try {
const deletedCategory = await CategoryModel.findByIdAndDelete(_id);
if (!deletedCategory) {
return res.status(404).json({ message: "Category not found" });
}
res.status(200).json({ success: true, deletedCategory, message: "Category deleted successfully" });
} catch (error) {
res.status(500).json({
success: false,
message: error.message || "Something went wrong",
});
}
};

View File

@ -10,20 +10,20 @@ const router = express.Router();
router
.route("/add")
.post(isAuthenticatedUser, authorizeRoles("admin", "Employee"), addCategory);
.post(isAuthenticatedUser, authorizeRoles("admin"), addCategory);
router.route("/getCategories").get(getCategories);
router
.route("/update/:_id")
.patch(
isAuthenticatedUser,
authorizeRoles("admin", "Employee"),
authorizeRoles("admin"),
updateCategory
);
router
.route("/delete/:_id")
.delete(
isAuthenticatedUser,
authorizeRoles("admin", "Employee"),
authorizeRoles("admin"),
deleteCategory
);

View File

@ -79,8 +79,6 @@ export const getDistributors = async (req, res) => {
export const getAllInventories = async (req, res) => {
try {
const { page = 1, show = 10, startDate, endDate, name } = req.query;
// Build query for date filtering
const query = {};
if (startDate && endDate) {
@ -98,18 +96,17 @@ export const getAllInventories = async (req, res) => {
$lte: new Date(end).setDate(end.getDate() + 1),
};
}
} else if (startDate) {
} else if (startDate && endDate==='') {
query.createdAt = {
$gte: new Date(startDate),
$lte: new Date(),
};
} else if (endDate) {
} else if (endDate && startDate==='') {
query.createdAt = {
$lte: new Date(endDate),
};
}
// Fetch all matching documents (without pagination) to calculate total data
const allInventories = await Inventory.find(query).sort({ createdAt: -1 });
// Populate additional details
@ -127,14 +124,17 @@ export const getAllInventories = async (req, res) => {
if (inventory.addedFor === "PrincipalDistributor") {
addedForData = await User.findById(inventory.addedForId);
const shippingAddress = await ShippingAddress.findOne({
user: addedForData._id,
});
addedForData = {
...addedForData.toObject(),
shippingAddress,
};
tradeName = addedForData.shippingAddress?.tradeName?.toLowerCase() || "";
if (addedForData) {
const shippingAddress = await ShippingAddress.findOne({
user: addedForData._id,
});
addedForData = {
...addedForData.toObject(),
shippingAddress,
};
tradeName =
addedForData.shippingAddress?.tradeName?.toLowerCase() || "";
}
} else if (inventory.addedFor === "RetailDistributor") {
addedForData = await KYC.findById(inventory.addedForId);
tradeName = addedForData?.trade_name?.toLowerCase() || "";
@ -149,11 +149,13 @@ export const getAllInventories = async (req, res) => {
})
);
// Apply name filter
// Apply name filter if the name parameter is provided
let filteredInventories = populatedInventories;
if (name) {
filteredInventories = filteredInventories.filter(
(inventory) => inventory.tradeName && inventory.tradeName.includes(name.toLowerCase())
(inventory) =>
inventory.tradeName &&
inventory.tradeName.includes(name.toLowerCase())
);
}
@ -161,8 +163,10 @@ export const getAllInventories = async (req, res) => {
const total_data = filteredInventories.length;
// Apply pagination after filtering
const paginatedInventories = filteredInventories
.slice((page - 1) * show, page * show);
const paginatedInventories = filteredInventories.slice(
(page - 1) * show,
page * show
);
// Calculate total pages
const total_pages = Math.ceil(total_data / show);
@ -171,10 +175,11 @@ export const getAllInventories = async (req, res) => {
res.status(200).json({
total_data,
total_pages,
current_page: page,
current_page: Number(page),
inventories: paginatedInventories,
});
} catch (error) {
console.error("Error in getAllInventories:", error);
res.status(500).json({ message: error.message });
}
};

View File

@ -2,6 +2,8 @@ import { Product } from "./ProductModel.js";
import cloudinary from "../../Utils/cloudinary.js";
import { v4 as uuidv4 } from "uuid";
import { CategoryModel } from "../Category/CategoryModel.js";
import { BrandModel } from "../Brands/BrandsModel.js";
import User from "../user/userModel.js";
import { Tax } from "../Tax/tax_model.js";
import XLSX from "xlsx";
import fs from "fs";
@ -9,6 +11,267 @@ import path from "path";
import mongoose from "mongoose";
// Function to handle product upload
// export const uploadProducts = async (req, res) => {
// try {
// if (!req.files || !req.files.file) {
// return res.status(400).json({ message: "No file uploaded" });
// }
// const file = req.files.file;
// const filePath = path.join("public", "uploads", file.name);
// // Ensure 'uploads' directory exists
// if (!fs.existsSync(path.dirname(filePath))) {
// fs.mkdirSync(path.dirname(filePath), { recursive: true });
// }
// // Move the file from temp to the uploads directory
// await file.mv(filePath);
// // Process the file
// const fileBuffer = fs.readFileSync(filePath);
// const workbook = XLSX.read(fileBuffer, { type: "buffer" });
// const sheetName = workbook.SheetNames[0];
// const worksheet = workbook.Sheets[sheetName];
// const data = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
// if (data.length <= 1) {
// return res.status(400).json({ message: "Empty spreadsheet or no data found" });
// }
// const headers = data[0];
// // Map headers from the Excel file to your schema
// const headerMapping = {
// SKU: "SKU",
// "Product Name": "name",
// "Category Name": "category",
// "Brand Name": "brand",
// Price: "price",
// "GST (in %)": "GST",
// "HSN Code": "HSN_Code",
// "Description (Optional)": "description",
// };
// const requiredHeaders = Object.keys(headerMapping);
// if (!requiredHeaders.every((header) => headers.includes(header))) {
// return res.status(400).json({ message: "Missing required columns in spreadsheet" });
// }
// const errors = [];
// const newlyCreated = [];
// const updatedProducts = [];
// for (let i = 1; i < data.length; i++) {
// const row = data[i];
// const item = {};
// headers.forEach((header, index) => {
// if (headerMapping[header]) {
// item[headerMapping[header]] = row[index] !== undefined ? row[index] : "";
// }
// });
// // Initialize error tracking for each item
// const missingFields = new Set();
// const notFoundErrors = new Set();
// let { SKU, name, category, brand, price, GST, HSN_Code, description } = item;
// // Trim leading and trailing spaces from product name and GST
// name = name ? name.trim() : "";
// // Validate required fields
// if (!SKU) missingFields.add("SKU");
// if (!name) missingFields.add("name");
// if (!category) missingFields.add("category");
// if (!brand) missingFields.add("brand");
// if (price === undefined || price === "") missingFields.add("price");
// if (!GST) missingFields.add("GST");
// if (!HSN_Code) missingFields.add("HSN_Code");
// // Validate or create category
// let categoryName = "";
// if (category) {
// let categoryDoc = await CategoryModel.findOne({
// categoryName: { $regex: new RegExp(`^${category.trim()}$`, "i") },
// }).exec();
// if (!categoryDoc) {
// // If category not found, create a new one
// categoryDoc = await CategoryModel.create({
// categoryName: category.trim(),
// addedBy: req.user._id,
// });
// }
// item.category = categoryDoc._id;
// categoryName = categoryDoc.categoryName;
// }
// // Validate or create brand
// let brandName = "";
// if (brand) {
// let brandDoc = await BrandModel.findOne({
// brandName: { $regex: new RegExp(`^${brand.trim()}$`, "i") },
// }).exec();
// if (!brandDoc) {
// // If brand not found, create a new one
// brandDoc = await BrandModel.create({
// brandName: brand.trim(),
// addedBy: req.user._id,
// });
// }
// item.brand = brandDoc._id;
// brandName = brandDoc.brandName;
// }
// // Combine all errors into a single message
// let errorMessage = "";
// if (missingFields.size > 0) {
// errorMessage += `Missing fields: ${Array.from(missingFields).join(", ")}. `;
// }
// if (notFoundErrors.size > 0) {
// errorMessage += `Not found: ${Array.from(notFoundErrors).join(", ")}.`;
// }
// // If there are errors, push them to the errors array
// if (errorMessage.trim()) {
// errors.push({
// SKU: SKU || "N/A",
// productName: name || "N/A",
// category: category || "N/A",
// brand: brand || "N/A",
// GST: GST || "N/A",
// HSN_Code: HSN_Code || "N/A",
// price: price || "N/A",
// message: errorMessage.trim(),
// });
// continue;
// }
// // Ensure fields are set to empty strings if not provided
// description = description !== undefined ? description : "";
// // Check for existing product by SKU
// let existingProduct = await Product.findOne({ SKU }).exec();
// if (existingProduct) {
// // Track changes
// const updatedFields = [];
// let updatedProduct = { ...existingProduct._doc };
// // Fetch existing category name and brand name
// const existingCategory = await CategoryModel.findById(existingProduct.category).exec();
// const existingBrand = await BrandModel.findById(existingProduct.brand).exec();
// // Update product fields if they have changed
// if (name !== existingProduct.name) {
// updatedFields.push("name");
// updatedProduct.name = name;
// }
// if (category && existingProduct.category.toString() !== item.category.toString()) {
// updatedFields.push("category");
// updatedProduct.category = categoryName;
// } else {
// updatedProduct.category = existingCategory ? existingCategory.categoryName : "";
// }
// if (price !== undefined && price !== "" && existingProduct.price !== price) {
// updatedFields.push("price");
// updatedProduct.price = price;
// }
// if (brand && existingProduct.brand.toString() !== item.brand.toString()) {
// updatedFields.push("brand");
// updatedProduct.brand = brandName;
// } else {
// updatedProduct.brand = existingBrand ? existingBrand.brandName : "";
// }
// if (HSN_Code !== existingProduct.HSN_Code) {
// updatedFields.push("HSN_Code");
// updatedProduct.HSN_Code = HSN_Code;
// }
// if (GST !== existingProduct.GST) {
// updatedFields.push("GST");
// updatedProduct.GST = GST;
// }
// if (description !== existingProduct.description) {
// updatedFields.push("description");
// updatedProduct.description = description;
// }
// // Only update if there are changes
// if (updatedFields.length > 0) {
// try {
// await Product.updateOne(
// { SKU: existingProduct.SKU },
// {
// $set: {
// category: item.category || existingProduct.category,
// price: price !== undefined && price !== "" ? price : existingProduct.price,
// GST: GST || existingProduct.GST,
// HSN_Code: HSN_Code || existingProduct.HSN_Code,
// name: name,
// description: description,
// product_Status: item.product_Status || existingProduct.product_Status || "Active",
// },
// }
// );
// updatedProducts.push({
// ...updatedProduct,
// updatedFields: updatedFields.join(", "), // Track updated fields
// });
// } catch (error) {
// errors.push({
// SKU,
// message: "Failed to update product",
// });
// }
// }
// continue;
// }
// // Create new product
// if (item.category && item.brand) {
// const productData = {
// SKU,
// name,
// category: item.category,
// brand: item.brand,
// price,
// GST,
// HSN_Code,
// description: description,
// product_Status: item.product_Status || "Active",
// addedBy: req.user._id,
// };
// try {
// const newProduct = await Product.create(productData);
// newlyCreated.push({
// ...newProduct._doc,
// category: categoryName,
// brand: brandName,
// });
// } catch (error) {
// errors.push({
// SKU,
// message: "Failed to create product",
// });
// }
// }
// }
// fs.unlinkSync(filePath); // Clean up uploaded file
// res.status(201).json({
// message: errors.length > 0 ? "Products processed with errors!" : "Products processed successfully!",
// newlyCreated: newlyCreated,
// updatedProducts: updatedProducts,
// errors,
// });
// } catch (error) {
// console.error("Error:", error);
// res.status(500).json({ message: "Internal server error" });
// }
// };
export const uploadProducts = async (req, res) => {
try {
if (!req.files || !req.files.file) {
@ -45,11 +308,12 @@ export const uploadProducts = async (req, res) => {
const headerMapping = {
SKU: "SKU",
"Product Name": "name",
"category Name": "category",
price: "price",
"GST Name": "GST",
description: "description",
special_instructions: "special_instructions",
"Category Name": "category",
"Brand Name": "brand",
Price: "price",
"GST (in %)": "GST",
"HSN Code": "HSN_Code",
"Description (Optional)": "description",
};
const requiredHeaders = Object.keys(headerMapping);
@ -64,6 +328,12 @@ export const uploadProducts = async (req, res) => {
const newlyCreated = [];
const updatedProducts = [];
const capitalizeWords = (str) =>
str
.toLowerCase()
.replace(/\b\w/g, (char) => char.toUpperCase())
.trim();
for (let i = 1; i < data.length; i++) {
const row = data[i];
const item = {};
@ -75,61 +345,66 @@ export const uploadProducts = async (req, res) => {
}
});
// Check if the row has meaningful data, skip if it's mostly empty
const hasValidData = Object.values(item).some((value) => value && value.trim());
if (!hasValidData) {
continue;
}
// Initialize error tracking for each item
const missingFields = new Set();
const notFoundErrors = new Set();
let {
SKU,
name,
category,
price,
GST,
description,
special_instructions,
} = item;
let { SKU, name, category, brand, price, GST, HSN_Code, description } =
item;
// Trim leading and trailing spaces from product name and GST
// Trim leading and trailing spaces and apply case formatting
name = name ? name.trim() : "";
GST = GST ? GST.toString().trim() : "";
category = category ? capitalizeWords(category) : "";
brand = brand ? capitalizeWords(brand) : "";
// Validate required fields
if (!SKU) missingFields.add("SKU");
if (!name) missingFields.add("name");
if (!category) missingFields.add("category");
if (!brand) missingFields.add("brand");
if (price === undefined || price === "") missingFields.add("price");
if (!GST) missingFields.add("GST");
if (!HSN_Code) missingFields.add("HSN_Code");
// Validate category
let categoryName = "";
// Validate or create category
let categoryDoc = null;
let categoryname = "";
if (category) {
const categoryDoc = await CategoryModel.findOne({
categoryName: { $regex: new RegExp(`^${category.trim()}$`, "i") },
categoryDoc = await CategoryModel.findOne({
categoryName: { $regex: new RegExp(`^${category}$`, "i") },
}).exec();
if (categoryDoc) {
item.category = categoryDoc._id;
categoryName = categoryDoc.categoryName;
} else {
notFoundErrors.add("category");
if (!categoryDoc) {
categoryDoc = await CategoryModel.create({
categoryName: category,
addedBy: req.user._id,
});
}
} else {
missingFields.add("category");
categoryname = categoryDoc.categoryName;
item.category = categoryDoc._id;
}
// Validate GST
let gstName = "";
if (GST) {
const gstDoc = await Tax.findOne({
name: { $regex: new RegExp(`^${GST}$`, "i") },
// Validate or create brand
let brandDoc = null;
let brandname = "";
if (brand) {
brandDoc = await BrandModel.findOne({
brandName: { $regex: new RegExp(`^${brand}$`, "i") },
}).exec();
if (gstDoc) {
item.GST = gstDoc._id;
gstName = gstDoc.name;
} else {
notFoundErrors.add("GST");
if (!brandDoc) {
brandDoc = await BrandModel.create({
brandName: brand,
addedBy: req.user._id,
});
}
} else {
missingFields.add("GST");
brandname = brandDoc.brandName;
item.brand = brandDoc._id;
}
// Combine all errors into a single message
@ -139,17 +414,16 @@ export const uploadProducts = async (req, res) => {
", "
)}. `;
}
if (notFoundErrors.size > 0) {
errorMessage += `Not found: ${Array.from(notFoundErrors).join(", ")}.`;
}
// If there are errors, push them to the errors array
if (errorMessage.trim()) {
errors.push({
SKU: SKU || "N/A",
productName: name || "N/A",
category: category || "N/A",
category: categoryname || "N/A",
brand: brandname || "N/A",
GST: GST || "N/A",
HSN_Code: HSN_Code || "N/A",
price: price || "N/A",
message: errorMessage.trim(),
});
@ -158,8 +432,6 @@ export const uploadProducts = async (req, res) => {
// Ensure fields are set to empty strings if not provided
description = description !== undefined ? description : "";
special_instructions =
special_instructions !== undefined ? special_instructions : "";
// Check for existing product by SKU
let existingProduct = await Product.findOne({ SKU }).exec();
@ -169,22 +441,19 @@ export const uploadProducts = async (req, res) => {
const updatedFields = [];
let updatedProduct = { ...existingProduct._doc };
// Fetch existing category name and GST name
const existingCategory = await CategoryModel.findById(
existingProduct.category
).exec();
const existingGST = await Tax.findById(existingProduct.GST).exec();
// Update product fields if they have changed
if (name !== existingProduct.name) {
updatedFields.push("name");
updatedProduct.name = name;
}
if (
category &&
categoryDoc &&
existingProduct.category.toString() !== item.category.toString()
) {
updatedFields.push("category");
updatedProduct.category = categoryName;
updatedProduct.category = categoryname;
} else {
updatedProduct.category = existingCategory
? existingCategory.categoryName
: "";
updatedProduct.category = categoryDoc.categoryName;
}
if (
price !== undefined &&
@ -194,20 +463,27 @@ export const uploadProducts = async (req, res) => {
updatedFields.push("price");
updatedProduct.price = price;
}
if (GST && existingProduct.GST.toString() !== item.GST.toString()) {
updatedFields.push("GST");
updatedProduct.GST = gstName;
if (
brandDoc &&
existingProduct.brand.toString() !== item.brand.toString()
) {
updatedFields.push("brand");
updatedProduct.brand = brandname;
} else {
updatedProduct.GST = existingGST ? existingGST.name : "";
updatedProduct.brand = brandDoc.brandName;
}
if (HSN_Code !== existingProduct.HSN_Code) {
updatedFields.push("HSN_Code");
updatedProduct.HSN_Code = HSN_Code;
}
if (GST !== existingProduct.GST) {
updatedFields.push("GST");
updatedProduct.GST = GST;
}
if (description !== existingProduct.description) {
updatedFields.push("description");
updatedProduct.description = description;
}
if (special_instructions !== existingProduct.special_instructions) {
updatedFields.push("special_instructions");
updatedProduct.special_instructions = special_instructions;
}
// Only update if there are changes
if (updatedFields.length > 0) {
@ -217,13 +493,15 @@ export const uploadProducts = async (req, res) => {
{
$set: {
category: item.category || existingProduct.category,
brand: item.brand || existingProduct.brand,
price:
price !== undefined && price !== ""
? price
: existingProduct.price,
GST: item.GST || existingProduct.GST,
GST: GST || existingProduct.GST,
HSN_Code: HSN_Code || existingProduct.HSN_Code,
name: name,
description: description,
special_instructions: special_instructions,
product_Status:
item.product_Status ||
existingProduct.product_Status ||
@ -246,15 +524,16 @@ export const uploadProducts = async (req, res) => {
}
// Create new product
if (item.category && item.GST) {
if (item.category && item.brand) {
const productData = {
SKU,
name,
category: item.category,
brand: item.brand,
price,
GST: item.GST,
GST,
HSN_Code,
description: description,
special_instructions: special_instructions,
product_Status: item.product_Status || "Active",
addedBy: req.user._id,
};
@ -262,8 +541,8 @@ export const uploadProducts = async (req, res) => {
const newProduct = await Product.create(productData);
newlyCreated.push({
...newProduct._doc,
category: categoryName,
GST: gstName,
category: categoryDoc.categoryName,
brand: brandDoc.brandName,
});
} catch (error) {
errors.push({
@ -286,8 +565,8 @@ export const uploadProducts = async (req, res) => {
errors,
});
} catch (error) {
console.error("Error:", error);
res.status(500).json({ message: error.message || "Something went wrong!" });
console.error("Error uploading products:", error);
res.status(500).json({ message: "Server error" });
}
};
@ -296,7 +575,7 @@ export const createProduct = async (req, res) => {
let findProduct = "";
let product = { _id: "" };
const sku = req.body?.SKU;
// console.log(req.body);
if (!sku) {
return res.status(400).json({ message: "SKU is required!" });
}
@ -450,13 +729,16 @@ export const getAllProductAdmin = async (req, res) => {
if (req.query.category) {
filter.category = mongoose.Types.ObjectId(req.query.category);
}
if (req.query.brand) {
filter.brand = mongoose.Types.ObjectId(req.query.brand);
}
const total = await Product.countDocuments(filter);
const products = await Product.find(filter)
.populate({
path: "category addedBy GST",
select: "categoryName name tax",
path: "category addedBy brand",
select: "categoryName name brandName",
})
.limit(PAGE_SIZE)
.skip(skip)
@ -488,7 +770,9 @@ export const getAllProductUser = async (req, res) => {
// Filter by category name
if (req.query?.category) {
const category = await CategoryModel.findOne({ categoryName: req.query.category });
const category = await CategoryModel.findOne({
categoryName: req.query.category,
});
if (category) {
filter.category = category._id;
} else {
@ -498,7 +782,9 @@ export const getAllProductUser = async (req, res) => {
});
}
}
if (req.query.brand) {
filter.brand = mongoose.Types.ObjectId(req.query.brand);
}
// Filter by SKU
if (req.query?.SKU) {
filter.SKU = req.query.SKU;
@ -507,7 +793,7 @@ export const getAllProductUser = async (req, res) => {
// Filter by product name using regex for case-insensitive partial matching
if (req.query?.name) {
filter.name = {
$regex: new RegExp(req.query.name, 'i'),
$regex: new RegExp(req.query.name, "i"),
};
}
@ -520,8 +806,8 @@ export const getAllProductUser = async (req, res) => {
// Retrieve products with pagination, filtering, and sorting
const products = await Product.find(filter)
.populate({
path: "category addedBy GST",
select: "categoryName name tax",
path: "category addedBy brand",
select: "categoryName name brandName",
})
.limit(PAGE_SIZE)
.skip(PAGE_SIZE * page)
@ -588,8 +874,8 @@ export const ChangeProductStatus = async (req, res) => {
export const getOneProduct = async (req, res) => {
try {
const data = await Product.findById(req.params.id).populate({
path: "category addedBy GST",
select: "name categoryName tax",
path: "category addedBy brand",
select: "categoryName name brandName",
});
if (data) {
return res.status(200).json({

View File

@ -20,24 +20,27 @@ const productSchema = new Schema(
type: Schema.Types.ObjectId,
ref: "CategoryModel",
},
brand: {
type: Schema.Types.ObjectId,
ref: "BrandModel",
},
price: {
type: Number,
required: true,
},
GST: {
type: mongoose.Schema.ObjectId,
ref: "Tax",
type: Number,
required: true,
},
HSN_Code: {
type: Number,
required: true,
},
description: {
type: String,
maxLength: [400, "description cannot exceed 100 characters"],
// required: [true, "Please Enter product Description"],
},
special_instructions: {
type: String,
},
image: [
{
public_id: {