diff --git a/package.json b/package.json index 7eee194..ddd0246 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "nodemon --inspect src/server.js", "test": "echo \"Error: no test specified\" && exit 1", - "deploy": "curl -X POST http://35.162.222.18:9000/hooks/deploy-va-middleware", + "deploy": "curl -X POST http://35.95.209.161:9000/hooks/deploy-va-middleware", "build": "npx webpack --mode production", "dev": "npx webpack --mode development" }, diff --git a/src/controllers/project/projectAddSf.controller.js b/src/controllers/project/projectAddSf.controller.js index ccad5d0..9bad91a 100644 --- a/src/controllers/project/projectAddSf.controller.js +++ b/src/controllers/project/projectAddSf.controller.js @@ -4,21 +4,21 @@ import { updateEntityRelationships } from "../../helper/updateEntityRelationship // Register a new VA async function project_add_sf(req, res) { try { - const payload = req.body|| {}; - const { name, hourlyRate, clientId, vaAssigned, dedicatedHours, vaWorkingScheduleStart, vaWorkingScheduleEnd, isFlexibleAllowedPt, vaWorkingDelayAllowedStart, vaWorkingDelayAllowedEnd } = payload; + const payload = req.body || {}; + const { name, hourlyRate, clientId, vaAssigned, dedicatedHours, vaWorkingScheduleStart, vaWorkingScheduleEnd, isFlexibleAllowed, vaWorkingDelayAllowedStart, vaWorkingDelayAllowedEnd } = payload; // Validate required fields if (!name) { - return res.status(400).json({ - success: false, - message: "Project name is required" + return res.status(400).json({ + success: false, + message: "Project name is required" }); } if (!clientId) { - return res.status(400).json({ - success: false, - message: "Client ID is required" + return res.status(400).json({ + success: false, + message: "Client ID is required" }); } @@ -27,53 +27,62 @@ async function project_add_sf(req, res) { try { clientObjectId = new Types.ObjectId(clientId); } catch (error) { - return res.status(400).json({ - success: false, - message: "Invalid Client ID format" + return res.status(400).json({ + success: false, + message: "Invalid Client ID format" }); } // Validate and convert vaAssigned to array of ObjectIds - let vaAssignedArray = []; - if (vaAssigned) { - if (Array.isArray(vaAssigned)) { - try { - vaAssignedArray = vaAssigned.map(vaId => new Types.ObjectId(vaId)); - } catch (error) { - return res.status(400).json({ - success: false, - message: "Invalid VA ID format in vaAssigned array" - }); - } - } else if (typeof vaAssigned === 'string') { - // Handle single VA ID as string - try { - vaAssignedArray = [new Types.ObjectId(vaAssigned)]; - } catch (error) { - return res.status(400).json({ - success: false, - message: "Invalid VA ID format" - }); - } - } - } + // let vaAssignedArray = []; + // if (vaAssigned) { + // if (Array.isArray(vaAssigned)) { + // try { + // vaAssignedArray = vaAssigned.map(vaId => { + // if(typeof vaId === 'object' && "isFlexibleAllowed" in vaId){ + // // Handle Error form SF Side for now - That vaId is coming as object + // return new Types.ObjectId(vaId.vaId) + // } else { + // return new Types.ObjectId(vaId) + // } + // }); + // } catch (error) { + // return res.status(400).json({ + // success: false, + // message: "Invalid VA ID format in vaAssigned array" + // }); + // } + // } else if (typeof vaAssigned === 'string') { + // // Handle single VA ID as string + // try { + // vaAssignedArray = [new Types.ObjectId(vaAssigned)]; + // } catch (error) { + // return res.status(400).json({ + // success: false, + // message: "Invalid VA ID format" + // }); + // } + // } + // } // sanitize/construct allowed fields const toCreate = { name: name.trim(), hourlyRate: hourlyRate || '0', clientId: clientObjectId, - vaAssigned: vaAssignedArray, + vaAssigned: vaAssigned, dedicatedHours: dedicatedHours ? parseFloat(dedicatedHours) : 0, vaWorkingScheduleStart: vaWorkingScheduleStart || null, vaWorkingScheduleEnd: vaWorkingScheduleEnd || null, - isFlexibleAllowedPt: isFlexibleAllowedPt || true, + isFlexibleAllowed: isFlexibleAllowed || true, vaWorkingDelayAllowedStart: vaWorkingDelayAllowedStart || null, vaWorkingDelayAllowedEnd: vaWorkingDelayAllowedEnd || null }; const created = await ProjectModel.create(toCreate); + const vaAssignedArray = vaAssigned ? vaAssigned.map(vaDtl => vaDtl.vaId) : []; + const relationshipUpdate = await updateEntityRelationships({ project: { projectId: created._id, @@ -87,7 +96,7 @@ async function project_add_sf(req, res) { } res.status(201).json({ success: true, data: created, relationships: relationshipUpdate }); - + } catch (error) { console.error("project_add_sf error:", error); return res.status(500).json({ success: false, message: "Internal Server Error" }); diff --git a/src/controllers/project/projectUpdateSf.controller.js b/src/controllers/project/projectUpdateSf.controller.js index 62e3047..545cdd5 100644 --- a/src/controllers/project/projectUpdateSf.controller.js +++ b/src/controllers/project/projectUpdateSf.controller.js @@ -10,25 +10,25 @@ async function update_project_sf(req, res) { try { const { projectId } = req.params; const payload = req.body || {}; - const { - name, - hourlyRate, - vaAssigned, - dedicatedHours, + const { + name, + hourlyRate, + vaAssigned, + dedicatedHours, status, - totalLoggedHours , + totalLoggedHours, vaWorkingScheduleStart, vaWorkingScheduleEnd, - isFlexibleAllowedPt, + isFlexibleAllowed, vaWorkingDelayAllowedStart, vaWorkingDelayAllowedEnd } = payload; // Validate projectId if (!projectId) { - return res.status(400).json({ - success: false, - message: "Project ID is required" + return res.status(400).json({ + success: false, + message: "Project ID is required" }); } @@ -36,18 +36,18 @@ async function update_project_sf(req, res) { try { projectObjectId = new Types.ObjectId(projectId); } catch (error) { - return res.status(400).json({ - success: false, - message: "Invalid Project ID format" + return res.status(400).json({ + success: false, + message: "Invalid Project ID format" }); } // Check if project exists const existingProject = await ProjectModel.findById(projectObjectId); if (!existingProject) { - return res.status(404).json({ - success: false, - message: "Project not found" + return res.status(404).json({ + success: false, + message: "Project not found" }); } @@ -59,9 +59,9 @@ async function update_project_sf(req, res) { // Update name if provided if (name !== undefined) { if (!name.trim()) { - return res.status(400).json({ - success: false, - message: "Project name cannot be empty" + return res.status(400).json({ + success: false, + message: "Project name cannot be empty" }); } updateData.name = name.trim(); @@ -85,9 +85,9 @@ async function update_project_sf(req, res) { // Update status if provided if (status !== undefined) { if (!["ACTIVE", "INACTIVE"].includes(status)) { - return res.status(400).json({ - success: false, - message: "Status must be either ACTIVE or INACTIVE" + return res.status(400).json({ + success: false, + message: "Status must be either ACTIVE or INACTIVE" }); } updateData.status = status; @@ -102,8 +102,8 @@ async function update_project_sf(req, res) { updateData.vaWorkingScheduleEnd = vaWorkingScheduleEnd || null; } - if (isFlexibleAllowedPt !== undefined) { - updateData.isFlexibleAllowedPt = isFlexibleAllowedPt; + if (isFlexibleAllowed !== undefined) { + updateData.isFlexibleAllowed = isFlexibleAllowed; } if (vaWorkingDelayAllowedStart !== undefined) { @@ -114,34 +114,45 @@ async function update_project_sf(req, res) { updateData.vaWorkingDelayAllowedEnd = vaWorkingDelayAllowedEnd || null; } + if (vaAssigned !== undefined && vaAssigned !== null && Array.isArray(vaAssigned)) { + updateData.vaAssigned = vaAssigned; + } + // Handle VA assignments - this requires relationship updates if (vaAssigned !== undefined) { - let newVaAssignedArray = []; + let newVaAssignedArray = updateData.vaAssigned.map(vaDtl => vaDtl.vaId); // Parse and validate VA IDs if (vaAssigned && vaAssigned.length > 0) { if (Array.isArray(vaAssigned)) { try { - newVaAssignedArray = vaAssigned.map(vaId => new Types.ObjectId(vaId)); + newVaAssignedArray = vaAssigned.map(vaId => { + if (typeof vaId === 'object' && "isFlexibleAllowed" in vaId) { + // Handle Error form SF Side for now - That vaId is coming as object + return new Types.ObjectId(vaId.vaId) + } else { + return new Types.ObjectId(vaId) + } + }); } catch (error) { - return res.status(400).json({ - success: false, - message: "Invalid VA ID format in vaAssigned array" + return res.status(400).json({ + success: false, + message: "Invalid VA ID format in vaAssigned array" }); } } else if (typeof vaAssigned === 'string') { try { newVaAssignedArray = [new Types.ObjectId(vaAssigned)]; } catch (error) { - return res.status(400).json({ - success: false, - message: "Invalid VA ID format" + return res.status(400).json({ + success: false, + message: "Invalid VA ID format" }); } } } - updateData.vaAssigned = newVaAssignedArray; + // updateData.vaAssigned = newVaAssignedArray; // Calculate VAs to add and remove for relationship updates const currentVaIds = existingProject.vaAssigned.map(va => va.toString()); @@ -175,9 +186,9 @@ async function update_project_sf(req, res) { // If no fields to update if (Object.keys(updateData).length === 0) { - return res.status(400).json({ - success: false, - message: "No valid fields to update" + return res.status(400).json({ + success: false, + message: "No valid fields to update" }); } @@ -187,7 +198,7 @@ async function update_project_sf(req, res) { updateData, { new: true, runValidators: true } ).populate('clientId', 'userDetails.name userDetails.email') - .populate('vaAssigned', 'userDetails.firstName userDetails.lastName userDetails.email'); + .populate('vaAssigned', 'userDetails.firstName userDetails.lastName userDetails.email'); // If VA assignments were changed but relationship update failed, log warning if (vaAssigned !== undefined) { @@ -211,33 +222,33 @@ async function update_project_sf(req, res) { } catch (error) { console.error("update_project_sf error:", error); - + // MongoDB duplicate key error if (error.code === 11000) { - return res.status(400).json({ - success: false, - message: "Project with this name already exists" + return res.status(400).json({ + success: false, + message: "Project with this name already exists" }); } - + // MongoDB validation error if (error.name === 'ValidationError') { const errors = Object.values(error.errors).map(err => err.message); - return res.status(400).json({ - success: false, + return res.status(400).json({ + success: false, message: "Validation error", - errors: errors + errors: errors }); } - - return res.status(500).json({ - success: false, + + return res.status(500).json({ + success: false, message: "Internal Server Error", - error: error.message + error: error.message }); } } -export { +export { update_project_sf }; \ No newline at end of file diff --git a/src/controllers/va/vaProfile/vaDelete.controller.js b/src/controllers/va/vaProfile/vaDelete.controller.js index 8b71c12..7031c39 100644 --- a/src/controllers/va/vaProfile/vaDelete.controller.js +++ b/src/controllers/va/vaProfile/vaDelete.controller.js @@ -44,7 +44,7 @@ async function va_remove_function(req, res) { if (projectIds.length > 0) { const projectResult = await ProjectModel.updateMany( { _id: { $in: projectIds } }, - { $pull: { vaAssigned: vaId } } + { $pull: { "vaAssigned.vaId": vaId } } ); projectsUpdated = projectResult.modifiedCount; console.log(`Removed VA from ${projectsUpdated} projects`); diff --git a/src/controllers/va/vaProjects/vaProjectLog.controller.js b/src/controllers/va/vaProjects/vaProjectLog.controller.js index 651c27e..45ed2c2 100644 --- a/src/controllers/va/vaProjects/vaProjectLog.controller.js +++ b/src/controllers/va/vaProjects/vaProjectLog.controller.js @@ -105,7 +105,7 @@ function getCurrentUTCTime() { // console.log(`Schedule Check - Current: ${currentMinutes}, Start: ${scheduleStartMinutes}, End: ${scheduleEndMinutes}, Allowed Start: ${allowedStartMinutes}, Allowed End: ${allowedEndMinutes}`); // // Check for PARTTIME with flexible schedule -// if (vaStatus === "PARTTIME" && project.isFlexibleAllowedPt) { +// if (vaStatus === "PARTTIME" && project.isFlexibleAllowed) { // return { isCompliant: true, warnings }; // } diff --git a/src/controllers/va/vaProjects/vaProjectLogList.controller.js b/src/controllers/va/vaProjects/vaProjectLogList.controller.js index 13bafb5..708ad80 100644 --- a/src/controllers/va/vaProjects/vaProjectLogList.controller.js +++ b/src/controllers/va/vaProjects/vaProjectLogList.controller.js @@ -72,7 +72,7 @@ async function va_projects_log_list_function(req, res) { console.log("VA ID:", vaId.toString()); - projectList = await ProjectModel.find({ vaAssigned: vaUser._id }); + projectList = await ProjectModel.find({ "vaAssigned.vaId": vaUser._id }); } if (!projectList.length) { diff --git a/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js index 5ca4a5a..3884422 100644 --- a/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js +++ b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js @@ -34,7 +34,7 @@ async function va_timesheet_adjustment_function(req, res) { // Validate project exists and VA is assigned to it const project = await ProjectModel.findOne({ _id: projectId, - vaAssigned: vaId + "vaAssigned.vaId": vaId }); if (!project) { diff --git a/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js index 94020f2..f75d5e8 100644 --- a/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js +++ b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js @@ -43,7 +43,7 @@ async function va_timesheet_summary_function(req, res) { // Validate project exists and VA is assigned to it const project = await ProjectModel.findOne({ _id: projectId, - vaAssigned: vaId + "vaAssigned.vaId": vaId }); if (!project) { diff --git a/src/controllers/va/vaTips/vaTipsManage.controller.js b/src/controllers/va/vaTips/vaTipsManage.controller.js index 010ae35..29db442 100644 --- a/src/controllers/va/vaTips/vaTipsManage.controller.js +++ b/src/controllers/va/vaTips/vaTipsManage.controller.js @@ -20,7 +20,7 @@ async function va_tips_manage_function(req, res) { clientId, status: "Unbilled", amount: parseFloat(amount).toFixed(2), - description, + description: description || "", vaName: vaUser.userDetails.firstName ? vaUser.userDetails.firstName : "" + " " + vaUser.userDetails.lastName ? vaUser.userDetails.lastName : "", vaId, }; @@ -34,7 +34,7 @@ async function va_tips_manage_function(req, res) { "vaId": createdTip.vaId.toString(), "status": "Unbilled", "clientId": createdTip.clientId.toString(), - "comment": createdTip.description, + "comment": createdTip.description || "", "tipAmount": Number(parseFloat(createdTip.amount).toFixed(2)), // Convert to cents } diff --git a/src/helper/updateEntityRelationships.js b/src/helper/updateEntityRelationships.js index 4a81d1f..85d7af6 100644 --- a/src/helper/updateEntityRelationships.js +++ b/src/helper/updateEntityRelationships.js @@ -69,7 +69,7 @@ async function updateEntityRelationships(data) { if (vaId && Array.isArray(vaId)) { await ProjectModel.findByIdAndUpdate( projectId, - { $addToSet: { vaAssigned: { $each: vaId } } } + { $addToSet: { "vaAssigned.vaId": { $each: vaId } } } ); } @@ -103,7 +103,7 @@ async function updateEntityRelationships(data) { { _id: { $in: projectId } }, { $addToSet: { - vaAssigned: vaId + "vaAssigned.vaId": vaId } } ); @@ -285,7 +285,7 @@ async function removeEntityRelationships(data) { if (projectId && Array.isArray(projectId)) { await ProjectModel.updateMany( { _id: { $in: projectId } }, - { $pull: { vaAssigned: vaId } } + { $pull: { "vaAssigned.vaId": vaId } } ); } diff --git a/src/models/vaModel.js b/src/models/vaModel.js index 419d3d7..3b797f3 100644 --- a/src/models/vaModel.js +++ b/src/models/vaModel.js @@ -89,9 +89,16 @@ const projectSchema = new Schema({ }, vaAssigned: [ { - type: Types.ObjectId, - ref: "VA", - }, + _id: false, + vaId: { + type: Types.ObjectId, + ref: "VA", + }, + isFlexibleAllowed: { + type: Boolean, + default: true + } + } ], dedicatedHours: { type: String, @@ -110,7 +117,7 @@ const projectSchema = new Schema({ type: String, default: null }, - isFlexibleAllowedPt: { + isFlexibleAllowed: { type: Boolean, default: true }, @@ -189,7 +196,7 @@ const clientDetailsSchema = new Schema({ enum: ["CHECKING", "SAVINGS"], type: String, }, - + accountHolderName: { type: String, }, @@ -363,36 +370,36 @@ const vaWorkTrackSchema = new Schema({ ) const passwordResetSchema = new mongoose.Schema({ - email: { - type: String, - required: true, - lowercase: true, - index: true - }, - token: { - type: String, - required: true, - unique: true, - index: true - }, - userType: { - type: String, - required: true, - enum: ['va', 'client'], - index: true - }, - expiresAt: { - type: Date, - required: true, - index: true, - expires: 3600 // TTL index for 1 hour - }, - used: { - type: Boolean, - default: false - } + email: { + type: String, + required: true, + lowercase: true, + index: true + }, + token: { + type: String, + required: true, + unique: true, + index: true + }, + userType: { + type: String, + required: true, + enum: ['va', 'client'], + index: true + }, + expiresAt: { + type: Date, + required: true, + index: true, + expires: 3600 // TTL index for 1 hour + }, + used: { + type: Boolean, + default: false + } }, { - timestamps: true + timestamps: true }); passwordResetSchema.index({ email: 1, used: 1 }); diff --git a/src/server.js b/src/server.js index 5bbade2..b604314 100644 --- a/src/server.js +++ b/src/server.js @@ -341,7 +341,7 @@ io.on("connection", (socket) => { const projectVAIds = new Set(); const populated = await ProjectModel.findById(projectId).populate("vaAssigned"); - populated.vaAssigned.forEach((va) => projectVAIds.add(va._id.toString())); + populated.vaAssigned.forEach((va) => projectVAIds.add(va.vaId.toString())); socket.data.allowedVAs = Array.from(projectVAIds); console.log(`Client ${clientId} can view VAs:`, socket.data.allowedVAs); @@ -498,6 +498,14 @@ io.on("connection", (socket) => { }); +app.get("/heath", () => { + if(Math.round(Math.random()) === 1) { + return res.status(200).json({"success": true, "message": "Server is Healthy"}) + } else { + return res.status(403).json({"success": false, "message": "Server is not Healthy"}) + } +}) + app.use((req, res) => { res.status(404).render("not_found", { title: "404 - Page Not Found" diff --git a/views/client/dashboard-manage-va-tips.ejs b/views/client/dashboard-manage-va-tips.ejs index dbba167..edc9e67 100644 --- a/views/client/dashboard-manage-va-tips.ejs +++ b/views/client/dashboard-manage-va-tips.ejs @@ -184,7 +184,7 @@
- +