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:
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user