get(); Log::info('All users in database:', [ 'total_users' => $allUsers->count(), 'users_with_roles' => $allUsers->map(function($user) { $roleName = 'No role'; if ($user->role) { $roleName = is_string($user->role) ? $user->role : $user->role->name; } return [ 'id' => $user->id, 'name' => $user->name, 'role_id' => $user->role_id, 'role_name' => $roleName, 'dealer_id' => $user->dealer_id ]; }) ]); // Get all works with category in single query $works = Work::with(['category']) ->orderBy('name') ->get(); // Get all mechanics (users with role name = 'mechanic') $mechanics = User::with('role')->whereHas('role', function($query) { $query->where('name', 'mechanic'); }) ->when($dealerId, function($query) use ($dealerId) { return $query->where('dealer_id', $dealerId); }) ->orderBy('name') ->get(['id', 'name', 'role_id', 'dealer_id']); // Fallback: If no mechanics found, get all users with dealer_id if ($mechanics->isEmpty()) { Log::info('No users with role "mechanic" found, using fallback: all users with dealer_id'); $mechanics = User::with('role')->whereNotNull('dealer_id') ->whereNotNull('role_id') ->when($dealerId, function($query) use ($dealerId) { return $query->where('dealer_id', $dealerId); }) ->orderBy('name') ->get(['id', 'name', 'role_id', 'dealer_id']); } Log::info('Mechanics found:', [ 'count' => $mechanics->count(), 'dealer_id_filter' => $dealerId, 'mechanics' => $mechanics->map(function($mechanic) { $roleName = 'Unknown'; if ($mechanic->role) { $roleName = is_string($mechanic->role) ? $mechanic->role : $mechanic->role->name; } return [ 'id' => $mechanic->id, 'name' => $mechanic->name, 'role_id' => $mechanic->role_id, 'role_name' => $roleName, 'dealer_id' => $mechanic->dealer_id ]; }) ]); // Get all transaction data in single optimized query $transactions = $this->getOptimizedTransactionData($dealerId, $startDate, $endDate, $mechanics->pluck('id'), $works->pluck('id')); Log::info('Transaction data:', [ 'transaction_count' => count($transactions), 'sample_transactions' => array_slice($transactions, 0, 5, true) ]); $data = []; foreach ($works as $work) { $row = [ 'work_id' => $work->id, 'work_name' => $work->name, 'work_code' => $work->shortname, 'category_name' => $work->category ? $work->category->name : '-', 'total_tickets' => 0 ]; // Calculate totals for each mechanic foreach ($mechanics as $mechanic) { $key = $work->id . '_' . $mechanic->id; $mechanicData = $transactions[$key] ?? ['total' => 0, 'completed' => 0, 'pending' => 0]; $row["mechanic_{$mechanic->id}_total"] = $mechanicData['total']; // Add to totals $row['total_tickets'] += $mechanicData['total']; } $data[] = $row; } Log::info('Final data prepared:', [ 'data_count' => count($data), 'sample_data' => array_slice($data, 0, 2) ]); return [ 'data' => $data, 'mechanics' => $mechanics, 'works' => $works ]; } catch (\Exception $e) { Log::error('Error in getTechnicianReportData: ' . $e->getMessage(), [ 'dealer_id' => $dealerId, 'start_date' => $startDate, 'end_date' => $endDate, 'trace' => $e->getTraceAsString() ]); // Return empty data structure but with proper format return [ 'data' => [], 'mechanics' => collect(), 'works' => collect() ]; } } /** * Get optimized transaction data in single query */ private function getOptimizedTransactionData($dealerId = null, $startDate = null, $endDate = null, $mechanicIds = null, $workIds = null) { $query = Transaction::select( 'work_id', 'user_id', 'status', DB::raw('COUNT(*) as count') ) ->groupBy('work_id', 'user_id', 'status'); if ($dealerId) { $query->where('dealer_id', $dealerId); } if ($startDate) { $query->where('date', '>=', $startDate); } if ($endDate) { $query->where('date', '<=', $endDate); } if ($mechanicIds && $mechanicIds->count() > 0) { $query->whereIn('user_id', $mechanicIds); } if ($workIds && $workIds->count() > 0) { $query->whereIn('work_id', $workIds); } // Remove index hint that doesn't exist $results = $query->get(); // Organize data by work_id_user_id key $organizedData = []; foreach ($results as $result) { $key = $result->work_id . '_' . $result->user_id; if (!isset($organizedData[$key])) { $organizedData[$key] = [ 'total' => 0, 'completed' => 0, 'pending' => 0 ]; } $organizedData[$key]['total'] += $result->count; if ($result->status == 1) { $organizedData[$key]['completed'] += $result->count; } else { $organizedData[$key]['pending'] += $result->count; } } return $organizedData; } /** * Get total ticket count for a specific work and mechanic (legacy method for backward compatibility) */ private function getTicketCount($workId, $mechanicId, $dealerId = null, $startDate = null, $endDate = null) { $query = Transaction::where('work_id', $workId) ->where('user_id', $mechanicId); if ($dealerId) { $query->where('dealer_id', $dealerId); } if ($startDate) { $query->where('date', '>=', $startDate); } if ($endDate) { $query->where('date', '<=', $endDate); } return $query->count(); } /** * Get completed ticket count for a specific work and mechanic (legacy method for backward compatibility) */ private function getCompletedTicketCount($workId, $mechanicId, $dealerId = null, $startDate = null, $endDate = null) { $query = Transaction::where('work_id', $workId) ->where('user_id', $mechanicId) ->where('status', 1); // Assuming status 1 is completed if ($dealerId) { $query->where('dealer_id', $dealerId); } if ($startDate) { $query->where('date', '>=', $startDate); } if ($endDate) { $query->where('date', '<=', $endDate); } return $query->count(); } /** * Get pending ticket count for a specific work and mechanic (legacy method for backward compatibility) */ private function getPendingTicketCount($workId, $mechanicId, $dealerId = null, $startDate = null, $endDate = null) { $query = Transaction::where('work_id', $workId) ->where('user_id', $mechanicId) ->where('status', 0); // Assuming status 0 is pending if ($dealerId) { $query->where('dealer_id', $dealerId); } if ($startDate) { $query->where('date', '>=', $startDate); } if ($endDate) { $query->where('date', '<=', $endDate); } return $query->count(); } /** * Get all dealers for filter */ public function getDealers() { return Dealer::orderBy('name')->get(['id', 'name', 'dealer_code']); } /** * Get default dealer for filter (tidak perlu berbasis user) */ public function getDefaultDealer() { // Dealer pertama saja jika ada return Dealer::orderBy('name')->first(); } /** * Get mechanics for a specific dealer */ public function getMechanicsByDealer($dealerId = null) { $query = User::with('role')->whereHas('role', function($query) { $query->where('name', 'mechanic'); }); if ($dealerId) { $query->where('dealer_id', $dealerId); } return $query->orderBy('name')->get(['id', 'name', 'dealer_id']); } /** * Get technician report data for Yajra DataTable */ public function getTechnicianReportDataForDataTable($dealerId = null, $startDate = null, $endDate = null) { try { // Get all works with category $works = Work::with(['category']) ->orderBy('name') ->get(); // Get all mechanics $mechanics = User::with('role')->whereHas('role', function($query) { $query->where('name', 'mechanic'); }) ->when($dealerId, function($query) use ($dealerId) { return $query->where('dealer_id', $dealerId); }) ->orderBy('name') ->get(['id', 'name', 'role_id', 'dealer_id']); // Fallback: If no mechanics found, get all users with dealer_id if ($mechanics->isEmpty()) { Log::info('No users with role "mechanic" found, using fallback: all users with dealer_id'); $mechanics = User::with('role')->whereNotNull('dealer_id') ->whereNotNull('role_id') ->when($dealerId, function($query) use ($dealerId) { return $query->where('dealer_id', $dealerId); }) ->orderBy('name') ->get(['id', 'name', 'role_id', 'dealer_id']); } // Get transaction data $transactions = $this->getOptimizedTransactionData($dealerId, $startDate, $endDate, $mechanics->pluck('id'), $works->pluck('id')); $data = []; foreach ($works as $work) { $row = [ 'DT_RowIndex' => count($data) + 1, 'work_name' => $work->name, 'work_code' => $work->shortname, 'category_name' => $work->category ? $work->category->name : '-' ]; // Add mechanic columns foreach ($mechanics as $mechanic) { $key = $work->id . '_' . $mechanic->id; $mechanicData = $transactions[$key] ?? ['total' => 0, 'completed' => 0, 'pending' => 0]; $row["mechanic_{$mechanic->id}_total"] = $mechanicData['total']; } $data[] = $row; } // Create DataTable response return response()->json([ 'draw' => request()->input('draw', 1), 'recordsTotal' => count($data), 'recordsFiltered' => count($data), 'data' => $data, 'mechanics' => $mechanics, 'works' => $works ]); } catch (\Exception $e) { Log::error('Error in getTechnicianReportDataForDataTable: ' . $e->getMessage(), [ 'dealer_id' => $dealerId, 'start_date' => $startDate, 'end_date' => $endDate, 'trace' => $e->getTraceAsString() ]); return response()->json([ 'draw' => request()->input('draw', 1), 'recordsTotal' => 0, 'recordsFiltered' => 0, 'data' => [], 'mechanics' => collect(), 'works' => collect() ]); } } }