load(['customer', 'vehicle', 'assignedTechnician']); // Send email notification $this->sendConfirmationEmail($appointment); // Log successful notification Log::info('Appointment confirmation notification sent', [ 'appointment_id' => $appointment->id, 'customer_id' => $appointment->customer_id, 'scheduled_datetime' => $appointment->scheduled_datetime, ]); return true; } catch (\Exception $e) { Log::error('Failed to send appointment confirmation notification', [ 'appointment_id' => $appointment->id, 'error' => $e->getMessage(), ]); return false; } } /** * Send appointment reminder notification */ public function sendReminderNotification(Appointment $appointment): bool { try { $appointment->load(['customer', 'vehicle', 'assignedTechnician']); // Send email reminder $this->sendReminderEmail($appointment); Log::info('Appointment reminder notification sent', [ 'appointment_id' => $appointment->id, 'customer_id' => $appointment->customer_id, 'scheduled_datetime' => $appointment->scheduled_datetime, ]); return true; } catch (\Exception $e) { Log::error('Failed to send appointment reminder notification', [ 'appointment_id' => $appointment->id, 'error' => $e->getMessage(), ]); return false; } } /** * Send appointment cancellation notification */ public function sendCancellationNotification(Appointment $appointment, string $reason = ''): bool { try { $appointment->load(['customer', 'vehicle', 'assignedTechnician']); // Send email notification $this->sendCancellationEmail($appointment, $reason); Log::info('Appointment cancellation notification sent', [ 'appointment_id' => $appointment->id, 'customer_id' => $appointment->customer_id, 'reason' => $reason, ]); return true; } catch (\Exception $e) { Log::error('Failed to send appointment cancellation notification', [ 'appointment_id' => $appointment->id, 'error' => $e->getMessage(), ]); return false; } } /** * Send appointment reschedule notification */ public function sendRescheduleNotification(Appointment $appointment, Carbon $oldDateTime): bool { try { $appointment->load(['customer', 'vehicle', 'assignedTechnician']); // Send email notification $this->sendRescheduleEmail($appointment, $oldDateTime); Log::info('Appointment reschedule notification sent', [ 'appointment_id' => $appointment->id, 'customer_id' => $appointment->customer_id, 'old_datetime' => $oldDateTime, 'new_datetime' => $appointment->scheduled_datetime, ]); return true; } catch (\Exception $e) { Log::error('Failed to send appointment reschedule notification', [ 'appointment_id' => $appointment->id, 'error' => $e->getMessage(), ]); return false; } } /** * Send completed service notification */ public function sendCompletionNotification(Appointment $appointment): bool { try { $appointment->load(['customer', 'vehicle', 'assignedTechnician', 'serviceOrder']); // Send email notification $this->sendCompletionEmail($appointment); Log::info('Service completion notification sent', [ 'appointment_id' => $appointment->id, 'customer_id' => $appointment->customer_id, 'completed_at' => $appointment->completed_at, ]); return true; } catch (\Exception $e) { Log::error('Failed to send service completion notification', [ 'appointment_id' => $appointment->id, 'error' => $e->getMessage(), ]); return false; } } /** * Send daily appointment reminders */ public function sendDailyReminders(): int { $tomorrow = now()->addDay(); $remindersSent = 0; // Get appointments scheduled for tomorrow that are confirmed $appointments = Appointment::with(['customer', 'vehicle', 'assignedTechnician']) ->whereDate('scheduled_datetime', $tomorrow->toDateString()) ->where('status', 'confirmed') ->get(); foreach ($appointments as $appointment) { if ($this->sendReminderNotification($appointment)) { $remindersSent++; } } Log::info('Daily appointment reminders sent', [ 'date' => $tomorrow->toDateString(), 'reminders_sent' => $remindersSent, 'total_appointments' => $appointments->count(), ]); return $remindersSent; } /** * Send overdue appointment notifications */ public function sendOverdueNotifications(): int { $notificationsSent = 0; // Get appointments that are overdue (scheduled but past their time) $overdueAppointments = Appointment::with(['customer', 'vehicle', 'assignedTechnician']) ->where('status', 'scheduled') ->where('scheduled_datetime', '<', now()->subMinutes(30)) // 30 minutes past ->get(); foreach ($overdueAppointments as $appointment) { // Mark as no-show and send notification if ($appointment->markNoShow()) { $this->sendNoShowNotification($appointment); $notificationsSent++; } } Log::info('Overdue appointment notifications sent', [ 'notifications_sent' => $notificationsSent, 'overdue_appointments' => $overdueAppointments->count(), ]); return $notificationsSent; } /** * Send no-show notification */ private function sendNoShowNotification(Appointment $appointment): bool { try { // This would typically send an internal notification to staff // and possibly a follow-up email to the customer Log::info('Customer marked as no-show', [ 'appointment_id' => $appointment->id, 'customer_id' => $appointment->customer_id, 'scheduled_datetime' => $appointment->scheduled_datetime, ]); return true; } catch (\Exception $e) { Log::error('Failed to send no-show notification', [ 'appointment_id' => $appointment->id, 'error' => $e->getMessage(), ]); return false; } } /** * Send confirmation email */ private function sendConfirmationEmail(Appointment $appointment): void { $data = [ 'appointment' => $appointment, 'customer' => $appointment->customer, 'vehicle' => $appointment->vehicle, 'technician' => $appointment->assignedTechnician, 'shopName' => config('app.name', 'Auto Repair Shop'), ]; // In a real application, you would create a Mailable class // For now, we'll simulate the email sending $this->simulateEmail($appointment->customer->email, 'Appointment Confirmation', $data); } /** * Send reminder email */ private function sendReminderEmail(Appointment $appointment): void { $data = [ 'appointment' => $appointment, 'customer' => $appointment->customer, 'vehicle' => $appointment->vehicle, 'technician' => $appointment->assignedTechnician, 'shopName' => config('app.name', 'Auto Repair Shop'), ]; $this->simulateEmail($appointment->customer->email, 'Appointment Reminder', $data); } /** * Send cancellation email */ private function sendCancellationEmail(Appointment $appointment, string $reason): void { $data = [ 'appointment' => $appointment, 'customer' => $appointment->customer, 'vehicle' => $appointment->vehicle, 'reason' => $reason, 'shopName' => config('app.name', 'Auto Repair Shop'), ]; $this->simulateEmail($appointment->customer->email, 'Appointment Cancelled', $data); } /** * Send reschedule email */ private function sendRescheduleEmail(Appointment $appointment, Carbon $oldDateTime): void { $data = [ 'appointment' => $appointment, 'customer' => $appointment->customer, 'vehicle' => $appointment->vehicle, 'technician' => $appointment->assignedTechnician, 'oldDateTime' => $oldDateTime, 'shopName' => config('app.name', 'Auto Repair Shop'), ]; $this->simulateEmail($appointment->customer->email, 'Appointment Rescheduled', $data); } /** * Send completion email */ private function sendCompletionEmail(Appointment $appointment): void { $data = [ 'appointment' => $appointment, 'customer' => $appointment->customer, 'vehicle' => $appointment->vehicle, 'technician' => $appointment->assignedTechnician, 'serviceOrder' => $appointment->serviceOrder, 'shopName' => config('app.name', 'Auto Repair Shop'), ]; $this->simulateEmail($appointment->customer->email, 'Service Completed', $data); } /** * Simulate email sending (replace with actual Mail::send in production) */ private function simulateEmail(string $email, string $subject, array $data): void { // In production, replace this with: // Mail::send('emails.appointment.template', $data, function ($message) use ($email, $subject) { // $message->to($email)->subject($subject); // }); Log::info('Email notification simulated', [ 'to' => $email, 'subject' => $subject, 'appointment_id' => $data['appointment']->id ?? null, ]); } /** * Get notification preferences for a customer */ public function getCustomerNotificationPreferences($customerId): array { // In a real application, this would fetch from customer preferences // For now, return default preferences return [ 'email_confirmations' => true, 'email_reminders' => true, 'email_cancellations' => true, 'sms_reminders' => false, // Could be implemented later 'reminder_hours_before' => 24, ]; } /** * Check if notification should be sent based on customer preferences */ public function shouldSendNotification($customerId, string $notificationType): bool { $preferences = $this->getCustomerNotificationPreferences($customerId); return match($notificationType) { 'confirmation' => $preferences['email_confirmations'] ?? true, 'reminder' => $preferences['email_reminders'] ?? true, 'cancellation' => $preferences['email_cancellations'] ?? true, default => true, }; } }