*/ use HasFactory; protected $fillable = [ 'customer_id', 'vehicle_id', 'assigned_technician_id', 'scheduled_datetime', 'estimated_duration_minutes', 'appointment_type', 'service_requested', 'customer_notes', 'internal_notes', 'status', 'checked_in_at', 'completed_at', 'service_order_id', ]; protected $casts = [ 'scheduled_datetime' => 'datetime', 'checked_in_at' => 'datetime', 'completed_at' => 'datetime', 'estimated_duration_minutes' => 'integer', ]; // Relationships public function customer(): BelongsTo { return $this->belongsTo(Customer::class); } public function vehicle(): BelongsTo { return $this->belongsTo(Vehicle::class); } public function assignedTechnician(): BelongsTo { return $this->belongsTo(Technician::class, 'assigned_technician_id'); } public function serviceOrder(): BelongsTo { return $this->belongsTo(ServiceOrder::class); } // Scopes public function scopeToday($query) { return $query->whereDate('scheduled_datetime', today()); } public function scopeUpcoming($query) { return $query->where('scheduled_datetime', '>=', now()); } public function scopeForTechnician($query, $technicianId) { return $query->where('assigned_technician_id', $technicianId); } public function scopeByStatus($query, $status) { return $query->where('status', $status); } public function scopeInDateRange($query, $startDate, $endDate) { return $query->whereBetween('scheduled_datetime', [$startDate, $endDate]); } // Accessors & Mutators public function getFormattedDateTimeAttribute(): string { return $this->scheduled_datetime->format('M j, Y g:i A'); } public function getFormattedDateAttribute(): string { return $this->scheduled_datetime->format('M j, Y'); } public function getFormattedTimeAttribute(): string { return $this->scheduled_datetime->format('g:i A'); } public function getEndTimeAttribute(): Carbon { return $this->scheduled_datetime->addMinutes($this->estimated_duration_minutes); } public function getFormattedEndTimeAttribute(): string { return $this->end_time->format('g:i A'); } public function getStatusColorAttribute(): string { return match($this->status) { 'scheduled' => 'blue', 'confirmed' => 'green', 'in_progress' => 'yellow', 'completed' => 'emerald', 'cancelled' => 'red', 'no_show' => 'gray', default => 'blue' }; } public function getTypeColorAttribute(): string { return match($this->appointment_type) { 'maintenance' => 'blue', 'repair' => 'red', 'inspection' => 'yellow', 'estimate' => 'purple', 'pickup' => 'green', 'delivery' => 'indigo', default => 'blue' }; } // Helper Methods public function canBeModified(): bool { return in_array($this->status, ['scheduled', 'confirmed']) && $this->scheduled_datetime->isFuture(); } public function canBeCheckedIn(): bool { return $this->status === 'confirmed' && $this->scheduled_datetime->isPast() && !$this->checked_in_at; } public function canBeCompleted(): bool { return in_array($this->status, ['confirmed', 'in_progress']) && $this->checked_in_at; } public function isOverdue(): bool { return $this->status === 'scheduled' && $this->scheduled_datetime->isPast(); } public function getDurationInHours(): float { return round($this->estimated_duration_minutes / 60, 1); } // Status Management public function confirm(): bool { if ($this->status === 'scheduled') { return $this->update(['status' => 'confirmed']); } return false; } public function checkIn(): bool { if ($this->canBeCheckedIn()) { return $this->update([ 'status' => 'in_progress', 'checked_in_at' => now() ]); } return false; } public function complete(): bool { if ($this->canBeCompleted()) { return $this->update([ 'status' => 'completed', 'completed_at' => now() ]); } return false; } public function cancel(): bool { if ($this->canBeModified()) { return $this->update(['status' => 'cancelled']); } return false; } public function markNoShow(): bool { if ($this->isOverdue()) { return $this->update(['status' => 'no_show']); } return false; } }