Car-Repairs-Shop/app/Services/AppointmentNotificationService.php
sackey e839d40a99
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Initial commit
2025-07-30 17:15:50 +00:00

371 lines
12 KiB
PHP

<?php
namespace App\Services;
use App\Models\Appointment;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
class AppointmentNotificationService
{
/**
* Send appointment confirmation notification
*/
public function sendConfirmationNotification(Appointment $appointment): bool
{
try {
// Load relationships if not already loaded
$appointment->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,
};
}
}