Files
saqel/backend/app/Services/ParentReportService.php
T

118 lines
5.7 KiB
PHP

<?php
namespace App\Services;
use App\Core\Database;
use App\Core\Security;
class ParentReportService
{
public static function compileMonthlyReport(int $studentId): array
{
$student = Database::selectOne(
"SELECT s.id, s.full_name, s.grade_level, s.stream, sc.name AS school_name,
ai.phone_number AS guardian_phone
FROM students s
LEFT JOIN schools sc ON sc.id = s.school_id
JOIN guardian_students gs ON gs.student_id = s.id AND gs.can_view_analytics = 1
JOIN guardians g ON g.id = gs.guardian_id
JOIN auth_identities ai ON ai.id = g.identity_id AND ai.status = 'active'
WHERE s.id = ? ORDER BY gs.id LIMIT 1",
[$studentId]
);
if (!$student) {
throw new \RuntimeException('لا يوجد ولي أمر مخوّل ومرتبط بهذا الطالب');
}
$learning = Database::selectOne(
"SELECT COUNT(*) AS lessons_started,
SUM(CASE WHEN is_completed = 1 THEN 1 ELSE 0 END) AS lessons_completed,
COALESCE(AVG(completion_percentage), 0) AS average_completion
FROM lesson_progress WHERE student_id = ?",
[$studentId]
);
$mastery = Database::selectOne(
"SELECT COALESCE(AVG(tawjihi_readiness_score), 0) AS readiness,
COALESCE(SUM(exams_passed_count), 0) AS exams_passed,
COALESCE(SUM(exams_total_count), 0) AS exams_total
FROM student_mastery_analytics WHERE student_id = ?",
[$studentId]
);
$errors = Database::selectOne(
"SELECT SUM(CASE WHEN status = 'mastered' THEN 1 ELSE 0 END) AS mastered,
COUNT(*) AS total_errors FROM student_error_notebook WHERE student_id = ?",
[$studentId]
);
$latestExam = Database::selectOne(
"SELECT percentage FROM exam_attempts WHERE student_id = ? AND completed_at IS NOT NULL ORDER BY completed_at DESC LIMIT 1",
[$studentId]
);
$student['guardian_phone'] = Security::decrypt((string)$student['guardian_phone']);
$student['month'] = date('Y-m');
$metrics = [
'average_lesson_completion' => round((float)($learning['average_completion'] ?? 0), 2),
'lessons_completed' => (int)($learning['lessons_completed'] ?? 0),
'lessons_started' => (int)($learning['lessons_started'] ?? 0),
'remediation_mastered' => (int)($errors['mastered'] ?? 0),
'remediation_total' => (int)($errors['total_errors'] ?? 0),
'latest_exam_score' => $latestExam ? (float)$latestExam['percentage'] : null,
'exams_passed' => (int)($mastery['exams_passed'] ?? 0),
'exams_total' => (int)($mastery['exams_total'] ?? 0),
'general_readiness' => round((float)($mastery['readiness'] ?? 0), 2),
];
return ['student' => $student, 'metrics' => $metrics, 'whatsapp_message' => self::buildWhatsAppMessage($student, $metrics)];
}
public static function dispatchReportToGuardian(int $studentId): array
{
try {
$report = self::compileMonthlyReport($studentId);
$result = (new NabehService())->sendMessage($report['student']['guardian_phone'], $report['whatsapp_message']);
if (!($result['success'] ?? false)) {
return ['status' => 'error', 'message' => $result['error'] ?? 'تعذر إرسال التقرير عبر نبيه'];
}
return ['status' => 'success', 'message' => 'تم إرسال التقرير الفعلي لولي الأمر', 'dispatched_at' => date('Y-m-d H:i:s')];
} catch (\Throwable $e) {
return ['status' => 'error', 'message' => $e->getMessage()];
}
}
public static function dispatchBatchReports(int $schoolId): array
{
$students = Database::select(
"SELECT DISTINCT s.id FROM students s JOIN guardian_students gs ON gs.student_id = s.id AND gs.can_view_analytics = 1 WHERE s.school_id = ?",
[$schoolId]
);
$sent = 0;
$failed = 0;
foreach ($students as $student) {
$result = self::dispatchReportToGuardian((int)$student['id']);
($result['status'] ?? 'error') === 'success' ? $sent++ : $failed++;
}
return [
'status' => $failed === 0 ? 'success' : 'partial',
'school_id' => $schoolId,
'total_dispatched' => $sent,
'failed_count' => $failed,
'total_eligible' => count($students),
];
}
private static function buildWhatsAppMessage(array $student, array $metrics): string
{
$latestExam = $metrics['latest_exam_score'] === null ? 'لا توجد محاولة مكتملة' : $metrics['latest_exam_score'] . '%';
return "تقرير صَقِل الشهري — {$student['month']}\n"
. "الطالب: {$student['full_name']}\n"
. "المدرسة: " . ($student['school_name'] ?: 'غير مرتبطة') . "\n"
. "الصف: {$student['grade_level']} / {$student['stream']}\n\n"
. "الحصص المكتملة: {$metrics['lessons_completed']} من {$metrics['lessons_started']}\n"
. "متوسط إكمال الحصص: {$metrics['average_lesson_completion']}%\n"
. "المعالجات المتقنة: {$metrics['remediation_mastered']} من {$metrics['remediation_total']}\n"
. "آخر امتحان: {$latestExam}\n"
. "مؤشر الجاهزية: {$metrics['general_readiness']}%\n\n"
. "للتفاصيل ادخل إلى تطبيق صَقِل بحساب ولي الأمر.";
}
}