sackey a65fee9d75
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Add customer portal workflow progress component and analytics dashboard
- Implemented the customer portal workflow progress component with detailed service progress tracking, including current status, workflow steps, and contact information.
- Developed a management workflow analytics dashboard featuring key performance indicators, charts for revenue by branch, labor utilization, and recent quality issues.
- Created tests for admin-only middleware to ensure proper access control for admin routes.
- Added tests for customer portal view rendering and workflow integration, ensuring the workflow service operates correctly through various stages.
- Introduced a .gitignore file for the debugbar storage directory to prevent unnecessary files from being tracked.
2025-08-10 19:41:25 +00:00

161 lines
4.9 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
class JobCard extends Model
{
use HasFactory;
protected $fillable = [
'job_card_number',
'branch_code',
'customer_id',
'vehicle_id',
'arrival_datetime',
'expected_completion_date',
'mileage_in',
'mileage_out',
'fuel_level_in',
'fuel_level_out',
'status',
'priority',
'service_advisor_id',
'notes',
'customer_reported_issues',
'vehicle_condition_notes',
'keys_location',
'personal_items_removed',
'photos_taken',
'completion_datetime',
'delivery_method',
'customer_satisfaction_rating',
'delivered_by_id',
'delivery_notes',
'archived_at',
'incoming_inspection_data',
'outgoing_inspection_data',
'quality_alerts',
];
// Enhanced status constants following the 11-step workflow
public const STATUS_RECEIVED = 'received';
public const STATUS_INSPECTED = 'inspected';
public const STATUS_ASSIGNED_FOR_DIAGNOSIS = 'assigned_for_diagnosis';
public const STATUS_IN_DIAGNOSIS = 'in_diagnosis';
public const STATUS_ESTIMATE_SENT = 'estimate_sent';
public const STATUS_APPROVED = 'approved';
public const STATUS_PARTS_PROCUREMENT = 'parts_procurement';
public const STATUS_IN_PROGRESS = 'in_progress';
public const STATUS_QUALITY_REVIEW_REQUIRED = 'quality_review_required';
public const STATUS_COMPLETED = 'completed';
public const STATUS_DELIVERED = 'delivered';
public static function getStatusOptions(): array
{
return [
self::STATUS_RECEIVED => 'Vehicle Received',
self::STATUS_INSPECTED => 'Initial Inspection Complete',
self::STATUS_ASSIGNED_FOR_DIAGNOSIS => 'Assigned for Diagnosis',
self::STATUS_IN_DIAGNOSIS => 'Diagnosis In Progress',
self::STATUS_ESTIMATE_SENT => 'Estimate Sent to Customer',
self::STATUS_APPROVED => 'Estimate Approved',
self::STATUS_PARTS_PROCUREMENT => 'Parts Procurement',
self::STATUS_IN_PROGRESS => 'Work in Progress',
self::STATUS_QUALITY_REVIEW_REQUIRED => 'Quality Review Required',
self::STATUS_COMPLETED => 'Work Completed',
self::STATUS_DELIVERED => 'Vehicle Delivered',
];
}
protected $casts = [
'arrival_datetime' => 'datetime',
'expected_completion_date' => 'datetime',
'completion_datetime' => 'datetime',
'archived_at' => 'datetime',
'personal_items_removed' => 'boolean',
'photos_taken' => 'boolean',
'mileage_in' => 'integer',
'mileage_out' => 'integer',
'customer_satisfaction_rating' => 'integer',
'incoming_inspection_data' => 'array',
'outgoing_inspection_data' => 'array',
];
protected static function boot()
{
parent::boot();
static::creating(function ($jobCard) {
if (empty($jobCard->job_card_number)) {
$branchCode = $jobCard->branch_code ?? config('app.default_branch_code', 'ACC');
$nextNumber = static::where('branch_code', $branchCode)
->whereYear('created_at', now()->year)
->count() + 1;
$jobCard->job_card_number = $branchCode . '/' . str_pad($nextNumber, 5, '0', STR_PAD_LEFT);
}
});
}
public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}
public function vehicle(): BelongsTo
{
return $this->belongsTo(Vehicle::class);
}
public function serviceAdvisor(): BelongsTo
{
return $this->belongsTo(User::class, 'service_advisor_id');
}
public function incomingInspection(): HasOne
{
return $this->hasOne(VehicleInspection::class)->incoming();
}
public function outgoingInspection(): HasOne
{
return $this->hasOne(VehicleInspection::class)->outgoing();
}
public function diagnosis(): HasOne
{
return $this->hasOne(Diagnosis::class);
}
public function workOrders(): HasMany
{
return $this->hasMany(WorkOrder::class);
}
public function timesheets(): HasMany
{
return $this->hasMany(Timesheet::class);
}
public function estimates(): HasMany
{
return $this->hasMany(Estimate::class);
}
public function scopeByBranch($query, $branchCode)
{
return $query->where('branch_code', $branchCode);
}
public function scopeByStatus($query, $status)
{
return $query->where('status', $status);
}
}