diff --git a/src/controllers/bmdashboard/bmIssueController.js b/src/controllers/bmdashboard/bmIssueController.js index 8bcbe3d00..7f773181a 100644 --- a/src/controllers/bmdashboard/bmIssueController.js +++ b/src/controllers/bmdashboard/bmIssueController.js @@ -1,29 +1,185 @@ const mongoose = require('mongoose'); const bmIssueController = function (BuildingIssue) { - const bmGetIssue = async (req, res) => { - try { - BuildingIssue - .find() - .populate() - .then((result) => res.status(200).send(result)) - .catch((error) => res.status(500).send(error)); - } catch (err) { - res.json(err); - } - }; - - const bmPostIssue = async (req, res) => { - try { - const newIssue = BuildingIssue.create(req.body) - .then((result) => res.status(201).send(result)) - .catch((error) => res.status(500).send(error)); - } catch (err) { - res.json(err); - } - }; - - return { bmGetIssue, bmPostIssue }; + const bmGetIssue = async (req, res) => { + try { + BuildingIssue.find() + .populate() + .then((result) => res.status(200).send(result)) + .catch((error) => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + + const bmPostIssue = async (req, res) => { + try { + const newIssue = BuildingIssue.create(req.body) + .then((result) => res.status(201).send(result)) + .catch((error) => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + + // GET /issues/longest-open?projectIds=proj1,proj2&startDate=xxx&endDate=xxx + const bmLongestOpenIssues = async (req, res) => { + try { + const { projectIds, startDate, endDate } = req.query; + + const projectIdArray = projectIds + ? projectIds.split(',').map((id) => mongoose.Types.ObjectId(id)) + : []; + const start = startDate ? new Date(startDate) : null; + const end = endDate ? new Date(endDate) : null; + + const today = new Date(); + + // Build dynamic $match filter + const matchStage = { + closeDate: { $exists: false }, // open issues only + }; + + if (projectIdArray.length > 0) { + matchStage.projectId = { $in: projectIdArray }; + } + + if (start || end) { + matchStage.createdDate = {}; + if (start) matchStage.createdDate.$gte = start; + if (end) matchStage.createdDate.$lte = end; + } + + const pipeline = [ + // Match only issues that are still open (no closeDate) + { + $match: matchStage, + // { closeDate: { $exists: false } } + }, + + // Add calculated daysOpen field + { + $addFields: { + daysOpen: { + $divide: [ + { $subtract: [today, '$createdDate'] }, + 1000 * 60 * 60 * 24, // milliseconds to days + ], + }, + }, + }, + + // Limit to top results (you can make this configurable) + { $limit: 5 }, + + // Project only the required fields + { + $project: { + _id: 0, // exclude default _id + IssueId: '$_id', // rename _id to IssueId + title: '$issueTitle', + daysOpen: { $round: ['$daysOpen', 0] }, // round to whole number + }, + }, + { $sort: { daysOpen: -1 } }, + ]; + + const longestOpenIssues = await BuildingIssue.aggregate(pipeline); + + res.status(200).json({ + success: true, + count: longestOpenIssues.length, + data: longestOpenIssues, + }); + } catch (error) { + console.error('Error fetching longest open issues:', error); + res.status(500).json({ + success: false, + message: 'Server error while fetching longest open issues', + }); + } + }; + + const bmMostExpensiveIssues = async (req, res) => { + try { + const { projectIds, startDate, endDate } = req.query; + + const projectIdArray = projectIds + ? projectIds.split(',').map((id) => mongoose.Types.ObjectId(id)) + : []; + const start = startDate ? new Date(startDate) : null; + const end = endDate ? new Date(endDate) : null; + + const today = new Date(); + + // Build dynamic $match filter + const matchStage = { + closeDate: { $exists: false }, // open issues only + }; + + if (projectIdArray.length > 0) { + matchStage.projectId = { $in: projectIdArray }; + } + + if (start || end) { + matchStage.createdDate = {}; + if (start) matchStage.createdDate.$gte = start; + if (end) matchStage.createdDate.$lte = end; + } + const pipeline = [ + // Match only issues that are still open (no closeDate) + { + $match: matchStage, + // { + // closeDate: { $exists: false } + // } + }, + + // Add calculated daysOpen field + { + $addFields: { + daysOpen: { + $divide: [ + { $subtract: [today, '$createdDate'] }, + 1000 * 60 * 60 * 24, // milliseconds to days + ], + }, + }, + }, + + // Limit to top results (you can make this configurable) + { $limit: 5 }, + + // Project only the required fields + { + $project: { + _id: 0, // exclude default _id + IssueId: '$_id', // rename _id to IssueId + title: '$issueTitle', + totalCost: { $ifNull: ['$totalCost', null] }, // include if exists + daysOpen: { $round: ['$daysOpen', 0] }, // round to whole number + }, + }, + { $sort: { totalCost: -1 } }, + ]; + + const mostExpensiveIssues = await BuildingIssue.aggregate(pipeline); + + res.status(200).json({ + success: true, + count: mostExpensiveIssues.length, + data: mostExpensiveIssues, + }); + } catch (error) { + console.error('Error fetching longest open issues:', error); + res.status(500).json({ + success: false, + message: 'Server error while fetching longest open issues', + }); + } + }; + + return { bmGetIssue, bmPostIssue, bmLongestOpenIssues, bmMostExpensiveIssues }; }; module.exports = bmIssueController; diff --git a/src/routes/bmdashboard/bmIssueRouter.js b/src/routes/bmdashboard/bmIssueRouter.js index 99c4c022d..8099038d1 100644 --- a/src/routes/bmdashboard/bmIssueRouter.js +++ b/src/routes/bmdashboard/bmIssueRouter.js @@ -1,13 +1,13 @@ const express = require('express'); const routes = function (buildingIssue) { - const IssueRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmIssueController')(buildingIssue); + const IssueRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmIssueController')(buildingIssue); - IssueRouter.route('/issues') - .get(controller.bmGetIssue); - IssueRouter.route('/issue/add') - .post(controller.bmPostIssue); - return IssueRouter; + IssueRouter.route('/issues').get(controller.bmGetIssue); + IssueRouter.route('/issue/add').post(controller.bmPostIssue); + IssueRouter.route('/issues/longest-open').get(controller.bmLongestOpenIssues); + IssueRouter.route('/issues/most-expensive').get(controller.bmMostExpensiveIssues); + return IssueRouter; }; module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index e93c7492c..093f48c26 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -19,12 +19,11 @@ const currentWarnings = require('../models/currentWarnings'); const village = require('../models/lbdashboard/villages'); const registration = require('../models/registration'); - // Title const title = require('../models/title'); const blueSquareEmailAssignment = require('../models/BlueSquareEmailAssignment'); -const hgnformRouter=require('../routes/hgnformRouter'); -const hgnFormResponseRouter=require('../routes/hgnFormResponseRouter'); +const hgnformRouter = require('../routes/hgnformRouter'); +const hgnFormResponseRouter = require('../routes/hgnFormResponseRouter'); const weeklySummaryAIPrompt = require('../models/weeklySummaryAIPrompt'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); @@ -83,7 +82,8 @@ const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter') mapLocations, ); const permissionChangeLogRouter = require('../routes/permissionChangeLogsRouter')( - permissionChangeLog, userPermissionChangeLog, + permissionChangeLog, + userPermissionChangeLog, ); const isEmailExistsRouter = require('../routes/isEmailExistsRouter')(); const jobNotificationListRouter = require('../routes/jobNotificationListRouter'); @@ -105,9 +105,9 @@ const timeOffRequestRouter = require('../routes/timeOffRequestRouter')( userProfile, ); const followUpRouter = require('../routes/followUpRouter')(followUp); -const form=require('../models/forms') -const formResponse=require('../models/formResponse') -const formRouter=require('../routes/formRouter')(form,formResponse); +const form = require('../models/forms'); +const formResponse = require('../models/formResponse'); +const formRouter = require('../routes/formRouter')(form, formResponse); // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(buildingMaterial); @@ -139,8 +139,7 @@ const blueSquareEmailAssignmentRouter = require('../routes/BlueSquareEmailAssign const registrationRouter = require('../routes/registrationRouter')(registration); -const collaborationRouter=require('../routes/collaborationRouter'); - +const collaborationRouter = require('../routes/collaborationRouter'); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -180,11 +179,11 @@ module.exports = function (app) { app.use('/api', timeOffRequestRouter); app.use('/api', followUpRouter); app.use('/api', blueSquareEmailAssignmentRouter); - app.use('/api',formRouter); + app.use('/api', formRouter); app.use('/api', collaborationRouter); app.use('/api/jobs', jobsRouter); app.use('/api/questions', hgnformRouter); - app.use('/api/hgnform',hgnFormResponseRouter); + app.use('/api/hgnform', hgnFormResponseRouter); app.use('/api/job-notification-list/', jobNotificationListRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); @@ -197,7 +196,7 @@ module.exports = function (app) { app.use('/api/bm', bmEquipmentRouter); app.use('/api/bm', bmConsumablesRouter); app.use('/api/bm', bmExternalTeam); - app.use('api', bmIssueRouter); + app.use('/api', bmIssueRouter); app.use('/api/villages', require('../routes/lb_dashboard/villages')); app.use('/api', registrationRouter); };