Updated track log api to auto logout project after completing dedicated hours
This commit is contained in:
parent
4a2734cf2c
commit
d50c18856f
|
|
@ -1,6 +1,91 @@
|
|||
import jwt from "jsonwebtoken";
|
||||
import { WorkTrackModel, VAModel, ProjectModel, LoggedModel } from "../../../models/vaModel.js";
|
||||
|
||||
// Helper function to get start and end of day
|
||||
function getDayRange(date = new Date()) {
|
||||
const start = new Date(date);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
|
||||
const end = new Date(date);
|
||||
end.setHours(23, 59, 59, 999);
|
||||
|
||||
return { start, end };
|
||||
}
|
||||
|
||||
function formatHoursToReadable(hours) {
|
||||
const wholeHours = Math.floor(hours);
|
||||
const decimalMinutes = (hours - wholeHours) * 60;
|
||||
const wholeMinutes = Math.round(decimalMinutes);
|
||||
|
||||
if (wholeHours > 0 && wholeMinutes > 0) {
|
||||
return `${wholeHours}h ${wholeMinutes}m`;
|
||||
} else if (wholeHours > 0) {
|
||||
return `${wholeHours}h`;
|
||||
} else {
|
||||
return `${wholeMinutes}m`;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to check daily hours and create logout log if needed
|
||||
async function checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, currentSessionId = null, additionalTimeMs = 0) {
|
||||
try {
|
||||
const today = new Date();
|
||||
const { start, end } = getDayRange(today);
|
||||
|
||||
// Get today's work entries for this VA and project
|
||||
// Exclude the current session if it's already in the database
|
||||
const query = {
|
||||
vaId,
|
||||
projectId,
|
||||
from: { $gte: start, $lte: end }
|
||||
};
|
||||
|
||||
if (currentSessionId) {
|
||||
query._id = { $ne: currentSessionId };
|
||||
}
|
||||
|
||||
const todayWorkEntries = await WorkTrackModel.find(query);
|
||||
|
||||
// Calculate total hours worked today
|
||||
let totalTodayMs = todayWorkEntries.reduce((total, entry) => {
|
||||
return total + (entry.totalTime || 0);
|
||||
}, 0);
|
||||
|
||||
// Add the additional time from current session if provided
|
||||
totalTodayMs += additionalTimeMs;
|
||||
|
||||
const totalTodayHours = totalTodayMs / (1000 * 60 * 60);
|
||||
|
||||
// Check if daily dedicated hours are completed
|
||||
if (project.dedicatedHours > 0 && totalTodayHours >= project.dedicatedHours) {
|
||||
// Create automatic logout log
|
||||
const logoutLog = await LoggedModel.create({
|
||||
loggedType: "LOGOUT",
|
||||
vaId,
|
||||
vaEmail,
|
||||
projectId
|
||||
});
|
||||
|
||||
return {
|
||||
shouldLogout: true,
|
||||
totalTodayHours: totalTodayHours,
|
||||
dedicatedHours: project.dedicatedHours,
|
||||
logoutLogId: logoutLog._id
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
shouldLogout: false,
|
||||
totalTodayHours: totalTodayHours,
|
||||
dedicatedHours: project.dedicatedHours
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error in checkDailyHoursAndLogout:", error);
|
||||
return { shouldLogout: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Getting logged hours in a specific project of VA
|
||||
async function va_log_track_work_callback(req, res) {
|
||||
try {
|
||||
|
|
@ -50,6 +135,16 @@ async function va_log_track_work_callback(req, res) {
|
|||
|
||||
// Handle POST → create entry
|
||||
if (req.method === "POST") {
|
||||
const dailyCheck = await checkDailyHoursAndLogout(vaId, vaEmail, projectId, project);
|
||||
|
||||
if (dailyCheck.shouldLogout) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `Cannot start work - daily hours completed (${formatHoursToReadable(dailyCheck.totalTodayHours)} / ${formatHoursToReadable(dailyCheck.dedicatedHours)})`,
|
||||
autoLogout: true
|
||||
});
|
||||
}
|
||||
|
||||
const createdTrack = await WorkTrackModel.create({
|
||||
vaId,
|
||||
projectId,
|
||||
|
|
@ -63,6 +158,11 @@ async function va_log_track_work_callback(req, res) {
|
|||
success: true,
|
||||
message: "Work tracking started",
|
||||
data: createdTrack,
|
||||
dailyHours: {
|
||||
todayTotal: formatHoursToReadable(dailyCheck.totalTodayHours),
|
||||
dailyLimit: formatHoursToReadable(dailyCheck.dedicatedHours),
|
||||
remaining: formatHoursToReadable(dailyCheck.dedicatedHours - dailyCheck.totalTodayHours)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -89,11 +189,14 @@ async function va_log_track_work_callback(req, res) {
|
|||
|
||||
const formattedTotalTime = `${hours}h ${minutes}m ${seconds}s`;
|
||||
|
||||
// Check if daily dedicated hours are completed after this work session
|
||||
const dailyCheck = await checkDailyHoursAndLogout(vaId, vaEmail, projectId, project, id, totalTimeMs);
|
||||
|
||||
workEntry.to = toTime;
|
||||
workEntry.totalTime = totalTimeMs; // store as number of minutes
|
||||
await workEntry.save();
|
||||
|
||||
return res.status(200).json({
|
||||
const response = {
|
||||
success: true,
|
||||
message: "Work tracking stopped",
|
||||
data: {
|
||||
|
|
@ -101,9 +204,24 @@ async function va_log_track_work_callback(req, res) {
|
|||
from: workEntry.from,
|
||||
to: workEntry.to,
|
||||
formattedTotalTime,
|
||||
totalTimeMs
|
||||
totalTimeMs,
|
||||
sessionHours: totalTimeMs / (1000 * 60 * 60)
|
||||
},
|
||||
});
|
||||
dailyHours: {
|
||||
todayTotal: formatHoursToReadable(dailyCheck.totalTodayHours),
|
||||
dailyLimit: formatHoursToReadable(dailyCheck.dedicatedHours),
|
||||
remaining: formatHoursToReadable(Math.max(0, dailyCheck.dedicatedHours - dailyCheck.totalTodayHours))
|
||||
}
|
||||
};
|
||||
|
||||
// If auto-logout was triggered, add that info to response
|
||||
if (dailyCheck.shouldLogout) {
|
||||
response.autoLogout = true;
|
||||
response.message = `Work tracking stopped. Auto-logout created - daily hours completed (${formatHoursToReadable(dailyCheck.totalTodayHours)} / ${formatHoursToReadable(dailyCheck.dedicatedHours)})`;
|
||||
response.logoutLogId = dailyCheck.logoutLogId;
|
||||
}
|
||||
|
||||
return res.status(200).json(response);
|
||||
}
|
||||
|
||||
// Fallback for unsupported methods
|
||||
|
|
|
|||
|
|
@ -1,4 +1,29 @@
|
|||
import { LoggedModel } from "../../../models/vaModel.js";
|
||||
import { LoggedModel, WorkTrackModel, ProjectModel } from "../../../models/vaModel.js";
|
||||
|
||||
// Helper function to get start and end of day
|
||||
function getDayRange(date = new Date()) {
|
||||
const start = new Date(date);
|
||||
start.setHours(0, 0, 0, 0);
|
||||
|
||||
const end = new Date(date);
|
||||
end.setHours(23, 59, 59, 999);
|
||||
|
||||
return { start, end };
|
||||
}
|
||||
|
||||
function formatHoursToReadable(hours) {
|
||||
const wholeHours = Math.floor(hours);
|
||||
const decimalMinutes = (hours - wholeHours) * 60;
|
||||
const wholeMinutes = Math.round(decimalMinutes);
|
||||
|
||||
if (wholeHours > 0 && wholeMinutes > 0) {
|
||||
return `${wholeHours}h ${wholeMinutes}m`;
|
||||
} else if (wholeHours > 0) {
|
||||
return `${wholeHours}h`;
|
||||
} else {
|
||||
return `${wholeMinutes}m`;
|
||||
}
|
||||
}
|
||||
|
||||
// Getting logged hours in a specific project of VA
|
||||
async function va_project_log_callback(req, res) {
|
||||
|
|
@ -7,6 +32,50 @@ async function va_project_log_callback(req, res) {
|
|||
const { vaId, vaEmail, projectId, type } = payload;
|
||||
|
||||
if (!vaId, !vaEmail, !projectId, !type) return res.status(400).send("Missing Props");
|
||||
|
||||
const project = await ProjectModel.findById(projectId);
|
||||
if (!project) {
|
||||
return res.status(400).json({ success: false, message: "Project not found" });
|
||||
}
|
||||
|
||||
// For LOGIN requests, check daily hours
|
||||
if (type === "LOGIN") {
|
||||
const { start, end } = getDayRange();
|
||||
// Get today's total hours
|
||||
const todayWorkEntries = await WorkTrackModel.find({
|
||||
vaId,
|
||||
projectId,
|
||||
from: { $gte: start, $lte: end }
|
||||
});
|
||||
|
||||
const totalTodayMs = todayWorkEntries.reduce((total, entry) => {
|
||||
return total + (entry.totalTime || 0);
|
||||
}, 0);
|
||||
|
||||
const totalTodayHours = totalTodayMs / (1000 * 60 * 60);
|
||||
|
||||
// Check if daily hours are already completed
|
||||
if (project.dedicatedHours > 0 && totalTodayHours >= project.dedicatedHours) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `Cannot login - daily hours already completed (${formatHoursToReadable(totalTodayHours)} / ${formatHoursToReadable(project.dedicatedHours)})`
|
||||
});
|
||||
}
|
||||
|
||||
// Check last log entry
|
||||
const lastLog = await LoggedModel.findOne({ vaId, projectId })
|
||||
.sort({ time: -1 })
|
||||
.lean();
|
||||
|
||||
// Prevent login if last action was login (not logout)
|
||||
if (lastLog && lastLog.loggedType === "LOGIN") {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "User is already logged in to this project"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const createdLog = await LoggedModel.create({ loggedType: type, vaId, vaEmail, projectId })
|
||||
|
||||
return res.status(201).send({ success: true, message: `${type} Successfully`, logId: createdLog._id });
|
||||
|
|
|
|||
|
|
@ -9,6 +9,21 @@ function formatHMS(ms) {
|
|||
return `${h}h ${m}m ${s}s`;
|
||||
}
|
||||
|
||||
function formatHoursToReadable(hours) {
|
||||
const wholeHours = Math.floor(hours);
|
||||
const decimalMinutes = (hours - wholeHours) * 60;
|
||||
const wholeMinutes = Math.round(decimalMinutes);
|
||||
|
||||
if (wholeHours > 0 && wholeMinutes > 0) {
|
||||
return `${wholeHours}h ${wholeMinutes}m`;
|
||||
} else if (wholeHours > 0) {
|
||||
return `${wholeHours}h`;
|
||||
} else {
|
||||
return `${wholeMinutes}m`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function va_projects_log_list_function(req, res) {
|
||||
try {
|
||||
const { projectId, from, to } = req.params;
|
||||
|
|
@ -101,7 +116,9 @@ async function va_projects_log_list_function(req, res) {
|
|||
activityStatus,
|
||||
totalWorkTime: formatHMS(totalWorkMs),
|
||||
totalWorkMs,
|
||||
totalLogs: logs.length
|
||||
dedicatedHours: formatHoursToReadable(project?.dedicatedHours),
|
||||
totalLogs: logs.length,
|
||||
status: project?.status
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ const projectSchema = new Schema({
|
|||
},
|
||||
],
|
||||
dedicatedHours: {
|
||||
type: Number,
|
||||
type: String,
|
||||
default: 0
|
||||
},
|
||||
status: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue