// import hashPassword from '../utils/hashPassword'; import crypto from "crypto"; import mongoose from "mongoose"; import SalesCoOrdinator from "./SalesCoOrdinatorModel.js"; import sendEmail, { sendOtp } from "../../Utils/sendEmail.js"; import validator from "validator"; import password from "secure-random-password"; import catchAsyncErrors from "../../middlewares/catchAsyncErrors.js"; import { generatePassword } from "../../Utils/generatepassword.js"; import XLSX from "xlsx"; import fs from "fs"; import path from "path"; export const uploadSalesCoordinators = async (req, res) => { try { if (!mongoose.Types.ObjectId.isValid(req.user._id)) { return res.status(400).json({ message: "Please login again" }); } 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 = { "Sales Coordinator Name": "name", Email: "email", "Phone Number": "mobileNumber", }; 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 updatedsalesCoordinators = []; for (let i = 1; i < data.length; i++) { const row = data[i]; // Skip the row if it's completely empty if (row.every(cell => cell === undefined || cell === "")) { continue; } 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 validationErrors = new Set(); // Validate required fields if (!item.name) missingFields.add("name"); if (!item.email) missingFields.add("email"); if (!item.mobileNumber) missingFields.add("mobileNumber"); // Check email validity if (item.email && !validator.isEmail(item.email)) { validationErrors.add("incorrect mail"); } // Validate mobile number if (item.mobileNumber && !/^\d{10}$/.test(item.mobileNumber)) { validationErrors.add("Invalid Mobile Number (should be 10 digits)"); } // Combine all errors into a single message let errorMessage = ""; if (missingFields.size > 0) { errorMessage += `Missing fields: ${Array.from(missingFields).join( ", " )}. `; } if (validationErrors.size > 0) { errorMessage += `Validation errors: ${Array.from(validationErrors).join( ", " )}.`; } // If there are errors, push them to the errors array if (errorMessage.trim()) { errors.push({ name: item.name || "N/A", email: item.email || "N/A", phone: item.mobileNumber || "N/A", message: errorMessage.trim(), }); continue; } // Generate a password const password = generatePassword(item.name, item.email); // Check for existing user by uniqueId let salesCoordinator = await SalesCoOrdinator.findOne({ email: item.email, }); if (salesCoordinator) { // Track updated fields const updatedFields = []; // Check for changes in user details let territoryManagerUpdated = false; for (let field in item) { const currentValue = salesCoordinator[field]?.toString(); const newValue = item[field]?.toString(); if (currentValue !== newValue) { updatedFields.push(field); salesCoordinator[field] = item[field]; territoryManagerUpdated = true; } } if (territoryManagerUpdated) { await salesCoordinator.save(); updatedsalesCoordinators.push({ ...salesCoordinator._doc, updatedFields: updatedFields.join(", "), }); } } else { // Create a new salesCoordinator salesCoordinator = new SalesCoOrdinator({ ...item, password, isVerified: true, }); await salesCoordinator.save(); // Send email with the new password await sendEmail({ to: `${item?.email}`, // Change to your recipient from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender subject: `Cheminova Account Created`, html: `Your Sales Coordinator Account is created successfully.
name is: ${item?.name}

MobileNumber is: ${item?.mobileNumber}

password is: ${password}

If you have not requested this email, please ignore it.`, }); newlyCreated.push({ salesCoordinator }); } } res.status(200).json({ message: "File processed successfully", newlyCreated, updatedsalesCoordinators, errors, }); } catch (error) { console.error(error); res.status(500).json({ message: "Internal Server Error" }); } }; export const register = async (req, res) => { let { name, email, countryCode, mobileNumber, territoryManager } = req.body; // console.log(req.body); countryCode = countryCode?.trim(); mobileNumber = mobileNumber?.trim(); const fullMobileNumber = `${countryCode}${mobileNumber}`; try { let salesCoordinator = await SalesCoOrdinator.findOne({ mobileNumber: fullMobileNumber, }); if (salesCoordinator && salesCoordinator.isVerified) { return res.status(400).json({ message: "SalesCoordinator already registered and verified for this mobile number.", }); } // const otp = crypto.randomInt(100000, 1000000).toString(); const otp = "123456"; const otpExpires = Date.now() + 1 * 60 * 1000; if (salesCoordinator) { salesCoordinator.otp = otp; salesCoordinator.otpExpires = otpExpires; salesCoordinator.mappedby = territoryManager; } else { salesCoordinator = new SalesCoOrdinator({ name, email, mobileNumber: fullMobileNumber, otp, otpExpires, mappedby: territoryManager, }); } // Generate uniqueId if not already present if (!salesCoordinator.uniqueId) { const currentYear = new Date().getFullYear().toString().slice(-2); const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase(); salesCoordinator.uniqueId = `${currentYear}-${randomChars}`; } await salesCoordinator.save(); // await sendOtp( // fullMobileNumber, // Your Cheminova verification OTP is: ${otp} // ); return res.status(200).json({ message: `OTP sent to your mobile number ${fullMobileNumber} successfully`, }); } catch (error) { res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; export const verifyOtp = async (req, res) => { const { fullMobileNumber, otp } = req.body; try { let mobileNmr = fullMobileNumber?.trim(); const salesCoordinator = await SalesCoOrdinator.findOne({ mobileNumber: mobileNmr, }); if (!salesCoordinator) { return res.status(400).json({ message: "Invalid mobile number or OTP" }); } if ( salesCoordinator.otp !== otp || salesCoordinator.otpExpires < Date.now() ) { return res.status(400).json({ message: "Invalid or expired OTP" }); } const name = salesCoordinator.name; const mobile = salesCoordinator.mobileNumber; salesCoordinator.isVerified = true; salesCoordinator.otp = undefined; salesCoordinator.otpExpires = undefined; // Generate a random password const newPassword = password.randomPassword({ length: 12, characters: [ { characters: password.upper, exactly: 1 }, { characters: password.symbols, exactly: 1 }, password.lower, password.digits, ], }); // Save the new password (hashed) salesCoordinator.password = newPassword; await salesCoordinator.save(); // Send email with the new password await sendEmail({ to: `${salesCoordinator?.email}`, // Change to your recipient from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender subject: `Cheminova Account Created`, html: `Your Sales Coordinator Account is created successfully.
name is: ${name}

MobileNumber is: ${mobile}

password is: ${newPassword}

If you have not requested this email, please ignore it.`, }); const token = salesCoordinator.getJWTToken(); res.status(200).json({ success: true, token, message: "Mobile number verified and new password sent successfully", }); } catch (error) { res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; // Login SalesCoOrdinator export const loginSalesCoOrdinator = async (req, res) => { const { email, password } = req.body; try { if (!email || !password) { return res.status(400).json({ message: "Please Enter Email & Password" }); } const salesCoordinator = await SalesCoOrdinator.findOne({ email }).select( "+password" ); if (!salesCoordinator) { return res.status(400).json({ message: "Invalid Email or Password" }); } const isPasswordMatched = await salesCoordinator.comparePassword(password); if (!isPasswordMatched) { return res.status(400).json({ message: "Invalid Email or Password" }); } const token = salesCoordinator.getJWTToken(); return res.status(200).json({ success: true, token, message: "Login Successfully", }); } catch (error) { return res.status(500).json({ message: error.message ? error.message : "Something went wrong!", }); } }; // Logout User export const logout = catchAsyncErrors(async (req, res, next) => { res.cookie("token", null, { expires: new Date(Date.now()), httpOnly: true, }); res.status(200).json({ success: true, message: "Logged Out", }); }); //get All salescoordinator export const getAllSalesCoOrdinator = async (req, res) => { try { const PAGE_SIZE = parseInt(req.query?.show || "10"); const page = parseInt(req.query?.page || "1") - 1; if (!req.user || !req.user._id) { return res.status(401).json({ success: false, message: "Please login to a TM account", }); } let filter = {}; if (req.query?.name) { filter.name = { $regex: new RegExp(req.query.name, "i"), }; } if (req.query?.mobileNumber) { filter.mobileNumber = { $regex: new RegExp(req.query.mobileNumber, "i"), }; } if (req.query?.isVerified) { filter.isVerified = req.query.isVerified === "true"; } const total = await SalesCoOrdinator.countDocuments(filter); const salesCoOrinators = await SalesCoOrdinator.find(filter) .populate("mappedby", "name") .limit(PAGE_SIZE) .skip(PAGE_SIZE * page) .sort({ createdAt: -1 }); return res.status(200).json({ success: true, total_data: total, total_pages: Math.ceil(total / PAGE_SIZE), salesCoOrinators, }); } catch (error) { res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; export const getAllSalesCoOrdinatorforTM_App = async (req, res) => { try { const PAGE_SIZE = parseInt(req.query?.show || "10"); const page = parseInt(req.query?.page || "1") - 1; if (!req.user || !req.user._id) { return res.status(401).json({ success: false, message: "Please login to a TM account", }); } let filter = {}; if (req.query?.name) { filter.name = { $regex: new RegExp(req.query.name, "i"), }; } if (req.query?.mobileNumber) { filter.mobileNumber = { $regex: new RegExp(req.query.mobileNumber, "i"), }; } if (req.query?.isVerified) { filter.isVerified = req.query.isVerified === "true"; } // Mandatory filter for mappedby filter.mappedby = req.user._id; const total = await SalesCoOrdinator.countDocuments(filter); const salesCoOrinators = await SalesCoOrdinator.find(filter) .limit(PAGE_SIZE) .skip(PAGE_SIZE * page) .sort({ createdAt: -1 }); return res.status(200).json({ success: true, total_data: total, total_pages: Math.ceil(total / PAGE_SIZE), salesCoOrinators, }); } catch (error) { res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; export const getAllSalesCoOrdinatorbytmId = async (req, res) => { try { const PAGE_SIZE = parseInt(req.query?.show || "10"); const page = parseInt(req.query?.page || "1") - 1; let filter = { mappedby: req.params.id }; // Include the mappedby field in the filter // Adding optional filters if (req.query?.name) { filter.name = { $regex: new RegExp(req.query.name, "i"), }; } if (req.query?.mobileNumber) { filter.mobileNumber = { $regex: new RegExp(req.query.mobileNumber, "i"), }; } if (req.query?.isVerified) { filter.isVerified = req.query.isVerified === "true"; } const total = await SalesCoOrdinator.countDocuments(filter); const salesCoOrinators = await SalesCoOrdinator.find(filter) .populate("mappedby", "name") .limit(PAGE_SIZE) .skip(PAGE_SIZE * page) .sort({ createdAt: -1 }); return res.status(200).json({ success: true, total_data: total, total_pages: Math.ceil(total / PAGE_SIZE), salesCoOrinators, }); } catch (error) { res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; export const mappedbyTM = async (req, res) => { try { 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.", }); } // Find the SalesCoOrdinator by ID const salesCoordinator = await SalesCoOrdinator.findById(id); // If no SalesCoOrdinator is found if (!salesCoordinator) { return res.status(404).json({ success: false, message: "Sales Coordinator not found.", }); } // Update the mappedby field salesCoordinator.mappedby = mappedby; // Save the updated SalesCoOrdinator await salesCoordinator.save(); return res.status(200).json({ success: true, message: "Sales Coordinator successfully updated.", salesCoordinator, }); } catch (error) { res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; 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) { return res .status(400) .json({ message: "Please provide sales coordinator ID" }); } const salesCoordinator = await SalesCoOrdinator.findById(req.params.id); if (salesCoordinator) { return res.status(200).json({ success: true, message: "Fetched successfully", data: salesCoordinator, }); } else { return res.status(404).json({ success: false, message: "Sales coordinator not found", }); } } catch (error) { return res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; // 4.Forgot Password export const forgotPassword = async (req, res) => { const salescoordinator = await SalesCoOrdinator.findOne({ email: req.body.email, }); if (!req.body.email) { return res.status(400).json({ message: "please Enter Email!" }); } if (!salescoordinator) { return res.status(404).json({ message: "SalesCoOrdinator not found" }); } // Get ResetPassword Token // const resetToken = salescoordinator.getResetPasswordToken(); //call function //save database reset token // await salescoordinator.save({ validateBeforeSave: false }); const passwords = password.randomPassword({ length: 12, characters: [ { characters: password.upper, exactly: 1 }, { characters: password.symbols, exactly: 1 }, password.lower, password.digits, ], }); // console.log(passwords); salescoordinator.password = passwords; await salescoordinator.save(); // const message = `Your password reset token are :- \n\n ${resetPasswordUrl} \n\nyour new password is:${password}\n\nIf you have not requested this email then, please ignore it.`; try { await sendEmail({ to: `${salescoordinator?.email}`, // Change to your recipient from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender subject: `Cheminova Password Recovery`, html: `your new password is:
${passwords}

If you have not requested this email then, please ignore it.`, }); res.status(200).json({ success: true, message: `Email sent to ${salescoordinator?.email} successfully`, }); } catch (error) { salescoordinator.resetPasswordToken = undefined; salescoordinator.resetPasswordExpire = undefined; await salescoordinator.save({ validateBeforeSave: false }); return res.status(500).json({ message: error.message ? error.message : "Something went wrong!", }); } }; //Update mobile Number export const updateMobileNumber = async (req, res) => { const { id } = req.params; const userId = id || req.user._id; let { newCountryCode, newMobileNumber } = req.body; newCountryCode = newCountryCode?.trim(); newMobileNumber = newMobileNumber?.trim(); const newFullMobileNumber = `${newCountryCode}${newMobileNumber}`; try { const salescoordinator = await SalesCoOrdinator.findById(userId); if (!salescoordinator) { return res.status(400).json({ message: "SalesCoOrdinator not found" }); } if (salescoordinator.mobileNumber === newFullMobileNumber) { return res.status(400).json({ message: "New mobile number cannot be the same as the old mobile number", }); } // Check if the new mobile number already exists in another document const existingSalesCoordinator = await SalesCoOrdinator.findOne({ mobileNumber: newFullMobileNumber, }); if (existingSalesCoordinator) { return res.status(400).json({ message: "Mobile number already registered and verified by someone", }); } // const otp = crypto.randomInt(100000, 1000000).toString(); const otp = "123456"; const otpExpires = Date.now() + 3 * 60 * 1000; // 3 minutes salescoordinator.newMobileNumber = newFullMobileNumber; salescoordinator.otp = otp; salescoordinator.otpExpires = otpExpires; await salescoordinator.save(); await sendOtp( newFullMobileNumber, `Your Cheminova verification OTP is: ${otp}` ); return res.status(200).json({ message: `OTP sent to your new mobile number ${newFullMobileNumber} successfully`, }); } catch (error) { console.error("Error updating mobile number:", error); return res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; //verify Updated Number OTP export const verifyUpdatedMobileOtp = async (req, res) => { const { newMobileNumber, otp } = req.body; try { let mobileNmr = newMobileNumber?.trim(); const salesCoordinator = await SalesCoOrdinator.findOne({ newMobileNumber: mobileNmr, }); if (!salesCoordinator) { return res.status(400).json({ message: "Invalid mobile number or OTP" }); } if ( salesCoordinator.otp !== otp || salesCoordinator.otpExpires < Date.now() ) { return res.status(400).json({ message: "Invalid or expired OTP" }); } // Update sales coordinator's mobile number and verification status salesCoordinator.mobileNumber = salesCoordinator.newMobileNumber; salesCoordinator.newMobileNumber = undefined; salesCoordinator.isVerified = true; salesCoordinator.otp = undefined; salesCoordinator.otpExpires = undefined; // Save changes to the database await salesCoordinator.save(); const token = salesCoordinator.getJWTToken(); return res.status(200).json({ success: true, token, message: "Mobile number updated and verified successfully", }); } catch (error) { console.error("Error verifying mobile OTP:", error); return res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; //getmyProfile export const getmyProfile = async (req, res) => { try { const myData = await SalesCoOrdinator.findById(req.user?._id); if (myData) { return res.status(200).json({ success: true, message: "feched!", myData, }); } } catch (error) { return res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; // export const deleteSalesCoOrdinator = 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: "salescoordinator not Found!", }); } //-------------------------// const salescoordinator = await SalesCoOrdinator.findByIdAndDelete( req.params.id ); if (!salescoordinator) { return res.status(404).json({ message: "salescoordinator Not Found" }); } await salescoordinator.remove(); res.status(200).json({ success: true, message: "salescoordinator Deleted Successfully!!", }); } catch (error) { res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; export const UpdateProfile = async (req, res) => { const { name, email } = req.body; const { id } = req.params; const userId = id || req.user._id; // Validate email if (!validator.isEmail(email)) { return res.status(400).json({ message: "Invalid email address" }); } try { const salesCoordinator = await SalesCoOrdinator.findById(userId); // Use the ID from params if (!salesCoordinator) { return res.status(404).json({ message: "SalesCoOrdinator not found" }); } if (!salesCoordinator.isVerified) { return res.status(400).json({ message: "SalesCoOrdinator not verified" }); } // Check if email is being changed and already exists if (email && email !== salesCoordinator.email) { const emailExists = await SalesCoOrdinator.findOne({ email }); if (emailExists && emailExists._id.toString() !== userId) { return res.status(400).json({ message: "This Email ID is already in use by another SalesCoOrdinator", }); } salesCoordinator.email = email; } // Update name if provided if (name) { salesCoordinator.name = name; } // Save the updated salesCoordinator await salesCoordinator.save(); return res.status(200).json({ salesCoordinator, message: "Profile updated successfully", }); } catch (error) { res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; //change SalesCoOrdinator password export const ChangePassword = async (req, res) => { const { id } = req.params; // Retrieve id from req.params const { oldPassword, newPassword, confirmPassword } = req.body; const userId = id || req.user._id; // Use the ID from the URL or from the authenticated user // console.log(userId); if (!oldPassword) { return res.status(400).json({ message: "Please Enter Old password" }); } if (!newPassword) { return res.status(400).json({ message: "Please Enter New Password " }); } if (!confirmPassword) { return res.status(400).json({ message: "Please Enter Confirm Password" }); } try { const Salescoordinator = await SalesCoOrdinator.findById(userId).select( "+password" ); if (!Salescoordinator) { return res.status(404).json({ message: "SalesCoOrdinator not found" }); } const isPasswordMatched = await Salescoordinator.comparePassword( oldPassword ); if (!isPasswordMatched) { return res.status(400).json({ message: "Old password is incorrect" }); } if (newPassword !== confirmPassword) { return res .status(400) .json({ message: "New password and confirm Password do not match" }); } Salescoordinator.password = newPassword; await Salescoordinator.save(); return res .status(200) .json({ success: true, message: "Password updated successfully" }); } catch (error) { console.error("Error updating password:", error); return res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; export const Otp = async (req, res) => { // const { name, mobileNumber } = req.body; try { // let salescoordinator = await SalesCoOrdinator.findOne({ mobileNumber }); // if (salescoordinator && salescoordinator.isVerified) { // return res.status(400).json({ message: 'SalesCoOrdinator already registered and verified for This Mobile No.' }); // } // const otp = crypto.randomInt(100000, 1000000).toString(); // // const otp ="123456"; // const otpExpires = Date.now() + 10 * 60 * 1000; // 10 minutes // if (salescoordinator) { // salescoordinator.otp = otp; // salescoordinator.otpExpires = otpExpires; // } else { // salescoordinator = new SalesCoOrdinator({ name, mobileNumber, otp, otpExpires }); // } // await salescoordinator.save(); await sendOtp(); // res.status(200).json({salescoordinator, message: `OTP ${otp} sent to your mobile number successfully` }); } catch (error) { res.status(500).json({ message: error.message ? error.message : "Server error!", }); } };