// import hashPassword from '../utils/hashPassword'; import crypto from "crypto"; import mongoose from "mongoose"; import TerritoryManager from "./TerritoryManagerModel.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 uploadTerritoryManagers = 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 = { "Employee Code": "uniqueId", "Territory Manager 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 updatedtrritoryManagers = []; 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.uniqueId) missingFields.add("Employee Code"); 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"); } // Normalize the mobileNumber if (item.mobileNumber) { item.mobileNumber = item.mobileNumber.toString().trim(); // Check if it already has +91 if (item.mobileNumber.startsWith("+91")) { // If it has +91, remove it for validation const strippedNumber = item.mobileNumber.substring(3); // Validate that the remaining number is 10 digits if (/^\d{10}$/.test(strippedNumber)) { // Keep the mobile number with +91 for storage item.mobileNumber = `+91${strippedNumber}`; } else { validationErrors.add( "Invalid Mobile Number (should be 10 digits after +91)" ); } } else { // If not prefixed with +91, check if it is exactly 10 digits if (/^\d{10}$/.test(item.mobileNumber)) { // Add +91 for storage item.mobileNumber = `+91${item.mobileNumber}`; } else { 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({ uniqueId: item.uniqueId || "N/A", 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 territotymanagerByUniqueId = await TerritoryManager.findOne({ uniqueId: item.uniqueId, }); // Search for Territory Manager by mobile number let territorymanagerByMobileNumber = await TerritoryManager.findOne({ $or: [ { mobileNumber: item.mobileNumber }, // Check stored mobile number with +91 { mobileNumber: item.mobileNumber.substring(3) }, // Check 10-digit number (remove +91) ], }); // Case 1: Both uniqueId and mobileNumber exist if (territotymanagerByUniqueId && territorymanagerByMobileNumber) { if ( territotymanagerByUniqueId._id.equals( territorymanagerByMobileNumber._id ) ) { // Both match and are the same person, proceed to update let territorymanagerUpdated = false; for (let field in item) { const currentValue = territotymanagerByUniqueId[field]?.toString(); const newValue = item[field]?.toString(); if (currentValue !== newValue) { territotymanagerByUniqueId[field] = item[field]; territorymanagerUpdated = true; } } if (territorymanagerUpdated) { await territotymanagerByUniqueId.save(); updatedtrritoryManagers.push({ ...territotymanagerByUniqueId._doc, updatedFields: updatedFields.join(", "), }); } } else { // Both exist but refer to different users errors.push({ uniqueId: item.uniqueId, name: item.name, email: item.email, phone: item.mobileNumber, message: ` Employee Code (${territotymanagerByUniqueId.uniqueId}) is refer to (${territotymanagerByUniqueId.name}) and Mobile Number (${territorymanagerByMobileNumber.mobileNumber}) refer to (${territorymanagerByMobileNumber.name}) Territory Manager. Please provide the correct employee code or mobile number.`, }); } } else if (territotymanagerByUniqueId) { // Case 2: uniqueId exists, but mobileNumber is new territotymanagerByUniqueId.mobileNumber = item.mobileNumber; // Update mobile number await territotymanagerByUniqueId.save(); updatedtrritoryManagers.push({ ...territotymanagerByUniqueId._doc, updatedFields: "mobileNumber", }); } else if (territorymanagerByMobileNumber) { // Case 3: mobileNumber exists but uniqueId is new errors.push({ uniqueId: item.uniqueId, name: item.name, email: item.email, phone: item.mobileNumber, message: `Mobile number already exists for ${territorymanagerByMobileNumber.name} user.`, }); } else { // Case 4: Both uniqueId and mobileNumber are new, create a new salesCoordinator const territoryManager = new TerritoryManager({ ...item, password, isVerified: true, }); await territoryManager.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 Territory Manager 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({ territoryManager }); } } res.status(200).json({ message: "File processed successfully", newlyCreated, updatedtrritoryManagers, 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, uniqueId } = req.body; countryCode = countryCode?.trim(); mobileNumber = mobileNumber?.trim(); const fullMobileNumber = `${countryCode}${mobileNumber}`; try { let territoryManager = await TerritoryManager.findOne({ uniqueId, mobileNumber: fullMobileNumber, }); if (territoryManager && territoryManager.isVerified) { return res.status(400).json({ message: "TerritoryManager 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 (territoryManager) { territoryManager.otp = otp; territoryManager.otpExpires = otpExpires; } else { territoryManager = new TerritoryManager({ name, email, mobileNumber: fullMobileNumber, otp, otpExpires, uniqueId, }); } await territoryManager.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 territoryManager = await TerritoryManager.findOne({ mobileNumber: mobileNmr, }); if (!territoryManager) { return res.status(400).json({ message: "Invalid mobile number or OTP" }); } if ( territoryManager.otp !== otp || territoryManager.otpExpires < Date.now() ) { return res.status(400).json({ message: "Invalid or expired OTP" }); } const name = territoryManager.name; const mobile = territoryManager.mobileNumber; territoryManager.isVerified = true; territoryManager.otp = undefined; territoryManager.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) territoryManager.password = newPassword; await territoryManager.save(); // Send email with the new password await sendEmail({ to: `${territoryManager?.email}`, // Change to your recipient from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender subject: `Cheminova Account Created`, html: `Your Territory Manager 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 = territoryManager.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 TerritoryManager export const loginTerritoryManager = async (req, res) => { const { email, password } = req.body; // console.log(email, password); try { if (!email || !password) { return res.status(400).json({ message: "Please Enter Email & Password" }); } const territoryManager = await TerritoryManager.findOne({ email }).select( "+password" ); if (!territoryManager) { return res.status(400).json({ message: "Invalid Email or Password" }); } const isPasswordMatched = await territoryManager.comparePassword(password); if (!isPasswordMatched) { return res.status(400).json({ message: "Invalid Email or Password" }); } const token = territoryManager.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 territorymanager export const getAllTerritoryManager = async (req, res) => { try { const PAGE_SIZE = parseInt(req.query?.show || "10"); const page = parseInt(req.query?.page || "1") - 1; 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 TerritoryManager.countDocuments(filter); const territoryManager = await TerritoryManager.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), territoryManager, }); } catch (error) { res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; //for dropdown export const getAllTerritoryManagerdropdown = async (req, res) => { try { let filter = {}; if (req.query?.name) { filter.name = { $regex: new RegExp(req.query.name, "i"), }; } const total = await TerritoryManager.countDocuments(filter); const territoryManager = await TerritoryManager.find(filter).sort({ createdAt: -1, }); return res.status(200).json({ success: true, total_data: total, territoryManager, }); } catch (error) { res.status(500).json({ success: false, message: error.message ? error.message : "Something went wrong!", }); } }; export const getOneTerritoryManager = async (req, res) => { try { if (!req.params.id) { return res .status(400) .json({ message: "Please provide sales coordinator ID" }); } const territoryManager = await TerritoryManager.findById(req.params.id); if (territoryManager) { return res.status(200).json({ success: true, message: "Fetched successfully", data: territoryManager, }); } 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 territorymanager = await TerritoryManager.findOne({ email: req.body.email, }); if (!req.body.email) { return res.status(400).json({ message: "please Enter Email!" }); } if (!territorymanager) { return res.status(404).json({ message: "TerritoryManager not found" }); } // Get ResetPassword Token // const resetToken = territorymanager.getResetPasswordToken(); //call function //save database reset token // await territorymanager.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); territorymanager.password = passwords; await territorymanager.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: `${territorymanager?.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 ${territorymanager?.email} successfully`, }); } catch (error) { territorymanager.resetPasswordToken = undefined; territorymanager.resetPasswordExpire = undefined; await territorymanager.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 territorymanager = await TerritoryManager.findById(userId); if (!territorymanager) { return res.status(400).json({ message: "TerritoryManager not found" }); } if (territorymanager.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 existingTerritoryManager = await TerritoryManager.findOne({ mobileNumber: newFullMobileNumber, }); if (existingTerritoryManager) { 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 territorymanager.newMobileNumber = newFullMobileNumber; territorymanager.otp = otp; territorymanager.otpExpires = otpExpires; await territorymanager.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; // console.log(newMobileNumber, otp); try { let mobileNmr = newMobileNumber?.trim(); const territoryManager = await TerritoryManager.findOne({ newMobileNumber: mobileNmr, }); if (!territoryManager) { return res.status(400).json({ message: "Invalid mobile number or OTP" }); } if ( territoryManager.otp !== otp || territoryManager.otpExpires < Date.now() ) { return res.status(400).json({ message: "Invalid or expired OTP" }); } // Update sales coordinator's mobile number and verification status territoryManager.mobileNumber = territoryManager.newMobileNumber; territoryManager.newMobileNumber = undefined; territoryManager.isVerified = true; territoryManager.otp = undefined; territoryManager.otpExpires = undefined; // Save changes to the database await territoryManager.save(); const token = territoryManager.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 TerritoryManager.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 deleteTerritoryManager = async (req, res) => { try { if (!req.params.id) { return res.status(400).json({ success: false, message: "Please Provide TerritoryManager ID!", }); } const getTerritoryManager = await TerritoryManager.findById(req.params.id); if (!getTerritoryManager) { return res.status(404).json({ success: false, message: "territorymanager not Found!", }); } //-------------------------// const territorymanager = await TerritoryManager.findByIdAndDelete( req.params.id ); if (!territorymanager) { return res.status(404).json({ message: "territorymanager Not Found" }); } await territorymanager.remove(); res.status(200).json({ success: true, message: "territorymanager 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; // console.log(name, email); const userId = id || req.user._id; // console.log(userId); // Validate email if (!validator.isEmail(email)) { return res.status(400).json({ message: "Invalid email address" }); } try { const territoryManager = await TerritoryManager.findById(userId); // Use the ID from params if (!territoryManager) { return res.status(404).json({ message: "TerritoryManager not found" }); } if (!territoryManager.isVerified) { return res.status(400).json({ message: "TerritoryManager not verified" }); } // Check if email is being changed and already exists if (email && email !== territoryManager.email) { const emailExists = await TerritoryManager.findOne({ email }); if (emailExists && emailExists._id.toString() !== userId) { return res.status(400).json({ message: "This Email ID is already in use by another TerritoryManager", }); } territoryManager.email = email; } // Update name if provided if (name) { territoryManager.name = name; } // Save the updated territoryManager await territoryManager.save(); return res.status(200).json({ territoryManager, message: "Profile updated successfully", }); } catch (error) { res.status(500).json({ message: error.message ? error.message : "Server error!", }); } }; //change TerritoryManager 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 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 territorymanager = await TerritoryManager.findById(userId).select( "+password" ); if (!territorymanager) { return res.status(404).json({ message: "TerritoryManager not found" }); } const isPasswordMatched = await territorymanager.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" }); } territorymanager.password = newPassword; await territorymanager.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 territorymanager = await TerritoryManager.findOne({ mobileNumber }); // if (territorymanager && territorymanager.isVerified) { // return res.status(400).json({ message: 'TerritoryManager 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 (territorymanager) { // territorymanager.otp = otp; // territorymanager.otpExpires = otpExpires; // } else { // territorymanager = new TerritoryManager({ name, mobileNumber, otp, otpExpires }); // } // await territorymanager.save(); await sendOtp(); // res.status(200).json({territorymanager, message: `OTP ${otp} sent to your mobile number successfully` }); } catch (error) { res.status(500).json({ message: error.message ? error.message : "Server error!", }); } };