diff --git a/resources/SalesCoOrdinators/SalesCoOrdinatorController.js b/resources/SalesCoOrdinators/SalesCoOrdinatorController.js index 42ce554..f0b879f 100644 --- a/resources/SalesCoOrdinators/SalesCoOrdinatorController.js +++ b/resources/SalesCoOrdinators/SalesCoOrdinatorController.js @@ -294,6 +294,40 @@ export const mappedbyTM = async (req, res) => { }); } }; +export const unmapSalesCoOrdinator = async (req, res) => { + try { + if (!req.params.id) { + return res.status(400).json({ + success: false, + message: "Please provide SalesCoOrdinator ID!", + }); + } + + const getSalesCoOrdinator = await SalesCoOrdinator.findById(req.params.id); + if (!getSalesCoOrdinator) { + return res.status(404).json({ + success: false, + message: "Sales Coordinator not found!", + }); + } + + // Set mappedby field to null + getSalesCoOrdinator.mappedby = null; + + // Save the updated sales coordinator + await getSalesCoOrdinator.save(); + + res.status(200).json({ + success: true, + message: "Sales Coordinator unmapped successfully!", + }); + } catch (error) { + res.status(500).json({ + success: false, + message: error.message ? error.message : "Something went wrong!", + }); + } +}; export const getOneSalesCoOrdinator = async (req, res) => { try { if (!req.params.id) { diff --git a/resources/SalesCoOrdinators/SalesCoOrdinatorModel.js b/resources/SalesCoOrdinators/SalesCoOrdinatorModel.js index 4e3d73b..05ad4c3 100644 --- a/resources/SalesCoOrdinators/SalesCoOrdinatorModel.js +++ b/resources/SalesCoOrdinators/SalesCoOrdinatorModel.js @@ -59,7 +59,6 @@ const salescoordinatorSchema = new mongoose.Schema( mappedby: { type: mongoose.Schema.Types.ObjectId, ref: "TerritoryManager", - required: true, }, }, { timestamps: true } diff --git a/resources/SalesCoOrdinators/SalesCoOrdinatorRoute.js b/resources/SalesCoOrdinators/SalesCoOrdinatorRoute.js index 1b69333..2359904 100644 --- a/resources/SalesCoOrdinators/SalesCoOrdinatorRoute.js +++ b/resources/SalesCoOrdinators/SalesCoOrdinatorRoute.js @@ -18,6 +18,7 @@ import { logout, getAllSalesCoOrdinatorbytmId, mappedbyTM, + unmapSalesCoOrdinator, } from "./SalesCoOrdinatorController.js"; import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js"; import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js"; @@ -51,6 +52,12 @@ router.put( authorizeRoles("admin"), mappedbyTM ); +router.delete( + "/unmap/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + unmapSalesCoOrdinator +); router.get( "/getOne/:id", isAuthenticatedUser, diff --git a/resources/user/userController.js b/resources/user/userController.js index 2e2247d..1c700d2 100644 --- a/resources/user/userController.js +++ b/resources/user/userController.js @@ -12,7 +12,7 @@ import { Config } from "../setting/Configration/Config_model.js"; import XLSX from "xlsx"; import fs from "fs"; import path from "path"; -import validator from 'validator'; +import validator from "validator"; import ShippingAddress from "../ShippingAddresses/ShippingAddressModel.js"; const generatePassword = (name, email) => { @@ -356,7 +356,9 @@ export const uploadPrincipaldistributors = async (req, res) => { 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" }); + return res + .status(400) + .json({ message: "Empty spreadsheet or no data found" }); } const headers = data[0]; @@ -364,23 +366,25 @@ export const uploadPrincipaldistributors = async (req, res) => { // Map headers from the Excel file to your schema const headerMapping = { "PD ID (From SAP)": "uniqueId", - "SBU":"SBU", + SBU: "SBU", "Principal Distributor Name": "name", - "Email": "email", + Email: "email", "Phone Number": "phone", "PAN Number": "panNumber", "Trade Name": "tradeName", "GST Number": "gstNumber", - "State": "state", - "City": "city", - "Street": "street", - "Pincode": "postalCode", + State: "state", + City: "city", + Street: "street", + Pincode: "postalCode", }; const requiredHeaders = Object.keys(headerMapping); if (!requiredHeaders.every((header) => headers.includes(header))) { - return res.status(400).json({ message: "Missing required columns in spreadsheet" }); + return res + .status(400) + .json({ message: "Missing required columns in spreadsheet" }); } const errors = []; @@ -393,7 +397,8 @@ export const uploadPrincipaldistributors = async (req, res) => { headers.forEach((header, index) => { if (headerMapping[header]) { - item[headerMapping[header]] = row[index] !== undefined ? row[index] : ""; + item[headerMapping[header]] = + row[index] !== undefined ? row[index] : ""; } }); @@ -403,7 +408,7 @@ export const uploadPrincipaldistributors = async (req, res) => { // Validate required fields if (!item.uniqueId) missingFields.add("uniqueId"); - if(!item.SBU) missingFields.add("SBU"); + if (!item.SBU) missingFields.add("SBU"); if (!item.name) missingFields.add("name"); if (!item.email) missingFields.add("email"); if (!item.phone) missingFields.add("phone"); @@ -430,12 +435,18 @@ export const uploadPrincipaldistributors = async (req, res) => { item.gstNumber = item.gstNumber ? item.gstNumber.toUpperCase() : ""; // Validate PAN Number - if (item.panNumber && !/^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(item.panNumber)) { + if ( + item.panNumber && + !/^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(item.panNumber) + ) { validationErrors.add("Invalid PAN Number"); } // Validate GST Number - if (item.gstNumber && !/^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test(item.gstNumber)) { + if ( + item.gstNumber && + !/^(\d{2}[A-Z]{5}\d{4}[A-Z]{1}\d[Z]{1}[A-Z\d]{1})$/.test(item.gstNumber) + ) { validationErrors.add("Invalid GST Number"); } @@ -447,17 +458,21 @@ export const uploadPrincipaldistributors = async (req, res) => { // Combine all errors into a single message let errorMessage = ""; if (missingFields.size > 0) { - errorMessage += `Missing fields: ${Array.from(missingFields).join(", ")}. `; + errorMessage += `Missing fields: ${Array.from(missingFields).join( + ", " + )}. `; } if (validationErrors.size > 0) { - errorMessage += `Validation errors: ${Array.from(validationErrors).join(", ")}.`; + errorMessage += `Validation errors: ${Array.from(validationErrors).join( + ", " + )}.`; } // If there are errors, push them to the errors array if (errorMessage.trim()) { errors.push({ uniqueId: item.uniqueId || "N/A", - SBU:item.SBU || "N/A", + SBU: item.SBU || "N/A", name: item.name || "N/A", email: item.email || "N/A", phone: item.phone || "N/A", @@ -478,8 +493,18 @@ export const uploadPrincipaldistributors = async (req, res) => { if (distributor) { // Track updated fields const updatedFields = []; - const addressFields = ['panNumber', 'gstNumber', 'state', 'city', 'street', 'tradeName', 'postalCode']; - const existingAddress = await ShippingAddress.findOne({ user: distributor._id }); + const addressFields = [ + "panNumber", + "gstNumber", + "state", + "city", + "street", + "tradeName", + "postalCode", + ]; + const existingAddress = await ShippingAddress.findOne({ + user: distributor._id, + }); // Check for changes in user details let userUpdated = false; @@ -493,7 +518,7 @@ export const uploadPrincipaldistributors = async (req, res) => { distributor.email = item.email; userUpdated = true; } - if(distributor.SBU !== item.SBU){ + if (distributor.SBU !== item.SBU) { updatedFields.push("SBU"); distributor.SBU = item.SBU; userUpdated = true; @@ -525,7 +550,7 @@ export const uploadPrincipaldistributors = async (req, res) => { let addressUpdated = false; if (existingAddress) { const addressUpdates = []; - addressFields.forEach(field => { + addressFields.forEach((field) => { if (existingAddress[field] !== addressData[field]) { addressUpdates.push(field); addressUpdated = true; @@ -533,9 +558,14 @@ export const uploadPrincipaldistributors = async (req, res) => { }); if (addressUpdated) { - await ShippingAddress.updateOne({ user: distributor._id }, addressData); + await ShippingAddress.updateOne( + { user: distributor._id }, + addressData + ); if (addressUpdates.length > 0) { - updatedFields.push(`Address fields: ${addressUpdates.join(", ")}`); + updatedFields.push( + `Address fields: ${addressUpdates.join(", ")}` + ); } } } else { @@ -548,7 +578,7 @@ export const uploadPrincipaldistributors = async (req, res) => { if (updatedFields.length > 0) { updatedDistributors.push({ ...distributor._doc, - updatedFields: updatedFields.join(", ") + updatedFields: updatedFields.join(", "), }); } } else { @@ -613,7 +643,7 @@ export const uploadPrincipaldistributors = async (req, res) => { // 1.Register a User export const registerUser = async (req, res) => { try { - const { name, email, phone, accessTo, role,PD_ID,SBU } = req.body; + const { name, email, phone, accessTo, role, PD_ID, SBU } = req.body; // console.log(req.body); const password = generatePassword(name, email); // console.log(password); @@ -627,7 +657,7 @@ export const registerUser = async (req, res) => { user.phone = phone; user.role = role; user.accessTo = accessTo; - user.SBU=SBU; + user.SBU = SBU; // Save updates await user.save(); // console.log("finduser", user); @@ -967,14 +997,130 @@ export const updateProfile = catchAsyncErrors(async (req, res, next) => { // 9.Get all users(admin) export const getAllUser = catchAsyncErrors(async (req, res, next) => { // Assuming your User model is imported as 'User' - const users = await User.find({ role: "principal-Distributor" }) - .sort({ createdAt: -1 }); + const { page = 1, show = 10, name, mobileNumber } = req.query; + // Create a filter object + const filter = { role: "principal-Distributor" }; + if (name) { + filter.name = { $regex: name, $options: "i" }; // Case-insensitive regex search + } + + if (mobileNumber) { + filter.phone = mobileNumber; + } + // Calculate pagination values + const limit = parseInt(show, 10); + const skip = (parseInt(page, 10) - 1) * limit; + // Count total users matching the filter + + // Find users with pagination and filters + const users = await User.find(filter) + .sort({ createdAt: -1 }) + .skip(skip) + .limit(limit); + const totalUsers = await User.countDocuments(filter); res.status(200).json({ success: true, users, + totalUsers, }); }); +export const getAllPrincipalDistributorbytmId = catchAsyncErrors( + async (req, res, next) => { + const { page = 1, show = 10, name, mobileNumber } = req.query; + const tmId = req.params.id; + if(!tmId){ + return res.status(400).json({ message: "Please provide Territory Manager ID" }); + } + // Create a filter object + const filter = { role: "principal-Distributor" }; + + if (name) { + filter.name = { $regex: name, $options: "i" }; // Case-insensitive regex search + } + + if (mobileNumber) { + filter.phone = mobileNumber; + } + + // Filter based on the mapped Territory Manager ID if provided + if (tmId) { + filter.mappedby = tmId; + } + + // Calculate pagination values + const limit = parseInt(show, 10); + const skip = (parseInt(page, 10) - 1) * limit; + + // Find users with pagination and filters + const users = await User.find(filter) + .sort({ createdAt: -1 }) + .skip(skip) + .limit(limit); + + // Count total users matching the filter + const totalUsers = await User.countDocuments(filter); + + res.status(200).json({ + success: true, + principaldistributor: users, + total_data: totalUsers, + page: parseInt(page, 10), + limit, + }); + } +); +export const mappedbyTM = catchAsyncErrors(async (req, res, next) => { + const { id } = req.params; // SalesCoOrdinator ID from URL parameters + const { mappedby } = req.body; // TerritoryManager ID from request body + // console.log(id, mappedby); + // Validate that the TerritoryManager ID is provided + if (!mappedby) { + return res.status(400).json({ + success: false, + message: "Territory Manager ID (mappedby) is required.", + }); + } + const principalDistributor = await User.findById(id); + + if (!principalDistributor) { + return res.status(404).json({ + success: false, + message: "Principal Distributor not found", + }); + } + // Update the mappedby field + principalDistributor.mappedby = mappedby; + await principalDistributor.save(); + return res.status(200).json({ + success: true, + message: "Principal Distributor updated successfully", + principalDistributor, + }); +}); +export const unmappedTMinPrincipalDistributor = catchAsyncErrors( + async (req, res, next) => { + const { id } = req.params; // Principal Distributor ID from URL parameters + // console.log(id); + const principalDistributor = await User.findById(id); + + if (!principalDistributor) { + return res.status(404).json({ + success: false, + message: "Principal Distributor not found", + }); + } + + // Remove the mappedby field + principalDistributor.mappedby = null; + await principalDistributor.save(); + return res.status(200).json({ + success: true, + message: "Principal Distributor updated successfully", + principalDistributor, + }); + } +); export const getAllEmployee = catchAsyncErrors(async (req, res, next) => { // Assuming your User model is imported as 'User' const employee = await User.find({ role: "Employee" }); diff --git a/resources/user/userModel.js b/resources/user/userModel.js index fbe6c36..592e5a0 100644 --- a/resources/user/userModel.js +++ b/resources/user/userModel.js @@ -58,6 +58,10 @@ const userSchema = new mongoose.Schema( type: String, default: "user", }, + mappedby: { + type: mongoose.Schema.Types.ObjectId, + ref: "TerritoryManager", + }, accessTo: {}, resetPasswordToken: String, resetPasswordExpire: Date, diff --git a/resources/user/userRoute.js b/resources/user/userRoute.js index 9541235..4294d4e 100644 --- a/resources/user/userRoute.js +++ b/resources/user/userRoute.js @@ -15,6 +15,9 @@ import { deleteEmployeeById, updateEmployeeById, uploadPrincipaldistributors, + getAllPrincipalDistributorbytmId, + mappedbyTM, + unmappedTMinPrincipalDistributor, } from "./userController.js"; import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js"; @@ -32,14 +35,34 @@ router.route("/user/logout").get(logout); router.route("/user/details").get(isAuthenticatedUser, getUserDetails); router - .route('/principaldistributor/upload').post( - isAuthenticatedUser, - authorizeRoles('admin'), - uploadPrincipaldistributors -); + .route("/principaldistributor/upload") + .post( + isAuthenticatedUser, + authorizeRoles("admin"), + uploadPrincipaldistributors + ); router .route("/admin/users") .get(isAuthenticatedUser, authorizeRoles("admin", "Employee"), getAllUser); +router + .route("/getbyTmId/:id") + .get( + isAuthenticatedUser, + authorizeRoles("admin"), + getAllPrincipalDistributorbytmId + ); +router.put( + "/mappedtm/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + mappedbyTM +); +router.patch( + "/unmap/:id", + isAuthenticatedUser, + authorizeRoles("admin"), + unmappedTMinPrincipalDistributor +); router .route("/admin/delete-employee/:id") .delete(