Car-Repairs-Shop/app/Services/WorkflowService.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

299 lines
11 KiB
PHP

<?php
namespace App\Services;
use App\Models\JobCard;
use App\Models\Estimate;
use App\Models\WorkOrder;
use App\Models\Diagnosis;
use App\Models\VehicleInspection;
use App\Models\User;
use Illuminate\Support\Facades\DB;
class WorkflowService
{
public function __construct(
private NotificationService $notificationService
) {}
/**
* Create job card when vehicle arrives
*/
public function createJobCard(array $data): JobCard
{
return DB::transaction(function () use ($data) {
$jobCard = JobCard::create([
'customer_id' => $data['customer_id'],
'vehicle_id' => $data['vehicle_id'],
'service_advisor_id' => $data['service_advisor_id'],
'branch_code' => $data['branch_code'] ?? config('app.default_branch_code', 'ACC'),
'arrival_datetime' => $data['arrival_datetime'],
'mileage_in' => $data['mileage_in'],
'fuel_level_in' => $data['fuel_level_in'],
'customer_reported_issues' => $data['customer_reported_issues'],
'vehicle_condition_notes' => $data['vehicle_condition_notes'],
'keys_location' => $data['keys_location'],
'personal_items_removed' => $data['personal_items_removed'] ?? false,
'photos_taken' => $data['photos_taken'] ?? false,
'expected_completion_date' => $data['expected_completion_date'] ?? null,
'priority' => $data['priority'] ?? 'medium',
'notes' => $data['notes'] ?? null,
]);
// Create incoming inspection checklist
if (isset($data['inspection_checklist'])) {
VehicleInspection::create([
'job_card_id' => $jobCard->id,
'vehicle_id' => $jobCard->vehicle_id,
'inspector_id' => $data['inspector_id'],
'inspection_type' => 'incoming',
'current_mileage' => $data['mileage_in'],
'fuel_level' => $data['fuel_level_in'],
'inspection_checklist' => $data['inspection_checklist'],
'photos' => $data['inspection_photos'] ?? [],
'overall_condition' => $data['overall_condition'],
'inspection_date' => now(),
'notes' => $data['inspection_notes'] ?? null,
]);
}
return $jobCard;
});
}
/**
* Assign job card to service coordinator and start diagnosis
*/
public function assignToServiceCoordinator(JobCard $jobCard, int $serviceCoordinatorId): Diagnosis
{
$diagnosis = Diagnosis::create([
'job_card_id' => $jobCard->id,
'service_coordinator_id' => $serviceCoordinatorId,
'customer_reported_issues' => $jobCard->customer_reported_issues,
'diagnosis_status' => 'in_progress',
'diagnosis_date' => now(),
]);
$jobCard->update(['status' => 'in_diagnosis']);
return $diagnosis;
}
/**
* Complete diagnosis and create estimate
*/
public function completeDiagnosis(Diagnosis $diagnosis, array $diagnosisData, array $estimateItems): Estimate
{
return DB::transaction(function () use ($diagnosis, $diagnosisData, $estimateItems) {
// Update diagnosis
$diagnosis->update([
'diagnostic_findings' => $diagnosisData['diagnostic_findings'],
'root_cause_analysis' => $diagnosisData['root_cause_analysis'],
'recommended_repairs' => $diagnosisData['recommended_repairs'],
'additional_issues_found' => $diagnosisData['additional_issues_found'] ?? null,
'priority_level' => $diagnosisData['priority_level'] ?? 'medium',
'estimated_repair_time' => $diagnosisData['estimated_repair_time'],
'parts_required' => $diagnosisData['parts_required'] ?? [],
'labor_operations' => $diagnosisData['labor_operations'] ?? [],
'special_tools_required' => $diagnosisData['special_tools_required'] ?? [],
'safety_concerns' => $diagnosisData['safety_concerns'] ?? null,
'customer_authorization_required' => $diagnosisData['customer_authorization_required'] ?? false,
'diagnosis_status' => 'completed',
'notes' => $diagnosisData['notes'] ?? null,
]);
// Create estimate
$estimate = Estimate::create([
'job_card_id' => $diagnosis->job_card_id,
'diagnosis_id' => $diagnosis->id,
'prepared_by_id' => $diagnosis->service_coordinator_id,
'tax_rate' => config('app.default_tax_rate', 8.25),
'validity_period_days' => 30,
'terms_and_conditions' => config('app.default_estimate_terms'),
'status' => 'draft',
]);
// Add estimate line items
foreach ($estimateItems as $item) {
$estimate->lineItems()->create($item);
}
// Calculate totals
$estimate->calculateTotals();
// Update job card status
$diagnosis->jobCard->update(['status' => 'estimate_sent']);
return $estimate;
});
}
/**
* Send estimate to customer
*/
public function sendEstimateToCustomer(Estimate $estimate): void
{
$this->notificationService->sendEstimateToCustomer($estimate);
}
/**
* Approve estimate and create work order
*/
public function approveEstimate(Estimate $estimate, string $approvalMethod = 'portal'): WorkOrder
{
return DB::transaction(function () use ($estimate, $approvalMethod) {
// Update estimate
$estimate->update([
'customer_approval_status' => 'approved',
'customer_approved_at' => now(),
'customer_approval_method' => $approvalMethod,
'status' => 'approved',
]);
// Update job card
$estimate->jobCard->update(['status' => 'approved']);
// Send notifications
$this->notificationService->notifyEstimateApproved($estimate);
// Create work order
$workOrder = WorkOrder::create([
'job_card_id' => $estimate->job_card_id,
'estimate_id' => $estimate->id,
'service_coordinator_id' => $estimate->diagnosis->service_coordinator_id,
'priority' => $estimate->jobCard->priority,
'work_description' => $estimate->diagnosis->recommended_repairs,
'special_instructions' => $estimate->diagnosis->notes,
'quality_check_required' => true,
'status' => 'pending',
]);
return $workOrder;
});
}
/**
* Assign work order to technician and start work
*/
public function assignWorkOrder(WorkOrder $workOrder, int $technicianId): void
{
$workOrder->update([
'assigned_technician_id' => $technicianId,
'status' => 'assigned',
'actual_start_time' => now(),
]);
$workOrder->jobCard->update(['status' => 'in_progress']);
}
/**
* Complete work order and perform quality check
*/
public function completeWorkOrder(WorkOrder $workOrder, int $qualityCheckerId): void
{
$workOrder->update([
'status' => 'quality_check',
'actual_completion_time' => now(),
'quality_checked_by_id' => $qualityCheckerId,
'quality_check_date' => now(),
'completion_percentage' => 100,
]);
}
/**
* Perform outgoing inspection and final quality check
*/
public function performOutgoingInspection(JobCard $jobCard, array $inspectionData, int $inspectorId): void
{
// Create outgoing inspection
$outgoingInspection = VehicleInspection::create([
'job_card_id' => $jobCard->id,
'vehicle_id' => $jobCard->vehicle_id,
'inspector_id' => $inspectorId,
'inspection_type' => 'outgoing',
'current_mileage' => $inspectionData['mileage_out'],
'fuel_level' => $inspectionData['fuel_level_out'],
'inspection_checklist' => $inspectionData['inspection_checklist'],
'photos' => $inspectionData['photos'] ?? [],
'overall_condition' => $inspectionData['overall_condition'],
'inspection_date' => now(),
'notes' => $inspectionData['notes'] ?? null,
]);
// Compare with incoming inspection
$incomingInspection = $jobCard->incomingInspection;
if ($incomingInspection) {
$discrepancies = $outgoingInspection->compareWithOtherInspection($incomingInspection);
if (!empty($discrepancies)) {
// Alert service supervisor about discrepancies
$this->notificationService->sendQualityAlert($jobCard, $discrepancies);
$outgoingInspection->update([
'discrepancies_found' => $discrepancies,
'follow_up_required' => true,
]);
} else {
// No discrepancies, mark as completed
$jobCard->update([
'status' => 'completed',
'mileage_out' => $inspectionData['mileage_out'],
'fuel_level_out' => $inspectionData['fuel_level_out'],
'completion_datetime' => now(),
]);
// Notify customer
$this->notificationService->notifyVehicleReady($jobCard);
}
}
}
/**
* Close job card after delivery
*/
public function closeJobCard(JobCard $jobCard, array $deliveryData): void
{
$jobCard->update([
'status' => 'delivered',
'delivery_method' => $deliveryData['delivery_method'],
'customer_satisfaction_rating' => $deliveryData['satisfaction_rating'] ?? null,
'completion_datetime' => now(),
]);
}
/**
* Get workflow status for a job card
*/
public function getWorkflowStatus(JobCard $jobCard): array
{
return [
'job_card' => $jobCard,
'incoming_inspection' => $jobCard->incomingInspection,
'diagnosis' => $jobCard->diagnosis,
'estimate' => $jobCard->estimates()->latest()->first(),
'work_orders' => $jobCard->workOrders,
'outgoing_inspection' => $jobCard->outgoingInspection,
'completion_percentage' => $this->calculateCompletionPercentage($jobCard),
];
}
/**
* Calculate completion percentage for a job card
*/
private function calculateCompletionPercentage(JobCard $jobCard): int
{
$steps = [
'received' => 10,
'in_diagnosis' => 25,
'estimate_sent' => 40,
'approved' => 50,
'in_progress' => 75,
'quality_check' => 90,
'completed' => 95,
'delivered' => 100,
];
return $steps[$jobCard->status] ?? 0;
}
}