$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; } }