'aktiv', 2 => 'nicht aktiv', 3 => 'alle']; private $filter_next_level = [ 0 => 'Alle Status', 1 => 'Qualifiziert (grün)', 2 => 'In Arbeit (gelb)', 3 => 'Kein Level (rot)' ]; private $month; private $year; public function __construct() { $this->middleware('admin'); } /** * Zeigt die Business-Übersicht (identisch zur Original-Version) */ public function show() { $this->setFilterVars(); $data = [ 'filter_months' => HTMLHelper::getTransMonths(), 'filter_years' => HTMLHelper::getYearRange(), 'filter_active' => $this->filter_active, 'filter_levels' => $this->getFilterLevels(), 'filter_next_level' => $this->filter_next_level, 'optimized' => true, // Flag für View um zu zeigen, dass optimierte Version läuft ]; return view('admin.business_optimized.show', $data); } /** * Zeigt die Business-Struktur mit optimierter TreeCalcBot-Version */ public function structure() { $startTime = microtime(true); $startMemory = memory_get_usage(); try { $this->setFilterVars(); $this->month = session('business_user_filter_month'); $this->year = session('business_user_filter_year'); Log::info("BusinessControllerOptimized: Building structure for {$this->month}/{$this->year}"); // Verwende optimierte TreeCalcBot-Version $TreeCalcBot = new TreeCalcBotOptimized($this->month, $this->year, 'admin'); // Prüfe ob Live-Berechnung für Struktur erzwungen wird $forceLiveCalculation = Request::get('force_live_calculation', false) || Request::get('force_live_structure', false) || Request::get('live', false); if ($forceLiveCalculation) { Log::info("BusinessControllerOptimized: Force live calculation requested"); $TreeCalcBot->initStructureAdmin(true, $forceLiveCalculation); // check=true, forceLiveCalculation=true } else { Log::info("BusinessControllerOptimized: Force live calculation not requested"); $TreeCalcBot->initStructureAdmin(); // Standard: verwende gespeicherte wenn verfügbar } $endTime = microtime(true); $endMemory = memory_get_usage(); $executionTime = round(($endTime - $startTime) * 1000, 2); $memoryUsed = $this->formatBytes($endMemory - $startMemory); $calculationType = $forceLiveCalculation ? " (LIVE)" : " (CACHE)"; Log::info("BusinessControllerOptimized: Structure built in {$executionTime}ms, Memory: {$memoryUsed}{$calculationType}"); $data = [ 'filter_months' => HTMLHelper::getTransMonths(), 'filter_years' => HTMLHelper::getYearRange(), 'TreeCalcBot' => $TreeCalcBot, 'performance' => [ 'execution_time' => $executionTime, 'memory_used' => $memoryUsed, 'user_count' => $TreeCalcBot->getTotalUserCount(), 'parentless_count' => $TreeCalcBot->isParentless() ? count($TreeCalcBot->__get('parentless')) : 0, 'calculation_type' => $forceLiveCalculation ? 'Live' : 'Cache' ], 'optimized' => true, 'forceLiveCalculation' => $forceLiveCalculation, ]; return view('admin.business_optimized.structure', $data); } catch (\Exception $e) { Log::error("BusinessControllerOptimized: Error in structure: " . $e->getMessage()); return view('admin.business_optimized.error', [ 'error' => $e->getMessage(), 'month' => $this->month, 'year' => $this->year ]); } } /** * Zeigt User-Details mit optimierter Performance */ public function userDetail($user_id) { $startTime = microtime(true); try { $user = User::with(['account', 'user_level', 'user_sponsor.account'])->findOrFail($user_id); $this->setFilterVars(); $data = []; $data['month'] = session('business_user_filter_month'); $data['year'] = session('business_user_filter_year'); Log::info("BusinessControllerOptimized: Building user detail for user {$user_id}"); $TreeCalcBot = new TreeCalcBotOptimized($data['month'], $data['year'], 'admin'); // Prüfe ob Live-Berechnung über URL-Parameter erzwungen wird $forceLiveCalculation = Request::get('force_live_calculation', false) || Request::get('force_live', false) || Request::get('live', false); if ($forceLiveCalculation) { Log::info("BusinessControllerOptimized: Force live calculation requested for user {$user_id}"); } $TreeCalcBot->initBusinesslUserDetail($user, $forceLiveCalculation); if (!$TreeCalcBot->__get('business_user')) { Log::warning("BusinessControllerOptimized: No business user found for {$user_id}"); abort(403, 'No business user found'); } $endTime = microtime(true); $executionTime = round(($endTime - $startTime) * 1000, 2); $data['performance'] = [ 'execution_time' => $executionTime, 'user_id' => $user_id, 'calculation_type' => $forceLiveCalculation ? 'Live' : 'Cache' ]; $data['forceLiveCalculation'] = $forceLiveCalculation; $calculationType = $forceLiveCalculation ? " (LIVE)" : " (CACHE)"; Log::info("BusinessControllerOptimized: User detail built in {$executionTime}ms{$calculationType}"); return view('admin.business_optimized.user_detail', compact('TreeCalcBot', 'user', 'data')); } catch (\Exception $e) { Log::error("BusinessControllerOptimized: Error in userDetail for {$user_id}: " . $e->getMessage()); return view('admin.business_optimized.error', [ 'error' => $e->getMessage(), 'user_id' => $user_id ]); } } /** * Store-Funktion (identisch zur Original-Version) */ public function userStore($user_id) { dd('function on: App\Console\Commands\BusinessStore'); } /** * Optimierte DataTable für Users mit besserer Performance */ public function userDatatable(): JsonResponse { try { $this->month = Request::get('business_user_filter_month'); $this->year = Request::get('business_user_filter_year'); Log::info("BusinessControllerOptimized: Building datatable for {$this->month}/{$this->year}"); // Prüfe ob optimierte Repository-Daten verfügbar sind if (TreeCalcBotOptimized::isFromStored($this->month, $this->year)) { return $this->userStoredDatatableOptimized(); } else { return $this->userCurrentlyDatatableOptimized(); } } catch (\Exception $e) { Log::error("BusinessControllerOptimized: Error in userDatatable: " . $e->getMessage()); return response()->json([ 'error' => 'Datatable could not be loaded: ' . $e->getMessage() ], 500); } } /** * Optimierte Stored-Datatable mit besserer Query-Performance */ private function userStoredDatatableOptimized(): JsonResponse { $query = $this->initStoredSearchOptimized(); return \DataTables::eloquent($query) ->addColumn('id', function (UserBusiness $userBusiness) { return TreeHelperOptimized::generateActionButtons($userBusiness->user_id); }) ->addColumn('m_account', function (UserBusiness $userBusiness) { return e($userBusiness->m_account); }) ->addColumn('user_level', function (UserBusiness $userBusiness) { return e($userBusiness->user_level_name); }) ->addColumn('is_qual_kp', function (UserBusiness $userBusiness) { return TreeHelperOptimized::generateQualKPBadge($userBusiness); }) ->addColumn('sales_volume_KP_points', function (UserBusiness $userBusiness) { return TreeHelperOptimized::generateSalesVolumeDisplay($userBusiness, 'points'); }) ->addColumn('sales_volume_total', function (UserBusiness $userBusiness) { return TreeHelperOptimized::generateSalesVolumeDisplay($userBusiness, 'total'); }) ->addColumn('email', function (UserBusiness $userBusiness) { return e($userBusiness->email); }) ->addColumn('first_name', function (UserBusiness $userBusiness) { return e($userBusiness->first_name); }) ->addColumn('last_name', function (UserBusiness $userBusiness) { return e($userBusiness->last_name); }) ->addColumn('sponsor', function (UserBusiness $userBusiness) { return TreeHelperOptimized::generateSponsorDisplay($userBusiness); }) ->addColumn('active_account', function (UserBusiness $userBusiness) { return get_active_badge($userBusiness->active_account); }) ->addColumn('next_level_qualified', function (UserBusiness $userBusiness) { return NextLevelBadgeHelper::generateBadgeFromUserBusiness($userBusiness); }) ->addColumn('payment_account_date', function (UserBusiness $userBusiness) { return $userBusiness->active_date ? formatDate($userBusiness->active_date) : "-"; }) ->filterColumn('m_account', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("user_businesses.m_account LIKE ?", '%' . $keyword . '%'); } }) ->filterColumn('first_name', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("user_businesses.first_name LIKE ?", '%' . $keyword . '%'); } }) ->filterColumn('last_name', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("user_businesses.last_name LIKE ?", '%' . $keyword . '%'); } }) ->filterColumn('email', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("user_businesses.email LIKE ?", '%' . $keyword . '%'); } }) ->orderColumn('id', 'id $1') ->orderColumn('m_account', 'm_account $1') ->orderColumn('email', 'email $1') ->orderColumn('first_name', 'first_name $1') ->orderColumn('last_name', 'last_name $1') ->orderColumn('active_account', 'payment_account $1') ->rawColumns(['id', 'is_qual_kp', 'sales_volume_KP_points', 'sales_volume_total', 'sponsor', 'active_account', 'next_level_qualified']) ->make(true); } /** * Optimierte Currently-Datatable mit Repository Pattern */ private function userCurrentlyDatatableOptimized(): JsonResponse { $repository = new BusinessUserRepository($this->month, $this->year); // Nutze Repository für optimierte Abfragen $query = $this->initCurrentlySearchOptimized(); return \DataTables::eloquent($query) ->addColumn('id', function (User $user) { return TreeHelperOptimized::generateActionButtons($user->id); }) ->addColumn('m_account', function (User $user) { return $user->account ? e($user->account->m_account) : ''; }) ->addColumn('user_level', function (User $user) { return $user->user_level ? e($user->user_level->getLang('name')) : ''; }) ->addColumn('is_qual_kp', function (User $user) { return TreeHelperOptimized::generateQualKPBadgeForUser($user, $this->month, $this->year); }) ->addColumn('sales_volume_KP_points', function (User $user) { return TreeHelperOptimized::generateSalesVolumeDisplayForUser($user, 'points', $this->month, $this->year); }) ->addColumn('sales_volume_total', function (User $user) { return TreeHelperOptimized::generateSalesVolumeDisplayForUser($user, 'total', $this->month, $this->year); }) ->addColumn('email', function (User $user) { return e($user->email); }) ->addColumn('first_name', function (User $user) { return $user->account ? e($user->account->first_name) : ''; }) ->addColumn('last_name', function (User $user) { return $user->account ? e($user->account->last_name) : ''; }) ->addColumn('sponsor', function (User $user) { return TreeHelperOptimized::generateSponsorDisplayForUser($user); }) ->addColumn('active_account', function (User $user) { return get_active_badge($user->isActiveAccount()); }) ->addColumn('next_level_qualified', function (User $user) { // Für Live-DataTable: Verwende bereits berechnete Daten wenn verfügbar $userBusiness = UserBusiness::where('user_id', $user->id) ->where('month', $this->month) ->where('year', $this->year) ->first(); if ($userBusiness) { return NextLevelBadgeHelper::generateBadgeFromUserBusiness($userBusiness); } return NextLevelBadgeHelper::renderNoDataBadge(); }) ->addColumn('payment_account_date', function (User $user) { return $user->payment_account ? $user->getPaymentAccountDateFormat(false) : "-"; }) ->filterColumn('m_account', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("user_accounts.m_account LIKE ?", '%' . $keyword . '%'); } }) ->filterColumn('first_name', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("user_accounts.first_name LIKE ?", '%' . $keyword . '%'); } }) ->filterColumn('last_name', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("user_accounts.last_name LIKE ?", '%' . $keyword . '%'); } }) ->filterColumn('email', function ($query, $keyword) { if ($keyword != "") { $query->whereRaw("users.email LIKE ?", '%' . $keyword . '%'); } }) ->orderColumn('id', 'users.id $1') ->orderColumn('m_account', 'user_accounts.m_account $1') ->orderColumn('first_name', 'user_accounts.first_name $1') ->orderColumn('last_name', 'user_accounts.last_name $1') ->orderColumn('email', 'users.email $1') ->orderColumn('active_account', 'users.payment_account $1') ->rawColumns(['id', 'is_qual_kp', 'sales_volume_KP_points', 'sales_volume_total', 'sponsor', 'active_account', 'next_level_qualified']) ->make(true); } // ===== PRIVATE HELPER METHODS ===== /** * Optimierte Stored Search Query */ private function initStoredSearchOptimized() { $this->setFilterVars(); $query = UserBusiness::select('user_businesses.*') ->where('month', $this->month) ->where('year', $this->year); $activeFilter = Request::get('business_user_filter_active') ?: session('business_user_filter_active'); if ($activeFilter == 1) { $query->where('user_businesses.active_account', 1); } elseif ($activeFilter == 2) { $query->where('user_businesses.active_account', 0); } // activeFilter == 3 bedeutet alle (keine weitere Einschränkung) $levelFilter = Request::get('business_user_filter_level') ?: session('business_user_filter_level'); if ($levelFilter && $levelFilter != 0) { $query->where('user_businesses.m_level_id', $levelFilter); } $nextLevelFilter = Request::get('business_user_filter_next_level') ?: session('business_user_filter_next_level'); if ($nextLevelFilter && $nextLevelFilter != 0) { switch ($nextLevelFilter) { case 1: // Qualifiziert (grün) - hat next_qual_user_level $query->whereNotNull('user_businesses.next_qual_user_level') ->where('user_businesses.next_qual_user_level', '!=', '[]'); break; case 2: // In Arbeit (gelb) - hat next_can_user_level aber kein next_qual_user_level $query->where(function ($q) { $q->whereNull('user_businesses.next_qual_user_level') ->orWhere('user_businesses.next_qual_user_level', '=', '[]'); }) ->whereNotNull('user_businesses.next_can_user_level') ->where('user_businesses.next_can_user_level', '!=', '[]'); break; case 3: // Kein Level (rot) - hat weder next_qual noch next_can $query->where(function ($q) { $q->where(function ($q1) { $q1->whereNull('user_businesses.next_qual_user_level') ->orWhere('user_businesses.next_qual_user_level', '=', '[]'); }) ->where(function ($q2) { $q2->whereNull('user_businesses.next_can_user_level') ->orWhere('user_businesses.next_can_user_level', '=', '[]'); }); }); break; } } return $query; } /** * Optimierte Currently Search Query mit besseren Joins */ private function initCurrentlySearchOptimized() { $this->setFilterVars(); $query = User::with(['account', 'user_level', 'user_sponsor.account']) ->select('users.*', 'user_accounts.m_account', 'user_accounts.first_name', 'user_accounts.last_name') ->leftJoin('user_accounts', 'users.id', '=', 'user_accounts.id') ->where('users.deleted_at', '=', null) ->where('users.id', '!=', 1) ->where('users.admin', '<', 4) ->where('users.m_level', '!=', null) ->where('users.payment_account', '!=', null); $activeFilter = Request::get('business_user_filter_active') ?: session('business_user_filter_active'); if ($activeFilter == 1) { $query->where('users.payment_account', '>=', now()); } elseif ($activeFilter == 2) { $query->where('users.payment_account', '<', now()); } // activeFilter == 3 bedeutet alle (keine weitere Einschränkung) $levelFilter = Request::get('business_user_filter_level') ?: session('business_user_filter_level'); if ($levelFilter && $levelFilter != 0) { $query->where('users.m_level', $levelFilter); } // Next-Level-Filter wird bei Live-Berechnungen ignoriert (Performance-Gründe) // Dieser Filter funktioniert nur mit gespeicherten Daten $nextLevelFilter = Request::get('business_user_filter_next_level') ?: session('business_user_filter_next_level'); if ($nextLevelFilter && $nextLevelFilter != 0) { Log::info("BusinessControllerOptimized: Next-Level-Filter bei Live-Berechnung ignoriert (Performance-Gründe)"); } return $query; } /** * Filter-Variablen setzen (identisch zur Original-Version) */ private function setFilterVars() { if (!session('business_user_filter_month')) { session(['business_user_filter_month' => intval(date('m'))]); } if (!session('business_user_filter_year')) { session(['business_user_filter_year' => intval(date('Y'))]); } if (!session('business_user_filter_active')) { session(['business_user_filter_active' => 1]); } if (!session('business_user_filter_level')) { session(['business_user_filter_level' => 0]); } if (!session('business_user_filter_next_level')) { session(['business_user_filter_next_level' => 0]); } if (!session('business_user_filter_depiction')) { session(['business_user_filter_depiction' => 'active']); } if (Request::get('business_user_filter_depiction')) { session(['business_user_filter_depiction' => Request::get('business_user_filter_depiction')]); } if (Request::get('business_user_filter_name')) { session(['business_user_filter_name' => Request::get('business_user_filter_name')]); } else { session(['business_user_filter_name' => '']); } if (Request::get('business_user_filter_active')) { session(['business_user_filter_active' => Request::get('business_user_filter_active')]); } if (Request::get('business_user_filter_level')) { session(['business_user_filter_level' => Request::get('business_user_filter_level')]); } else { session(['business_user_filter_level' => 0]); } if (Request::get('business_user_filter_next_level')) { session(['business_user_filter_next_level' => Request::get('business_user_filter_next_level')]); } else { session(['business_user_filter_next_level' => 0]); } if (Request::get('business_user_filter_month')) { session(['business_user_filter_month' => Request::get('business_user_filter_month')]); } if (Request::get('business_user_filter_year')) { session(['business_user_filter_year' => Request::get('business_user_filter_year')]); } } /** * Formatiert Bytes in lesbare Einheiten */ private function formatBytes(int $bytes, int $precision = 2): string { $units = array('B', 'KB', 'MB', 'GB', 'TB'); for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) { $bytes /= 1024; } return round($bytes, $precision) . ' ' . $units[$i]; } /** * Holt verfügbare User Level für Filter */ private function getFilterLevels(): array { $levels = [0 => 'Alle Level']; $userLevels = \App\Models\UserLevel::orderBy('pos')->get(['id', 'name']); foreach ($userLevels as $level) { $levels[$level->id] = $level->name; } return $levels; } // Performance-optimierte Badge-Generierung wurde in NextLevelBadgeHelper ausgelagert // Alte performance-lastige Methoden wurden entfernt um die Datatable-Performance zu verbessern }