// 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 });
}
}
// 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: `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!",
});
}
};
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 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.
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!", }); } };