travelTo('2025-10-05 10:00:00'); $this->seedApiTestConfig(self::E2E_SCHOOL_YEAR, self::E2E_SEMESTER); DB::table('configuration')->updateOrInsert( ['config_key' => 'fall_semester_start'], ['config_value' => '2025-09-01'] ); DB::table('configuration')->updateOrInsert( ['config_key' => 'spring_semester_start'], ['config_value' => '2026-01-15'] ); DB::table('configuration')->updateOrInsert( ['config_key' => 'last_school_day'], ['config_value' => '2026-06-15'] ); } protected function seedClosedSchoolYear(): void { SchoolYear::query()->updateOrCreate( ['name' => self::E2E_PREV_SCHOOL_YEAR], [ 'start_date' => '2024-09-01', 'end_date' => '2025-06-30', 'status' => SchoolYear::STATUS_CLOSED, 'is_current' => false, ] ); } protected function seedClassSection( int $classSectionId = 701, string $name = '5A', int $classId = 5 ): int { DB::table('classSection')->insert([ 'class_id' => $classId, 'class_section_id' => $classSectionId, 'class_section_name' => $name, 'semester' => self::E2E_SEMESTER, 'school_year' => self::E2E_SCHOOL_YEAR, ]); return $classSectionId; } protected function seedTeacherClassAssignment(int $teacherId, int $classSectionId, string $position = 'main'): void { DB::table('teacher_class')->insert([ 'teacher_id' => $teacherId, 'class_section_id' => $classSectionId, 'position' => $position, 'school_year' => self::E2E_SCHOOL_YEAR, 'semester' => self::E2E_SEMESTER, 'created_at' => now(), 'updated_at' => now(), ]); } protected function seedStudentClassAssignment(int $studentId, int $classSectionId): void { DB::table('student_class')->insert([ 'student_id' => $studentId, 'class_section_id' => $classSectionId, 'school_year' => self::E2E_SCHOOL_YEAR, 'semester' => self::E2E_SEMESTER, 'is_event_only' => 0, 'created_at' => now(), 'updated_at' => now(), ]); } /** * @return array{teacher: User, class_section_id: int, student_id: int, parent_id: int} */ protected function seedTeacherClassWithStudent(?int $classSectionId = null): array { $this->seedE2EConfiguration(); $classSectionId ??= $this->seedClassSection(801, '3A', 3); $teacher = $this->createApiUserWithRole('teacher', [ 'firstname' => 'Tara', 'lastname' => 'Teacher', 'email' => 'e2e.teacher.' . uniqid('', true) . '@example.test', ]); $this->seedTeacherClassAssignment($teacher->id, $classSectionId); $parent = $this->createApiUserWithRole('parent', [ 'firstname' => 'Parent', 'lastname' => 'Fixture', 'email' => 'e2e.parent.' . uniqid('', true) . '@example.test', ]); $studentId = DB::table('students')->insertGetId([ 'school_id' => 'S-E2E-' . random_int(1000, 9999), 'firstname' => 'Kai', 'lastname' => 'Student', 'dob' => '2014-09-01', 'age' => 11, 'gender' => 'Male', 'photo_consent' => 1, 'parent_id' => $parent->id, 'year_of_registration' => '2025', 'school_year' => self::E2E_SCHOOL_YEAR, 'semester' => self::E2E_SEMESTER, 'is_active' => 1, ]); $this->seedStudentClassAssignment($studentId, $classSectionId); return [ 'teacher' => $teacher, 'class_section_id' => $classSectionId, 'student_id' => $studentId, 'parent_id' => $parent->id, 'parent' => $parent, ]; } protected function createParentAccountViaApi(array $overrides = []): int { $parentRoleId = (int) Role::query()->where('name', 'parent')->value('id'); $unique = str_replace('.', '', uniqid('', true)); $payload = array_merge([ 'firstname' => 'E2E', 'lastname' => 'Parent', 'gender' => 'Female', 'cellphone' => '5551234567', 'email' => "e2e.parent.$unique@example.test", 'address_street' => '42 Cedar Lane', 'city' => 'Brooklyn', 'state' => 'NY', 'zip' => '11201', 'accept_school_policy' => true, 'role_id' => $parentRoleId, 'password' => 'secret123', 'semester' => self::E2E_SEMESTER, 'school_year' => self::E2E_SCHOOL_YEAR, 'user_type' => 'primary', 'status' => 'Active', 'is_verified' => true, ], $overrides); $response = $this->postJson('/api/v1/users', $payload); $response->assertStatus(201)->assertJsonPath('ok', true); return (int) $response->json('user_id'); } protected function createStudentViaApi(int $parentId, array $overrides = [], bool $firstChild = true): int { $unique = str_replace('.', '', uniqid('', true)); $payload = array_merge([ 'firstname' => 'E2E', 'lastname' => 'Student', 'dob' => '2015-05-10', 'age' => 10, 'gender' => 'Male', 'is_active' => true, 'registration_grade' => '5', 'is_new' => true, 'photo_consent' => true, 'parent_id' => $parentId, 'registration_date' => '2025-09-01', 'tuition_paid' => false, 'semester' => self::E2E_SEMESTER, 'year_of_registration' => 2025, 'school_year' => self::E2E_SCHOOL_YEAR, ], $overrides); if ($firstChild) { $payload = array_merge($payload, [ 'name' => $overrides['name'] ?? 'E2E Parent', 'cellphone' => $overrides['cellphone'] ?? '5551234567', 'email' => $overrides['email'] ?? "e2e.contact.$unique@example.test", 'relation' => $overrides['relation'] ?? 'Mother', ]); } $response = $this->postJson('/api/v1/students', $payload); $response->assertStatus(201)->assertJsonPath('ok', true); return (int) $response->json('student.id'); } protected function assignStudentToClassViaApi(int $studentId, int $classSectionId): TestResponse { return $this->postJson('/api/v1/students/assign-class', [ 'student_id' => $studentId, 'class_section_id' => [$classSectionId], ]); } protected function postEnrollmentStatuses(array $studentStatusMap): TestResponse { return $this->post( '/api/v1/administrator/enrollment-withdrawal/update-statuses?' . http_build_query(['enrollment_status' => $studentStatusMap]), [] ); } protected function seedInvoiceForParent(int $parentId, array $overrides = []): int { return DB::table('invoices')->insertGetId(array_merge([ 'parent_id' => $parentId, 'invoice_number' => 'INV-E2E-' . random_int(1000, 9999), 'total_amount' => 500.00, 'balance' => 500.00, 'paid_amount' => 0, 'has_discount' => 0, 'issue_date' => '2025-09-01', 'due_date' => '2025-10-01', 'status' => 'unpaid', 'school_year' => self::E2E_SCHOOL_YEAR, 'semester' => self::E2E_SEMESTER, 'created_at' => now(), 'updated_at' => now(), ], $overrides)); } protected function seedPriorYearUnpaidInvoice(int $parentId): int { return DB::table('invoices')->insertGetId([ 'parent_id' => $parentId, 'invoice_number' => 'INV-PRIOR-' . random_int(1000, 9999), 'total_amount' => 200.00, 'balance' => 150.00, 'paid_amount' => 50.00, 'has_discount' => 0, 'issue_date' => '2024-09-01', 'due_date' => '2024-10-01', 'status' => 'unpaid', 'school_year' => self::E2E_PREV_SCHOOL_YEAR, 'semester' => self::E2E_SEMESTER, 'created_at' => now(), 'updated_at' => now(), ]); } protected function seedDiscountVoucher(): int { return DB::table('discount_vouchers')->insertGetId([ 'code' => 'E2E10-' . random_int(100, 999), 'discount_type' => 'fixed', 'discount_value' => 50, 'max_uses' => 100, 'times_used' => 0, 'is_active' => 1, ]); } }