diff --git a/src/controllers/va/vaAuth/vaLogin.controller.js b/src/controllers/va/vaAuth/vaLogin.controller.js index 625280f..d603004 100644 --- a/src/controllers/va/vaAuth/vaLogin.controller.js +++ b/src/controllers/va/vaAuth/vaLogin.controller.js @@ -40,7 +40,7 @@ async function va_login_callback(req, res) { name: user.userDetails.firstName, }, process.env.JWT_SECRET_ACCESS_TOKEN || "DocTrackerSecretKey", - { expiresIn: "24h" } + // { expiresIn: "24h" } ); // Generate JWT refreshToken with 24h expiry @@ -51,7 +51,7 @@ async function va_login_callback(req, res) { name: user.userDetails.firstName, }, process.env.JWT_SECRET_REFRESH_TOKEN || "DocTrackerSecretKeyRefreshToken", - { expiresIn: "30d" } + // { expiresIn: "30d" } ); await VAModel.updateOne({ "userDetails.email": userDetails.email }, { diff --git a/src/controllers/va/vaLog/vaTimesheetAdjustment.controller.js b/src/controllers/va/vaLog/vaTimesheetAdjustment.controller.js deleted file mode 100644 index fafbc59..0000000 --- a/src/controllers/va/vaLog/vaTimesheetAdjustment.controller.js +++ /dev/null @@ -1,151 +0,0 @@ -import jwt from "jsonwebtoken"; -import { VAModel, ProjectModel, LoggedModel } from "../../../models/vaModel.js"; - -// Adjust missing hours by creating new records -async function va_timesheet_adjustment_function(req, res) { - try { - const accessToken = req.headers.token; - - if (!accessToken) { - return res.status(401).json({ success: false, message: "Missing token" }); - } - - const decoded = jwt.verify(accessToken, process.env.JWT_SECRET_ACCESS_TOKEN); - if (!decoded || !decoded.email) { - return res.status(401).json({ success: false, message: "Invalid token" }); - } - - const vaEmail = decoded.email; - const vaUser = await VAModel.findOne({ "userDetails.email": vaEmail }); - if (!vaUser) { - return res.status(404).json({ success: false, message: "VA not found" }); - } - - const vaId = vaUser._id; - const { projectId, date } = req.params; - const { loginTime, logoutTime, reason } = req.body; - - if (!projectId || !date) { - return res.status(400).json({ success: false, message: "Project ID and date are required" }); - } - - if (!loginTime || !logoutTime) { - return res.status(400).json({ success: false, message: "Login time and logout time are required" }); - } - - // Validate project exists and VA is assigned to it - const project = await ProjectModel.findOne({ - _id: projectId, - vaAssigned: vaId - }); - - if (!project) { - return res.status(404).json({ success: false, message: "Project not found or VA not assigned to this project" }); - } - - // Parse and validate times - const adjustmentDate = new Date(date); - const loginDateTime = new Date(loginTime); - const logoutDateTime = new Date(logoutTime); - - // Ensure times are within the target date - const startOfDay = new Date(adjustmentDate); - startOfDay.setHours(0, 0, 0, 0); - - const endOfDay = new Date(adjustmentDate); - endOfDay.setHours(23, 59, 59, 999); - - if (loginDateTime < startOfDay || loginDateTime > endOfDay || - logoutDateTime < startOfDay || logoutDateTime > endOfDay) { - return res.status(400).json({ - success: false, - message: "Login and logout times must be within the specified date" - }); - } - - if (loginDateTime >= logoutDateTime) { - return res.status(400).json({ - success: false, - message: "Login time must be before logout time" - }); - } - - // Check for existing logs that might conflict with this adjustment - const existingLogs = await LoggedModel.find({ - vaId, - projectId, - time: { - $gte: loginDateTime, - $lte: logoutDateTime - } - }); - - if (existingLogs.length > 0) { - return res.status(400).json({ - success: false, - message: "There are existing logs in the specified time range. Please choose a different time range." - }); - } - - // Create adjustment logs - const loginLog = new LoggedModel({ - loggedType: "LOGIN", - time: loginDateTime, - vaId, - vaEmail, - projectId, - isAdjustment: true, - adjustmentReason: reason - }); - - const logoutLog = new LoggedModel({ - loggedType: "LOGOUT", - time: logoutDateTime, - vaId, - vaEmail, - projectId, - isAdjustment: true, - adjustmentReason: reason - }); - - // Save both logs in transaction - await loginLog.save(); - await logoutLog.save(); - - // Calculate adjusted hours - const adjustedSeconds = (logoutDateTime - loginDateTime) / 1000; - const formatTime = (seconds) => { - const h = Math.floor(seconds / 3600); - const m = Math.floor((seconds % 3600) / 60); - const s = Math.floor(seconds % 60); - return `${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`; - }; - - const response = { - success: true, - message: "Timesheet adjustment completed successfully", - data: { - adjustment: { - date: adjustmentDate.toISOString().split('T')[0], - loginTime: loginDateTime.toISOString(), - logoutTime: logoutDateTime.toISOString(), - adjustedHours: formatTime(adjustedSeconds), - adjustedHoursDecimal: (adjustedSeconds / 3600).toFixed(2), - reason: reason - }, - logs: { - loginLogId: loginLog._id, - logoutLogId: logoutLog._id - } - } - }; - - return res.status(201).json(response); - - } catch (error) { - console.error("Timesheet adjustment error:", error); - return res.status(500).json({ success: false, message: "Internal Server Error" }); - } -} - -export { va_timesheet_adjustment_function }; \ No newline at end of file diff --git a/src/controllers/va/vaProfile/vaProfile.controller.js b/src/controllers/va/vaProfile/vaProfile.controller.js index 869de05..6417dce 100644 --- a/src/controllers/va/vaProfile/vaProfile.controller.js +++ b/src/controllers/va/vaProfile/vaProfile.controller.js @@ -34,7 +34,7 @@ async function va_profile_callback(req, res) { return res.status(200).json({ success: true, message: "VA profile", - data: vaUser + data: vaUser.userDetails }); } catch (error) { return res.status(500).json({ success: false, message: "Internal Server Error" }); diff --git a/src/controllers/va/vaProjects/vaProjectReport.controller.js b/src/controllers/va/vaProjects/vaProjectReport.controller.js index c140fa1..2b2bbc6 100644 --- a/src/controllers/va/vaProjects/vaProjectReport.controller.js +++ b/src/controllers/va/vaProjects/vaProjectReport.controller.js @@ -1,3 +1,4 @@ +import jwt from "jsonwebtoken"; import { LoggedModel, WorkTrackModel, VAModel } from "../../../models/vaModel.js"; function formatHMS(ms) { @@ -10,6 +11,23 @@ function formatHMS(ms) { async function va_projects_report_function(req, res) { try { + const accessToken = req.headers.token; + if (!accessToken) { + return res.status(401).json({ success: false, message: "Missing token" }); + } + + const decoded = jwt.verify(accessToken, process.env.JWT_SECRET_ACCESS_TOKEN); + if (!decoded || !decoded.email) { + return res.status(401).json({ success: false, message: "Invalid token" }); + } + + const vaEmail = decoded.email; + const vaUser = await VAModel.findOne({ "userDetails.email": vaEmail }); + if (!vaUser) { + return res.status(404).json({ success: false, message: "VA not found" }); + } + + const vaId = vaUser._id; const { projectId, from, to } = req.params; if (!projectId) { @@ -25,6 +43,7 @@ async function va_projects_report_function(req, res) { // Get all VA login/logout logs for this project in range const logs = await LoggedModel.find({ projectId, + vaId, time: { $gte: fromDate, $lte: toDate } }).sort({ time: 1 }).lean(); diff --git a/src/controllers/va/vaTimesheetAdjustment/vaAllTimesheetAdjustmentReuqest.controller.js b/src/controllers/va/vaTimesheetAdjustment/vaAllTimesheetAdjustmentReuqest.controller.js new file mode 100644 index 0000000..4ba9488 --- /dev/null +++ b/src/controllers/va/vaTimesheetAdjustment/vaAllTimesheetAdjustmentReuqest.controller.js @@ -0,0 +1,71 @@ +import { AdjustedHoursModel } from "../../../models/vaModel.js"; + +// Get all adjustment requests (with filtering options) +async function get_adjustment_requests_list(req, res) { + try { + const { status, projectId, vaId } = req.params; + + // Build filter object + const filter = {}; + if (status) filter.status = status; + if (projectId) filter.projectId = projectId; + if (vaId) filter.vaId = vaId; + + const adjustments = await AdjustedHoursModel.find(filter) + .sort({ createdAt: -1 }) + .populate('vaId', 'userDetails.name userDetails.email') + .populate('projectId', 'name') + .lean(); + + // Format response + const formattedData = adjustments.map(adj => ({ + id: adj._id, + va: { + id: adj.vaId._id, + name: adj.vaId.userDetails?.name, + email: adj.vaId.userDetails?.email + }, + project: { + id: adj.projectId._id, + name: adj.projectId.name + }, + date: adj.date, + loginTime: adj.loginTime, + logoutTime: adj.logoutTime, + comment: adj.comment, + status: adj.status, + requestedAt: adj.createdAt, + reviewedAt: adj.reviewedAt, + rejectionReason: adj.rejectionReason, + adjustedHours: formatTime((new Date(adj.logoutTime) - new Date(adj.loginTime)) / 1000) + })); + + return res.status(200).json({ + success: true, + data: formattedData, + pagination: { + currentPage: adjustments.page, + totalPages: adjustments.totalPages, + totalItems: adjustments.totalDocs, + hasNext: adjustments.hasNextPage, + hasPrev: adjustments.hasPrevPage + } + }); + + } catch (error) { + console.error("Get adjustment requests error:", error); + return res.status(500).json({ + success: false, + message: "Internal Server Error" + }); + } +} + +function formatTime(seconds) { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = Math.floor(seconds % 60); + return `${h}h ${m}m ${s}s`; +} + +export { get_adjustment_requests_list } \ No newline at end of file diff --git a/src/controllers/va/vaTimesheetAdjustment/vaManageTimesheetAdjustment.controller.js b/src/controllers/va/vaTimesheetAdjustment/vaManageTimesheetAdjustment.controller.js new file mode 100644 index 0000000..f114406 --- /dev/null +++ b/src/controllers/va/vaTimesheetAdjustment/vaManageTimesheetAdjustment.controller.js @@ -0,0 +1,122 @@ +import { AdjustedHoursModel, LoggedModel } from "../../../models/vaModel.js"; + +// Approve or reject adjustment request +async function va_timesheet_manage_adjustment_request(req, res) { + try { + const { adjustmentId } = req.params; + const { action, rejectionReason } = req.body; // action: "approve" or "reject" + + if (!adjustmentId || !action) { + return res.status(400).json({ + success: false, + message: "Adjustment ID and action are required" + }); + } + + // Find adjustment request + const adjustment = await AdjustedHoursModel.findById(adjustmentId) + .populate('vaId', 'userDetails.email'); + + if (!adjustment) { + return res.status(404).json({ + success: false, + message: "Adjustment request not found" + }); + } + + if (adjustment.status !== "PENDING") { + return res.status(400).json({ + success: false, + message: "Adjustment request has already been processed" + }); + } + + if (action === "approve") { + // Create new log entries in LoggedModel + const loginLog = new LoggedModel({ + loggedType: "LOGIN", + time: adjustment.loginTime, + vaId: adjustment.vaId._id, + vaEmail: adjustment.vaId.userDetails.email, + projectId: adjustment.projectId, + isAdjustment: true, + adjustmentId: adjustment._id + }); + + const logoutLog = new LoggedModel({ + loggedType: "LOGOUT", + time: adjustment.logoutTime, + vaId: adjustment.vaId._id, + vaEmail: adjustment.vaId.userDetails.email, + projectId: adjustment.projectId, + isAdjustment: true, + adjustmentId: adjustment._id + }); + + await loginLog.save(); + await logoutLog.save(); + + // Update adjustment record + adjustment.status = "APPROVED"; + adjustment.reviewedAt = new Date(); + adjustment.adjustedLogs = [ + { loginLogId: loginLog._id }, + { logoutLogId: logoutLog._id } + ]; + + await adjustment.save(); + + return res.status(200).json({ + success: true, + message: "Adjustment request approved successfully", + data: { + adjustmentId: adjustment._id, + status: "APPROVED", + loginLogId: loginLog._id, + logoutLogId: logoutLog._id, + adjustedHours: formatTime((adjustment.logoutTime - adjustment.loginTime) / 1000) + } + }); + + } else if (action === "reject") { + // Update adjustment record as rejected + adjustment.status = "REJECTED"; + adjustment.reviewedAt = new Date(); + adjustment.rejectionReason = rejectionReason || "No reason provided"; + + await adjustment.save(); + + return res.status(200).json({ + success: true, + message: "Adjustment request rejected", + data: { + adjustmentId: adjustment._id, + status: "REJECTED", + rejectionReason: adjustment.rejectionReason + } + }); + + } else { + return res.status(400).json({ + success: false, + message: "Invalid action. Use 'approve' or 'reject'" + }); + } + + } catch (error) { + console.error("Manage adjustment error:", error); + return res.status(500).json({ + success: false, + message: "Internal Server Error" + }); + } +} + +function formatTime(seconds) { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = Math.floor(seconds % 60); + return `${h}h ${m}m ${s}s`; +} + +export { va_timesheet_manage_adjustment_request } \ No newline at end of file diff --git a/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js new file mode 100644 index 0000000..6614c71 --- /dev/null +++ b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js @@ -0,0 +1,159 @@ +import jwt from "jsonwebtoken"; +import { VAModel, ProjectModel, AdjustedHoursModel } from "../../../models/vaModel.js"; + +// Adjust missing hours by creating new records +async function va_timesheet_adjustment_function(req, res) { + try { + const accessToken = req.headers.token; + + if (!accessToken) { + return res.status(401).json({ success: false, message: "Missing token" }); + } + + const decoded = jwt.verify(accessToken, process.env.JWT_SECRET_ACCESS_TOKEN); + if (!decoded || !decoded.email) { + return res.status(401).json({ success: false, message: "Invalid token" }); + } + + const vaEmail = decoded.email; + const vaUser = await VAModel.findOne({ "userDetails.email": vaEmail }); + if (!vaUser) { + return res.status(404).json({ success: false, message: "VA not found" }); + } + + const vaId = vaUser._id; + const { projectId, date, loginTime, logoutTime, comment } = req.body; + + if (!projectId || !date || !loginTime || !logoutTime || !comment) { + return res.status(400).json({ + success: false, + message: "Project ID, date, loginTime, logoutTime, and comment are required" + }); + } + + // Validate project exists and VA is assigned to it + const project = await ProjectModel.findOne({ + _id: projectId, + vaAssigned: vaId + }); + + if (!project) { + return res.status(404).json({ success: false, message: "Project not found or VA not assigned to this project" }); + } + + let adjustmentDate; + try { + adjustmentDate = new Date(date); + if (isNaN(adjustmentDate.getTime())) { + return res.status(400).json({ + success: false, + message: "Invalid date format. Use YYYY-MM-DD" + }); + } + } catch (error) { + return res.status(400).json({ + success: false, + message: "Invalid date format" + }); + } + + const combineDateTime = (dateObj, timeStr) => { + const [hours, minutes, seconds] = timeStr.split(':').map(Number); + + // Extract date components from the Date object + const year = dateObj.getFullYear(); + const month = dateObj.getMonth(); + const day = dateObj.getDate(); + + // Create UTC date directly + return new Date(Date.UTC(year, month, day, hours, minutes, seconds)); + }; + + const loginDateTime = combineDateTime(adjustmentDate, loginTime); + const logoutDateTime = combineDateTime(adjustmentDate, logoutTime); + + if (isNaN(adjustmentDate.getTime()) || isNaN(loginDateTime.getTime()) || isNaN(logoutDateTime.getTime())) { + return res.status(400).json({ + success: false, + message: "Invalid date format" + }); + } + + // Ensure login time is before logout time + if (loginDateTime >= logoutDateTime) { + return res.status(400).json({ + success: false, + message: "Login time must be before logout time" + }); + } + + // Ensure times are within the target date + const startOfDay = new Date(adjustmentDate); + startOfDay.setHours(0, 0, 0, 0); + + const endOfDay = new Date(adjustmentDate); + endOfDay.setHours(23, 59, 59, 999); + + if (loginDateTime < startOfDay || loginDateTime > endOfDay || + logoutDateTime < startOfDay || logoutDateTime > endOfDay) { + return res.status(400).json({ + success: false, + message: "Login and logout times must be within the specified date" + }); + } + + const existingAdjustment = await AdjustedHoursModel.findOne({ + vaId, + projectId, + date: startOfDay, + status: "PENDING" + }); + + if (existingAdjustment) { + return res.status(400).json({ + success: false, + message: "You already have a pending adjustment request for this date and project" + }); + } + + const adjustmentRequest = new AdjustedHoursModel({ + vaId, + projectId, + date: startOfDay, + loginTime: loginDateTime, + logoutTime: logoutDateTime, + comment, + status: "PENDING" + }); + + await adjustmentRequest.save(); + + const adjustedSeconds = (logoutDateTime - loginDateTime) / 1000; + const formatTime = (seconds) => { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = Math.floor(seconds % 60); + return `${h}h ${m}m ${s}s`; + }; + + return res.status(201).json({ + success: true, + message: "Adjustment request submitted successfully", + data: { + adjustmentId: adjustmentRequest._id, + date: adjustmentDate.toISOString().split('T')[0], + loginTime: loginDateTime.toISOString(), + logoutTime: logoutDateTime.toISOString(), + adjustedHours: formatTime(adjustedSeconds), + comment: comment, + status: "PENDING" + } + }); + + } catch (error) { + console.error("Timesheet adjustment error:", error); + return res.status(500).json({ success: false, message: "Internal Server Error" }); + } +} + +export { va_timesheet_adjustment_function }; \ No newline at end of file diff --git a/src/controllers/va/vaLog/vaTimesheetAdjustmentSummary.controller.js b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js similarity index 96% rename from src/controllers/va/vaLog/vaTimesheetAdjustmentSummary.controller.js rename to src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js index 010afea..e0d2096 100644 --- a/src/controllers/va/vaLog/vaTimesheetAdjustmentSummary.controller.js +++ b/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js @@ -86,7 +86,7 @@ async function va_timesheet_summary_function(req, res) { if (!firstLoginTime || logTime < firstLoginTime) { firstLoginTime = logTime; } - } else if (log.loggedType === "LOGOUT" && lastLogin) { + } else if (log.loggedType === "LOGOUT") { if (loginStack.length > 0) { // Pop the last login from stack const lastLogin = loginStack.pop(); @@ -157,7 +157,6 @@ async function va_timesheet_summary_function(req, res) { const response = { success: true, data: { - date: targetDate.toISOString().split('T')[0], project: { id: project._id, name: project.name, @@ -171,10 +170,10 @@ async function va_timesheet_summary_function(req, res) { summary: { totalWorkedHours: formatTime(totalWorkSeconds), totalWorkedHoursDetailed: formatTimeDetailed(totalWorkSeconds), - totalWorkedHoursDecimal: totalWorkedHours.toFixed(4), + totalWorkedHoursDecimal: totalWorkedHours.toFixed(2), totalWorkedMinutes: (totalWorkSeconds / 60).toFixed(2), dedicatedHours: dedicatedHours, - pendingHours: pendingHours.toFixed(4), + pendingHours: pendingHours.toFixed(2), firstLoginTime: firstLoginTime ? firstLoginTime.toISOString() : null, lastLogoutTime: lastLogoutTime ? lastLogoutTime.toISOString() : null }, diff --git a/src/models/vaModel.js b/src/models/vaModel.js index 179bbc0..aaf9fb3 100644 --- a/src/models/vaModel.js +++ b/src/models/vaModel.js @@ -358,6 +358,57 @@ passwordResetSchema.index({ email: 1, used: 1 }); passwordResetSchema.index({ token: 1, used: 1, expiresAt: 1 }); passwordResetSchema.index({ userType: 1, email: 1 }); + +const adjustedHoursSchema = new Schema({ + vaId: { + type: Types.ObjectId, + ref: "VA", + required: true + }, + projectId: { + type: Types.ObjectId, + ref: "Project", + required: true + }, + date: { + type: Date, + required: true + }, + loginTime: { + type: Date, + required: true + }, + logoutTime: { + type: Date, + required: true + }, + comment: { + type: String, + required: true + }, + status: { + type: String, + enum: ["PENDING", "APPROVED", "REJECTED"], + default: "PENDING" + }, + reviewedAt: { + type: Date + }, + rejectionReason: { + type: String // If rejected, store the reason + }, + adjustedLogs: [{ + loginLogId: { + type: Types.ObjectId, + ref: "Logged" + }, + logoutLogId: { + type: Types.ObjectId, + ref: "Logged" + } + }] +}, { timestamps: true }); + /* ---------------------- Model Exports ---------------------- */ const VAModel = model("VA", vaSchema); const ClientModel = model("Client", clientSchema); @@ -365,5 +416,6 @@ const ProjectModel = model("Project", projectSchema); const LoggedModel = model("TrackLog", loggedSchema); const WorkTrackModel = model("TrackWork", vaWorkTrackSchema); const PasswordResetModel = model("PasswordReset", passwordResetSchema); +const AdjustedHoursModel = model("AdjustedHours", adjustedHoursSchema); -export { VAModel, ClientModel, ProjectModel, LoggedModel, WorkTrackModel, PasswordResetModel }; \ No newline at end of file +export { VAModel, ClientModel, ProjectModel, LoggedModel, WorkTrackModel, PasswordResetModel, AdjustedHoursModel }; \ No newline at end of file diff --git a/src/routes/v1/va.routes.js b/src/routes/v1/va.routes.js index 99e431d..59533cf 100644 --- a/src/routes/v1/va.routes.js +++ b/src/routes/v1/va.routes.js @@ -18,8 +18,10 @@ import { va_log_work_report_callback } from "../../controllers/va/vaLog/vaLogWor import { va_projects_report_function } from "../../controllers/va/vaProjects/vaProjectReport.controller.js"; import { va_projects_log_list_function } from "../../controllers/va/vaProjects/vaProjectLogList.controller.js"; import { va_request_password_reset } from "../../controllers/passwordReset.controllers.js"; -import { va_timesheet_summary_function } from "../../controllers/va/vaLog/vaTimesheetAdjustmentSummary.controller.js"; -import { va_timesheet_adjustment_function } from "../../controllers/va/vaLog/vaTimesheetAdjustment.controller.js"; +import { va_timesheet_summary_function } from "../../controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustmentSummary.controller.js"; +import { va_timesheet_adjustment_function } from "../../controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js"; +import { get_adjustment_requests_list } from "../../controllers/va/vaTimesheetAdjustment/vaAllTimesheetAdjustmentReuqest.controller.js" +import { va_timesheet_manage_adjustment_request } from "../../controllers/va/vaTimesheetAdjustment/vaManageTimesheetAdjustment.controller.js" vaRoutes.get("/", va_callback); // VA Callback for getting active VA @@ -36,9 +38,13 @@ vaRoutes.patch("/profile", authValidator, va_profile_update_callback); // Update vaRoutes.get("/:userName", va_username_callback); // VA Username Callback (NC) - +// timesheet adjustment routes vaRoutes.get("/timesheet/summary/:projectId/:date", authValidator, va_timesheet_summary_function); // Get Timesheet Adjustment for VA on specific project and date -vaRoutes.post("/timesheet/adjustment/:projectId/:date", authValidator, va_timesheet_adjustment_function); // Get Timesheet Adjustment for VA on specific project and date +vaRoutes.post("/timesheet/adjustment/request", authValidator, va_timesheet_adjustment_function); // Timesheet Adjustment for VA +vaRoutes.get("/timesheet/adjustments/list/:status?/:projectId?/:vaId?", get_adjustment_requests_list); // show all adjustment list to approve and reject +vaRoutes.patch("/timesheet/adjustments/:adjustmentId", va_timesheet_manage_adjustment_request); + +// timesheet adjustment routes // Example: GET /va/search?name=john&email=@example.com&from=2025-01-01&to=2025-01-31 (NC) vaRoutes.get("/search", va_filter_search);