*/ use HasFactory, Notifiable; /** * Get the attributes that should be cast. * * @return array */ protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'password' => 'hashed', 'subscription_expires_at' => 'datetime', ]; } public function isAdmin(): bool { return $this->role === 'admin'; } public function isEmployer(): bool { return $this->role === 'employer'; } public function hasActiveSubscription(): bool { return $this->subscription_status === 'active' && ($this->subscription_expires_at === null || $this->subscription_expires_at > now()); } protected $appends = [ 'rating', 'reviews_count', ]; public function employerReviews() { return $this->hasMany(EmployerReview::class, 'employer_id'); } public function getRatingAttribute() { if ($this->role !== 'employer') { return 0.0; } $dbReviews = $this->employerReviews; $count = $dbReviews->count(); return $count > 0 ? round($dbReviews->avg('rating'), 1) : 0.0; } public function getReviewsCountAttribute() { if ($this->role !== 'employer') { return 0; } return $this->employerReviews()->count(); } public function subscription() { return $this->hasOne(Subscription::class); } public function emiratesIdVerification() { return $this->hasOne(EmployerProfile::class, 'user_id'); } public function employerProfile() { return $this->hasOne(EmployerProfile::class, 'user_id'); } public function sponsor() { return $this->hasOne(Sponsor::class, 'email', 'email'); } public function announcements() { return $this->hasMany(Announcement::class, 'employer_id'); } public function payments() { return $this->hasMany(Payment::class, 'user_id'); } public static function checkAndActivatePendingSubscriptions($userId) { $user = self::find($userId); if (!$user) { return; } // 1. Check if the active subscription has expired $activeSub = \App\Models\Subscription::where('user_id', $user->id) ->where('status', 'active') ->first(); if ($activeSub && $activeSub->expires_at && $activeSub->expires_at <= now()) { $activeSub->update(['status' => 'expired']); $activeSub = null; } // 2. If no active subscription exists, activate the next pending one if (!$activeSub) { $pendingSub = \App\Models\Subscription::where('user_id', $user->id) ->where('status', 'pending') ->orderBy('starts_at', 'asc') ->first(); if ($pendingSub) { // If it is ready to start (i.e. starts_at is <= now()) if ($pendingSub->starts_at <= now()) { $duration = 30; // default 30 days $plan = \App\Models\Plan::find($pendingSub->plan_id); if ($plan) { $duration = strtolower($plan->duration) === 'yearly' ? 365 : 30; } $pendingSub->starts_at = now(); $pendingSub->expires_at = now()->addDays($duration); } $pendingSub->status = 'active'; $pendingSub->save(); // Update user details $user->subscription_status = 'active'; $user->subscription_expires_at = $pendingSub->expires_at; $user->save(); // Recursive check for sequential queueing activation self::checkAndActivatePendingSubscriptions($userId); } else { // Set to expired only if they previously had a subscription $hasPriorSub = \App\Models\Subscription::where('user_id', $user->id)->exists(); if ($hasPriorSub) { $user->subscription_status = 'expired'; $user->save(); } } } } /** * Get the count of unique workers contacted or hired by the employer. */ public static function contactedWorkersCount($employerId) { $conversationWorkerIds = \App\Models\Conversation::where('employer_id', $employerId)->pluck('worker_id')->toArray(); $offerWorkerIds = \App\Models\JobOffer::where('employer_id', $employerId)->pluck('worker_id')->toArray(); $applicationWorkerIds = \App\Models\JobApplication::whereIn('status', ['shortlisted', 'contacted', 'interview scheduled', 'interview_scheduled', 'selected', 'hired']) ->whereHas('jobPost', function ($query) use ($employerId) { $query->where('employer_id', $employerId); }) ->pluck('worker_id') ->toArray(); $uniqueWorkerIds = array_unique(array_merge($conversationWorkerIds, $offerWorkerIds, $applicationWorkerIds)); return count($uniqueWorkerIds); } /** * Check if the employer is allowed to contact the given worker based on plan limits. */ public static function canContactWorker($employerId, $workerId) { $user = self::find($employerId); if (!$user) { return false; } // 1. If already contacted, it does not consume an additional contact slot $alreadyContacted = \App\Models\Conversation::where('employer_id', $employerId) ->where('worker_id', $workerId) ->exists() || \App\Models\JobOffer::where('employer_id', $employerId) ->where('worker_id', $workerId) ->exists() || \App\Models\JobApplication::whereIn('status', ['shortlisted', 'contacted', 'interview scheduled', 'interview_scheduled', 'selected', 'hired']) ->where('worker_id', $workerId) ->whereHas('jobPost', function ($query) use ($employerId) { $query->where('employer_id', $employerId); }) ->exists(); if ($alreadyContacted) { return true; } // 2. Retrieve plan limit settings $activeSub = \App\Models\Subscription::where('user_id', $employerId) ->where('status', 'active') ->first(); $planId = $activeSub ? $activeSub->plan_id : 'basic'; $plan = \App\Models\Plan::find($planId); if ($plan && !$plan->unlimited_contacts) { $maxContacts = $plan->max_contact_people; $currentContactsCount = self::contactedWorkersCount($employerId); if ($currentContactsCount >= $maxContacts) { return false; } } return true; } }