fix(professors, settings): add auto-migration for legacy professors, deep populate user in class/session/course services, and fix SMS bypass number persistence
This commit is contained in:
@@ -61,6 +61,7 @@ const normalizeNumberOfSessions = (value) => {
|
||||
};
|
||||
|
||||
const enrichClassForDisplay = (cls) => {
|
||||
if (!cls) return cls;
|
||||
const tuitionFee = cls.tuitionFee || 0;
|
||||
const discount = cls.hasDiscount ? (cls.discount || 0) : 0;
|
||||
const finalTuitionFee = Math.max(0, tuitionFee - discount);
|
||||
@@ -68,7 +69,23 @@ const enrichClassForDisplay = (cls) => {
|
||||
if (cls.startDate) {
|
||||
daysUntilStart = Math.ceil((new Date(cls.startDate).getTime() - Date.now()) / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
return { ...cls, finalTuitionFee, daysUntilStart };
|
||||
|
||||
let professor = cls.professor;
|
||||
if (professor && typeof professor === 'object') {
|
||||
const profUser = professor.user && typeof professor.user === 'object' ? professor.user : null;
|
||||
const profName = String(profUser?.name || professor.name || '').trim();
|
||||
const profPhone = String(profUser?.phoneNumber || professor.phoneNumber || '').trim();
|
||||
const parts = profName.split(/\s+/);
|
||||
professor = {
|
||||
...professor,
|
||||
name: parts[0] || profName || 'استاد',
|
||||
surname: parts.length > 1 ? parts.slice(1).join(' ') : (professor.surname || ''),
|
||||
fullName: profName || 'استاد',
|
||||
phoneNumber: profPhone
|
||||
};
|
||||
}
|
||||
|
||||
return { ...cls, professor, finalTuitionFee, daysUntilStart };
|
||||
};
|
||||
|
||||
const getAll = async (query = {}) => {
|
||||
@@ -83,8 +100,13 @@ const getAll = async (query = {}) => {
|
||||
filter.isDeleted = { $ne: true };
|
||||
}
|
||||
|
||||
if (query.courseId) filter.course = query.courseId;
|
||||
if (query.isActive !== undefined) filter.isActive = query.isActive === 'true';
|
||||
if (query.courseId) {
|
||||
filter.course = query.courseId;
|
||||
}
|
||||
|
||||
if (query.isActive !== undefined) {
|
||||
filter.isActive = query.isActive === 'true';
|
||||
}
|
||||
|
||||
const searchTerm = getSearchTerm(query);
|
||||
if (searchTerm) {
|
||||
@@ -95,7 +117,10 @@ const getAll = async (query = {}) => {
|
||||
Class.find(filter)
|
||||
.select(CLASS_LIST_FIELDS)
|
||||
.populate({ path: 'course', select: 'title type price sectionCount hoursPerSection' })
|
||||
.populate({ path: 'professor', select: 'name surname' })
|
||||
.populate({
|
||||
path: 'professor',
|
||||
populate: { path: 'user', select: 'name phoneNumber email nationalIdCode' }
|
||||
})
|
||||
.skip(skip).limit(limit).sort({ createdAt: -1 }).lean(),
|
||||
Class.countDocuments(filter)
|
||||
]);
|
||||
@@ -106,8 +131,11 @@ const getAll = async (query = {}) => {
|
||||
const getOne = async (id) => {
|
||||
const cls = await Class.findById(id)
|
||||
.populate({ path: 'course', select: 'title type price sectionCount hoursPerSection' })
|
||||
.populate({ path: 'professor', select: 'name surname phoneNumber' })
|
||||
.populate({ path: 'students', select: 'name phoneNumber gender' })
|
||||
.populate({
|
||||
path: 'professor',
|
||||
populate: { path: 'user', select: 'name phoneNumber email nationalIdCode' }
|
||||
})
|
||||
.populate({ path: 'students', select: 'name phoneNumber gender' })
|
||||
.lean();
|
||||
if (!cls) throw new AppError('CLASS_NOT_FOUND');
|
||||
return enrichClassForDisplay(cls);
|
||||
@@ -247,7 +275,10 @@ const getMyClasses = async (userId, query = {}) => {
|
||||
const [items, total] = await Promise.all([
|
||||
Class.find(filter)
|
||||
.populate({ path: 'course', select: 'title type price description' })
|
||||
.populate({ path: 'professor', select: 'name surname' })
|
||||
.populate({
|
||||
path: 'professor',
|
||||
populate: { path: 'user', select: 'name phoneNumber nationalIdCode' }
|
||||
})
|
||||
.skip(skip).limit(limit).sort({ startDate: -1, createdAt: -1 }).lean(),
|
||||
Class.countDocuments(filter)
|
||||
]);
|
||||
@@ -271,7 +302,10 @@ const getPublicClasses = async (query = {}) => {
|
||||
Class.find(filter)
|
||||
.select('name course professor capacity tuitionFee hasDiscount discount freeSpots startDate endDate days startTime endTime')
|
||||
.populate({ path: 'course', select: 'title type description' })
|
||||
.populate({ path: 'professor', select: 'name surname' })
|
||||
.populate({
|
||||
path: 'professor',
|
||||
populate: { path: 'user', select: 'name phoneNumber' }
|
||||
})
|
||||
.skip(skip).limit(limit).sort({ startDate: 1, createdAt: -1 }).lean(),
|
||||
Class.countDocuments(filter)
|
||||
]);
|
||||
@@ -288,7 +322,10 @@ const getPublicOne = async (id) => {
|
||||
})
|
||||
.select('name course professor capacity tuitionFee hasDiscount discount freeSpots startDate endDate days startTime endTime isActive')
|
||||
.populate({ path: 'course', select: 'title type description sectionCount hoursPerSection price' })
|
||||
.populate({ path: 'professor', select: 'name surname' })
|
||||
.populate({
|
||||
path: 'professor',
|
||||
populate: { path: 'user', select: 'name phoneNumber' }
|
||||
})
|
||||
.lean();
|
||||
|
||||
if (!cls) throw new AppError('CLASS_NOT_FOUND', null, 'کلاس یافت نشد یا برای ثبتنام در دسترس نیست.');
|
||||
@@ -298,7 +335,10 @@ const getPublicOne = async (id) => {
|
||||
const sendClassPlanToProfessor = async (classId) => {
|
||||
const classDoc = await Class.findById(classId)
|
||||
.populate('course', 'title')
|
||||
.populate('professor', 'name surname phoneNumber');
|
||||
.populate({
|
||||
path: 'professor',
|
||||
populate: { path: 'user', select: 'name phoneNumber email' }
|
||||
});
|
||||
|
||||
if (!classDoc) {
|
||||
throw new AppError('CLASS_NOT_FOUND', null, 'کلاس یافت نشد.');
|
||||
@@ -309,11 +349,13 @@ const sendClassPlanToProfessor = async (classId) => {
|
||||
}
|
||||
|
||||
const professor = classDoc.professor;
|
||||
if (!professor.phoneNumber) {
|
||||
const profUser = professor.user && typeof professor.user === 'object' ? professor.user : null;
|
||||
const phoneNumber = profUser?.phoneNumber || professor.phoneNumber;
|
||||
if (!phoneNumber) {
|
||||
throw new AppError('VALIDATION_FAILED', { field: 'phoneNumber' }, 'شماره همراه استاد ثبت نشده است.');
|
||||
}
|
||||
|
||||
const profName = `${professor.name || ''} ${professor.surname || ''}`.trim() || 'استاد';
|
||||
const profName = profUser?.name || `${professor.name || ''} ${professor.surname || ''}`.trim() || 'استاد';
|
||||
const className = classDoc.name || classDoc.course?.title || 'کلاس';
|
||||
const classDays = formatClassDaysFromIndexes(classDoc.days) || 'طبق هماهنگی';
|
||||
const classTimes = (classDoc.startTime && classDoc.endTime)
|
||||
|
||||
Reference in New Issue
Block a user