Improve attendance completion checks and expose recorded counts.

Only count existing enrolled students when deciding if a session is fully recorded, and return per-session attendance totals for the dashboard list.
This commit is contained in:
2026-08-16 09:22:41 +03:30
parent 0d57854dc3
commit 7d59448991
+47 -8
View File
@@ -3,6 +3,7 @@
const Session = require('./sessionModel'); const Session = require('./sessionModel');
const Course = require('../courses/courseModel'); const Course = require('../courses/courseModel');
const Class = require('../classes/classModel'); const Class = require('../classes/classModel');
const User = require('../users/userModel');
const Professor = require('../professors/professorModel'); const Professor = require('../professors/professorModel');
const AppError = require('../../utils/AppError'); const AppError = require('../../utils/AppError');
const eventEmitter = require('../../events/eventEmitter'); const eventEmitter = require('../../events/eventEmitter');
@@ -124,7 +125,31 @@ const buildStudentsByClassId = async (sessions) => {
if (!classIds.length) return new Map(); if (!classIds.length) return new Map();
const classes = await Class.find({ _id: { $in: classIds } }).select('students').lean(); const classes = await Class.find({ _id: { $in: classIds } }).select('students').lean();
return new Map(classes.map((cls) => [String(cls._id), cls.students || []])); const allStudentIds = [...new Set(
classes.flatMap((cls) => (cls.students || []).map(normalizeId)).filter(Boolean)
)];
let existingSet = new Set();
if (allStudentIds.length) {
const existingUsers = await User.find({ _id: { $in: allStudentIds } }).select('_id').lean();
existingSet = new Set(existingUsers.map((user) => normalizeId(user._id)));
}
return new Map(classes.map((cls) => {
const validStudentIds = (cls.students || [])
.map(normalizeId)
.filter((id) => existingSet.has(id));
return [String(cls._id), validStudentIds];
}));
};
const getValidStudentIdsForClass = async (classItem) => {
if (!classItem) return [];
const rawIds = (classItem.students || []).map(normalizeId).filter(Boolean);
if (!rawIds.length) return [];
const existingUsers = await User.find({ _id: { $in: rawIds } }).select('_id').lean();
const existingSet = new Set(existingUsers.map((user) => normalizeId(user._id)));
return rawIds.filter((id) => existingSet.has(id));
}; };
const isSessionDue = (session) => { const isSessionDue = (session) => {
@@ -156,12 +181,21 @@ const hasCompleteAttendance = (session, studentsByClassId = null) => {
const isAttendancePending = (session, studentsByClassId = null) => const isAttendancePending = (session, studentsByClassId = null) =>
isSessionDue(session) && !hasCompleteAttendance(session, studentsByClassId); isSessionDue(session) && !hasCompleteAttendance(session, studentsByClassId);
const enrichSessionAttendance = (session, studentsByClassId = null) => ({ const enrichSessionAttendance = (session, studentsByClassId = null) => {
...session, const studentIds = getClassStudentIds(session, studentsByClassId);
isDue: isSessionDue(session), const recordedIds = getRecordedUserIds(session);
attendanceComplete: hasCompleteAttendance(session, studentsByClassId), const studentSet = new Set(studentIds);
attendancePending: isAttendancePending(session, studentsByClassId) const attendanceRecordedCount = recordedIds.filter((id) => studentSet.has(id)).length;
});
return {
...session,
isDue: isSessionDue(session),
attendanceTotalCount: studentIds.length,
attendanceRecordedCount,
attendanceComplete: hasCompleteAttendance(session, studentsByClassId),
attendancePending: isAttendancePending(session, studentsByClassId)
};
};
const filterByAttendanceScope = (sessions, scope, studentsByClassId = null) => { const filterByAttendanceScope = (sessions, scope, studentsByClassId = null) => {
const dueSessions = sessions.filter(isSessionDue); const dueSessions = sessions.filter(isSessionDue);
@@ -351,7 +385,12 @@ const updateSessionAttendance = async (sessionId, attendanceList, recordedBy = n
await session.save(); await session.save();
const classItem = await Class.findById(session.class).select('students').lean(); const classItem = await Class.findById(session.class).select('students').lean();
if (classItem && hasCompleteAttendance({ ...session.toObject(), class: classItem }) && session.status !== 'cancelled') { const validStudentIds = await getValidStudentIdsForClass(classItem);
if (
classItem
&& hasCompleteAttendance({ ...session.toObject(), class: { ...classItem, students: validStudentIds } })
&& session.status !== 'cancelled'
) {
session.status = 'held'; session.status = 'held';
await session.save(); await session.save();
} }