From 21db87f14f57fb4eee58c1d5c4a82525fd8775c4 Mon Sep 17 00:00:00 2001 From: Nikita Kolla <42067463+ArtemisNyx3@users.noreply.github.com> Date: Sat, 3 May 2025 10:09:23 -0400 Subject: [PATCH 1/2] Longest open and most expensive without filters --- .../bmdashboard/bmIssueController.js | 150 +++++++++++++++--- src/routes/bmdashboard/bmIssueRouter.js | 14 +- src/startup/routes.js | 23 ++- 3 files changed, 145 insertions(+), 42 deletions(-) diff --git a/src/controllers/bmdashboard/bmIssueController.js b/src/controllers/bmdashboard/bmIssueController.js index 8bcbe3d00..8d9b09dee 100644 --- a/src/controllers/bmdashboard/bmIssueController.js +++ b/src/controllers/bmdashboard/bmIssueController.js @@ -1,29 +1,133 @@ 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) => { + const today = new Date(); + try { + const pipeline = [ + // Match only issues that are still open (no closeDate) + { $match: { 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: { totalCost: -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', + }); + } + }; + + return { bmGetIssue, bmPostIssue, bmLongestOpenIssues, bmMostExpensiveIssues }; +}; + + const bmMostExpensiveIssues = async (req, res) => { + const today = new Date(); + try { + const pipeline = [ + // Match only issues that are still open (no closeDate) + { $match: { 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); }; From d4dcbc166209ec5c0e6ad241245b11a492561cac Mon Sep 17 00:00:00 2001 From: Nikita Kolla <42067463+ArtemisNyx3@users.noreply.github.com> Date: Sat, 10 May 2025 07:10:42 -0400 Subject: [PATCH 2/2] added filters --- .../bmdashboard/bmIssueController.js | 68 ++++++++++++++++--- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/src/controllers/bmdashboard/bmIssueController.js b/src/controllers/bmdashboard/bmIssueController.js index 8d9b09dee..7f773181a 100644 --- a/src/controllers/bmdashboard/bmIssueController.js +++ b/src/controllers/bmdashboard/bmIssueController.js @@ -24,11 +24,38 @@ const bmIssueController = function (BuildingIssue) { // GET /issues/longest-open?projectIds=proj1,proj2&startDate=xxx&endDate=xxx const bmLongestOpenIssues = async (req, res) => { - const today = new Date(); 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: { closeDate: { $exists: false } } }, + { + $match: matchStage, + // { closeDate: { $exists: false } } + }, // Add calculated daysOpen field { @@ -54,7 +81,7 @@ const bmIssueController = function (BuildingIssue) { daysOpen: { $round: ['$daysOpen', 0] }, // round to whole number }, }, - { $sort: { totalCost: -1 } }, + { $sort: { daysOpen: -1 } }, ]; const longestOpenIssues = await BuildingIssue.aggregate(pipeline); @@ -73,15 +100,40 @@ const bmIssueController = function (BuildingIssue) { } }; - return { bmGetIssue, bmPostIssue, bmLongestOpenIssues, bmMostExpensiveIssues }; -}; - const bmMostExpensiveIssues = async (req, res) => { - const today = new Date(); 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: { closeDate: { $exists: false } } }, + { + $match: matchStage, + // { + // closeDate: { $exists: false } + // } + }, // Add calculated daysOpen field {