va-tracker-middleware/src/controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.contr...

224 lines
8.3 KiB
JavaScript

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(year, month, day, hours, minutes, seconds);
const combined = new Date(dateObj);
combined.setHours(hours, minutes, seconds, 0);
return combined;
};
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`;
};
try {
const salesforceUrl = `${process.env.SF_DOCTRACKER_API_URL}services/apexrest/docva/api/timesheet-adjustment`;
const sfData = {
"id": adjustmentRequest._id,
"va": {
"id": vaId
},
"project": {
"id": projectId
},
"date": adjustmentDate.toISOString().split('T')[0],
"loginTime": loginDateTime.toISOString(),
"logoutTime": logoutDateTime.toISOString(),
"comment": comment,
"status": "PENDING",
"rejectionReason": "",
"adjustedHours": formatTime(adjustedSeconds)
}
const response = await fetch(salesforceUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Add any required headers for Salesforce authentication
// 'Authorization': 'Bearer ' + process.env.SF_ACCESS_TOKEN
},
body: JSON.stringify({"data": sfData})
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Salesforce API responded with status ${response.status}: ${errorText}`);
}
const result = await response.json();
// console.log("✅ Successfully synced VA data to Salesforce:", result);
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"
},
SyncSalesforce: result
});
} catch (error) {
console.error("Failed to sync with Salesforce:", error.message);
console.log(error)
// Create a custom error to distinguish Salesforce errors
const salesforceError = new Error(`Salesforce sync failed: ${error.message}`);
salesforceError.isSalesforceError = true;
throw salesforceError;
}
// 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 };