option('test-email')) { return $this->sendTestEmail($this->option('test-email')); } $today = Carbon::today(); $tomorrow = Carbon::tomorrow(); $activities = ClientProjectActivities::query() ->with(['client:id,name,customer_id', 'user:id,name,email']) ->whereNull('completed_at') ->whereNotNull('estimated_completed_at') ->whereDate('estimated_completed_at', '<=', $tomorrow) ->orderBy('estimated_completed_at') ->get(); $activities ->groupBy('user_id') ->each(function ($userActivities, $userId) use ($today, $tomorrow) { $user = $userActivities->first()->user; if (! $user || empty($user->email)) { $this->warn("Skipping project activity reminder for user_id={$userId}; no valid email found."); return; } $overdue = $userActivities->filter(function (ClientProjectActivities $activity) use ($today) { return $activity->estimated_completed_at->lt($today); }); $dueToday = $userActivities->filter(function (ClientProjectActivities $activity) use ($today) { return $activity->estimated_completed_at->isSameDay($today); }); $dueTomorrow = $userActivities->filter(function (ClientProjectActivities $activity) use ($tomorrow) { return $activity->estimated_completed_at->isSameDay($tomorrow); }); if ($overdue->isEmpty() && $dueToday->isEmpty()) { return; } $mailData = [ 'user_name' => $user->name, 'role_label' => 'Activity Owner', 'overdue' => $overdue->map(fn (ClientProjectActivities $activity) => $this->formatActivity($activity, $today))->values()->all(), 'due_today' => $dueToday->map(fn (ClientProjectActivities $activity) => $this->formatActivity($activity, $today))->values()->all(), 'due_tomorrow' => $dueTomorrow->map(fn (ClientProjectActivities $activity) => $this->formatActivity($activity, $today))->values()->all(), ]; Mail::send('mail.project_activity_reminder', ['data' => $mailData], function ($message) use ($user) { $message->to($user->email, $user->name) ->subject('Pending Project Activity Reminder'); }); $this->info("Sent pending project activity reminder to {$user->email} ({$user->name})."); }); return self::SUCCESS; } catch (\Throwable $e) { Log::error('Error sending pending project activity reminders: '.$e->getMessage(), [ 'trace' => $e->getTraceAsString(), ]); $this->error('Failed to send pending project activity reminders.'); return self::FAILURE; } } private function formatActivity(ClientProjectActivities $activity, Carbon $today): array { $estimatedDate = $activity->estimated_completed_at->copy()->startOfDay(); return [ 'activity_no' => $activity->activity_no, 'customer_id' => $activity->client?->customer_id ?? '-', 'customer' => $activity->client?->name ?? '-', 'activity_type' => $activity->activity_type ?? '-', 'task_description' => $activity->task_description ?? '-', 'estimated_completed_at' => $estimatedDate->format('Y-m-d'), 'number_of_days' => (int) $today->diffInDays($estimatedDate, false), ]; } private function sendTestEmail(string $email): int { $today = Carbon::today(); $mailData = [ 'user_name' => 'Brian', 'role_label' => 'Activity Owner', 'overdue' => [ [ 'activity_no' => 'ACT0001', 'customer_id' => '1234567890', 'customer' => 'Example Client A', 'activity_type' => 'scheduled', 'task_description' => 'Review SEM performance report and update client notes.', 'estimated_completed_at' => $today->copy()->subDays(2)->format('Y-m-d'), 'number_of_days' => -2, ], ], 'due_today' => [ [ 'activity_no' => 'ACT0002', 'customer_id' => '1234567891', 'customer' => 'Example Client B', 'activity_type' => 'scheduled', 'task_description' => 'Prepare optimisation checklist for campaign review.', 'estimated_completed_at' => $today->format('Y-m-d'), 'number_of_days' => 0, ], ], 'due_tomorrow' => [ [ 'activity_no' => 'ACT0003', 'customer_id' => '1234567892', 'customer' => 'Example Client C', 'activity_type' => 'scheduled', 'task_description' => 'Follow up on budget pacing and next-month planning.', 'estimated_completed_at' => $today->copy()->addDay()->format('Y-m-d'), 'number_of_days' => 1, ], ], ]; Mail::send('mail.project_activity_reminder', ['data' => $mailData], function ($message) use ($email) { $message->to($email) ->subject('Test: Pending Project Activity Reminder'); }); $this->info("Sent test pending project activity reminder to {$email}."); return self::SUCCESS; } }