category and product updated and brand created
This commit is contained in:
parent
b8e525e774
commit
69dc2cb1b4
3
app.js
3
app.js
@ -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);
|
||||
|
BIN
public/temp/tmp-1-1724319327212
Normal file
BIN
public/temp/tmp-1-1724319327212
Normal file
Binary file not shown.
111
resources/Brands/BrandsController.js
Normal file
111
resources/Brands/BrandsController.js
Normal 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",
|
||||
});
|
||||
}
|
||||
};
|
18
resources/Brands/BrandsModel.js
Normal file
18
resources/Brands/BrandsModel.js
Normal 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);
|
26
resources/Brands/BrandsRoutes.js
Normal file
26
resources/Brands/BrandsRoutes.js
Normal 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;
|
@ -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",
|
||||
|
@ -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",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
);
|
||||
|
||||
|
@ -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 });
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
@ -485,10 +767,12 @@ export const getAllProductUser = async (req, res) => {
|
||||
const PAGE_SIZE = parseInt(req.query?.show || "10");
|
||||
const page = parseInt(req.query?.page || "1") - 1;
|
||||
let filter = {};
|
||||
|
||||
|
||||
// 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({
|
||||
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user