info('Starting automated reminder notification system...'); $this->info('1. Checking Worker Documents...'); $this->checkWorkerDocuments(); $this->info('2. Checking Employer Profiles (Emirates ID Expiry)...'); $this->checkEmployerProfiles(); $this->info('3. Checking Sponsors (Emirates ID and License Expiry)...'); $this->checkSponsors(); $this->info('4. Checking Pending Hire Confirmations (Employer)...'); $this->checkHireConfirmations(); $this->info('5. Checking Pending Joining Confirmations (Worker)...'); $this->checkJoiningConfirmations(); $this->info('6. Checking Pending Direct Job Offers...'); $this->checkJobOffers(); $this->info('Automated reminder system run complete!'); } private function getReminderLevel(int $days): ?string { if ($days === 7) { return '7_days'; } elseif ($days === 3) { return '3_days'; } elseif ($days === 1) { return '1_day'; } return null; } private function alreadySent($notifiable, string $eventType, $entity, string $reminderLevel): bool { return \App\Models\ReminderLog::where('user_type', get_class($notifiable)) ->where('user_id', $notifiable->id) ->where('event_type', $eventType) ->where('entity_type', get_class($entity)) ->where('entity_id', $entity->id) ->where('reminder_level', $reminderLevel) ->exists(); } private function logReminder($notifiable, string $eventType, $entity, string $reminderLevel, string $channel): void { \App\Models\ReminderLog::create([ 'user_type' => get_class($notifiable), 'user_id' => $notifiable->id, 'event_type' => $eventType, 'entity_type' => get_class($entity), 'entity_id' => $entity->id, 'reminder_level' => $reminderLevel, 'channel' => $channel, 'sent_at' => now(), ]); } private function checkWorkerDocuments() { $workerDocs = \App\Models\WorkerDocument::whereNotNull('expiry_date')->get(); foreach ($workerDocs as $doc) { $worker = $doc->worker; if (!$worker) continue; $expiry = Carbon::parse($doc->expiry_date); $days = (int) now()->startOfDay()->diffInDays($expiry->startOfDay(), false); $level = $this->getReminderLevel($days); if (!$level) continue; if ($this->alreadySent($worker, 'document_expiry', $doc, $level)) continue; $this->info("Sending {$level} reminder to worker {$worker->name} for document {$doc->type} expiry."); $worker->notify(new \App\Notifications\DocumentExpiryNotification( ucfirst($doc->type), $doc->expiry_date, $days, $level )); $this->logReminder($worker, 'document_expiry', $doc, $level, 'all'); } } private function checkEmployerProfiles() { $profiles = \App\Models\EmployerProfile::whereNotNull('emirates_id_expiry')->get(); foreach ($profiles as $profile) { $user = \App\Models\User::find($profile->user_id); if (!$user) continue; $expiry = Carbon::parse($profile->emirates_id_expiry); $days = (int) now()->startOfDay()->diffInDays($expiry->startOfDay(), false); $level = $this->getReminderLevel($days); if (!$level) continue; if ($this->alreadySent($user, 'document_expiry', $profile, $level)) continue; $this->info("Sending {$level} reminder to employer {$user->name} for Emirates ID expiry."); $user->notify(new \App\Notifications\DocumentExpiryNotification( 'Emirates ID', $profile->emirates_id_expiry, $days, $level )); $this->logReminder($user, 'document_expiry', $profile, $level, 'all'); } } private function checkSponsors() { $sponsors = \App\Models\Sponsor::all(); foreach ($sponsors as $sponsor) { // 1. Check Emirates ID expiry if ($sponsor->emirates_id_expiry) { $expiry = Carbon::parse($sponsor->emirates_id_expiry); $days = (int) now()->startOfDay()->diffInDays($expiry->startOfDay(), false); $level = $this->getReminderLevel($days); if ($level && !$this->alreadySent($sponsor, 'document_expiry_emirates', $sponsor, $level)) { $this->info("Sending {$level} reminder to sponsor {$sponsor->full_name} for Emirates ID expiry."); $sponsor->notify(new \App\Notifications\DocumentExpiryNotification( 'Emirates ID', $sponsor->emirates_id_expiry, $days, $level )); $this->logReminder($sponsor, 'document_expiry_emirates', $sponsor, $level, 'all'); } } // 2. Check License expiry if ($sponsor->license_expiry) { $expiry = Carbon::parse($sponsor->license_expiry); $days = (int) now()->startOfDay()->diffInDays($expiry->startOfDay(), false); $level = $this->getReminderLevel($days); if ($level && !$this->alreadySent($sponsor, 'document_expiry_license', $sponsor, $level)) { $this->info("Sending {$level} reminder to sponsor {$sponsor->full_name} for License expiry."); $sponsor->notify(new \App\Notifications\DocumentExpiryNotification( 'Trade License', $sponsor->license_expiry->toDateString(), $days, $level )); $this->logReminder($sponsor, 'document_expiry_license', $sponsor, $level, 'all'); } } } } private function checkHireConfirmations() { $applications = \App\Models\JobApplication::where('status', 'selected') ->with('jobPost.employer') ->get(); foreach ($applications as $app) { $job = $app->jobPost; if (!$job || !$job->start_date) continue; $employer = $job->employer; if (!$employer) continue; $worker = $app->worker; if (!$worker) continue; $startDate = Carbon::parse($job->start_date); $days = (int) now()->startOfDay()->diffInDays($startDate->startOfDay(), false); $level = $this->getReminderLevel($days); if (!$level) continue; if ($this->alreadySent($employer, 'hire_confirmation', $app, $level)) continue; $this->info("Sending {$level} reminder to employer {$employer->name} to confirm hiring for job {$job->title}."); $employer->notify(new \App\Notifications\HireConfirmationNotification( $job->title, $worker->name, $days, $level, $app->id )); $this->logReminder($employer, 'hire_confirmation', $app, $level, 'all'); } } private function checkJoiningConfirmations() { $applications = \App\Models\JobApplication::where('status', 'hired') ->whereNull('joining_confirmed_at') ->with(['jobPost.employer', 'worker']) ->get(); foreach ($applications as $app) { $job = $app->jobPost; if (!$job || !$job->start_date) continue; $worker = $app->worker; if (!$worker) continue; $employer = $job->employer; $employerName = $employer ? $employer->name : 'Employer'; $startDate = Carbon::parse($job->start_date); $days = (int) now()->startOfDay()->diffInDays($startDate->startOfDay(), false); $level = $this->getReminderLevel($days); if (!$level) continue; if ($this->alreadySent($worker, 'joining_confirmation', $app, $level)) continue; $this->info("Sending {$level} reminder to worker {$worker->name} to confirm joining for job {$job->title}."); $worker->notify(new \App\Notifications\JoiningConfirmationNotification( $job->title, $employerName, $days, $level, $app->id )); $this->logReminder($worker, 'joining_confirmation', $app, $level, 'all'); } } private function checkJobOffers() { $offers = \App\Models\JobOffer::where('status', 'pending') ->with(['worker', 'employer']) ->get(); foreach ($offers as $offer) { $worker = $offer->worker; if (!$worker) continue; $employer = $offer->employer; $employerName = $employer ? $employer->name : 'Employer'; if (!$offer->work_date) continue; $workDate = Carbon::parse($offer->work_date); $days = (int) now()->startOfDay()->diffInDays($workDate->startOfDay(), false); $level = $this->getReminderLevel($days); if (!$level) continue; if ($this->alreadySent($worker, 'pending_confirmation', $offer, $level)) continue; $this->info("Sending {$level} reminder to worker {$worker->name} for pending direct offer from {$employerName}."); $worker->notify(new \App\Notifications\PendingConfirmationNotification( 'accept_offer', "Pending Job Offer", "You have a pending job offer from {$employerName} starting on {$offer->work_date->toDateString()}.", $days, $level, get_class($offer), $offer->id )); $this->logReminder($worker, 'pending_confirmation', $offer, $level, 'all'); } } }