From 29029625f2c53d11105512b4b8ba164d7a05fd5c Mon Sep 17 00:00:00 2001 From: Vikrant Date: Tue, 21 Apr 2026 14:51:53 +0530 Subject: [PATCH 01/12] fix: update thisMonthYear assignment to use variable directly --- controllers/fund.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/fund.js b/controllers/fund.js index 92c755f..490029d 100644 --- a/controllers/fund.js +++ b/controllers/fund.js @@ -127,7 +127,7 @@ module.exports.fund = catchAsync(async (req, res) => { total, view, balance, - thisMonthYear: `${month}-${year}`, + thisMonthYear, thisMonthData, stuThisMonth, archiveFeesThisMonth, From 1bf3c2785fdcfdd3d4fbb02147a50a3098440d80 Mon Sep 17 00:00:00 2001 From: Vikrant Date: Mon, 4 May 2026 07:14:50 +0530 Subject: [PATCH 02/12] feat: enhance fund report with total students and paid students count --- controllers/fund.js | 22 +++++++++++++++++----- public/css/fund.css | 17 ++++++++++------- public/js/previousReports.js | 2 +- views/listings/fund.ejs | 23 +++++++++++++++++++---- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/controllers/fund.js b/controllers/fund.js index 490029d..7a1c6f9 100644 --- a/controllers/fund.js +++ b/controllers/fund.js @@ -2,10 +2,6 @@ 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); @@ -32,6 +28,19 @@ module.exports.fund = catchAsync(async (req, res) => { }, }, ], + totalStudents: [{ $count: "count" }], + paidStudents: [ + { + $match: { + feesHistory: { + $elemMatch: { + paidDate: { $gte: startOfMonth, $lt: endOfMonth }, + }, + }, + }, + }, + { $count: "count" }, + ], feesThisMonth: [ { $unwind: "$feesHistory" }, { @@ -93,6 +102,8 @@ 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]; @@ -127,10 +138,11 @@ module.exports.fund = catchAsync(async (req, res) => { total, view, balance, - thisMonthYear, thisMonthData, stuThisMonth, archiveFeesThisMonth, + totalStudents, + paidStudents, }); }); module.exports.addExpense = catchAsync(async (req, res) => { diff --git a/public/css/fund.css b/public/css/fund.css index 69fc1d2..1030b0b 100644 --- a/public/css/fund.css +++ b/public/css/fund.css @@ -46,11 +46,12 @@ body { .stat { width: 100%; - padding: 0.6rem; color: white; - border-bottom: 1px dashed #ddd; display: flex; - justify-content: space-around; + justify-content: start; +} +.stats{ + justify-content: center; } .stat .total { border-radius: 30px; @@ -69,7 +70,8 @@ body { .stat div { margin: 0; - font-size: 14px; + font-size: 12px; + margin-left: 10px; } .new-stu { @@ -102,7 +104,7 @@ body { display: flex; justify-content: space-between; padding: 8px 0; - border-bottom: 1px dashed #ddd; + border-bottom: 1px dashed #515151; color: white; } .history { @@ -116,8 +118,9 @@ body { margin-bottom: 10px; } .feeHistory { + margin-top: .8rem; width: 23vw; - height: 55vh; + max-height: 55vh; overflow-y: scroll; } .feeHistory p{ @@ -127,7 +130,7 @@ body { color: white; text-decoration: none; font-size: 1.4rem; - border-bottom: 1px dashed #ddd; + /* border-bottom: 1px dashed #515151; */ padding: 5px 0; cursor: pointer; } diff --git a/public/js/previousReports.js b/public/js/previousReports.js index 1224db4..d7a901a 100644 --- a/public/js/previousReports.js +++ b/public/js/previousReports.js @@ -36,7 +36,7 @@ function renderReportCard(data) {

${monthTitle}

-
+
${data.totalEarning.toLocaleString("en-IN")}₹Monthly Reports
-

<%= thisMonthYear %>

+

<%= new Date(thisMonthData.year, thisMonthData.month -1).toLocaleString( + "en-US",{ month: "short", year: "numeric" })%> +

<%=balance.toLocaleString('en-IN')%> ₹
Fund Balance
+
+ <%= total.toLocaleString('en-IN') %> ₹
Total Expenses +
+
+
<%=thisMonthData.totalEarning.toLocaleString('en-IN')%> ₹
Total Revenue
+
+ <%= totalDue.toLocaleString('en-IN') %> + ₹
Total Due +
@@ -33,6 +47,7 @@
+ <% if (thisMonthData && thisMonthData.expenses.length) { %>

Expense Details

    <%for(let exp of thisMonthData.expenses){%> @@ -47,8 +62,7 @@ <%}%>
-

Total Expenses : <%= total.toLocaleString('en-IN') %> ₹

-

Total Due : <%= totalDue.toLocaleString('en-IN') %> ₹

+ <% } %>
@@ -93,13 +107,14 @@

-  Fees This Month +  Fees History

<% if (view === "month") { %> Show Last 3 Days <% } else { %> Show Full Month <% } %> + Paid Students: <%=paidStudents%> / <%=totalStudents%>
<% if (feesThisMonth && feesThisMonth.length) { %> <% feesThisMonth.forEach(fee => { %> From d451954a96ae29a5400b4ebcf186d9bd85018683 Mon Sep 17 00:00:00 2001 From: Vikrant Date: Tue, 5 May 2026 19:36:13 +0530 Subject: [PATCH 03/12] feat: update fund report to include fees history and improve data retrieval --- controllers/fund.js | 22 ++++++------ public/css/fund.css | 1 + views/listings/fund.ejs | 76 ++++++++++++++++++++--------------------- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/controllers/fund.js b/controllers/fund.js index 7a1c6f9..8902eff 100644 --- a/controllers/fund.js +++ b/controllers/fund.js @@ -109,13 +109,10 @@ module.exports.fund = catchAsync(async (req, res) => { 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, @@ -125,11 +122,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, diff --git a/public/css/fund.css b/public/css/fund.css index 1030b0b..c3e7d8f 100644 --- a/public/css/fund.css +++ b/public/css/fund.css @@ -261,6 +261,7 @@ input::-webkit-inner-spin-button { } .history { padding: 3.5vw; + margin: 3vw 0 0 0 ; } .fee-entry { font-size: 1rem; diff --git a/views/listings/fund.ejs b/views/listings/fund.ejs index a071d69..f9549b3 100644 --- a/views/listings/fund.ejs +++ b/views/listings/fund.ejs @@ -65,6 +65,44 @@ <% } %>
+
+

+  Fees History +

+ <% if (view === "month") { %> + Show Last 3 Days + <% } else { %> + Show Full Month + <% } %> + Paid Students: <%=paidStudents%> / <%=totalStudents%> +
+ <% if (feesThisMonth && feesThisMonth.length) { %> <% + feesThisMonth.forEach(fee => { %> +
  • + <%= fee.feesHistory.amount %>₹ — <%= fee.name %> / <%= fee.grade %> + On : <%= new + Date(fee.feesHistory.paidDate) .toLocaleDateString('en-GB', { + weekday: 'short', day: 'numeric', month: 'short' }) + .replace(/,/g, '') %> <%if(fee.feesHistory.note){%>
    Note + : <%= fee.feesHistory.note %> <%}%>

    +
  • + <% }) %> <% } else { %> +

    No fees recorded this month.

    + <% } %> + <% if (archiveFeesThisMonth && archiveFeesThisMonth.length) { %> +

    Archive fees record

    + <% archiveFeesThisMonth.forEach(fee => { %> +
  • + <%= fee.feesHistory.amount %>₹ — <%= fee.name %> / <%= fee.grade %> + On : <%= new + Date(fee.feesHistory.paidDate) .toLocaleDateString('en-GB', { + weekday: 'short', day: 'numeric', month: 'short' }) + .replace(/,/g, '') %> <%if(fee.feesHistory.note){%>
    Note + : <%= fee.feesHistory.note %> <%}%>

    +
  • + <% })} %> +
    +

    Add Expenses

    -
    -

    -  Fees History -

    - <% if (view === "month") { %> - Show Last 3 Days - <% } else { %> - Show Full Month - <% } %> - Paid Students: <%=paidStudents%> / <%=totalStudents%> -
    - <% if (feesThisMonth && feesThisMonth.length) { %> <% - feesThisMonth.forEach(fee => { %> -
  • - <%= fee.feesHistory.amount %>₹ — <%= fee.name %> / <%= fee.grade %> - On : <%= new - Date(fee.feesHistory.paidDate) .toLocaleDateString('en-GB', { - weekday: 'short', day: 'numeric', month: 'short' }) - .replace(/,/g, '') %> <%if(fee.feesHistory.note){%>
    Note - : <%= fee.feesHistory.note %> <%}%>

    -
  • - <% }) %> <% } else { %> -

    No fees recorded this month.

    - <% } %> - <% if (archiveFeesThisMonth && archiveFeesThisMonth.length) { %> -

    Archive fees record

    - <% archiveFeesThisMonth.forEach(fee => { %> -
  • - <%= fee.feesHistory.amount %>₹ — <%= fee.name %> / <%= fee.grade %> - On : <%= new - Date(fee.feesHistory.paidDate) .toLocaleDateString('en-GB', { - weekday: 'short', day: 'numeric', month: 'short' }) - .replace(/,/g, '') %> <%if(fee.feesHistory.note){%>
    Note - : <%= fee.feesHistory.note %> <%}%>

    -
  • - <% })} %> -
    -
    From caae1844cdaa02d3a867d4f82787d295ab5ec024 Mon Sep 17 00:00:00 2001 From: vikrant Date: Sun, 14 Jun 2026 10:25:40 +0530 Subject: [PATCH 09/12] feat: add comments to indicate performance concerns in student retrieval methods --- controllers/students.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/controllers/students.js b/controllers/students.js index f88f4b2..6035399 100644 --- a/controllers/students.js +++ b/controllers/students.js @@ -43,6 +43,7 @@ module.exports.students = catchAsync(async (req, res) => { module.exports.showStudent = catchAsync(async (req, res, next) => { const { id } = req.params; let student = await Student.findOne({ _id: id, owner: req.user._id }); + // This method is too much time taking if (!student) { student = await ArchivedStudent.findOne({ _id: id, owner: req.user._id }); } @@ -203,6 +204,13 @@ module.exports.deleteStudent = catchAsync(async (req, res) => { _id: id, owner: req.user._id, }); + //this method is too much time taking + if(!removedStudent) { + let archivedStudent = await ArchivedStudent.findOne({ + _id: id, + owner: req.user._id, + }); + } if (!removedStudent) { req.flash("error", "Student not found or already deleted."); return res.redirect("/students"); From ff7a449bb755bd84139a7b4dd4edb9db23626338 Mon Sep 17 00:00:00 2001 From: vikrant Date: Sun, 14 Jun 2026 11:59:14 +0530 Subject: [PATCH 10/12] feat: implement showArchiveStu route and view for archived student details --- controllers/students.js | 18 ++-- routes/students.js | 3 + views/listings/archive.ejs | 12 +-- views/listings/showArchiveStu.ejs | 155 ++++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 22 deletions(-) create mode 100644 views/listings/showArchiveStu.ejs diff --git a/controllers/students.js b/controllers/students.js index 6035399..0f19b7b 100644 --- a/controllers/students.js +++ b/controllers/students.js @@ -43,10 +43,6 @@ module.exports.students = catchAsync(async (req, res) => { module.exports.showStudent = catchAsync(async (req, res, next) => { const { id } = req.params; let student = await Student.findOne({ _id: id, owner: req.user._id }); - // This method is too much time taking - if (!student) { - 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/show", { student, formattedDate }); @@ -204,13 +200,6 @@ module.exports.deleteStudent = catchAsync(async (req, res) => { _id: id, owner: req.user._id, }); - //this method is too much time taking - if(!removedStudent) { - let archivedStudent = await ArchivedStudent.findOne({ - _id: id, - owner: req.user._id, - }); - } if (!removedStudent) { req.flash("error", "Student not found or already deleted."); return res.redirect("/students"); @@ -269,6 +258,13 @@ 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.restoreStudent = catchAsync(async (req, res) => { const { id } = req.params; const archivedStudent = await ArchivedStudent.findOne({ diff --git a/routes/students.js b/routes/students.js index cc1ed78..bc2233e 100644 --- a/routes/students.js +++ b/routes/students.js @@ -17,6 +17,9 @@ router .get(isLoggedIn, validateObjectId, student.editStudent) .put(isLoggedIn, validateObjectId, student.saveEditStudent); router.get("/:id/deactivate", student.deactivateStudent); +router + .route("/:id/archive") + .get(isLoggedIn, validateObjectId, student.showArchiveStu) router.post("/:id/restore", student.restoreStudent); router.delete("/:id/delete", student.deletearchiveStudent); router.post("/:id/addFees", isLoggedIn, student.addFees); diff --git a/views/listings/archive.ejs b/views/listings/archive.ejs index bef4811..53b30cf 100644 --- a/views/listings/archive.ejs +++ b/views/listings/archive.ejs @@ -6,7 +6,7 @@

     Archive Students

    diff --git a/views/listings/showArchiveStu.ejs b/views/listings/showArchiveStu.ejs new file mode 100644 index 0000000..9a4e530 --- /dev/null +++ b/views/listings/showArchiveStu.ejs @@ -0,0 +1,155 @@ +<% layout('layouts/boilerPlate') -%> + + +
    +
    +
    +
    + <%= student.name %> Img +

    <%= student.name %>

    +
    +

    Grade : <%= student.grade %>

    +

    Fees : <%= student.fees %>

    +

    Due Fees : <%= student.dueFees %>

    +

    Joining Date : <%= formattedDate %>

    + <%if(student.parent){%> +

    Parent : <%= student.parent %>

    + <%}%> + <%if(student.contact){%> +

    + Contact : <%= student.contact %> + + + + +

    + <%}%> + <%if(student.phone){%> +

    + Phone : <%= student.phone %> +   + + + +

    + <%}%> + <%if(student.dueFees >= student.fees && (student.phone || student.contact)){%> + <%if(student.contact){%> +

    + Remind on : Contact +   + +

    + <%}%> + <%if(student.phone){%> +

    + Remind on : Phone +   + +

    + <%}%> + <%}%> + <%if(student.note){%> +

    Note : <%= student.note %>

    + <%}%> +
    +
    +
    +

    Fees

    +

    +   Add a new payment +

    + + + + +
    +
    +
    +

    +  Payment History +

    + <% if(student.feesHistory && student.feesHistory.length > 0) { %> + <%student.feesHistory.reverse().forEach(function(fees) { %> +
    +

    + ₹ <%= fees.amount %> + Paid On : <%= fees.paidDate.toLocaleDateString("en-GB", { weekday: + "short", day: "2-digit", month: "short", year: "numeric" }) %> +

    + <%if(fees.note){%> +

    Note : <%=fees.note%>

    + <%}%> +
    +
    + <% }); %> <% } else { %> +

    No payment history found.

    + <% } %> +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + From d215c1aa1784c3603afcbb992226668e3f708843 Mon Sep 17 00:00:00 2001 From: vikrant Date: Thu, 18 Jun 2026 19:49:06 +0530 Subject: [PATCH 11/12] feat: add functionality to record fees for archived students --- controllers/students.js | 45 +++++++++++++++++++++++++++++++ routes/students.js | 3 ++- views/listings/showArchiveStu.ejs | 2 +- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/controllers/students.js b/controllers/students.js index 0f19b7b..47e2a95 100644 --- a/controllers/students.js +++ b/controllers/students.js @@ -265,6 +265,51 @@ module.exports.showArchiveStu = catchAsync(async (req, res, next) => { 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({ diff --git a/routes/students.js b/routes/students.js index bc2233e..340ed51 100644 --- a/routes/students.js +++ b/routes/students.js @@ -19,8 +19,9 @@ router router.get("/:id/deactivate", student.deactivateStudent); router .route("/:id/archive") - .get(isLoggedIn, validateObjectId, student.showArchiveStu) + .get(isLoggedIn, validateObjectId, student.showArchiveStu); router.post("/:id/restore", student.restoreStudent); router.delete("/:id/delete", student.deletearchiveStudent); router.post("/:id/addFees", isLoggedIn, student.addFees); +router.post("/:id/addArchiveStuFee", isLoggedIn, student.addArchiveStuFee); module.exports = router; diff --git a/views/listings/showArchiveStu.ejs b/views/listings/showArchiveStu.ejs index 9a4e530..5335a60 100644 --- a/views/listings/showArchiveStu.ejs +++ b/views/listings/showArchiveStu.ejs @@ -73,7 +73,7 @@
    From fa4f89d8890453e6745cd1f516b55cb512befb09 Mon Sep 17 00:00:00 2001 From: vikrant Date: Fri, 19 Jun 2026 16:26:27 +0530 Subject: [PATCH 12/12] feat: add edit functionality for archived students with corresponding views --- controllers/students.js | 46 ++++++++++++ routes/students.js | 4 ++ views/listings/editArchiveStu.ejs | 115 ++++++++++++++++++++++++++++++ views/listings/showArchiveStu.ejs | 3 + 4 files changed, 168 insertions(+) create mode 100644 views/listings/editArchiveStu.ejs diff --git a/controllers/students.js b/controllers/students.js index 47e2a95..869a8df 100644 --- a/controllers/students.js +++ b/controllers/students.js @@ -66,6 +66,13 @@ 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 }); @@ -73,6 +80,45 @@ module.exports.editStudent = catchAsync(async (req, res, next) => { 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 { diff --git a/routes/students.js b/routes/students.js index 340ed51..9cfbefc 100644 --- a/routes/students.js +++ b/routes/students.js @@ -24,4 +24,8 @@ router.post("/:id/restore", student.restoreStudent); router.delete("/:id/delete", student.deletearchiveStudent); router.post("/:id/addFees", isLoggedIn, student.addFees); router.post("/:id/addArchiveStuFee", isLoggedIn, student.addArchiveStuFee); +router + .route("/:id/editArchiveStu") + .get(isLoggedIn, validateObjectId, student.editArchiveStu) + .put(isLoggedIn, validateObjectId, student.saveEditArchiveStu); module.exports = router; diff --git a/views/listings/editArchiveStu.ejs b/views/listings/editArchiveStu.ejs new file mode 100644 index 0000000..1ae6831 --- /dev/null +++ b/views/listings/editArchiveStu.ejs @@ -0,0 +1,115 @@ +<% layout('layouts/boilerPlate') -%> + + +
    + Student reading a book + +

    Edit Details

    + +
    + + + +
    + + + + + + + +
    + + diff --git a/views/listings/showArchiveStu.ejs b/views/listings/showArchiveStu.ejs index 5335a60..b76d42b 100644 --- a/views/listings/showArchiveStu.ejs +++ b/views/listings/showArchiveStu.ejs @@ -142,6 +142,9 @@