// 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: `Welcome to Cheminova - Account Created Successfully`, html: `

Dear ${item.name},

We are pleased to inform you that your Territory Manager account has been successfully created. Please find your account details below:

Name: ${item.name}

Mobile Number: ${item.mobileNumber}

Email: ${item.email}

Password: ${password}



For convenience, you can also download our mobile app from the following links:


If you have not requested this email or have any concerns, please contact our support team immediately.


Best regards,

Cheminova Support Team

`, }); newlyCreated.push({ territoryManager }); } } // Clean up uploaded file if any error occurs if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } res.status(200).json({ message: "File processed successfully", newlyCreated, updatedtrritoryManagers, errors, }); } catch (error) { console.error(error); // Clean up uploaded file if any error occurs if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } 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: `Welcome to Cheminova - Account Created Successfully`, html: `

Dear ${name},

We are pleased to inform you that your Territory Manager account has been successfully created. Please find your account details below:

Name: ${name}

Mobile Number: ${mobile}

Email: ${territoryManager.email}

Password: ${newPassword}



For convenience, you can also download our mobile app from the following links:


If you have not requested this email or have any concerns, please contact our support team immediately.


Best regards,

Cheminova Support Team

`, }); 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!", }); } }; export const ResetPassword = async (req, res) => { const id = req.params.id; // console.log(id); if (!id) { return res .status(400) .json({ message: "Invalid request. ID is required." }); } try { const territorymanager = await TerritoryManager.findById(id); if (!territorymanager) { return res.status(404).json({ message: "Territory Manager not found" }); } // Generate a new random password const newPassword = password.randomPassword({ length: 12, characters: [ { characters: password.upper, exactly: 1 }, { characters: password.symbols, exactly: 1 }, password.lower, password.digits, ], }); console.log(newPassword); // Update the territory manager's password territorymanager.password = newPassword; await territorymanager.save(); // Send email with the new credentials await sendEmail({ to: `${territorymanager.email}`, // Recipient email from: `${process.env.SEND_EMAIL_FROM}`, // Sender email subject: "Cheminova Account Credentials", html: `

Dear ${territorymanager.name},

Your Territory Manager account credentials have been updated. Please find your new login details below:

Email: ${territorymanager.email}

Password: ${newPassword}

Please use these credentials to log in to your account. For security reasons, it's recommended to change your password after logging in.


To download our mobile app, use the following links:


If you did not request this change, please contact our support team immediately.


Best regards,

Cheminova Support Team

`, }); // console.log(territorymanager); res.status(200).json({ success: true, message: `Account credentials sent to ${territorymanager.email} successfully.`, }); } catch (error) { console.error("Error resetting password:", error); res.status(500).json({ success: false, message: error.message || "Something went wrong while resetting the password.", }); } }; //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!", }); } };