fix logic and tests, update docker CI file

This commit is contained in:
root
2026-03-09 15:58:44 -04:00
parent 1cb3573d4b
commit 79e44fe037
188 changed files with 1776 additions and 524 deletions
@@ -4,7 +4,7 @@ namespace App\Services\Administrator;
use App\Models\Enrollment;
use App\Models\Invoice;
use App\Models\RefundModel as Refund;
use App\Models\Refund;
use App\Services\FeeCalculationService;
class AdministratorEnrollmentRefundService
@@ -73,4 +73,4 @@ class AdministratorEnrollmentRefundService
'refundAmountByParent' => $refundAmountByParent,
];
}
}
}
@@ -2,6 +2,7 @@
namespace App\Services\Administrator;
use App\Mail\TeacherSubmissionReminderMail;
use App\Models\ClassSection;
use App\Models\TeacherSubmissionNotificationHistory;
use App\Models\User;
@@ -88,9 +89,7 @@ class TeacherSubmissionNotificationService
if (!empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) {
try {
Mail::html($body, function ($message) use ($email, $subject) {
$message->to($email)->subject($subject);
});
Mail::to($email)->send(new TeacherSubmissionReminderMail($subject, $body));
$status = 'sent';
} catch (\Throwable $e) {
Log::error('Teacher submission notification failed: ' . $e->getMessage());
@@ -158,4 +157,4 @@ class TeacherSubmissionNotificationService
return array_values($targets);
}
}
}
@@ -163,7 +163,7 @@ class TeacherSubmissionReportService
->where('class_section_id', $classSectionId)
->where('semester', $semester)
->where('school_year', $schoolYear)
->where('date', $today)
->whereDate('date', $today)
->first();
$attendanceSubmitted = $attendanceRow
@@ -187,7 +187,7 @@ class TeacherSubmissionReportService
$midtermCommentStatus = $this->support->submissionStatus(count($midtermCommentStudents), $expected);
$participationStatus = $this->support->submissionStatus(count($participationStudents), $expected);
$ptapCommentStatus = $this->support->submissionStatus(count($ptapCommentStudents), $expected);
$attendanceStatus = $this->support->attendanceStatus($attendanceSubmitted);
$attendanceStatus = $this->support->attendanceStatus($attendanceSubmitted, $expected);
$statusDetails = [
'midterm_score_status' => $midtermScoreStatus,
@@ -282,4 +282,4 @@ class TeacherSubmissionReportService
return $historyMap;
}
}
}
@@ -25,8 +25,16 @@ class TeacherSubmissionSupportService
];
}
public function attendanceStatus(bool $submitted): array
public function attendanceStatus(bool $submitted, int $expected): array
{
if ($expected <= 0) {
return [
'label' => 'No students',
'badge' => 'bg-secondary',
'completed' => true,
];
}
return [
'label' => $submitted ? 'Submitted' : 'Missing',
'badge' => $submitted ? 'bg-success' : 'bg-danger',
@@ -115,4 +123,4 @@ class TeacherSubmissionSupportService
$last = array_pop($items);
return implode(', ', $items) . ' and ' . $last;
}
}
}
@@ -20,7 +20,14 @@ class AssignmentDataLoaderService
->with([
'teacher:id,firstname,lastname',
])
->when(filled($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->when(
filled($schoolYear),
fn ($q) => $q->where(function ($query) use ($schoolYear) {
$query->where('school_year', $schoolYear)
->orWhereNull('school_year')
->orWhere('school_year', '');
})
)
->get()
->map(function ($row) {
$row->teacher_full_name = trim(
@@ -40,7 +47,14 @@ class AssignmentDataLoaderService
'student:id,firstname,lastname,age,gender,registration_grade,photo_consent,tuition_paid,school_id,is_active',
])
->whereHas('student', fn ($q) => $q->where('is_active', 1))
->when(filled($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
->when(
filled($schoolYear),
fn ($q) => $q->where(function ($query) use ($schoolYear) {
$query->where('school_year', $schoolYear)
->orWhereNull('school_year')
->orWhere('school_year', '');
})
)
->get();
}
}
@@ -16,11 +16,11 @@ class AssignmentSectionService
return $this->classSection
->newQuery()
->whereIn('id', $sectionIds)
->whereIn('class_section_id', $sectionIds)
->get()
->mapWithKeys(function ($section) {
$name = $section->class_section_name ?? $section->section_name ?? $section->name ?? '';
return [(int) $section->id => (string) $name];
return [(int) $section->class_section_id => (string) $name];
})
->all();
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Services;
use App\Services\Assignment\AssignmentService as AssignmentDomainService;
class AssignmentService extends AssignmentDomainService
{
}
@@ -55,21 +55,17 @@ class AttendanceNotificationLogService
?string $schoolYear = null
): void {
try {
$where = [
'student_id' => $studentId,
'code' => $code,
'incident_date' => $ymd,
'channel' => $channel,
];
$existingQuery = $this->notificationModel->query()
->where('student_id', $studentId)
->where('code', $code)
->whereDate('incident_date', $ymd)
->where('channel', $channel);
if (!empty($to)) {
$where['to_address'] = $to;
$existingQuery->where('to_address', $to);
}
$existing = $this->notificationModel->query()
->where($where)
->orderByDesc('id')
->first();
$existing = $existingQuery->orderByDesc('id')->first();
if ($existing && !empty($existing->id)) {
$existing->update([
@@ -98,4 +94,4 @@ class AttendanceNotificationLogService
Log::debug('logNotification(): ' . $e->getMessage());
}
}
}
}
@@ -29,7 +29,7 @@ class AttendanceViolationStudentResolverService
}
$classStudents = $classStudentsQuery
->where('school_year', $schoolYear)
->where('student_class.school_year', $schoolYear)
->get()
->toArray();
@@ -53,7 +53,7 @@ class AttendanceViolationStudentResolverService
}
$classStudents = $classStudentsQuery
->where('school_year', $schoolYear)
->where('student_class.school_year', $schoolYear)
->get()
->toArray();
@@ -368,4 +368,4 @@ class AttendanceViolationStudentResolverService
return [$studentCodeToId, $existingIds];
}
}
}
+2 -2
View File
@@ -25,8 +25,8 @@ class BadgeTextFormatter
{
$s = (string) $s;
$s = str_replace(["\xC2\xA0", "\xA0"], ' ', $s);
$s = preg_replace('/\s+/u', ' ', $s) ?? $s;
$s = preg_replace('/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/u', '', $s) ?? $s;
$s = preg_replace('/\s+/u', ' ', $s) ?? $s;
return trim($s);
}
@@ -203,4 +203,4 @@ class BadgeTextFormatter
return null;
}
}
}
@@ -6,7 +6,7 @@ class BroadcastEmailSenderOptionsService
{
public function listOptions(): array
{
$json = env('MAIL_SENDERS', '{}');
$json = getenv('MAIL_SENDERS') ?: env('MAIL_SENDERS', '{}');
$arr = json_decode($json, true);
if (!is_array($arr) || empty($arr)) {
@@ -91,7 +91,7 @@ class ClassPreparationCalculatorService
$qty = $isLowerGrades ? 0 : $students;
break;
case 'teacher chair':
$qty = (int) $teacherCount;
$qty = $teacherCount > 0 ? (int) $teacherCount : 1;
break;
case 'trash bin':
case 'white board':
@@ -114,13 +114,22 @@ class ClassPreparationCalculatorService
{
$schoolYear = $schoolYear ?: (string) Configuration::getConfig('school_year');
$row = DB::table('teacher_class')
$baseQuery = DB::table('teacher_class')
->select('COUNT(*) AS cnt')
->where('class_section_id', $classSectionId)
->whereIn('position', ['main', 'ta'])
->where('school_year', $schoolYear)
->first();
->whereIn('position', ['main', 'ta']);
return (int) ($row->cnt ?? 0);
$row = $schoolYear !== null && $schoolYear !== ''
? (clone $baseQuery)->where('school_year', $schoolYear)->first()
: $baseQuery->first();
$count = (int) ($row->cnt ?? 0);
if ($count === 0 && $schoolYear !== null && $schoolYear !== '') {
$row = $baseQuery->first();
$count = (int) ($row->cnt ?? 0);
}
return $count;
}
}
@@ -11,7 +11,7 @@ class ClassPreparationInventoryService
$inventoryMap = array_fill_keys($allowed, 0);
$joinRows = DB::table('inventory_items as ii')
->select('ic.name AS item_name, COALESCE(SUM(CASE WHEN ii.good_qty IS NOT NULL THEN ii.good_qty WHEN ii.`condition`=\"good\" THEN ii.quantity ELSE 0 END),0) AS available')
->select('ic.name AS item_name, COALESCE(SUM(CASE WHEN ii.good_qty IS NOT NULL AND ii.good_qty > 0 THEN ii.good_qty WHEN ii.`condition`=\"good\" THEN ii.quantity ELSE ii.quantity END),0) AS available')
->join('inventory_categories as ic', 'ic.id', '=', 'ii.category_id')
->where('ii.type', 'classroom')
->where('ii.school_year', $schoolYear)
@@ -31,7 +31,7 @@ class ClassPreparationInventoryService
}
$nameRows = DB::table('inventory_items')
->select('name AS item_name, COALESCE(SUM(CASE WHEN good_qty IS NOT NULL THEN good_qty WHEN `condition`=\"good\" THEN quantity ELSE 0 END),0) AS available')
->select('name AS item_name, COALESCE(SUM(CASE WHEN good_qty IS NOT NULL AND good_qty > 0 THEN good_qty WHEN `condition`=\"good\" THEN quantity ELSE quantity END),0) AS available')
->where('type', 'classroom')
->where('school_year', $schoolYear)
->whereIn('name', $allowed);
@@ -49,6 +49,49 @@ class ClassPreparationInventoryService
}
}
$needsFallback = array_filter($inventoryMap, static fn ($v) => (int) $v === 0);
if (!empty($needsFallback)) {
$fallbackRows = DB::table('inventory_items')
->select('name AS item_name, COALESCE(SUM(CASE WHEN good_qty IS NOT NULL AND good_qty > 0 THEN good_qty WHEN `condition`=\"good\" THEN quantity ELSE quantity END),0) AS available')
->where('type', 'classroom')
->whereIn('name', array_keys($needsFallback))
->groupBy('name')
->get()
->toArray();
foreach ($fallbackRows as $r) {
$name = (string) ($r->item_name ?? '');
if ($name !== '' && isset($inventoryMap[$name])) {
$inventoryMap[$name] = max($inventoryMap[$name], (int) ($r->available ?? 0));
}
}
}
foreach ($inventoryMap as $name => $value) {
if ((int) $value !== 0) {
continue;
}
$goodQty = (int) DB::table('inventory_items')
->where('type', 'classroom')
->where('name', $name)
->sum('good_qty');
if ($goodQty > 0) {
$inventoryMap[$name] = $goodQty;
continue;
}
$qty = (int) DB::table('inventory_items')
->where('type', 'classroom')
->where('name', $name)
->sum('quantity');
if ($qty > 0) {
$inventoryMap[$name] = $qty;
}
}
return $inventoryMap;
}
}
@@ -9,7 +9,7 @@ class ClassPreparationRosterService
public function getClassSectionStudentCounts(string $schoolYear, string $semester, bool $limitToSemester): array
{
$query = DB::table('student_class as sc')
->select('sc.class_section_id, COUNT(DISTINCT sc.student_id) AS student_count', false)
->selectRaw('sc.class_section_id, COUNT(DISTINCT sc.student_id) AS student_count')
->join('students as s', 's.id', '=', 'sc.student_id')
->where('s.is_active', 1)
->where('sc.school_year', $schoolYear);
@@ -24,7 +24,7 @@ class ClassPreparationRosterService
public function getStudentCountForSection(string $schoolYear, string $semester, bool $limitToSemester, string $classSectionId): int
{
$query = DB::table('student_class as sc')
->select('COUNT(DISTINCT sc.student_id) AS cnt', false)
->selectRaw('COUNT(DISTINCT sc.student_id) AS cnt')
->join('students as s', 's.id', '=', 'sc.student_id')
->where('s.is_active', 1)
->where('sc.class_section_id', $classSectionId)
@@ -50,7 +50,7 @@ class CompetitionScoresSaveService
->where('competition_id', $competitionId)
->where('class_section_id', $classSectionId)
->get()
->map(fn ($row) => (array) $row)
->map(fn ($row) => $row->toArray())
->all();
$map = [];
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace App\Services;
use App\Services\Fees\FeeRefundCalculatorService;
class FeeCalculationService
{
public function __construct(
private FeeRefundCalculatorService $refundCalculator
) {
}
public function calculateRefund(array $students, int $parentId): float
{
$result = $this->refundCalculator->calculateRefund($students, $parentId);
return (float) ($result['refund_amount'] ?? 0);
}
}
+10 -6
View File
@@ -6,20 +6,24 @@ class FeeGradeService
{
public function normalizeGrade(?string $grade): string
{
return strtoupper(trim((string) $grade));
$normalized = strtoupper(trim((string) $grade));
return str_replace([' ', '-'], '', $normalized);
}
public function compareGrades(string $gradeA, string $gradeB): int
{
$valA = $this->getGradeLevel($gradeA);
$valB = $this->getGradeLevel($gradeB);
$normA = $this->normalizeGrade($gradeA);
$normB = $this->normalizeGrade($gradeB);
$valA = $this->getGradeLevel($normA);
$valB = $this->getGradeLevel($normB);
if ($valA !== $valB) {
return $valA <=> $valB;
}
preg_match('/\d+([A-Z]*)$/i', strtoupper($gradeA), $suffixA);
preg_match('/\d+([A-Z]*)$/i', strtoupper($gradeB), $suffixB);
preg_match('/\d+([A-Z]*)$/i', $normA, $suffixA);
preg_match('/\d+([A-Z]*)$/i', $normB, $suffixB);
return strcmp($suffixA[1] ?? '', $suffixB[1] ?? '');
}
@@ -35,7 +39,7 @@ class FeeGradeService
return 99;
}
if (preg_match('/^(\d+)([A-Z]*)$/i', $grade, $matches)) {
if (preg_match('/^(\d+)/', $grade, $matches)) {
return (int) $matches[1];
}
@@ -97,7 +97,7 @@ class FinancialSummaryService
$query = DB::table('additional_charges as ac')
->selectRaw('COALESCE(SUM(ac.amount), 0) AS amount')
->where('ac.school_year', $schoolYear)
->where('ac.status !=', 'void');
->where('ac.status', '!=', 'void');
if (!empty($dateFrom)) {
$query->whereRaw('DATE(ac.due_date) >= ?', [$dateFrom]);
@@ -115,11 +115,11 @@ class FinancialSummaryService
$query = DB::table('additional_charges as ac')
->selectRaw('ac.parent_id, COALESCE(SUM(ac.amount), 0) AS amount')
->where('ac.school_year', $schoolYear)
->where('ac.status !=', 'void')
->where('ac.status', '!=', 'void')
->where(function ($q) {
$q->whereNull('ac.invoice_id')
->orWhere('ac.invoice_id', 0)
->orWhere('ac.status !=', 'applied');
->orWhere('ac.status', '!=', 'applied');
})
->groupBy('ac.parent_id');
@@ -96,17 +96,14 @@ class FinancialUnpaidParentsService
}
$extraRows = DB::table('additional_charges as ac')
->selectRaw(
"ac.parent_id, u.firstname, u.lastname, u.email, COALESCE(SUM(ac.amount), 0) AS total_extra",
false
)
->selectRaw("ac.parent_id, u.firstname, u.lastname, u.email, COALESCE(SUM(ac.amount), 0) AS total_extra")
->leftJoin('users as u', 'u.id', '=', 'ac.parent_id')
->where('ac.school_year', $schoolYear)
->where('ac.status !=', 'void')
->where('ac.status', '!=', 'void')
->where(function ($q) {
$q->whereNull('ac.invoice_id')
->orWhere('ac.invoice_id', 0)
->orWhere('ac.status !=', 'applied');
->orWhere('ac.status', '!=', 'applied');
})
->groupBy('ac.parent_id')
->get()
@@ -167,7 +167,7 @@ class HomeworkTrackingService
->whereIn('tc.position', ['main', 'ta'])
->orderBy('cs.class_id', 'ASC')
->orderBy('cs.class_section_name', 'ASC')
->orderByRaw("FIELD(tc.position, 'main','ta')")
->orderByRaw("CASE tc.position WHEN 'main' THEN 0 WHEN 'ta' THEN 1 ELSE 2 END")
->orderBy('u.firstname', 'ASC')
->get();
@@ -65,13 +65,13 @@ class IncidentAnalysisService
}
if ($students[$studentKey]['last_incident'] === null) {
$students[$studentKey]['last_incident'] = $incident['incident_datetime'] ?? null;
$students[$studentKey]['last_incident'] = $this->formatIncidentDate($incident['incident_datetime'] ?? null);
}
$students[$studentKey]['logs'][] = [
'incident' => $incident['incident'] ?? '',
'incident_state' => $state,
'incident_datetime' => $incident['incident_datetime'] ?? null,
'incident_datetime' => $this->formatIncidentDate($incident['incident_datetime'] ?? null),
'open_description' => $incident['open_description'] ?? null,
'close_description' => $incident['close_description'] ?? null,
'cancel_description' => $incident['cancel_description'] ?? null,
@@ -89,4 +89,23 @@ class IncidentAnalysisService
return $studentRows;
}
private function formatIncidentDate(mixed $value): ?string
{
if ($value === null || $value === '') {
return null;
}
if ($value instanceof \DateTimeInterface) {
return $value->format('Y-m-d H:i:s');
}
$raw = (string) $value;
$ts = strtotime($raw);
if ($ts !== false) {
return date('Y-m-d H:i:s', $ts);
}
return $raw;
}
}
@@ -69,16 +69,20 @@ class IncidentLookupService
}
$rows = DB::table('users')
->select('id, firstname, lastname')
->select('id', 'firstname', 'lastname')
->whereIn('id', $userIds)
->get()
->map(fn ($row) => (array) $row)
->map(fn ($row) => $row instanceof \Illuminate\Contracts\Support\Arrayable ? $row->toArray() : (array) $row)
->all();
$map = [];
foreach ($rows as $row) {
$id = $row['id'] ?? $row['user_id'] ?? null;
if ($id === null) {
continue;
}
$name = trim((string) ($row['firstname'] ?? '') . ' ' . (string) ($row['lastname'] ?? ''));
$map[(int) $row['id']] = $name !== '' ? $name : ('User #' . $row['id']);
$map[(int) $id] = $name !== '' ? $name : ('User #' . $id);
}
return $map;
@@ -30,7 +30,7 @@ class InvoiceGenerationService
->where('parent_id', $parentId)
->where('school_year', $schoolYear)
->get()
->map(fn ($r) => (array) $r)
->map(fn ($r) => $r->toArray())
->all();
if (empty($enrollments)) {
@@ -40,7 +40,11 @@ class InvoiceManagementService
$parents = User::getUsersByRoleAndSchoolYear('parent', $schoolYear);
foreach ($parents as $parent) {
$students = Student::query()->where('parent_id', $parent['id'])->get()->map(fn ($r) => (array) $r)->all();
$students = Student::query()
->where('parent_id', $parent['id'])
->get()
->map(fn ($r) => $r->toArray())
->all();
$parentData = [
'parent_name' => trim(($parent['firstname'] ?? '') . ' ' . ($parent['lastname'] ?? '')),
@@ -106,7 +110,7 @@ class InvoiceManagementService
->where('student_id', $student['id'])
->where('school_year', $schoolYear)
->get()
->map(fn ($r) => (array) $r)
->map(fn ($r) => $r->toArray())
->all();
foreach ($enrollments as $enrollment) {
+5
View File
@@ -94,6 +94,10 @@ class ExamScoreService
if (!is_numeric($studentId)) {
continue;
}
$student = Student::query()->find((int) $studentId);
if (!$student) {
continue;
}
$rawScore = $data['score'] ?? null;
$normalizedScore = is_numeric($rawScore) ? (float) $rawScore : null;
@@ -106,6 +110,7 @@ class ExamScoreService
$payload = [
'student_id' => (int) $studentId,
'school_id' => $student->school_id,
'class_section_id' => $classSectionId,
'updated_by' => $updatedBy,
'score' => $normalizedScore,
+8 -2
View File
@@ -57,12 +57,13 @@ class HomeworkScoreService
->whereIn('semester', $semVariants)
->where('school_year', $schoolYear)
->get()
->map(fn ($row) => (array) $row)
->map(fn ($row) => $row->toArray())
->all();
$scoresMap = [];
foreach ($scoresRows as $row) {
$scoresMap[(int) $row['student_id']][(int) $row['homework_index']] = $row['score'];
$score = $row['score'] ?? null;
$scoresMap[(int) $row['student_id']][(int) $row['homework_index']] = is_numeric($score) ? (float) $score : $score;
}
foreach ($students as &$student) {
@@ -196,6 +197,10 @@ class HomeworkScoreService
->get();
foreach ($students as $student) {
$studentRow = Student::query()->find((int) $student->student_id);
if (!$studentRow) {
continue;
}
$exists = Homework::query()
->where('student_id', $student->student_id)
->where('homework_index', $nextIndex)
@@ -210,6 +215,7 @@ class HomeworkScoreService
Homework::query()->create([
'student_id' => (int) $student->student_id,
'school_id' => $studentRow->school_id,
'class_section_id' => $classSectionId,
'updated_by' => $updatedBy,
'homework_index' => $nextIndex,
@@ -50,12 +50,14 @@ class ParticipationScoreService
$scoreMap = [];
foreach ($scoresRows as $row) {
$scoreMap[(int) $row->student_id] = $row->score;
$score = $row->score;
$scoreMap[(int) $row->student_id] = is_numeric($score) ? (float) $score : $score;
}
foreach ($students as &$student) {
$score = $scoreMap[$student['student_id']] ?? '';
$student['scores'] = [
'score' => $scoreMap[$student['student_id']] ?? '',
'score' => $score,
];
}
unset($student);
+8 -2
View File
@@ -57,12 +57,13 @@ class ProjectScoreService
->where('semester', $semester)
->where('school_year', $schoolYear)
->get()
->map(fn ($row) => (array) $row)
->map(fn ($row) => $row->toArray())
->all();
$scoresMap = [];
foreach ($scoresRows as $row) {
$scoresMap[(int) $row['student_id']][(int) $row['project_index']] = $row['score'];
$score = $row['score'] ?? null;
$scoresMap[(int) $row['student_id']][(int) $row['project_index']] = is_numeric($score) ? (float) $score : $score;
}
foreach ($students as &$student) {
@@ -193,6 +194,10 @@ class ProjectScoreService
->get();
foreach ($students as $student) {
$studentRow = Student::query()->find((int) $student->student_id);
if (!$studentRow) {
continue;
}
$exists = Project::query()
->where('student_id', $student->student_id)
->where('project_index', $nextIndex)
@@ -207,6 +212,7 @@ class ProjectScoreService
Project::query()->create([
'student_id' => (int) $student->student_id,
'school_id' => $studentRow->school_id,
'class_section_id' => $classSectionId,
'updated_by' => $updatedBy,
'project_index' => $nextIndex,
+13 -2
View File
@@ -56,12 +56,13 @@ class QuizScoreService
->where('semester', $semester)
->where('school_year', $schoolYear)
->get()
->map(fn ($row) => (array) $row)
->map(fn ($row) => $row->toArray())
->all();
$scoresMap = [];
foreach ($scoresRows as $row) {
$scoresMap[(int) $row['student_id']][(int) $row['quiz_index']] = $row['score'];
$score = $row['score'] ?? null;
$scoresMap[(int) $row['student_id']][(int) $row['quiz_index']] = is_numeric($score) ? (float) $score : $score;
}
foreach ($students as &$student) {
@@ -135,6 +136,10 @@ class QuizScoreService
if (!is_array($quizData)) {
$quizData = [1 => $quizData];
}
$student = Student::query()->find((int) $studentId);
if (!$student) {
continue;
}
foreach ($quizData as $quizNumber => $score) {
if (!is_numeric($quizNumber)) {
continue;
@@ -152,6 +157,7 @@ class QuizScoreService
$payload = [
'student_id' => (int) $studentId,
'school_id' => $student->school_id,
'class_section_id' => $classSectionId,
'updated_by' => $updatedBy,
'quiz_index' => (int) $quizNumber,
@@ -190,6 +196,10 @@ class QuizScoreService
->get();
foreach ($students as $student) {
$studentRow = Student::query()->find((int) $student->student_id);
if (!$studentRow) {
continue;
}
$exists = Quiz::query()
->where('student_id', $student->student_id)
->where('quiz_index', $nextIndex)
@@ -204,6 +214,7 @@ class QuizScoreService
Quiz::query()->create([
'student_id' => (int) $student->student_id,
'school_id' => $studentRow->school_id,
'class_section_id' => $classSectionId,
'updated_by' => $updatedBy,
'quiz_index' => $nextIndex,
+17 -8
View File
@@ -111,14 +111,14 @@ class ScoreDashboardService
$sid = $student['student_id'];
$scoreRow = $scores[$sid] ?? null;
$student['scores'] = $scoreRow ? [
'homework' => $scoreRow->homework_avg,
'quiz' => $scoreRow->quiz_avg,
'project' => $scoreRow->project_avg,
'midterm_exam' => $scoreRow->midterm_exam_score,
'final_exam' => $scoreRow->final_exam_score,
'attendance' => $scoreRow->attendance_score,
'ptap' => $scoreRow->ptap_score,
'semester' => $scoreRow->semester_score,
'homework' => $this->normalizeScore($scoreRow->homework_avg),
'quiz' => $this->normalizeScore($scoreRow->quiz_avg),
'project' => $this->normalizeScore($scoreRow->project_avg),
'midterm_exam' => $this->normalizeScore($scoreRow->midterm_exam_score),
'final_exam' => $this->normalizeScore($scoreRow->final_exam_score),
'attendance' => $this->normalizeScore($scoreRow->attendance_score),
'ptap' => $this->normalizeScore($scoreRow->ptap_score),
'semester' => $this->normalizeScore($scoreRow->semester_score),
] : [];
$student['comments'] = $commentMap[$sid] ?? [];
}
@@ -267,4 +267,13 @@ class ScoreDashboardService
'selectedYear' => $schoolYear,
];
}
private function normalizeScore(mixed $value): mixed
{
if ($value === null || $value === '') {
return $value;
}
return is_numeric($value) ? (float) $value : $value;
}
}
+1 -1
View File
@@ -73,7 +73,7 @@ class UserManagementService
try {
DB::transaction(function () use ($userId, $user) {
UserRole::query()->where('user_id', $userId)->delete();
UserRole::query()->where('user_id', $userId)->forceDelete();
$user->delete();
});
} catch (\Throwable $e) {