'integer', 'parent_id' => 'integer', 'current_level_id' => 'integer', 'promoted_level_id' => 'integer', 'passed_current_level' => 'boolean', 'final_average' => 'float', 'attendance_ok' => 'boolean', 'enrollment_required' => 'boolean', 'enrollment_id' => 'integer', 'parent_notified_at' => 'datetime', 'enrollment_deadline' => 'date', 'enrollment_started_at' => 'datetime', 'enrollment_completed_at' => 'datetime', 'promotion_finalized_at' => 'datetime', 'info_confirmed' => 'boolean', 'documents_uploaded' => 'boolean', 'agreement_accepted' => 'boolean', 'payment_completed' => 'boolean', 'updated_by' => 'integer', ]; public function student(): BelongsTo { return $this->belongsTo(Student::class, 'student_id'); } public function parent(): BelongsTo { return $this->belongsTo(User::class, 'parent_id'); } public function enrollment(): BelongsTo { return $this->belongsTo(Enrollment::class, 'enrollment_id'); } public function scopeForNextYear(Builder $q, string $year): Builder { return $q->where('next_school_year', $year); } public function scopeStatus(Builder $q, string $status): Builder { return $q->where('promotion_status', $status); } public function scopeForStudent(Builder $q, int $studentId): Builder { return $q->where('student_id', $studentId); } public function scopeForParent(Builder $q, int $parentId): Builder { return $q->where('parent_id', $parentId); } /** * Statuses the parent portal should treat as "actionable" (parent * can still complete enrollment). */ public static function parentActionableStatuses(): array { return [ self::STATUS_ELIGIBLE, self::STATUS_AWAITING_PARENT, self::STATUS_ENROLLMENT_STARTED, ]; } /** * Statuses considered "open" for the next school year (admin views * may want to filter on these). */ public static function openStatuses(): array { return [ self::STATUS_NOT_REVIEWED, self::STATUS_ELIGIBLE, self::STATUS_AWAITING_PARENT, self::STATUS_ENROLLMENT_STARTED, self::STATUS_CONDITIONAL, self::STATUS_ON_HOLD, ]; } public function isFinalized(): bool { return in_array( $this->promotion_status, [ self::STATUS_PROMOTED_AND_ENROLLED, self::STATUS_REPEATED, self::STATUS_WITHDRAWN, self::STATUS_GRADUATED, self::STATUS_NOT_ENROLLED, ], true ); } public function enrollmentChecklistComplete(): bool { // Mirrors plan section 8 – parent-side completion criteria. // Payment is only required when payment_completed has been // explicitly set; treat null/false as still required by default. return (bool) $this->info_confirmed && (bool) $this->documents_uploaded && (bool) $this->agreement_accepted && (bool) $this->payment_completed; } }