add notifications logic and add support of both JWT and Sanctum

This commit is contained in:
root
2026-03-11 01:20:31 -04:00
parent f6be51576c
commit 182036cc41
141 changed files with 8685 additions and 648 deletions
@@ -0,0 +1,68 @@
<?php
namespace Tests\Unit\Services\Attendance;
use App\Services\Attendance\AttendanceAutoPublishJobService;
use App\Services\Attendance\AttendanceAutoPublishService;
use DateTimeImmutable;
use DateTimeZone;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class AttendanceAutoPublishJobServiceTest extends TestCase
{
use RefreshDatabase;
public function test_run_publishes_due_records(): void
{
$autoPublish = new AttendanceAutoPublishService();
$service = new AttendanceAutoPublishJobService($autoPublish);
$now = new DateTimeImmutable('2025-03-01 10:00:00', new DateTimeZone('UTC'));
$cutoff = $autoPublish->secondSundayBackwardDate($now);
DB::table('attendance_day')->insert([
[
'class_section_id' => 1,
'date' => '2025-03-01',
'status' => 'submitted',
'auto_publish_at' => '2025-03-01 09:00:00',
'semester' => 'Spring',
'school_year' => '2024-2025',
],
[
'class_section_id' => 2,
'date' => $cutoff,
'status' => 'submitted',
'auto_publish_at' => null,
'semester' => 'Spring',
'school_year' => '2024-2025',
],
[
'class_section_id' => 3,
'date' => '2025-02-20',
'status' => 'draft',
'auto_publish_at' => null,
'semester' => 'Spring',
'school_year' => '2024-2025',
],
]);
$result = $service->run($now);
$this->assertSame(2, $result['published']);
$this->assertDatabaseHas('attendance_day', [
'class_section_id' => 1,
'status' => 'published',
]);
$this->assertDatabaseHas('attendance_day', [
'class_section_id' => 2,
'status' => 'published',
]);
$this->assertDatabaseHas('attendance_day', [
'class_section_id' => 3,
'status' => 'draft',
]);
}
}
@@ -0,0 +1,29 @@
<?php
namespace Tests\Unit\Services\Attendance;
use App\Services\Attendance\AttendanceAutoPublishService;
use DateTimeImmutable;
use Tests\TestCase;
class AttendanceAutoPublishServiceTest extends TestCase
{
public function test_second_sunday_after_end_of_day(): void
{
$service = new AttendanceAutoPublishService();
$result = $service->secondSundayAfterEndOfDay('2025-02-03', 'UTC');
$this->assertSame('2025-02-16 23:59:59', $result);
}
public function test_second_sunday_backward_date(): void
{
$service = new AttendanceAutoPublishService();
$now = new DateTimeImmutable('2025-02-16 10:00:00', new \DateTimeZone('UTC'));
$result = $service->secondSundayBackwardDate($now, 'UTC');
$this->assertSame('2025-02-02', $result);
}
}
@@ -0,0 +1,79 @@
<?php
namespace Tests\Unit\Services\Attendance;
use App\Models\AttendanceTracking;
use App\Services\Attendance\AttendanceConsequenceService;
use App\Services\EmailService;
use App\Services\Notifications\UserNotificationDispatchService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;
class AttendanceConsequenceServiceTest extends TestCase
{
use RefreshDatabase;
public function test_send_follow_up_requires_parent_email(): void
{
$service = new AttendanceConsequenceService(
Mockery::mock(EmailService::class),
Mockery::mock(UserNotificationDispatchService::class)
);
$result = $service->sendFollowUp([
'parent' => ['user_id' => 5],
]);
$this->assertFalse($result['ok']);
}
public function test_send_follow_up_marks_tracking_and_notifies(): void
{
\Illuminate\Support\Facades\DB::table('students')->insert([
'id' => 1,
'school_id' => 1,
'parent_id' => 1,
'firstname' => 'Student',
'lastname' => 'One',
'dob' => '2015-01-01',
'age' => 10,
'gender' => 'Male',
'is_active' => 1,
'photo_consent' => 1,
'year_of_registration' => '2025',
'school_year' => '2025-2026',
]);
AttendanceTracking::query()->create([
'student_id' => 1,
'date' => now(),
'is_reported' => 1,
'reason' => 'ABS_2',
'semester' => 'Fall',
'school_year' => '2025-2026',
]);
$email = Mockery::mock(EmailService::class);
$email->shouldReceive('send')->once()->andReturn(true);
$notifier = Mockery::mock(UserNotificationDispatchService::class);
$notifier->shouldReceive('notifyUser')->once();
$service = new AttendanceConsequenceService($email, $notifier);
$result = $service->sendFollowUp([
'student_id' => 1,
'parent' => ['email' => 'parent@example.com', 'user_id' => 5],
'student' => ['firstname' => 'A', 'lastname' => 'B'],
'tracking_id' => 1,
'html' => '<p>Test</p>',
]);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('attendance_tracking', [
'id' => 1,
'is_notified' => 1,
]);
}
}
@@ -0,0 +1,68 @@
<?php
namespace Tests\Unit\Services\Attendance;
use App\Services\Attendance\AttendanceDailySummaryService;
use App\Services\EmailService;
use App\Services\Notifications\UserNotificationDispatchService;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Mockery;
use Tests\TestCase;
class AttendanceDailySummaryServiceTest extends TestCase
{
use RefreshDatabase;
public function test_send_absentees_summary_notifies_parent(): void
{
Carbon::setTestNow(Carbon::parse('2025-02-10 08:00:00'));
DB::table('users')->insert([
'id' => 5,
'firstname' => 'Parent',
'lastname' => 'One',
'email' => 'parent@example.com',
'status' => 'Active',
]);
DB::table('students')->insert([
'id' => 10,
'school_id' => 1,
'parent_id' => 5,
'firstname' => 'Student',
'lastname' => 'One',
'dob' => '2015-01-01',
'age' => 10,
'gender' => 'Male',
'is_active' => 1,
'photo_consent' => 1,
'year_of_registration' => '2025',
'school_year' => '2024-2025',
]);
DB::table('attendance_data')->insert([
'class_id' => 1,
'class_section_id' => 1,
'student_id' => 10,
'school_id' => 'S1',
'date' => '2025-02-10',
'status' => 'absent',
'semester' => 'Spring',
'school_year' => '2024-2025',
]);
$notifier = Mockery::mock(UserNotificationDispatchService::class);
$notifier->shouldReceive('notifyUser')->once();
$email = Mockery::mock(EmailService::class);
$email->shouldReceive('send')->once()->andReturn(true);
$service = new AttendanceDailySummaryService($notifier, $email);
$count = $service->sendAbsenteesSummary();
$this->assertSame(1, $count);
}
}
@@ -39,4 +39,12 @@ class AttendancePolicyServiceTest extends TestCase
$this->assertTrue($isAdmin);
}
public function test_can_manage_early_dismissals_for_teacher(): void
{
$service = new AttendancePolicyService();
$allowed = $service->canManageEarlyDismissals(['Teacher']);
$this->assertTrue($allowed);
}
}
@@ -95,7 +95,8 @@ class AttendanceQueryServiceTest extends TestCase
new \App\Models\AttendanceData(),
new \App\Models\Student(),
new \App\Services\Attendance\AttendanceRecordSyncService(new \App\Models\AttendanceRecord())
)
),
new \App\Services\Attendance\AttendanceAutoPublishService()
),
new \App\Services\Attendance\AttendanceRecordSyncService(new \App\Models\AttendanceRecord())
),
@@ -0,0 +1,68 @@
<?php
namespace Tests\Unit\Services\Attendance;
use App\Services\Attendance\AttendanceSummaryRebuildService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class AttendanceSummaryRebuildServiceTest extends TestCase
{
use RefreshDatabase;
public function test_rebuild_inserts_summary_rows(): void
{
DB::table('attendance_data')->insert([
[
'class_id' => 1,
'class_section_id' => 10,
'student_id' => 1,
'school_id' => 'S1',
'date' => '2025-02-01',
'status' => 'present',
'semester' => 'Spring',
'school_year' => '2024-2025',
],
[
'class_id' => 1,
'class_section_id' => 10,
'student_id' => 1,
'school_id' => 'S1',
'date' => '2025-02-02',
'status' => 'absent',
'semester' => 'Spring',
'school_year' => '2024-2025',
],
[
'class_id' => 1,
'class_section_id' => 11,
'student_id' => 2,
'school_id' => 'S1',
'date' => '2025-02-02',
'status' => 'late',
'semester' => 'Spring',
'school_year' => '2024-2025',
],
]);
$service = new AttendanceSummaryRebuildService();
$result = $service->rebuild();
$this->assertSame(2, $result['inserted']);
$this->assertDatabaseHas('attendance_record', [
'student_id' => 1,
'total_presence' => 1,
'total_absence' => 1,
'total_late' => 0,
'total_attendance' => 2,
]);
$this->assertDatabaseHas('attendance_record', [
'student_id' => 2,
'total_presence' => 0,
'total_absence' => 0,
'total_late' => 1,
'total_attendance' => 1,
]);
}
}
@@ -39,7 +39,8 @@ class TeacherAttendanceSubmissionServiceTest extends TestCase
new \App\Models\AttendanceData(),
new \App\Models\Student(),
new \App\Services\Attendance\AttendanceRecordSyncService(new \App\Models\AttendanceRecord())
)
),
new \App\Services\Attendance\AttendanceAutoPublishService()
);
$this->expectException(\RuntimeException::class);