diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index f4cd6cf99..491b7a127 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -32,12 +32,39 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp } const fetchToolTypes = async (req, res) => { + try { - ToolType.find() + ToolType + .find() + .populate([ + { + path: 'available', + select: '_id code project', + populate: { + path: 'project', + select: '_id name' + } + }, + { + path: 'using', + select: '_id code project', + populate: { + path: 'project', + select: '_id name' + } + } + ]) .exec() - .then((result) => res.status(200).send(result)) - .catch((error) => res.status(500).send(error)); + .then(result => { + res.status(200).send(result); + }) + .catch(error => { + console.error("fetchToolTypes error: ", error); + res.status(500).send(error); + }); + } catch (err) { + console.log("error: ", err) res.json(err); } }; diff --git a/src/controllers/bmdashboard/bmToolController.js b/src/controllers/bmdashboard/bmToolController.js index 4d1e71221..be37639ac 100644 --- a/src/controllers/bmdashboard/bmToolController.js +++ b/src/controllers/bmdashboard/bmToolController.js @@ -1,6 +1,6 @@ const mongoose = require('mongoose'); -const bmToolController = (BuildingTool) => { +const bmToolController = (BuildingTool, ToolType) => { const fetchAllTools = (req, res) => { const populateFields = [ @@ -156,10 +156,93 @@ const bmToolController = (BuildingTool) => { } }; + const bmLogTools = async function (req, res) { + const requestor = req.body.requestor.requestorId; + const {typesArray, action, date} = req.body + const results = []; + const errors = []; + + if(typesArray.length === 0 || typesArray === undefined){ + errors.push({ message: 'Invalid request. No tools selected'}) + return res.status(500).send({errors, results}); + } + + for (const type of typesArray) { + const toolName = type.toolName; + const toolCodes = type.toolCodes; + const codeMap = {}; + toolCodes.forEach(obj => { + codeMap[obj.value] = obj.label; + }) + + try{ + const toolTypeDoc = await ToolType.findOne({ _id: mongoose.Types.ObjectId(type.toolType) }); + if(!toolTypeDoc) { + errors.push({ message: `Tool type ${toolName} with id ${type.toolType} was not found.`}); + continue; + } + const availableItems = toolTypeDoc.available; + const usingItems = toolTypeDoc.using; + + for(const toolItem of type.toolItems){ + const buildingToolDoc = await BuildingTool.findOne({ _id: mongoose.Types.ObjectId(toolItem)}); + if(!buildingToolDoc){ + errors.push({ message: `${toolName} with id ${toolItem} was not found.`}); + continue; + } + + if(action === "Check Out" && availableItems.length > 0){ + const foundIndex = availableItems.indexOf(toolItem); + if(foundIndex >= 0){ + availableItems.splice(foundIndex, 1); + usingItems.push(toolItem); + }else{ + errors.push({ message: `${toolName} with code ${codeMap[toolItem]} is not available for ${action}`}); + continue; + } + } + + if(action === "Check In" && usingItems.length > 0){ + const foundIndex = usingItems.indexOf(toolItem); + if(foundIndex >= 0){ + usingItems.splice(foundIndex, 1); + availableItems.push(toolItem); + }else{ + errors.push({ message: `${toolName} ${codeMap[toolItem]} is not available for ${action}`}); + continue; + } + } + + const newRecord = { + date: date, + createdBy: requestor, + responsibleUser: buildingToolDoc.userResponsible, + type: action + } + + buildingToolDoc.logRecord.push(newRecord); + buildingToolDoc.save(); + results.push({message: `${action} successful for ${toolName} ${codeMap[toolItem]}`}) + } + + await toolTypeDoc.save(); + }catch(error){ + errors.push({message: `Error for tool type ${type}: ${error.message}` }); + } + } + + if (errors.length > 0) { + return res.status(404).send({ errors, results }); + } else { + return res.status(200).send({ errors, results }); + } + } + return { fetchAllTools, fetchSingleTool, bmPurchaseTools, + bmLogTools }; }; diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index dca64cb66..96a8a7269 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -22,8 +22,11 @@ const taskHelper = function () { isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, + weeklySummaryOption: 1, timeOffFrom: 1, timeOffTill: 1, + teamCode: 1, + teams: 1, adminLinks: 1, } ); @@ -31,14 +34,8 @@ const taskHelper = function () { if (userById === null) return null; const userRole = userById.role; - const pdtstart = moment() - .tz("America/Los_Angeles") - .startOf("week") - .format("YYYY-MM-DD"); - const pdtend = moment() - .tz("America/Los_Angeles") - .endOf("week") - .format("YYYY-MM-DD"); + const pdtstart = moment().tz('America/Los_Angeles').startOf('week').format('YYYY-MM-DD'); + const pdtend = moment().tz('America/Los_Angeles').endOf('week').format('YYYY-MM-DD'); let teamMemberIds = [userid]; let teamMembers = []; @@ -49,18 +46,28 @@ const taskHelper = function () { switch (true) { case isRequestorOwnerLike && isUserOwnerLike: { - teamMembers = await userProfile.find( - { isActive: true }, - { - role: 1, - firstName: 1, - lastName: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - adminLinks: 1, - } - ); + teamMembers = await userProfile + .find( + { isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + weeklySummaryOption: 1, + timeOffFrom: 1, + timeOffTill: 1, + teamCode: 1, + teams: 1, + adminLinks: 1, + }, + ) + .populate([ + { + path: 'teams', + select: 'teamName', + }, + ]); break; } case isRequestorOwnerLike && !isUserOwnerLike: { @@ -71,23 +78,32 @@ const taskHelper = function () { teamsResult.forEach((_myTeam) => { _myTeam.members.forEach((teamMember) => { - if (!teamMember.userId.equals(userid)) - teamMemberIds.push(teamMember.userId); + if (!teamMember.userId.equals(userid)) teamMemberIds.push(teamMember.userId); }); }); - teamMembers = await userProfile.find( - { _id: { $in: teamMemberIds }, isActive: true }, - { - role: 1, - firstName: 1, - lastName: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - adminLinks: 1, - } - ); + teamMembers = await userProfile + .find( + { _id: { $in: teamMemberIds }, isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + weeklySummaryOption: 1, + timeOffFrom: 1, + timeOffTill: 1, + teamCode: 1, + teams: 1, + adminLinks: 1, + }, + ) + .populate([ + { + path: 'teams', + select: 'teamName', + }, + ]); break; } default: { @@ -98,27 +114,36 @@ const taskHelper = function () { sharedTeamsResult.forEach((_myTeam) => { _myTeam.members.forEach((teamMember) => { - if (!teamMember.userId.equals(userid)) - teamMemberIds.push(teamMember.userId); + if (!teamMember.userId.equals(userid)) teamMemberIds.push(teamMember.userId); }); }); - teamMembers = await userProfile.find( - { _id: { $in: teamMemberIds }, isActive: true }, - { - role: 1, - firstName: 1, - lastName: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - adminLinks: 1, - } - ); + teamMembers = await userProfile + .find( + { _id: { $in: teamMemberIds }, isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + weeklySummaryOption: 1, + timeOffFrom: 1, + timeOffTill: 1, + teamCode: 1, + teams: 1, + adminLinks: 1, + }, + ) + .populate([ + { + path: 'teams', + select: 'teamName', + }, + ]); } } - teamMemberIds = teamMembers.map(member => member._id); + teamMemberIds = teamMembers.map((member) => member._id); const timeEntries = await timeentry.find({ dateOfWork: { @@ -139,8 +164,7 @@ const taskHelper = function () { }; } if (timeEntry.isTangible) { - timeEntryByPerson[personIdStr].tangibleSeconds += - timeEntry.totalSeconds; + timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; } timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; }); @@ -148,10 +172,10 @@ const taskHelper = function () { { "resources.userID": { $in: teamMemberIds } }, { "resources.profilePic": 0 } ).populate({ - path: "wbsId", - select: "projectId", + path: 'wbsId', + select: 'projectId', }); - const teamMemberTaskIds = teamMemberTasks.map(task => task._id); + const teamMemberTaskIds = teamMemberTasks.map((task) => task._id); const teamMemberTaskNotifications = await TaskNotification.find({ taskId: { $in: teamMemberTaskIds }, }); @@ -167,9 +191,7 @@ const taskHelper = function () { teamMemberTaskNotification ); } else { - taskNotificationByTaskNdUser[taskNdUserID] = [ - teamMemberTaskNotification, - ]; + taskNotificationByTaskNdUser[taskNdUserID] = [teamMemberTaskNotification]; } }); @@ -183,8 +205,11 @@ const taskHelper = function () { teamMemberTask.resources.forEach((resource) => { const resourceIdStr = resource.userID?.toString(); const taskNdUserID = `${taskIdStr},${resourceIdStr}`; - _teamMemberTask.taskNotifications = - taskNotificationByTaskNdUser[taskNdUserID] || []; + // initialize taskNotifications if not exists + if (!_teamMemberTask.taskNotifications) _teamMemberTask.taskNotifications = []; + // push all notifications into the list if taskNdUserId key exists + if (taskNotificationByTaskNdUser[taskNdUserID]) + _teamMemberTask.taskNotifications.push(...taskNotificationByTaskNdUser[taskNdUserID]); if (taskByPerson[resourceIdStr]) { taskByPerson[resourceIdStr].push(_teamMemberTask); } else { @@ -195,20 +220,22 @@ const taskHelper = function () { const teamMemberTasksData = []; teamMembers.forEach((teamMember) => { + const timeEntry = timeEntryByPerson[teamMember._id.toString()]; + const tangible = timeEntry?.tangibleSeconds || 0; + const total = timeEntry?.totalSeconds || 0; const obj = { personId: teamMember._id, role: teamMember.role, name: `${teamMember.firstName} ${teamMember.lastName}`, weeklycommittedHours: teamMember.weeklycommittedHours, - totaltangibletime_hrs: - timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / - 3600 || 0, - totaltime_hrs: - timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600 || - 0, + weeklySummaryOption: teamMember.weeklySummaryOption || null, + totaltangibletime_hrs: tangible / 3600, + totaltime_hrs: total / 3600, tasks: taskByPerson[teamMember._id.toString()] || [], timeOffFrom: teamMember.timeOffFrom || null, timeOffTill: teamMember.timeOffTill || null, + teamCode: teamMember.teamCode || null, + teams: teamMember.teams || null, adminLinks: teamMember.adminLinks || null, }; teamMemberTasksData.push(obj); @@ -504,14 +531,8 @@ const taskHelper = function () { // ]); }; const getTasksForSingleUser = function (userId) { - const pdtstart = moment() - .tz("America/Los_Angeles") - .startOf("week") - .format("YYYY-MM-DD"); - const pdtend = moment() - .tz("America/Los_Angeles") - .endOf("week") - .format("YYYY-MM-DD"); + const pdtstart = moment().tz('America/Los_Angeles').startOf('week').format('YYYY-MM-DD'); + const pdtend = moment().tz('America/Los_Angeles').endOf('week').format('YYYY-MM-DD'); return userProfile.aggregate([ { $match: { @@ -520,33 +541,33 @@ const taskHelper = function () { }, { $project: { - personId: "$_id", - role: "$role", + personId: '$_id', + role: '$role', name: { - $concat: ["$firstName", " ", "$lastName"], + $concat: ['$firstName', ' ', '$lastName'], }, weeklycommittedHours: { $sum: [ - "$weeklycommittedHours", + '$weeklycommittedHours', { - $ifNull: ["$missedHours", 0], + $ifNull: ['$missedHours', 0], }, ], }, timeOffFrom: { - $ifNull: ["$timeOffFrom", null], + $ifNull: ['$timeOffFrom', null], }, timeOffTill: { - $ifNull: ["$timeOffTill", null], + $ifNull: ['$timeOffTill', null], }, }, }, { $lookup: { - from: "timeEntries", - localField: "personId", - foreignField: "personId", - as: "timeEntryData", + from: 'timeEntries', + localField: 'personId', + foreignField: 'personId', + as: 'timeEntryData', }, }, { @@ -559,18 +580,18 @@ const taskHelper = function () { role: 1, timeEntryData: { $filter: { - input: "$timeEntryData", - as: "timeentry", + input: '$timeEntryData', + as: 'timeentry', cond: { $and: [ { - $gte: ["$$timeentry.dateOfWork", pdtstart], + $gte: ['$$timeentry.dateOfWork', pdtstart], }, { - $lte: ["$$timeentry.dateOfWork", pdtend], + $lte: ['$$timeentry.dateOfWork', pdtend], }, { - $in: ["$$timeentry.entryType", ["default", null]], + $in: ['$$timeentry.entryType', ['default', null]], }, ], }, @@ -580,7 +601,7 @@ const taskHelper = function () { }, { $unwind: { - path: "$timeEntryData", + path: '$timeEntryData', preserveNullAndEmptyArrays: true, }, }, @@ -595,18 +616,18 @@ const taskHelper = function () { totalSeconds: { $cond: [ { - $gte: ["$timeEntryData.totalSeconds", 0], + $gte: ['$timeEntryData.totalSeconds', 0], }, - "$timeEntryData.totalSeconds", + '$timeEntryData.totalSeconds', 0, ], }, isTangible: { $cond: [ { - $gte: ["$timeEntryData.totalSeconds", 0], + $gte: ['$timeEntryData.totalSeconds', 0], }, - "$timeEntryData.isTangible", + '$timeEntryData.isTangible', false, ], }, @@ -617,9 +638,9 @@ const taskHelper = function () { tangibletime: { $cond: [ { - $eq: ["$isTangible", true], + $eq: ['$isTangible', true], }, - "$totalSeconds", + '$totalSeconds', 0, ], }, @@ -628,44 +649,44 @@ const taskHelper = function () { { $group: { _id: { - personId: "$personId", - weeklycommittedHours: "$weeklycommittedHours", - timeOffFrom: "$timeOffFrom", - timeOffTill: "$timeOffTill", - name: "$name", - role: "$role", + personId: '$personId', + weeklycommittedHours: '$weeklycommittedHours', + timeOffFrom: '$timeOffFrom', + timeOffTill: '$timeOffTill', + name: '$name', + role: '$role', }, totalSeconds: { - $sum: "$totalSeconds", + $sum: '$totalSeconds', }, tangibletime: { - $sum: "$tangibletime", + $sum: '$tangibletime', }, }, }, { $project: { _id: 0, - personId: "$_id.personId", - name: "$_id.name", - weeklycommittedHours: "$_id.weeklycommittedHours", - timeOffFrom: "$_id.timeOffFrom", - timeOffTill: "$_id.timeOffTill", - role: "$_id.role", + personId: '$_id.personId', + name: '$_id.name', + weeklycommittedHours: '$_id.weeklycommittedHours', + timeOffFrom: '$_id.timeOffFrom', + timeOffTill: '$_id.timeOffTill', + role: '$_id.role', totaltime_hrs: { - $divide: ["$totalSeconds", 3600], + $divide: ['$totalSeconds', 3600], }, totaltangibletime_hrs: { - $divide: ["$tangibletime", 3600], + $divide: ['$tangibletime', 3600], }, }, }, { $lookup: { - from: "tasks", - localField: "personId", - foreignField: "resources.userID", - as: "tasks", + from: 'tasks', + localField: 'personId', + foreignField: 'resources.userID', + as: 'tasks', }, }, { @@ -679,25 +700,25 @@ const taskHelper = function () { }, { $unwind: { - path: "$tasks", + path: '$tasks', preserveNullAndEmptyArrays: true, }, }, { $lookup: { - from: "wbs", - localField: "tasks.wbsId", - foreignField: "_id", - as: "projectId", + from: 'wbs', + localField: 'tasks.wbsId', + foreignField: '_id', + as: 'projectId', }, }, { $addFields: { - "tasks.projectId": { + 'tasks.projectId': { $cond: [ - { $ne: ["$projectId", []] }, - { $arrayElemAt: ["$projectId", 0] }, - "$tasks.projectId", + { $ne: ['$projectId', []] }, + { $arrayElemAt: ['$projectId', 0] }, + '$tasks.projectId', ], }, }, @@ -719,40 +740,40 @@ const taskHelper = function () { }, { $addFields: { - "tasks.projectId": "$tasks.projectId.projectId", + 'tasks.projectId': '$tasks.projectId.projectId', }, }, { $lookup: { - from: "taskNotifications", - localField: "tasks._id", - foreignField: "taskId", - as: "tasks.taskNotifications", + from: 'taskNotifications', + localField: 'tasks._id', + foreignField: 'taskId', + as: 'tasks.taskNotifications', }, }, { $group: { - _id: "$personId", - tasks: { $push: "$tasks" }, + _id: '$personId', + tasks: { $push: '$tasks' }, data: { - $first: "$$ROOT", + $first: '$$ROOT', }, }, }, { $addFields: { - "data.tasks": { + 'data.tasks': { $filter: { - input: "$tasks", - as: "task", - cond: { $ne: ["$$task", {}] }, + input: '$tasks', + as: 'task', + cond: { $ne: ['$$task', {}] }, }, }, }, }, { $replaceRoot: { - newRoot: "$data", + newRoot: '$data', }, }, ]); @@ -760,7 +781,7 @@ const taskHelper = function () { const getUserProfileFirstAndLastName = function (userId) { return userProfile.findById(userId).then((results) => { if (!results) { - return " "; + return ' '; } return `${results.firstName} ${results.lastName}`; }); diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index f49bd6448..226e3e328 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -74,6 +74,7 @@ const largeItemBaseSchema = mongoose.Schema({ responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, type: { type: String, enum: ['Check In', 'Check Out'] }, }], + userResponsible: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, //new field }); const largeItemBase = mongoose.model('largeItemBase', largeItemBaseSchema, 'buildingInventoryItems'); diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js index 263738e68..fdd728029 100644 --- a/src/models/bmdashboard/buildingInventoryType.js +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -1,7 +1,6 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; - //--------------------------- // BASE INVENTORY TYPE SCHEMA //--------------------------- @@ -13,7 +12,7 @@ const invTypeBaseSchema = new Schema({ name: { type: String, required: true }, description: { type: String, required: true, maxLength: 150 }, imageUrl: String, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfiles' }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, }); const invTypeBase = mongoose.model('invTypeBase', invTypeBaseSchema, 'buildingInventoryTypes'); diff --git a/src/routes/bmdashboard/bmToolRouter.js b/src/routes/bmdashboard/bmToolRouter.js index b4e52e8cd..5a9a96e78 100644 --- a/src/routes/bmdashboard/bmToolRouter.js +++ b/src/routes/bmdashboard/bmToolRouter.js @@ -1,9 +1,8 @@ const express = require('express'); -const routes = function (BuildingTool) { +const routes = function (BuildingTool, ToolType) { const toolRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmToolController')(BuildingTool); - + const controller = require('../../controllers/bmdashboard/bmToolController')(BuildingTool, ToolType); toolRouter.route('/tools') .get(controller.fetchAllTools); @@ -14,6 +13,9 @@ const routes = function (BuildingTool) { toolRouter.route('/tools/purchase') .post(controller.bmPurchaseTools); + toolRouter.route('/tools/log') + .post(controller.bmLogTools); + return toolRouter; }; diff --git a/src/startup/routes.js b/src/startup/routes.js index 77078bb2c..51273acbf 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -43,7 +43,6 @@ const { buildingTool, buildingEquipment, } = require('../models/bmdashboard/buildingInventoryItem'); -// const buildingTool = require('../models/bmdashboard/buildingTool'); const timeOffRequest = require('../models/timeOffRequest'); const followUp = require('../models/followUp'); @@ -116,7 +115,7 @@ const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRout ); const titleRouter = require('../routes/titleRouter')(title); -const bmToolRouter = require('../routes/bmdashboard/bmToolRouter')(buildingTool); +const bmToolRouter = require('../routes/bmdashboard/bmToolRouter')(buildingTool, toolType); const bmEquipmentRouter = require('../routes/bmdashboard/bmEquipmentRouter')(buildingEquipment); const bmIssueRouter = require('../routes/bmdashboard/bmIssueRouter')(buildingIssue);