attendance and leave api created successfully
This commit is contained in:
parent
b4c88496fc
commit
7e169d7973
4
app.js
4
app.js
@ -171,6 +171,8 @@ import CouponRoute from "./resources/Affiliate&Coupon/Coupon/CouponRoute.js";
|
|||||||
//support Ticket
|
//support Ticket
|
||||||
// attandance
|
// attandance
|
||||||
import attendance from "./resources/Attendance/AttandanceRoute.js"
|
import attendance from "./resources/Attendance/AttandanceRoute.js"
|
||||||
|
//leave
|
||||||
|
import leave from "./resources/Leaves/LeaveRoute.js";
|
||||||
app.use("/api/v1", user);
|
app.use("/api/v1", user);
|
||||||
|
|
||||||
//Product
|
//Product
|
||||||
@ -228,6 +230,8 @@ app.use("/api/v1/coupon", CouponRoute);
|
|||||||
app.use("/api/v1/blog", BlogRoute);
|
app.use("/api/v1/blog", BlogRoute);
|
||||||
//attendance
|
//attendance
|
||||||
app.use("/api/v1", attendance);
|
app.use("/api/v1", attendance);
|
||||||
|
//leave
|
||||||
|
app.use("/api/v1", leave);
|
||||||
|
|
||||||
//config specialty
|
//config specialty
|
||||||
// app.use("/api/config/specialty", SpecialtiesRouter);
|
// app.use("/api/config/specialty", SpecialtiesRouter);
|
||||||
|
@ -1,21 +1,40 @@
|
|||||||
// import { Attendance } from "./AttandanceModel.js";
|
import { Attendance } from "./AttendanceModel.js";
|
||||||
|
|
||||||
|
// Mark attendance
|
||||||
// export const markAttendance = async (req, res) => {
|
// export const markAttendance = async (req, res) => {
|
||||||
// try {
|
// try {
|
||||||
// const { date, time, location, notes } = req.body;
|
// const { date, time, location, notes } = req.body;
|
||||||
// const salesCoordinatorId = req.user._id;
|
// const userId = req.user._id;
|
||||||
|
// const userType = req.userType;
|
||||||
|
|
||||||
// // Get the start and end of the day to check if the attendance is already marked
|
// // Parse the input date
|
||||||
// const startOfDay = new Date(date);
|
// const [year, month, day] = date.split("/");
|
||||||
// startOfDay.setHours(0, 0, 0, 0);
|
// const parsedDate = new Date(Date.UTC(year, month - 1, day));
|
||||||
|
// const today = new Date();
|
||||||
// const endOfDay = new Date(date);
|
// today.setUTCHours(0, 0, 0, 0);
|
||||||
// endOfDay.setHours(23, 59, 59, 999);
|
// // Check if the date in req.body is not today's date
|
||||||
|
// if (parsedDate.getTime() !== today.getTime()) {
|
||||||
|
// return res.status(400).json({
|
||||||
|
// success: false,
|
||||||
|
// message: `Leave can only be marked for today's date: ${
|
||||||
|
// today.toISOString().split("T")[0]
|
||||||
|
// }`,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// // Get the start and end of the day to check if the leave is already marked
|
||||||
|
// const startOfDay = new Date(parsedDate);
|
||||||
|
// const endOfDay = new Date(parsedDate);
|
||||||
|
// endOfDay.setUTCHours(23, 59, 59, 999);
|
||||||
|
|
||||||
// // Check if the attendance record exists for today
|
// // Check if the attendance record exists for today
|
||||||
// const existingAttendance = await AttendanceSalesCoOrdinator.findOne({
|
// const existingAttendance = await Attendance.findOne({
|
||||||
// salesCoordinator: salesCoordinatorId,
|
// userId,
|
||||||
// "records.date": { $gte: startOfDay, $lte: endOfDay },
|
// userType,
|
||||||
|
// records: {
|
||||||
|
// $elemMatch: {
|
||||||
|
// date: { $gte: startOfDay, $lte: endOfDay },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// if (existingAttendance) {
|
// if (existingAttendance) {
|
||||||
@ -25,205 +44,70 @@
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // Check if attendance record exists for the sales coordinator
|
// // Check if attendance record exists for the user
|
||||||
// let attendance = await AttendanceSalesCoOrdinator.findOne({
|
// let attendance = await Attendance.findOne({ userId, userType });
|
||||||
// salesCoordinator: salesCoordinatorId,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (!attendance) {
|
// if (!attendance) {
|
||||||
// // Create a new attendance record if it doesn't exist
|
// // Create a new attendance record if it doesn't exist
|
||||||
// attendance = new AttendanceSalesCoOrdinator({
|
// attendance = new Attendance({
|
||||||
// salesCoordinator: salesCoordinatorId,
|
// userId,
|
||||||
|
// userType,
|
||||||
// records: [],
|
// records: [],
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// // Add the new attendance record to the array
|
// // Add the new attendance record to the array
|
||||||
// attendance.records.push({ date, time, location, notes });
|
// attendance.records.push({ date: startOfDay, time, location, notes });
|
||||||
// await attendance.save();
|
// await attendance.save();
|
||||||
|
|
||||||
// res.status(201).json({
|
// res.status(201).json({
|
||||||
// success: true,
|
// success: true,
|
||||||
// message: "Attendance marked successfully",
|
// message: "Attendance marked successfully",
|
||||||
// record: { date, time, location, notes },
|
// record: { date: today, time, location, notes },
|
||||||
// });
|
// });
|
||||||
// } catch (error) {
|
// } catch (error) {
|
||||||
|
// console.error("Error marking attendance:", error);
|
||||||
// res.status(500).json({
|
// res.status(500).json({
|
||||||
// success: false,
|
// success: false,
|
||||||
// message: error.message || "Something went wrong",
|
// message: error.message || "Something went wrong",
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// export const getAttendanceBySalesCoordinator = async (req, res) => {
|
|
||||||
// try {
|
|
||||||
// const salesCoordinatorId = req.user._id;
|
|
||||||
|
|
||||||
// const attendance = await AttendanceSalesCoOrdinator.findOne({
|
|
||||||
// salesCoordinator: salesCoordinatorId,
|
|
||||||
// }).populate("salesCoordinator", "name email");
|
|
||||||
|
|
||||||
// if (!attendance) {
|
|
||||||
// return res.status(404).json({
|
|
||||||
// success: false,
|
|
||||||
// message: "No attendance records found for this sales coordinator.",
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// res.status(200).json({
|
|
||||||
// success: true,
|
|
||||||
// attendance,
|
|
||||||
// });
|
|
||||||
// } catch (error) {
|
|
||||||
// res.status(500).json({
|
|
||||||
// success: false,
|
|
||||||
// message: error.message || "Something went wrong",
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// // admin
|
|
||||||
// export const AdmingetAttendanceBySalesCoordinator = async (req, res) => {
|
|
||||||
// try {
|
|
||||||
// const { id } = req.params;
|
|
||||||
// const { page = 1, show = 10 } = req.query;
|
|
||||||
// const limit = parseInt(show);
|
|
||||||
// const skip = (page - 1) * limit;
|
|
||||||
|
|
||||||
// // Find attendance records for the given sales coordinator
|
|
||||||
// const attendanceDoc = await AttendanceSalesCoOrdinator.findOne({
|
|
||||||
// salesCoordinator: id,
|
|
||||||
// }).populate("salesCoordinator", "name email");
|
|
||||||
|
|
||||||
// if (!attendanceDoc) {
|
|
||||||
// return res.status(404).json({
|
|
||||||
// success: false,
|
|
||||||
// message: "No attendance records found for this sales coordinator.",
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Pagination and slicing records
|
|
||||||
// const totalData = attendanceDoc.records.length;
|
|
||||||
// const paginatedRecords = attendanceDoc.records.slice(skip, skip + limit);
|
|
||||||
|
|
||||||
// res.status(200).json({
|
|
||||||
// success: true,
|
|
||||||
// salesCoordinator: attendanceDoc.salesCoordinator,
|
|
||||||
// attendance: paginatedRecords,
|
|
||||||
// total_data: totalData,
|
|
||||||
// });
|
|
||||||
// } catch (error) {
|
|
||||||
// res.status(500).json({
|
|
||||||
// success: false,
|
|
||||||
// message: error.message || "Something went wrong",
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const getTodayAttendance = async (req, res) => {
|
|
||||||
// try {
|
|
||||||
// const today = new Date();
|
|
||||||
// today.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
// const startOfDay = new Date(today);
|
|
||||||
// const endOfDay = new Date(today);
|
|
||||||
// endOfDay.setHours(23, 59, 59, 999);
|
|
||||||
|
|
||||||
// const { page = 1, show = 10 } = req.query;
|
|
||||||
// const limit = parseInt(show);
|
|
||||||
// const skip = (page - 1) * limit;
|
|
||||||
|
|
||||||
// const attendances = await AttendanceSalesCoOrdinator.aggregate([
|
|
||||||
// { $unwind: '$records' },
|
|
||||||
// {
|
|
||||||
// $match: {
|
|
||||||
// 'records.date': { $gte: startOfDay, $lte: endOfDay }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// $lookup: {
|
|
||||||
// from: 'salescoordinators',
|
|
||||||
// localField: 'salesCoordinator',
|
|
||||||
// foreignField: '_id',
|
|
||||||
// as: 'salesCoordinator'
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// { $unwind: '$salesCoordinator' },
|
|
||||||
// {
|
|
||||||
// $facet: {
|
|
||||||
// totalData: [{ $count: 'count' }],
|
|
||||||
// attendance: [
|
|
||||||
// { $skip: skip },
|
|
||||||
// { $limit: limit },
|
|
||||||
// {
|
|
||||||
// $project: {
|
|
||||||
// salesCoordinator: {
|
|
||||||
// id: '$salesCoordinator._id',
|
|
||||||
// name: '$salesCoordinator.name',
|
|
||||||
// email: '$salesCoordinator.email'
|
|
||||||
// },
|
|
||||||
// date: '$records.date',
|
|
||||||
// time: '$records.time',
|
|
||||||
// location: '$records.location',
|
|
||||||
// note: '$records.notes'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
// const totalData = attendances[0].totalData[0] ? attendances[0].totalData[0].count : 0;
|
|
||||||
|
|
||||||
// res.status(200).json({
|
|
||||||
// success: true,
|
|
||||||
// attendance: attendances[0].attendance,
|
|
||||||
// total_data: totalData
|
|
||||||
// });
|
|
||||||
// } catch (error) {
|
|
||||||
// res.status(500).json({
|
|
||||||
// success: false,
|
|
||||||
// message: error.message || 'Something went wrong'
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
import { Attendance } from "./AttendanceModel.js";
|
|
||||||
|
|
||||||
// Mark attendance
|
|
||||||
export const markAttendance = async (req, res) => {
|
export const markAttendance = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { date, time, location, notes } = req.body;
|
const { date, time, location, notes } = req.body;
|
||||||
const userId = req.user._id;
|
const userId = req.user._id;
|
||||||
const userType = req.userType;
|
const userType = req.userType;
|
||||||
|
|
||||||
// Get today's date
|
// Parse the input date
|
||||||
|
const [year, month, day] = date.split("/");
|
||||||
|
const parsedDate = new Date(Date.UTC(year, month - 1, day));
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
today.setHours(0, 0, 0, 0);
|
today.setUTCHours(0, 0, 0, 0);
|
||||||
|
|
||||||
// Check if the date in req.body is not today's date
|
// Check if the date in req.body is not today's date
|
||||||
if (!isSameDay(new Date(date), today)) {
|
if (parsedDate.getTime() !== today.getTime()) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: `Attendance can only be marked for today's date: ${today.toLocaleDateString()}`,
|
message: `Attendance can only be marked for today's date: ${
|
||||||
|
today.toISOString().split("T")[0]
|
||||||
|
}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the start and end of the day to check if the attendance is already marked
|
// Get the start and end of the day to check if the attendance is already marked
|
||||||
const startOfDay = new Date(date);
|
const startOfDay = new Date(parsedDate);
|
||||||
startOfDay.setHours(0, 0, 0, 0);
|
const endOfDay = new Date(parsedDate);
|
||||||
|
endOfDay.setUTCHours(23, 59, 59, 999);
|
||||||
const endOfDay = new Date(date);
|
|
||||||
endOfDay.setHours(23, 59, 59, 999);
|
|
||||||
|
|
||||||
// Check if the attendance record exists for today
|
// Check if the attendance record exists for today
|
||||||
const existingAttendance = await Attendance.findOne({
|
const existingAttendance = await Attendance.findOne({
|
||||||
userId,
|
userId,
|
||||||
userType,
|
userType,
|
||||||
records: {
|
'records.date': {
|
||||||
$elemMatch: {
|
$gte: startOfDay,
|
||||||
date: { $gte: startOfDay, $lte: endOfDay }
|
$lte: endOfDay,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingAttendance) {
|
if (existingAttendance) {
|
||||||
@ -246,15 +130,16 @@ export const markAttendance = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the new attendance record to the array
|
// Add the new attendance record to the array
|
||||||
attendance.records.push({ date, time, location, notes });
|
attendance.records.push({ date: startOfDay, time, location, notes });
|
||||||
await attendance.save();
|
await attendance.save();
|
||||||
|
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
success: true,
|
success: true,
|
||||||
message: "Attendance marked successfully",
|
message: "Attendance marked successfully",
|
||||||
record: { date, time, location, notes },
|
record: { date: startOfDay, time, location, notes },
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error("Error marking attendance:", error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: error.message || "Something went wrong",
|
message: error.message || "Something went wrong",
|
||||||
@ -262,14 +147,6 @@ export const markAttendance = async (req, res) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to check if two dates are on the same day
|
|
||||||
function isSameDay(date1, date2) {
|
|
||||||
return (
|
|
||||||
date1.getFullYear() === date2.getFullYear() &&
|
|
||||||
date1.getMonth() === date2.getMonth() &&
|
|
||||||
date1.getDate() === date2.getDate()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get attendance by user ID
|
// Get attendance by user ID
|
||||||
export const getAttendanceByUser = async (req, res) => {
|
export const getAttendanceByUser = async (req, res) => {
|
||||||
@ -340,66 +217,102 @@ export const AdmingetAttendanceByUser = async (req, res) => {
|
|||||||
// Get today's attendance for admin
|
// Get today's attendance for admin
|
||||||
export const getTodayAttendance = async (req, res) => {
|
export const getTodayAttendance = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
// Step 1: Get today's date in UTC and set the time to start and end of the day
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
today.setHours(0, 0, 0, 0);
|
const todayStartUTC = new Date(
|
||||||
|
Date.UTC(
|
||||||
const startOfDay = new Date(today);
|
today.getUTCFullYear(),
|
||||||
const endOfDay = new Date(today);
|
today.getUTCMonth(),
|
||||||
endOfDay.setHours(23, 59, 59, 999);
|
today.getUTCDate(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const tomorrowStartUTC = new Date(todayStartUTC);
|
||||||
|
tomorrowStartUTC.setUTCDate(todayStartUTC.getUTCDate() + 1); // Start of the next day
|
||||||
|
|
||||||
|
// Step 2: Parse query parameters
|
||||||
const { page = 1, show = 10 } = req.query;
|
const { page = 1, show = 10 } = req.query;
|
||||||
const limit = parseInt(show);
|
const limit = parseInt(show, 10);
|
||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Step 3: Aggregate query to get today's attendance records
|
||||||
const attendances = await Attendance.aggregate([
|
const attendances = await Attendance.aggregate([
|
||||||
{ $unwind: '$records' },
|
{ $unwind: "$records" },
|
||||||
{
|
{
|
||||||
$match: {
|
$match: {
|
||||||
'records.date': { $gte: startOfDay, $lte: endOfDay }
|
"records.date": {
|
||||||
}
|
$gte: todayStartUTC,
|
||||||
|
$lt: tomorrowStartUTC,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
$lookup: {
|
$lookup: {
|
||||||
from: 'users',
|
from: "salescoordinators",
|
||||||
localField: 'userId',
|
localField: "userId",
|
||||||
foreignField: '_id',
|
foreignField: "_id",
|
||||||
as: 'user'
|
as: "salesCoOrdinatorUser",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{ $unwind: '$user' },
|
|
||||||
{
|
{
|
||||||
$facet: {
|
$lookup: {
|
||||||
totalData: [{ $count: 'count' }],
|
from: "territorymanagers",
|
||||||
attendance: [
|
localField: "userId",
|
||||||
{ $skip: skip },
|
foreignField: "_id",
|
||||||
{ $limit: limit },
|
as: "territoryManagerUser",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$addFields: {
|
||||||
|
user: {
|
||||||
|
$cond: {
|
||||||
|
if: { $eq: ["$userType", "SalesCoOrdinator"] },
|
||||||
|
then: { $arrayElemAt: ["$salesCoOrdinatorUser", 0] },
|
||||||
|
else: { $arrayElemAt: ["$territoryManagerUser", 0] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
$project: {
|
$project: {
|
||||||
user: {
|
salesCoOrdinatorUser: 0,
|
||||||
id: '$user._id',
|
territoryManagerUser: 0,
|
||||||
name: '$user.name',
|
},
|
||||||
email: '$user.email',
|
|
||||||
userType: '$userType'
|
|
||||||
},
|
},
|
||||||
date: '$records.date',
|
|
||||||
time: '$records.time',
|
|
||||||
location: '$records.location',
|
|
||||||
notes: '$records.notes',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
|
const totalData = attendances.length;
|
||||||
|
const paginatedattendance = attendances.slice(skip, skip + limit);
|
||||||
|
// Step 6: Format the response
|
||||||
|
const formattedattendance = paginatedattendance.map((record) => ({
|
||||||
|
user: record.user
|
||||||
|
? {
|
||||||
|
id: record.user._id,
|
||||||
|
name: record.user.name,
|
||||||
|
email: record.user.email,
|
||||||
|
mobileNumber: record.user.mobileNumber,
|
||||||
|
userType: record.userType,
|
||||||
|
uniqueId: record.user.uniqueId,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
date: record.records.date,
|
||||||
|
time: record.records.time,
|
||||||
|
location: record.records.location,
|
||||||
|
reason: record.records.reason,
|
||||||
|
leaveType: record.records.leaveType,
|
||||||
|
}));
|
||||||
|
|
||||||
const totalData = attendances[0].totalData[0]?.count || 0;
|
// Send response
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
total_data: totalData,
|
total_data: totalData,
|
||||||
attendance: attendances[0].attendance
|
attendance: formattedattendance,
|
||||||
|
page: parseInt(page, 10),
|
||||||
|
limit: limit,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error("Error fetching today’s attendance:", error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
message: error.message || "Something went wrong",
|
message: error.message || "Something went wrong",
|
||||||
|
@ -1,34 +1,3 @@
|
|||||||
// import mongoose from 'mongoose';
|
|
||||||
|
|
||||||
// const attendanceRecordSchema = new mongoose.Schema({
|
|
||||||
// date: {
|
|
||||||
// type: Date,
|
|
||||||
// required: true,
|
|
||||||
// },
|
|
||||||
// time: {
|
|
||||||
// type: String,
|
|
||||||
// required: true,
|
|
||||||
// },
|
|
||||||
// location: {
|
|
||||||
// type: String,
|
|
||||||
// required: true,
|
|
||||||
// },
|
|
||||||
// notes: {
|
|
||||||
// type: String,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const attendanceSchema = new mongoose.Schema({
|
|
||||||
// salesCoordinator: {
|
|
||||||
// type: mongoose.Schema.Types.ObjectId,
|
|
||||||
// ref: 'SalesCoOrdinator',
|
|
||||||
// required: true,
|
|
||||||
// unique: true,
|
|
||||||
// },
|
|
||||||
// records: [attendanceRecordSchema],
|
|
||||||
// }, { timestamps: true, versionKey: false });
|
|
||||||
|
|
||||||
// export const AttendanceSalesCoOrdinator = mongoose.model('Attendance', attendanceSchema);
|
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
// Define attendance record schema
|
// Define attendance record schema
|
||||||
@ -60,7 +29,7 @@ const attendanceSchema = new mongoose.Schema({
|
|||||||
userType: {
|
userType: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
enum: ['SalesCoOrdinator', 'TerritoryManager'], // Specify allowed user types
|
enum: ['SalesCoOrdinator', 'TerritoryManager'],
|
||||||
},
|
},
|
||||||
records: [attendanceRecordSchema],
|
records: [attendanceRecordSchema],
|
||||||
}, { timestamps: true, versionKey: false });
|
}, { timestamps: true, versionKey: false });
|
||||||
|
250
resources/Leaves/LeaveController.js
Normal file
250
resources/Leaves/LeaveController.js
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
import { Leave } from "./LeaveModel.js";
|
||||||
|
|
||||||
|
// Mark leave
|
||||||
|
export const markLeave = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { date, time, location, reason, leaveType } = req.body;
|
||||||
|
const userId = req.user._id;
|
||||||
|
const userType = req.userType;
|
||||||
|
|
||||||
|
// Parse the input date
|
||||||
|
const [year, month, day] = date.split("/");
|
||||||
|
const parsedDate = new Date(Date.UTC(year, month - 1, day));
|
||||||
|
const today = new Date();
|
||||||
|
today.setUTCHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Check if the date in req.body is not today's date
|
||||||
|
if (parsedDate.getTime() !== today.getTime()) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: `Leave can only be marked for today's date: ${
|
||||||
|
today.toISOString().split("T")[0]
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the start and end of the day to check if the leave is already marked
|
||||||
|
const startOfDay = new Date(parsedDate);
|
||||||
|
const endOfDay = new Date(parsedDate);
|
||||||
|
endOfDay.setUTCHours(23, 59, 59, 999);
|
||||||
|
|
||||||
|
// Check if the leave record exists for today
|
||||||
|
const existingLeave = await Leave.findOne({
|
||||||
|
userId,
|
||||||
|
userType,
|
||||||
|
records: {
|
||||||
|
$elemMatch: {
|
||||||
|
date: { $gte: startOfDay, $lte: endOfDay },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingLeave) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "Leave for today is already marked.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if leave record exists for the user
|
||||||
|
let leave = await Leave.findOne({ userId, userType });
|
||||||
|
|
||||||
|
if (!leave) {
|
||||||
|
// Create a new leave record if it doesn't exist
|
||||||
|
leave = new Leave({
|
||||||
|
userId,
|
||||||
|
userType,
|
||||||
|
records: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the new leave record to the array
|
||||||
|
leave.records.push({ date: startOfDay, time, location, reason, leaveType });
|
||||||
|
await leave.save();
|
||||||
|
|
||||||
|
res.status(201).json({
|
||||||
|
success: true,
|
||||||
|
message: "Leave marked successfully",
|
||||||
|
record: { date: startOfDay, time, location, reason, leaveType },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Something went wrong",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to check if two dates are on the same day
|
||||||
|
function isSameDay(date1, date2) {
|
||||||
|
return (
|
||||||
|
date1.getFullYear() === date2.getFullYear() &&
|
||||||
|
date1.getMonth() === date2.getMonth() &&
|
||||||
|
date1.getDate() === date2.getDate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get leave by user ID
|
||||||
|
export const getLeaveByUser = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.user._id;
|
||||||
|
|
||||||
|
const leave = await Leave.findOne({
|
||||||
|
userId,
|
||||||
|
}).populate("userId", "name email");
|
||||||
|
|
||||||
|
if (!leave) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: "No leave records found for this user.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
leave,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Something went wrong",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Admin route to get leave by user ID
|
||||||
|
export const AdmingetLeaveByUser = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const { page = 1, show = 10 } = req.query;
|
||||||
|
const limit = parseInt(show);
|
||||||
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Find leave records for the given user
|
||||||
|
const leaveDoc = await Leave.findOne({
|
||||||
|
userId: id,
|
||||||
|
}).populate("userId", "name email");
|
||||||
|
|
||||||
|
if (!leaveDoc) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: "No leave records found for this user.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pagination and slicing records
|
||||||
|
const totalData = leaveDoc.records.length;
|
||||||
|
const paginatedRecords = leaveDoc.records.slice(skip, skip + limit);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
user: leaveDoc.userId,
|
||||||
|
leave: paginatedRecords,
|
||||||
|
total_data: totalData,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status500().json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Something went wrong",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTodayLeave = async (req, res) => {
|
||||||
|
try {
|
||||||
|
// Step 1: Get today's date in UTC and set the time to 00:00:00.000
|
||||||
|
const today = new Date();
|
||||||
|
const todayStartUTC = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), 0, 0, 0));
|
||||||
|
const tomorrowStartUTC = new Date(todayStartUTC);
|
||||||
|
tomorrowStartUTC.setUTCDate(todayStartUTC.getUTCDate() + 1); // Start of the next day
|
||||||
|
|
||||||
|
// Step 2: Parse query parameters
|
||||||
|
const { page = 1, show = 10 } = req.query;
|
||||||
|
const limit = parseInt(show, 10);
|
||||||
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
// Step 3: Aggregate query to get today's leave records
|
||||||
|
const leavesWithUserLookup = await Leave.aggregate([
|
||||||
|
{ $unwind: '$records' },
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
'records.date': {
|
||||||
|
$gte: todayStartUTC,
|
||||||
|
$lt: tomorrowStartUTC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: 'salescoordinators',
|
||||||
|
localField: 'userId',
|
||||||
|
foreignField: '_id',
|
||||||
|
as: 'salesCoOrdinatorUser'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: 'territorymanagers',
|
||||||
|
localField: 'userId',
|
||||||
|
foreignField: '_id',
|
||||||
|
as: 'territoryManagerUser'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$addFields: {
|
||||||
|
user: {
|
||||||
|
$cond: {
|
||||||
|
if: { $eq: ["$userType", "SalesCoOrdinator"] },
|
||||||
|
then: { $arrayElemAt: ["$salesCoOrdinatorUser", 0] },
|
||||||
|
else: { $arrayElemAt: ["$territoryManagerUser", 0] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$project: {
|
||||||
|
salesCoOrdinatorUser: 0,
|
||||||
|
territoryManagerUser: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Step 4: Calculate total data
|
||||||
|
const totalData = leavesWithUserLookup.length;
|
||||||
|
|
||||||
|
// Step 5: Implement pagination
|
||||||
|
const paginatedLeaves = leavesWithUserLookup.slice(skip, skip + limit);
|
||||||
|
|
||||||
|
// Step 6: Format the response
|
||||||
|
const formattedLeaves = paginatedLeaves.map(record => ({
|
||||||
|
user: record.user ? {
|
||||||
|
id: record.user._id,
|
||||||
|
name: record.user.name,
|
||||||
|
email: record.user.email,
|
||||||
|
mobileNumber: record.user.mobileNumber,
|
||||||
|
userType: record.userType,
|
||||||
|
uniqueId: record.user.uniqueId,
|
||||||
|
} : null,
|
||||||
|
date: record.records.date,
|
||||||
|
time: record.records.time,
|
||||||
|
location: record.records.location,
|
||||||
|
reason: record.records.reason,
|
||||||
|
leaveType: record.records.leaveType,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
total_data: totalData,
|
||||||
|
leave: formattedLeaves,
|
||||||
|
page: parseInt(page, 10),
|
||||||
|
limit: limit,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching today’s leave:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: error.message || "Something went wrong",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
43
resources/Leaves/LeaveModel.js
Normal file
43
resources/Leaves/LeaveModel.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
|
// Define leave record schema
|
||||||
|
const leaveRecordSchema = new mongoose.Schema({
|
||||||
|
date: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
reason: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
leaveType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
enum: ['Sick Leave', 'Casual Leave'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define main leave schema
|
||||||
|
const leaveSchema = new mongoose.Schema({
|
||||||
|
userId: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
refPath: 'userType',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
userType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
enum: ['SalesCoOrdinator', 'TerritoryManager'],
|
||||||
|
},
|
||||||
|
records: [leaveRecordSchema],
|
||||||
|
}, { timestamps: true, versionKey: false });
|
||||||
|
|
||||||
|
export const Leave = mongoose.model('Leave', leaveSchema);
|
60
resources/Leaves/LeaveRoute.js
Normal file
60
resources/Leaves/LeaveRoute.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import express from "express";
|
||||||
|
import {
|
||||||
|
markLeave,
|
||||||
|
getLeaveByUser,
|
||||||
|
getTodayLeave,
|
||||||
|
AdmingetLeaveByUser,
|
||||||
|
} from "./LeaveController.js";
|
||||||
|
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
||||||
|
// import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
||||||
|
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// Place more specific routes first
|
||||||
|
|
||||||
|
// Route to get today's leave for admin
|
||||||
|
router.get(
|
||||||
|
"/leave/today",
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles("admin"),
|
||||||
|
getTodayLeave
|
||||||
|
);
|
||||||
|
|
||||||
|
// Route to mark leave for Sales Coordinators
|
||||||
|
router.post(
|
||||||
|
"/markleave/salescoordinator",
|
||||||
|
isAuthenticatedSalesCoOrdinator,
|
||||||
|
markLeave
|
||||||
|
);
|
||||||
|
|
||||||
|
// Route to mark leave for Territory Managers
|
||||||
|
router.post(
|
||||||
|
"/markleave/territorymanager",
|
||||||
|
// isAuthenticatedTerritoryManager,
|
||||||
|
markLeave
|
||||||
|
);
|
||||||
|
|
||||||
|
// Route to get leave for the logged-in sales coordinator
|
||||||
|
router.get(
|
||||||
|
"/leave/salescoordinator",
|
||||||
|
isAuthenticatedSalesCoOrdinator,
|
||||||
|
getLeaveByUser
|
||||||
|
);
|
||||||
|
|
||||||
|
// Route to get leave for the logged-in territory manager
|
||||||
|
router.get(
|
||||||
|
"/leave/territorymanager",
|
||||||
|
// isAuthenticatedTerritoryManager,
|
||||||
|
getLeaveByUser
|
||||||
|
);
|
||||||
|
|
||||||
|
// Admin route to get leave by user ID
|
||||||
|
router.get(
|
||||||
|
"/leave/:id",
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles("admin"),
|
||||||
|
AdmingetLeaveByUser
|
||||||
|
);
|
||||||
|
|
||||||
|
export default router;
|
Loading…
Reference in New Issue
Block a user