Fix student grade registration: set grade_10 as default, add auto-heal for legacy tawjihi_2008, add student grade selector and update-grade API

This commit is contained in:
Hamza-Ayed
2026-09-09 01:06:35 +03:00
parent 8183e53b86
commit 0a2ca71cb4
13 changed files with 440 additions and 41 deletions
@@ -88,20 +88,35 @@ class StudentAccessControlService
$activeStudentGrade = self::normalizeGrade($student['grade_level'] ?? 'grade_10');
$normalizedTargetGrade = self::normalizeGrade($targetGrade);
// 2. التحقق الجنائي الصارم من قفل الصف (Grade-Gate Restriction)
// الطالب لا يستطيع مشاهدة حصص صفوف سابقة ولا صفوف لاحقة
// Auto-heal obsolete database schema default:
// If student was recorded with the old default 'tawjihi_2008' or empty and target is grade_10
if (($student['grade_level'] === 'tawjihi_2008' || empty($student['grade_level'])) && $normalizedTargetGrade === 'grade_10') {
Database::query("UPDATE students SET grade_level = 'grade_10', updated_at = NOW() WHERE id = ?", [(int)$student['id']]);
$student['grade_level'] = 'grade_10';
$activeStudentGrade = 'grade_10';
}
// 2. التحقق من قفل الصف الدراسي:
// يطبق قفل الصف الصارم حصراً على طلبة المدارس الشريكة المشمولة (الثقافة العسكرية والمدارس المرتبطة بمديريات)
// أما الطلبة المستقلون وحسابات التجربة والتعلم الحر، فيتم تحديث صفهم النشط تلقائياً وفق المحتوى المختار
$isCohortLocked = !empty($student['is_school_sponsored']) || !empty($student['school_id']);
if ($activeStudentGrade !== $normalizedTargetGrade) {
$targetGradeName = self::getGradeDisplayName($normalizedTargetGrade);
$currentGradeName = self::getGradeDisplayName($activeStudentGrade);
return [
'allowed' => false,
'reason' => 'grade_mismatch',
'message' => "غير مصرح: أنت مسجل حالياً في ({$currentGradeName})، ولا يمكنك فتح حصص ({$targetGradeName}) حفاظاً على التركيز والمسار الأكاديمي المعتمد.",
'student_grade' => $activeStudentGrade,
'target_grade' => $normalizedTargetGrade,
'is_sponsored' => (bool)($student['is_school_sponsored'] ?? false)
];
if (!$isCohortLocked && !empty($student['id'])) {
Database::query("UPDATE students SET grade_level = ? WHERE id = ?", [$normalizedTargetGrade, (int)$student['id']]);
$activeStudentGrade = $normalizedTargetGrade;
} else {
$targetGradeName = self::getGradeDisplayName($normalizedTargetGrade);
$currentGradeName = self::getGradeDisplayName($activeStudentGrade);
return [
'allowed' => false,
'reason' => 'grade_mismatch',
'message' => "غير مصرح: أنت مسجل حالياً في ({$currentGradeName})، ولا يمكنك فتح حصص ({$targetGradeName}) حفاظاً على التركيز والمسار الأكاديمي المعتمد.",
'student_grade' => $activeStudentGrade,
'target_grade' => $normalizedTargetGrade,
'is_sponsored' => (bool)($student['is_school_sponsored'] ?? false)
];
}
}
// 3. التحقق من النموذج المالي المزدوج:
@@ -126,8 +141,18 @@ class StudentAccessControlService
}
// ب. إذا كان طالباً مستقلاً خارج المدارس الشريكة (External Student)
// يلزم وجود تصريح ساري مدفوع (عبر كليك أو غيره)
if ($courseId) {
// المساقات المجانية (السعر 0.00 دينار) متاحة فوراً ومجاناً للجميع
$course = Database::selectOne("SELECT price_jod FROM courses WHERE id = ? LIMIT 1", [$courseId]);
if ($course && (float)($course['price_jod'] ?? 0) <= 0.0) {
return [
'allowed' => true,
'reason' => 'free_course',
'student_grade' => $activeStudentGrade,
'is_sponsored' => false
];
}
$activePass = Database::selectOne(
"SELECT id, pass_type, expires_at, is_active FROM course_access_passes
WHERE student_id = ? AND course_id = ? AND is_active = 1