215 lines
5.3 KiB
PHP
215 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Carbon\Carbon;
|
|
|
|
class Appointment extends Model
|
|
{
|
|
/** @use HasFactory<\Database\Factories\AppointmentFactory> */
|
|
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;
|
|
}
|
|
}
|