api/resources/Task/TaskController.js
2024-11-13 17:42:43 +05:30

560 lines
16 KiB
JavaScript

import Task from "./TaskModel.js";
import crypto from "crypto";
import cron from "node-cron";
import { sendPushNotification } from "../../Utils/sendPushNotification.js";
import SalesCoOrdinator from "../SalesCoOrdinators/SalesCoOrdinatorModel.js";
import TerritoryManager from "../TerritoryManagers/TerritoryManagerModel.js";
import User from "../user/userModel.js";
import RetailDistributor from "../RetailDistributor/RetailDistributorModel.js";
// Function to update task statuses
export const updateOverdueTasks = async () => {
try {
const currentDate = new Date();
const currentDateOnly = new Date(currentDate.setHours(0, 0, 0, 0));
// Find tasks where dueDate is before the current date and status is "New"
const overdueTasks = await Task.find({
taskDueDate: { $lt: currentDateOnly },
taskStatus: "New",
});
// Update tasks to "Pending"
for (const task of overdueTasks) {
task.taskStatus = "Pending";
await task.save();
// Fetch the Sales Coordinator who is assigned the task
const salesCoordinator = await SalesCoOrdinator.findById(
task.taskAssignedTo
);
if (salesCoordinator) {
const fcmToken = salesCoordinator.fcm_token;
if (fcmToken) {
// Send push notification
const message = `Your task "${task.task}" is Pending.`;
await sendPushNotification(fcmToken, "Task Status Updated", message);
}
}
}
console.log('Overdue tasks updated to "Pending".');
} catch (error) {
console.error("Error updating overdue tasks:", error);
}
};
// Schedule the cron job to run daily at midnight
// cron.schedule("5 9 * * *", updateOverdueTasks, {
// timezone: "Asia/Kolkata",
// });
// cron.schedule("30 9 * * *", updateOverdueTasks);
const parseDate = (dateStr) => {
const [day, month, year] = dateStr.split("/").map(Number);
// Create a date object in local timezone
const localDate = new Date(year, month - 1, day);
// Convert to a date with time set to the start of the day in UTC
return new Date(Date.UTC(year, month - 1, day));
};
export const assignTask = async (req, res) => {
try {
const {
task,
note,
taskPriority,
taskDueDate,
taskAssignedTo,
addedFor,
addedForId,
tradename,
} = req.body;
// Convert the taskDueDate from DD/MM/YYYY string to Date object
const dueDate = parseDate(taskDueDate);
const currentDate = new Date();
// Set the time of the currentDate to the start of the day for comparison
const currentDateOnly = new Date(
Date.UTC(
currentDate.getUTCFullYear(),
currentDate.getUTCMonth(),
currentDate.getUTCDate()
)
);
// Check if the due date is in the past
if (dueDate < currentDateOnly) {
return res.status(400).json({
success: false,
message: "Due date cannot be earlier than the current date.",
});
}
const currentYear = new Date().getFullYear().toString().slice(-2);
const randomChars = crypto.randomBytes(4).toString("hex").toUpperCase();
const uniqueId = `${currentYear}-${randomChars}`;
// Create a new task
const newTask = await Task.create({
taskId: uniqueId,
task,
note,
taskStatus: "New",
taskPriority,
taskDueDate: dueDate, // Save the date as a Date object
taskAssignedTo,
taskAssignedBy: req.user._id,
addedFor,
addedForId,
tradename,
});
// Fetch the FCM token of the assigned sales coordinator
const salesCoordinator = await SalesCoOrdinator.findById(taskAssignedTo);
if (!salesCoordinator) {
return res.status(404).json({
success: false,
message: "Sales Coordinator not found.",
});
}
const fcmToken = salesCoordinator.fcm_token;
if (fcmToken) {
// Send push notification
const message = `You have been assigned a new task: ${task}`;
await sendPushNotification(fcmToken, "New Task Assigned", message);
}
res.status(201).json({
success: true,
message: "Task assigned successfully",
task: newTask,
});
} catch (error) {
res.status(400).json({
success: false,
message: error.message,
});
}
};
export const getTasksByStatus = async (req, res) => {
try {
await updateOverdueTasks();
const { status } = req.params; // This should be "New", "Pending", or "Completed"
// Validate the provided status
if (!["New", "Pending", "Completed"].includes(status)) {
return res.status(400).json({
success: false,
message: "Invalid status type provided.",
});
}
// Find tasks assigned to the user, filtered by status, and sorted by creation date (newest to oldest)
const tasks = await Task.find({
taskAssignedTo: req.user._id,
taskStatus: status,
}).sort({ createdAt: -1 }); // Sort by createdAt in descending order (-1 means newest first)
res.status(200).json({
success: true,
tasks,
});
} catch (error) {
res.status(500).json({
success: false,
message: error.message,
});
}
};
export const getStartAndEndOfDay = (date) => {
const startOfDay = new Date(date);
startOfDay.setUTCHours(0, 0, 0, 0); // Start of the day UTC
const endOfDay = new Date(date);
endOfDay.setUTCHours(23, 59, 59, 999); // End of the day UTC
return { startOfDay, endOfDay };
};
export const getTasksByDates = async (req, res) => {
try {
await updateOverdueTasks();
// Initialize filter object
const filter = {};
console.log(req.userType);
// Determine the filter based on user type
if (req.userType === "SalesCoOrdinator") {
filter.taskAssignedTo = req.user._id; // Use `=` to assign values, and `===` for comparison
} else {
filter.taskAssignedBy = req.user._id;
}
// Get the date from the query
const { Date: queryDate } = req.query;
let taskDate;
// If date is provided in query, parse it; otherwise, use today's date
if (queryDate) {
taskDate = parseDate(queryDate);
} else {
// Get today's date in UTC
taskDate = new Date();
}
// Get the start and end of the day in UTC
const { startOfDay, endOfDay } = getStartAndEndOfDay(taskDate);
// Find tasks for the user, filtered by createdAt within the start and end of the day
const tasks = await Task.find({
...filter, // Use the filter object for querying
createdAt: { $gte: startOfDay, $lte: endOfDay },
})
.populate({
path:
req.userType === "SalesCoOrdinator"
? "taskAssignedBy"
: "taskAssignedTo", // Change path based on user type
select: "name mobileNumber email",
})
.sort({ createdAt: -1 });
res.status(200).json({
success: true,
tasks,
});
} catch (error) {
res.status(500).json({
success: false,
message: error.message,
});
}
};
export const getAllTasksByStatus = async (req, res) => {
try {
await updateOverdueTasks();
const { status } = req.params; // This should be "New", "Pending", or "Completed"
// Validate the provided status
if (!["New", "Pending", "Completed"].includes(status)) {
return res.status(400).json({
success: false,
message: "Invalid status type provided.",
});
}
// Find tasks assigned to the user, filtered by status, and sorted by creation date (newest to oldest)
const tasks = await Task.find({
taskAssignedBy: req.user._id,
taskStatus: status,
})
.populate({
path: "taskAssignedTo",
select: "name mobileNumber email",
})
.sort({ createdAt: -1 }); // Sort by createdAt in descending order (-1 means newest first)
res.status(200).json({
success: true,
tasks,
});
} catch (error) {
res.status(500).json({
success: false,
message: error.message,
});
}
};
export const getTasksbytask = async (req, res) => {
try {
await updateOverdueTasks();
const { task } = req.params;
// Validate the provided status
if (
![
"Visit RD/PD",
"Update Sales Data",
"Update Inventory Data",
"Collect KYC",
].includes(task)
) {
return res.status(400).json({
success: false,
message: "Invalid task type provided.",
});
}
const tasks = await Task.find({
taskAssignedTo: req.user._id,
task: task,
}).sort({ createdAt: -1 });
res.status(200).json({
success: true,
tasks,
});
} catch (error) {
res.status(500).json({
success: false,
message: error.message,
});
}
};
export const updateTaskStatus = async (req, res) => {
try {
const { taskId } = req.params;
const task = await Task.findOne({
_id: taskId,
taskAssignedTo: req.user._id,
});
if (!task) {
return res.status(404).json({
success: false,
message: "Task not found or you're not authorized to update this task.",
});
}
// Update the task status to "Completed"
task.taskStatus = "Completed";
await task.save();
// Fetch the Sales Coordinator who completed the task
const salesCoordinator = await SalesCoOrdinator.findById(req.user._id);
if (!salesCoordinator) {
return res.status(404).json({
success: false,
message: "Sales Coordinator not found.",
});
}
// Fetch the FCM token of the Territory Manager
const territoryManager = await TerritoryManager.findById(
task.taskAssignedBy
);
if (!territoryManager) {
return res.status(404).json({
success: false,
message: "Territory Manager not found.",
});
}
const fcmToken = territoryManager.fcm_token;
if (fcmToken) {
// Send push notification
const message = `Task "${task.task}" has been completed by ${salesCoordinator.name}.`;
await sendPushNotification(fcmToken, "Task Completed", message);
}
res.status(200).json({
success: true,
message: "Task status updated to Completed.",
task,
});
} catch (error) {
res.status(400).json({
success: false,
message: error.message,
});
}
};
// 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
const tasks = await Task.find({
createdAt: {
$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
.exec();
// console.log(tasks);
// Populate addedForId conditionally
const populatedTasks = await Promise.all(
tasks.map(async (task) => {
if (task.addedFor === "PrincipalDistributor") {
// Populate with PrincipalDistributor
await task.populate("addedForId", User);
} else if (task.addedFor === "RetailDistributor") {
// Populate with RetailDistributor
await task.populate("addedForId", RetailDistributor);
}
return task; // Return the populated task
})
);
// 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: populatedTasks, // Paginated and populated 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" });
}
};
export const getTasks = async (req, res) => {
try {
const {
page = 1,
show = 10,
startDate = "",
endDate = "",
TMname = "",
SCname = "",
status = "",
} = req.query;
const limit = parseInt(show);
const skip = (parseInt(page) - 1) * limit;
const matchStage = {};
// Filter by date range
if (startDate && endDate) {
const start = new Date(startDate);
const end = new Date(endDate);
if (start.toDateString() === end.toDateString()) {
matchStage.createdAt = {
$gte: start,
$lt: new Date(start).setDate(start.getDate() + 1),
};
} else {
matchStage.createdAt = {
$gte: start,
$lte: new Date(end).setDate(end.getDate() + 1),
};
}
// matchStage.createdAt = {
// $gte: start,
// $lte: new Date(end.setDate(end.getDate() + 1)),
// };
} else if (startDate && endDate === "") {
matchStage.createdAt = {
$gte: new Date(startDate),
$lte: new Date(),
};
} else if (endDate && startDate === "") {
matchStage.createdAt = {
$lte: new Date(endDate),
};
}
// Filter by task status
if (status) {
matchStage.taskStatus = status;
}
// Aggregation pipeline
const tasks = await Task.aggregate([
{ $match: matchStage },
{
$lookup: {
from: "territorymanagers",
localField: "taskAssignedBy",
foreignField: "_id",
as: "taskAssignedBy",
},
},
{
$lookup: {
from: "salescoordinators",
localField: "taskAssignedTo",
foreignField: "_id",
as: "taskAssignedTo",
},
},
{
$match: {
...(TMname && {
"taskAssignedBy.name": { $regex: TMname, $options: "i" },
}),
...(SCname && {
"taskAssignedTo.name": { $regex: SCname, $options: "i" },
}),
},
},
{ $unwind: "$taskAssignedBy" },
{ $unwind: "$taskAssignedTo" },
{ $sort: { createdAt: -1 } },
{ $skip: skip },
{ $limit: limit },
{
$project: {
taskId: 1,
task: 1,
taskStatus: 1,
taskPriority: 1,
taskDueDate: 1,
note: 1,
createdAt: 1,
"taskAssignedBy.name": 1,
"taskAssignedTo.name": 1,
},
},
]);
// Total count
const totalTasks = await Task.countDocuments(matchStage);
res.status(200).json({
success: true,
data: tasks,
pagination: {
total: totalTasks,
page: parseInt(page),
show: limit,
pages: Math.ceil(totalTasks / limit),
},
});
} catch (error) {
console.error("Error fetching tasks:", error);
res.status(500).json({
success: false,
message: "Server error while fetching tasks",
error: error.message,
});
}
};