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 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' }); } };