Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
c11bd12
Merge pull request #25 from vikrant-vikrant/LiteMode
vikrant-vikrant Apr 4, 2026
8865ec2
Merge pull request #26 from vikrant-vikrant/LiteMode
vikrant-vikrant Apr 17, 2026
2902962
fix: update thisMonthYear assignment to use variable directly
vikrant-vikrant Apr 21, 2026
e88d946
Merge pull request #27 from vikrant-vikrant/Litemode
vikrant-vikrant Apr 21, 2026
1bf3c27
feat: enhance fund report with total students and paid students count
vikrant-vikrant May 4, 2026
d451954
feat: update fund report to include fees history and improve data ret…
vikrant-vikrant May 5, 2026
4896df2
feat: refactor date filtering and fees aggregation in fund report
vikrant-vikrant May 13, 2026
4f7034f
feat: enhance fees aggregation logic in fund report for improved mont…
vikrant-vikrant May 13, 2026
c18235c
feat: add text transformation to fee entry for improved readability
vikrant-vikrant May 13, 2026
0821af6
feat: update dotenv version and improve student details layout in arc…
vikrant-vikrant Jun 14, 2026
c9c31d1
feat: enhance student retrieval logic and improve archive view layout
vikrant-vikrant Jun 14, 2026
caae184
feat: add comments to indicate performance concerns in student retrie…
vikrant-vikrant Jun 14, 2026
ff7a449
feat: implement showArchiveStu route and view for archived student de…
vikrant-vikrant Jun 14, 2026
d215c1a
feat: add functionality to record fees for archived students
vikrant-vikrant Jun 18, 2026
fa4f89d
feat: add edit functionality for archived students with corresponding…
vikrant-vikrant Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 93 additions & 37 deletions controllers/fund.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,78 @@ const Student = require("../models/students");
const catchAsync = require("../utils/catchAsync");
const MonthlyReport = require("../models/monthlyReport");
const archivedStudent = require("../models/archivedStudent");
let thisMonthYear = new Date().toLocaleString("en-US", {
month: "short",
year: "numeric",
});
module.exports.fund = catchAsync(async (req, res) => {
const now = new Date();
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
const view = req.query.view;
let dateFilter;
if (view === "month") {
dateFilter = { $gte: startOfMonth, $lt: endOfMonth };
} else {
const threeDaysAgo = new Date();
threeDaysAgo.setDate(threeDaysAgo.getDate() - 3);
dateFilter = { $gte: threeDaysAgo };
}
const dateFilter =
view === "month"
? { "feesHistory.paidDate": { $gte: startOfMonth, $lt: endOfMonth } }
: { "feesHistory.paidDate": { $exists: true, $ne: null } };
const feesPipeline =
view === "month"
? [
{ $unwind: "$feesHistory" },
{
$match: {
"feesHistory.paidDate": {
$gte: startOfMonth,
$lt: endOfMonth,
},
},
},
{ $sort: { "feesHistory.paidDate": -1 } },
{
$project: {
name: 1,
grade: 1,
"feesHistory.amount": 1,
"feesHistory.paidDate": 1,
"feesHistory.note": 1,
},
},
]
: [
{ $unwind: "$feesHistory" },
{
$match: {
"feesHistory.paidDate": { $exists: true, $ne: null },
},
},
{ $sort: { "feesHistory.paidDate": -1 } },
{
$group: {
_id: {
$dateToString: {
format: "%Y-%m-%d",
date: "$feesHistory.paidDate",
},
},
records: {
$push: {
name: "$name",
grade: "$grade",
amount: "$feesHistory.amount",
paidDate: "$feesHistory.paidDate",
note: "$feesHistory.note",
},
},
},
},
{ $sort: { _id: -1 } },
{ $limit: 3 },
{ $unwind: "$records" },
{
$project: {
name: "$records.name",
grade: "$records.grade",
"feesHistory.amount": "$records.amount",
"feesHistory.paidDate": "$records.paidDate",
"feesHistory.note": "$records.note",
},
},
];
const [studentResult, archiveFeesThisMonth] = await Promise.all([
Student.aggregate([
{ $match: { owner: req.user._id } },
Expand All @@ -32,24 +87,20 @@ module.exports.fund = catchAsync(async (req, res) => {
},
},
],
feesThisMonth: [
{ $unwind: "$feesHistory" },
totalStudents: [{ $count: "count" }],
paidStudents: [
{
$match: {
"feesHistory.paidDate": dateFilter,
},
},
{ $sort: { "feesHistory.paidDate": -1 } },
{
$project: {
name: 1,
grade: 1,
"feesHistory.amount": 1,
"feesHistory.paidDate": 1,
"feesHistory.note": 1,
feesHistory: {
$elemMatch: {
paidDate: { $gte: startOfMonth, $lt: endOfMonth },
},
},
},
},
{ $count: "count" },
],
feesThisMonth: feesPipeline,
studentsThisMonth: [
{
$match: {
Expand All @@ -75,7 +126,7 @@ module.exports.fund = catchAsync(async (req, res) => {
{ $unwind: "$feesHistory" },
{
$match: {
"feesHistory.paidDate": dateFilter,
"feesHistory.paidDate": { $gte: startOfMonth, $lt: endOfMonth },
},
},
{ $sort: { "feesHistory.paidDate": -1 } },
Expand All @@ -93,18 +144,17 @@ module.exports.fund = catchAsync(async (req, res) => {
// ✅ Extract data from facet
const data = studentResult[0];
const totalDue = data.totalDue[0]?.totalDue || 0;
const totalStudents = data.totalStudents[0]?.count || 0;
const paidStudents = data.paidStudents[0]?.count || 0;
const feesThisMonth = data.feesThisMonth;
const stuThisMonth = data.studentsThisMonth;
const todayDate = new Date().toISOString().split("T")[0];
const month = now.getMonth() + 1;
const year = now.getFullYear();
let thisMonthData = await MonthlyReport.findOne({
owner: req.user._id,
month,
year,
}).lean();
if (!thisMonthData) {
thisMonthData = await MonthlyReport.create({
let thisMonthData = await MonthlyReport.findOneAndUpdate(
{ owner: req.user._id, month, year },
{
$setOnInsert: {
owner: req.user._id,
month,
year,
Expand All @@ -114,11 +164,16 @@ module.exports.fund = catchAsync(async (req, res) => {
newStudents: 0,
studentsLeft: 0,
createdAt: new Date(),
});
},
},
{
upsert: true,
new: true,
lean: true,
}
);
// ✅ Calculate expenses
let total = 0;
thisMonthData.expenses.forEach((e) => (total += e.amount));
const total = thisMonthData.expenses.reduce((sum, e) => sum + e.amount, 0);
const balance = Number(thisMonthData.totalEarning) - total;
res.render("listings/fund", {
totalDue,
Expand All @@ -127,10 +182,11 @@ module.exports.fund = catchAsync(async (req, res) => {
total,
view,
balance,
thisMonthYear,
thisMonthData,
stuThisMonth,
archiveFeesThisMonth,
totalStudents,
paidStudents,
});
});
module.exports.addExpense = catchAsync(async (req, res) => {
Expand Down
100 changes: 99 additions & 1 deletion controllers/students.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ module.exports.students = catchAsync(async (req, res) => {
});
module.exports.showStudent = catchAsync(async (req, res, next) => {
const { id } = req.params;
const student = await Student.findOne({ _id: id, owner: req.user._id });
let student = await Student.findOne({ _id: id, owner: req.user._id });
if (!student) throw new ExpressError(404, "Student not found");
const formattedDate = formatDate(student.joiningDate);
res.render("listings/show", { student, formattedDate });
Expand All @@ -66,13 +66,59 @@ module.exports.deactivateStudent = catchAsync(async (req, res) => {
req.flash("success", "Student deactivated successfully");
res.redirect("/students");
});
module.exports.editArchiveStu = catchAsync(async (req, res, next) => {
const { id } = req.params;
const student = await ArchivedStudent.findOne({ _id: id, owner: req.user._id });
if (!student) throw new ExpressError(404, "Archived student not found");
const formattedDate = formatDate(student.joiningDate, "input");
res.render("listings/editArchiveStu", { student, formattedDate });
});
module.exports.editStudent = catchAsync(async (req, res, next) => {
const { id } = req.params;
const student = await Student.findOne({ _id: id, owner: req.user._id });
if (!student) throw new ExpressError(404, "Student not found");
const formattedDate = formatDate(student.joiningDate, "input");
res.render("listings/edit", { student, formattedDate }); // create this view
});
module.exports.saveEditArchiveStu = catchAsync(async (req, res, next) => {
const { id } = req.params;
const {
name,
grade,
parent,
contact,
phone,
note,
joiningDate,
fees,
dueFees,
} = req.body;
let student = await ArchivedStudent.findOneAndUpdate(
{ _id: id, owner: req.user._id },
{
name,
grade,
parent,
contact,
phone,
note,
joiningDate,
dueFees,
fees,
},
{ new: true, runValidators: true },
);
if (!student) {
req.flash("error", "Student not found");
return res.redirect("/students");
}
const formattedDate = formatDate(student.joiningDate);
res.render("listings/show", {
student,
formattedDate,
success: "Details updated.",
});
});
module.exports.saveEditStudent = catchAsync(async (req, res, next) => {
const { id } = req.params;
const {
Expand Down Expand Up @@ -258,6 +304,58 @@ module.exports.archived = catchAsync(async (req, res) => {
.lean();
res.render("listings/archive", { studentsData: archived });
});
module.exports.showArchiveStu = catchAsync(async (req, res, next) => {
const { id } = req.params;
let student = await ArchivedStudent.findOne({ _id: id, owner: req.user._id });
if (!student) throw new ExpressError(404, "Student not found");
const formattedDate = formatDate(student.joiningDate);
res.render("listings/showArchiveStu", { student, formattedDate });
});
module.exports.addArchiveStuFee = catchAsync(async (req, res) => {
let { id } = req.params;
let { note, amount, paidOn } = req.body;
if (!amount || Number(amount) <= 0) {
req.flash("error", "Amount must be greater than 0");
return res.redirect(`/students/${id}`);
}
amount = Number(amount);
let paidDate = paidOn ? new Date(paidOn) : new Date();
const student = await ArchivedStudent.findOne({ _id: id, owner: req.user._id });
if (!student) {
return res.status(404).send("Student not found");
}
student.feesHistory.push({
note,
amount,
paidDate,
});
const month = new Date().getMonth() + 1;
const year = new Date().getFullYear();
let thisMonthData = await MonthlyReport.findOne({
owner: req.user._id,
month,
year,
});
if (!thisMonthData) {
thisMonthData = await MonthlyReport.create({
owner: req.user._id,
month,
year,
totalEarning: 0,
expenses: [],
totalExpenses: 0,
newStudents: 0,
studentsLeft: 0,
createdAt: new Date(),
});
}
thisMonthData.totalEarning += amount;
student.dueFees -= amount;
await student.save();
await thisMonthData.save();
req.flash("success", `Fees added for ${student.name}. `);
res.redirect(`/students`);
});
module.exports.restoreStudent = catchAsync(async (req, res) => {
const { id } = req.params;
const archivedStudent = await ArchivedStudent.findOne({
Expand Down
Loading
Loading