Added project report API
This commit is contained in:
parent
07075bdefb
commit
7d73299822
|
|
@ -0,0 +1,118 @@
|
|||
import { ProjectModel, VAModel, LoggedModel } from "../../../models/vaModel.js";
|
||||
|
||||
function formatHMS(ms) {
|
||||
const totalSeconds = Math.floor(ms / 1000);
|
||||
const h = Math.floor(totalSeconds / 3600);
|
||||
const m = Math.floor((totalSeconds % 3600) / 60);
|
||||
const s = totalSeconds % 60;
|
||||
return `${h}h ${m}m ${s}s`;
|
||||
}
|
||||
|
||||
async function va_projects_log_list_function(req, res) {
|
||||
try {
|
||||
const { projectId, from, to } = req.params;
|
||||
|
||||
if (!projectId) {
|
||||
return res.status(400).json({ success: false, message: "Missing projectId" });
|
||||
}
|
||||
|
||||
// 📅 Date filtering
|
||||
const now = new Date();
|
||||
const fromDate = from && from !== "undefined" ? new Date(from) : new Date(now.setHours(0, 0, 0, 0));
|
||||
const toDate = to && to !== "undefined" ? new Date(to) : new Date();
|
||||
toDate.setHours(23, 59, 59, 999);
|
||||
|
||||
// 🧩 Fetch Project
|
||||
const project = await ProjectModel.findById(projectId).populate("vaAssigned", {
|
||||
"userDetails.firstName": 1,
|
||||
"userDetails.lastName": 1,
|
||||
"userDetails.email": 1,
|
||||
status: 1
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
return res.status(404).json({ success: false, message: "Project not found" });
|
||||
}
|
||||
|
||||
const vaList = project.vaAssigned || [];
|
||||
if (!vaList.length) {
|
||||
return res.status(200).json({ success: true, message: "No VAs assigned to this project", data: [] });
|
||||
}
|
||||
|
||||
let totalProjectWorkMs = 0;
|
||||
let activeCount = 0;
|
||||
|
||||
const vaReport = [];
|
||||
|
||||
// 🔁 Loop through each VA assigned to the project
|
||||
for (const va of vaList) {
|
||||
const vaId = va._id;
|
||||
const vaEmail = va.userDetails?.email;
|
||||
|
||||
// 🔎 Get all login/logout logs for this VA in the date range
|
||||
const logs = await LoggedModel.find({
|
||||
vaId,
|
||||
projectId,
|
||||
time: { $gte: fromDate, $lte: toDate }
|
||||
}).sort({ time: 1 }).lean();
|
||||
|
||||
let totalWorkMs = 0;
|
||||
let currentLogin = null;
|
||||
|
||||
for (const entry of logs) {
|
||||
if (entry.loggedType === "LOGIN") {
|
||||
currentLogin = entry;
|
||||
} else if (entry.loggedType === "LOGOUT" && currentLogin) {
|
||||
totalWorkMs += new Date(entry.time) - new Date(currentLogin.time);
|
||||
currentLogin = null;
|
||||
}
|
||||
}
|
||||
|
||||
// if still logged in (no logout yet) — count up to now
|
||||
if (currentLogin) {
|
||||
totalWorkMs += new Date() - new Date(currentLogin.time);
|
||||
}
|
||||
|
||||
totalProjectWorkMs += totalWorkMs;
|
||||
|
||||
// 🟢 Determine Active / Away status
|
||||
const lastLog = logs[logs.length - 1];
|
||||
let activityStatus = "AWAY";
|
||||
if (lastLog?.loggedType === "LOGIN") {
|
||||
activityStatus = "ACTIVE";
|
||||
activeCount++;
|
||||
}
|
||||
|
||||
vaReport.push({
|
||||
vaId,
|
||||
name: `${va.userDetails?.firstName || ""} ${va.userDetails?.lastName || ""}`.trim(),
|
||||
email: vaEmail,
|
||||
status: va.status,
|
||||
activityStatus,
|
||||
totalWorkTime: formatHMS(totalWorkMs),
|
||||
totalWorkMs,
|
||||
});
|
||||
}
|
||||
|
||||
// 📊 Prepare Summary
|
||||
const totalVAs = vaReport.length;
|
||||
const awayCount = totalVAs - activeCount;
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
projectId,
|
||||
projectName: project.name,
|
||||
totalVAs,
|
||||
activeVAs: activeCount,
|
||||
awayVAs: awayCount,
|
||||
totalProjectWorkTime: formatHMS(totalProjectWorkMs),
|
||||
totalProjectWorkMs,
|
||||
data: vaReport
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).json({ success: false, message: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
export { va_projects_log_list_function };
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
import { LoggedModel, WorkTrackModel, VAModel } from "../../../models/vaModel.js";
|
||||
|
||||
function formatHMS(ms) {
|
||||
const totalSeconds = Math.floor(ms / 1000);
|
||||
const h = Math.floor(totalSeconds / 3600);
|
||||
const m = Math.floor((totalSeconds % 3600) / 60);
|
||||
const s = totalSeconds % 60;
|
||||
return `${h}h ${m}m ${s}s`;
|
||||
}
|
||||
|
||||
async function va_projects_report_function(req, res) {
|
||||
try {
|
||||
const { projectId, from, to } = req.params;
|
||||
|
||||
if (!projectId) {
|
||||
return res.status(400).json({ success: false, message: "Missing projectId" });
|
||||
}
|
||||
|
||||
// Default: current day range
|
||||
const now = new Date();
|
||||
const fromDate = from && from !== "undefined" ? new Date(from) : new Date(now.setHours(0, 0, 0, 0));
|
||||
const toDate = to && to !== "undefined" ? new Date(to) : new Date();
|
||||
toDate.setHours(23, 59, 59, 999);
|
||||
|
||||
// Get all VA login/logout logs for this project in range
|
||||
const logs = await LoggedModel.find({
|
||||
projectId,
|
||||
time: { $gte: fromDate, $lte: toDate }
|
||||
}).sort({ time: 1 }).lean();
|
||||
|
||||
if (!logs.length) {
|
||||
return res.json({ success: true, message: "No logs found for this project", data: [] });
|
||||
}
|
||||
|
||||
// Unique VA IDs
|
||||
const vaIds = [...new Set(logs.map(log => log.vaId?.toString()))].filter(Boolean);
|
||||
const vaUsers = await VAModel.find(
|
||||
{ _id: { $in: vaIds } },
|
||||
{ "userDetails.firstName": 1, "userDetails.lastName": 1, "userDetails.email": 1 }
|
||||
).lean();
|
||||
|
||||
const projectReport = [];
|
||||
|
||||
for (const vaId of vaIds) {
|
||||
const vaLogList = logs.filter(l => l.vaId.toString() === vaId);
|
||||
let sessions = [];
|
||||
let currentLogin = null;
|
||||
|
||||
// Pair login → logout
|
||||
for (const entry of vaLogList) {
|
||||
if (entry.loggedType === "LOGIN") {
|
||||
currentLogin = entry;
|
||||
} else if (entry.loggedType === "LOGOUT" && currentLogin) {
|
||||
sessions.push({ from: currentLogin.time, to: entry.time });
|
||||
currentLogin = null;
|
||||
}
|
||||
}
|
||||
|
||||
// If still logged in, close at end of day
|
||||
if (currentLogin) {
|
||||
sessions.push({ from: currentLogin.time, to: toDate });
|
||||
}
|
||||
|
||||
const vaDetails = vaUsers.find(v => v._id.toString() === vaId);
|
||||
let totalWorkMs = 0;
|
||||
const sessionDetails = [];
|
||||
|
||||
for (const s of sessions) {
|
||||
const workData = await WorkTrackModel.find({
|
||||
vaId,
|
||||
projectId,
|
||||
from: { $gte: s.from },
|
||||
to: { $lte: s.to }
|
||||
}).sort({ from: 1 }).lean();
|
||||
|
||||
const tabs = workData.map(t => ({
|
||||
title: t.title,
|
||||
appName: t.appName,
|
||||
from: t.from,
|
||||
to: t.to,
|
||||
durationMs: t.totalTime,
|
||||
durationFormatted: formatHMS(t.totalTime),
|
||||
}));
|
||||
|
||||
const sessionWorkMs = workData.reduce((sum, w) => sum + (w.totalTime || 0), 0);
|
||||
totalWorkMs += sessionWorkMs;
|
||||
|
||||
sessionDetails.push({
|
||||
from: s.from,
|
||||
to: s.to,
|
||||
totalSessionTime: formatHMS(sessionWorkMs),
|
||||
tabs,
|
||||
});
|
||||
}
|
||||
|
||||
projectReport.push({
|
||||
vaId,
|
||||
vaName: `${vaDetails?.userDetails?.firstName || ""} ${vaDetails?.userDetails?.lastName || ""}`.trim(),
|
||||
vaEmail: vaDetails?.userDetails?.email,
|
||||
totalWorkTime: formatHMS(totalWorkMs),
|
||||
totalWorkMs,
|
||||
sessions: sessionDetails
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
projectId,
|
||||
from: fromDate,
|
||||
to: toDate,
|
||||
totalVAs: projectReport.length,
|
||||
data: projectReport,
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
res.status(500).json({ success: false, message: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
export { va_projects_report_function };
|
||||
|
|
@ -18,6 +18,8 @@ import { va_projects_callback } from "../../controllers/va/vaProjects/vaProjects
|
|||
import { authValidator } from "../../middlewares/auth.middleware.js";
|
||||
import { va_log_track_work_callback } from "../../controllers/va/vaLog/vaLogTrackWork.controller.js";
|
||||
import { va_log_work_report_callback } from "../../controllers/va/vaLog/vaLogWorkReport.js";
|
||||
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";
|
||||
|
||||
vaRoutes.get("/", va_callback); // VA Callback for getting active VA
|
||||
|
||||
|
|
@ -41,9 +43,9 @@ vaRoutes.get("/clients/:clientId/projects/:projectId", va_clients_projects_callb
|
|||
|
||||
|
||||
// Getting Project List assigned to VA should be ACTIVE and add total logged hours added by VA
|
||||
vaRoutes.get("/list/project/:projectId", va_projects_callback);
|
||||
vaRoutes.get("/list/project/:projectId/:from?/:to?", va_projects_log_list_function);
|
||||
// GET Windows Tab Logged Data for VA IN Between Login and LOGOUT
|
||||
vaRoutes.get("/report/project/:projectId", va_projects_callback);
|
||||
vaRoutes.get("/report/project/:projectId/:from?/:to?", va_projects_report_function);
|
||||
|
||||
|
||||
vaRoutes.post("/log/project", authValidator, va_project_log_callback); // VA Logged IN / Logged Out in project
|
||||
|
|
|
|||
Loading…
Reference in New Issue