This commit is contained in:
ROSHAN GARG 2024-10-18 12:05:37 +05:30
commit 235e313c97
8 changed files with 298 additions and 72 deletions

Binary file not shown.

Binary file not shown.

View File

@ -47,6 +47,7 @@ export const uploadSalesCoordinators = async (req, res) => {
// Map headers from the Excel file to your schema // Map headers from the Excel file to your schema
const headerMapping = { const headerMapping = {
"Employee Code": "uniqueId",
"Sales Coordinator Name": "name", "Sales Coordinator Name": "name",
Email: "email", Email: "email",
"Phone Number": "mobileNumber", "Phone Number": "mobileNumber",
@ -67,7 +68,7 @@ export const uploadSalesCoordinators = async (req, res) => {
for (let i = 1; i < data.length; i++) { for (let i = 1; i < data.length; i++) {
const row = data[i]; const row = data[i];
// Skip the row if it's completely empty // Skip the row if it's completely empty
if (row.every(cell => cell === undefined || cell === "")) { if (row.every((cell) => cell === undefined || cell === "")) {
continue; continue;
} }
const item = {}; const item = {};
@ -84,6 +85,7 @@ export const uploadSalesCoordinators = async (req, res) => {
const validationErrors = new Set(); const validationErrors = new Set();
// Validate required fields // Validate required fields
if (!item.uniqueId) missingFields.add("Employee Code");
if (!item.name) missingFields.add("name"); if (!item.name) missingFields.add("name");
if (!item.email) missingFields.add("email"); if (!item.email) missingFields.add("email");
if (!item.mobileNumber) missingFields.add("mobileNumber"); if (!item.mobileNumber) missingFields.add("mobileNumber");
@ -93,10 +95,34 @@ export const uploadSalesCoordinators = async (req, res) => {
validationErrors.add("incorrect mail"); validationErrors.add("incorrect mail");
} }
// Validate mobile number // Normalize the mobileNumber
if (item.mobileNumber && !/^\d{10}$/.test(item.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)"); validationErrors.add("Invalid Mobile Number (should be 10 digits)");
} }
}
}
// Combine all errors into a single message // Combine all errors into a single message
let errorMessage = ""; let errorMessage = "";
@ -114,6 +140,7 @@ export const uploadSalesCoordinators = async (req, res) => {
// If there are errors, push them to the errors array // If there are errors, push them to the errors array
if (errorMessage.trim()) { if (errorMessage.trim()) {
errors.push({ errors.push({
uniqueId: item.uniqueId || "N/A",
name: item.name || "N/A", name: item.name || "N/A",
email: item.email || "N/A", email: item.email || "N/A",
phone: item.mobileNumber || "N/A", phone: item.mobileNumber || "N/A",
@ -126,37 +153,75 @@ export const uploadSalesCoordinators = async (req, res) => {
const password = generatePassword(item.name, item.email); const password = generatePassword(item.name, item.email);
// Check for existing user by uniqueId // Check for existing user by uniqueId
let salesCoordinator = await SalesCoOrdinator.findOne({ let salesCoordinatorByUniqueId = await SalesCoOrdinator.findOne({
email: item.email, uniqueId: item.uniqueId,
}); });
if (salesCoordinator) { // Search for sales coordinator by mobile number
// Track updated fields let salesCoordinatorByMobileNumber = await SalesCoOrdinator.findOne({
const updatedFields = []; $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 (salesCoordinatorByUniqueId && salesCoordinatorByMobileNumber) {
if (
salesCoordinatorByUniqueId._id.equals(
salesCoordinatorByMobileNumber._id
)
) {
// Both match and are the same person, proceed to update
let salescoordinatorUpdated = false;
// Check for changes in user details
let territoryManagerUpdated = false;
for (let field in item) { for (let field in item) {
const currentValue = salesCoordinator[field]?.toString(); const currentValue = salesCoordinatorByUniqueId[field]?.toString();
const newValue = item[field]?.toString(); const newValue = item[field]?.toString();
if (currentValue !== newValue) { if (currentValue !== newValue) {
updatedFields.push(field); salesCoordinatorByUniqueId[field] = item[field];
salesCoordinator[field] = item[field]; salescoordinatorUpdated = true;
territoryManagerUpdated = true;
} }
} }
if (territoryManagerUpdated) { if (salescoordinatorUpdated) {
await salesCoordinator.save(); await salesCoordinatorByUniqueId.save();
updatedsalesCoordinators.push({ updatedsalesCoordinators.push({
...salesCoordinator._doc, ...salesCoordinatorByUniqueId._doc,
updatedFields: updatedFields.join(", "), updatedFields: updatedFields.join(", "),
}); });
} }
} else { } else {
// Create a new salesCoordinator // Both exist but refer to different users
salesCoordinator = new SalesCoOrdinator({ errors.push({
uniqueId: item.uniqueId,
name: item.name,
email: item.email,
phone: item.mobileNumber,
message: ` Employee Code (${salesCoordinatorByUniqueId.uniqueId}) is refer to (${salesCoordinatorByUniqueId.name}) and Mobile Number (${salesCoordinatorByMobileNumber.mobileNumber}) refer to (${salesCoordinatorByMobileNumber.name}) Sales Coordinator. Please provide the correct employee code or mobile number.`,
});
}
} else if (salesCoordinatorByUniqueId) {
// Case 2: uniqueId exists, but mobileNumber is new
salesCoordinatorByUniqueId.mobileNumber = item.mobileNumber; // Update mobile number
await salesCoordinatorByUniqueId.save();
updatedsalesCoordinators.push({
...salesCoordinatorByUniqueId._doc,
updatedFields: "mobileNumber",
});
} else if (salesCoordinatorByMobileNumber) {
// 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 ${salesCoordinatorByMobileNumber.name} user.`,
});
} else {
// Case 4: Both uniqueId and mobileNumber are new, create a new salesCoordinator
const salesCoordinator = new SalesCoOrdinator({
...item, ...item,
password, password,
isVerified: true, isVerified: true,
@ -168,9 +233,9 @@ export const uploadSalesCoordinators = async (req, res) => {
from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender
subject: `Cheminova Account Created`, subject: `Cheminova Account Created`,
html: `Your Sales Coordinator Account is created successfully. html: `Your Sales Coordinator Account is created successfully.
<br/>name is: <strong>${item?.name}</strong><br/> <br/>Name: <strong>${item?.name}</strong><br/>
<br/>MobileNumber is: <strong>${item?.mobileNumber}</strong><br/> <br/>Mobile Number: <strong>${item?.mobileNumber}</strong><br/>
<br/>password is: <strong>${password}</strong><br/><br/>If you have not requested this email, please ignore it.`, <br/>Password: <strong>${password}</strong><br/><br/>If you have not requested this email, please ignore it.`,
}); });
newlyCreated.push({ salesCoordinator }); newlyCreated.push({ salesCoordinator });
} }
@ -188,7 +253,8 @@ export const uploadSalesCoordinators = async (req, res) => {
} }
}; };
export const register = async (req, res) => { export const register = async (req, res) => {
let { name, email, countryCode, mobileNumber, territoryManager } = req.body; let { name, email, countryCode, mobileNumber, territoryManager, uniqueId } =
req.body;
// console.log(req.body); // console.log(req.body);
countryCode = countryCode?.trim(); countryCode = countryCode?.trim();
mobileNumber = mobileNumber?.trim(); mobileNumber = mobileNumber?.trim();
@ -196,6 +262,7 @@ export const register = async (req, res) => {
try { try {
let salesCoordinator = await SalesCoOrdinator.findOne({ let salesCoordinator = await SalesCoOrdinator.findOne({
uniqueId,
mobileNumber: fullMobileNumber, mobileNumber: fullMobileNumber,
}); });
@ -221,14 +288,9 @@ export const register = async (req, res) => {
otp, otp,
otpExpires, otpExpires,
mappedby: territoryManager, mappedby: territoryManager,
uniqueId,
}); });
} }
// 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 salesCoordinator.save();
// await sendOtp( // await sendOtp(
// fullMobileNumber, // fullMobileNumber,

View File

@ -4,6 +4,8 @@ import cron from "node-cron";
import { sendPushNotification } from "../../Utils/sendPushNotification.js"; import { sendPushNotification } from "../../Utils/sendPushNotification.js";
import SalesCoOrdinator from "../SalesCoOrdinators/SalesCoOrdinatorModel.js"; import SalesCoOrdinator from "../SalesCoOrdinators/SalesCoOrdinatorModel.js";
import TerritoryManager from "../TerritoryManagers/TerritoryManagerModel.js"; import TerritoryManager from "../TerritoryManagers/TerritoryManagerModel.js";
import User from "../user/userModel.js";
import RetailDistributor from "../RetailDistributor/RetailDistributorModel.js";
// Function to update task statuses // Function to update task statuses
export const updateOverdueTasks = async () => { export const updateOverdueTasks = async () => {
try { try {
@ -362,3 +364,69 @@ export const updateTaskStatus = async (req, res) => {
}); });
} }
}; };
// Controller to get today's tasks with pagination and conditional population
export const getTodaysTasks = async (req, res) => {
try {
// Get the current page and items per page (defaults to page 1, 10 items per page)
const currentPage = parseInt(req.query.page) || 1;
const itemsPerPage = parseInt(req.query.show) || 10;
// Get today's date at midnight
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0); // Set time to 00:00:00
// Get the end of today at 23:59:59
const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999); // Set time to 23:59:59
// Calculate the number of items to skip
const skip = (currentPage - 1) * itemsPerPage;
// Find tasks that are due today, with pagination
let tasksQuery = Task.find({
taskDueDate: {
$gte: startOfToday,
$lte: endOfToday,
},
})
.populate('taskAssignedTo') // Optional: populate assigned coordinator details
.populate('taskAssignedBy') // Optional: populate assigned manager details
.skip(skip) // Skip documents for pagination
.limit(itemsPerPage); // Limit the number of documents
// Modify the population based on the `addedFor` field value
tasksQuery = tasksQuery.populate({
path: 'addedForId',
model: function (doc) {
return doc.addedFor === 'PrincipalDistributor' ? 'User' : 'RetailDistributor';
},
});
// Execute the query
const tasks = await tasksQuery.exec();
// Count the total number of tasks for pagination metadata
const totalTasks = await Task.countDocuments({
taskDueDate: {
$gte: startOfToday,
$lte: endOfToday,
},
});
// Calculate total pages
const totalPages = Math.ceil(totalTasks / itemsPerPage);
// Send paginated tasks in response
res.status(200).json({
tasks, // Paginated tasks
currentPage, // Current page number
itemsPerPage, // Number of tasks per page
totalTasks, // Total number of tasks
totalPages, // Total number of pages
});
} catch (error) {
console.error('Error fetching today\'s tasks with pagination:', error);
res.status(500).json({ message: 'Failed to retrieve tasks for today' });
}
};

View File

@ -6,11 +6,12 @@ import {
getTasksbytask, getTasksbytask,
getAllTasksByStatus, getAllTasksByStatus,
getTasksByDates, getTasksByDates,
getTodaysTasks,
} from "./TaskController.js"; } from "./TaskController.js";
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js"; import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js"; import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
import { isAuthenticated_SC_TM } from "../../middlewares/generalAuth.js"; import { isAuthenticated_SC_TM } from "../../middlewares/generalAuth.js";
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
const router = express.Router(); const router = express.Router();
// Route for Territory Manager to assign a task // Route for Territory Manager to assign a task
@ -31,5 +32,10 @@ router.put(
isAuthenticatedSalesCoOrdinator, isAuthenticatedSalesCoOrdinator,
updateTaskStatus updateTaskStatus
); );
router.get(
"/today",
isAuthenticatedUser,
authorizeRoles("admin"),
getTodaysTasks
);
export default router; export default router;

View File

@ -47,6 +47,7 @@ export const uploadTerritoryManagers = async (req, res) => {
// Map headers from the Excel file to your schema // Map headers from the Excel file to your schema
const headerMapping = { const headerMapping = {
"Employee Code": "uniqueId",
"Territory Manager Name": "name", "Territory Manager Name": "name",
Email: "email", Email: "email",
"Phone Number": "mobileNumber", "Phone Number": "mobileNumber",
@ -84,6 +85,7 @@ export const uploadTerritoryManagers = async (req, res) => {
const validationErrors = new Set(); const validationErrors = new Set();
// Validate required fields // Validate required fields
if (!item.uniqueId) missingFields.add("Employee Code");
if (!item.name) missingFields.add("name"); if (!item.name) missingFields.add("name");
if (!item.email) missingFields.add("email"); if (!item.email) missingFields.add("email");
if (!item.mobileNumber) missingFields.add("mobileNumber"); if (!item.mobileNumber) missingFields.add("mobileNumber");
@ -93,10 +95,34 @@ export const uploadTerritoryManagers = async (req, res) => {
validationErrors.add("incorrect mail"); validationErrors.add("incorrect mail");
} }
// Validate mobile number // Normalize the mobileNumber
if (item.mobileNumber && !/^\d{10}$/.test(item.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)"); validationErrors.add("Invalid Mobile Number (should be 10 digits)");
} }
}
}
// Combine all errors into a single message // Combine all errors into a single message
let errorMessage = ""; let errorMessage = "";
@ -114,6 +140,7 @@ export const uploadTerritoryManagers = async (req, res) => {
// If there are errors, push them to the errors array // If there are errors, push them to the errors array
if (errorMessage.trim()) { if (errorMessage.trim()) {
errors.push({ errors.push({
uniqueId: item.uniqueId || "N/A",
name: item.name || "N/A", name: item.name || "N/A",
email: item.email || "N/A", email: item.email || "N/A",
phone: item.mobileNumber || "N/A", phone: item.mobileNumber || "N/A",
@ -126,37 +153,73 @@ export const uploadTerritoryManagers = async (req, res) => {
const password = generatePassword(item.name, item.email); const password = generatePassword(item.name, item.email);
// Check for existing user by uniqueId // Check for existing user by uniqueId
let territoryManager = await TerritoryManager.findOne({ let territotymanagerByUniqueId = await TerritoryManager.findOne({
email: item.email, 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;
if (territoryManager) {
// Track updated fields
const updatedFields = [];
// Check for changes in user details
let territoryManagerUpdated = false;
for (let field in item) { for (let field in item) {
const currentValue = territoryManager[field]?.toString(); const currentValue = territotymanagerByUniqueId[field]?.toString();
const newValue = item[field]?.toString(); const newValue = item[field]?.toString();
if (currentValue !== newValue) { if (currentValue !== newValue) {
updatedFields.push(field); territotymanagerByUniqueId[field] = item[field];
territoryManager[field] = item[field]; territorymanagerUpdated = true;
territoryManagerUpdated = true;
} }
} }
if (territoryManagerUpdated) { if (territorymanagerUpdated) {
await territoryManager.save(); await territotymanagerByUniqueId.save();
updatedtrritoryManagers.push({ updatedtrritoryManagers.push({
...territoryManager._doc, ...territotymanagerByUniqueId._doc,
updatedFields: updatedFields.join(", "), updatedFields: updatedFields.join(", "),
}); });
} }
} else { } else {
// Create a new territoryManager // Both exist but refer to different users
territoryManager = new TerritoryManager({ 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, ...item,
password, password,
isVerified: true, isVerified: true,
@ -188,13 +251,14 @@ export const uploadTerritoryManagers = async (req, res) => {
} }
}; };
export const register = async (req, res) => { export const register = async (req, res) => {
let { name, email, countryCode, mobileNumber } = req.body; let { name, email, countryCode, mobileNumber, uniqueId } = req.body;
countryCode = countryCode?.trim(); countryCode = countryCode?.trim();
mobileNumber = mobileNumber?.trim(); mobileNumber = mobileNumber?.trim();
const fullMobileNumber = `${countryCode}${mobileNumber}`; const fullMobileNumber = `${countryCode}${mobileNumber}`;
try { try {
let territoryManager = await TerritoryManager.findOne({ let territoryManager = await TerritoryManager.findOne({
uniqueId,
mobileNumber: fullMobileNumber, mobileNumber: fullMobileNumber,
}); });
@ -218,14 +282,9 @@ export const register = async (req, res) => {
mobileNumber: fullMobileNumber, mobileNumber: fullMobileNumber,
otp, otp,
otpExpires, otpExpires,
uniqueId,
}); });
} }
// Generate uniqueId if not already present
if (!territoryManager.uniqueId) {
const currentYear = new Date().getFullYear().toString().slice(-2);
const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase();
territoryManager.uniqueId = `${currentYear}-${randomChars}`;
}
await territoryManager.save(); await territoryManager.save();
// await sendOtp( // await sendOtp(
// fullMobileNumber, // fullMobileNumber,
@ -390,7 +449,32 @@ export const getAllTerritoryManager = async (req, res) => {
}); });
} }
}; };
//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) => { export const getOneTerritoryManager = async (req, res) => {
try { try {
if (!req.params.id) { if (!req.params.id) {

View File

@ -17,6 +17,7 @@ import {
getOneTerritoryManager, getOneTerritoryManager,
logout, logout,
uploadTerritoryManagers, uploadTerritoryManagers,
getAllTerritoryManagerdropdown,
} from "./TerritoryManagerController.js"; } from "./TerritoryManagerController.js";
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js"; import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js"; import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
@ -35,6 +36,12 @@ router.get(
authorizeRoles("admin"), authorizeRoles("admin"),
getAllTerritoryManager getAllTerritoryManager
); );
router.get(
"/getAll-dropdown",
isAuthenticatedUser,
authorizeRoles("admin"),
getAllTerritoryManagerdropdown
);
router.get( router.get(
"/getOne/:id", "/getOne/:id",
isAuthenticatedUser, isAuthenticatedUser,

View File

@ -43,7 +43,6 @@ const userSchema = new mongoose.Schema(
email: { email: {
type: String, type: String,
required: [true, "Please Enter Your Email"], required: [true, "Please Enter Your Email"],
unique: true,
validate: [validator.isEmail, "Please Enter a valid Email"], validate: [validator.isEmail, "Please Enter a valid Email"],
}, },
phone: { phone: {