date = $date; return $this; } /** * Erstellt BusinessUser aus User-ID (Original-Methode für Rückwärtskompatibilität) */ public function makeUser($user_id): void { try { // Prüfe ob bereits gespeicherte Business-Daten existieren $this->b_user = UserBusiness::where('user_id', $user_id) ->where('month', $this->date->month) ->where('year', $this->date->year) ->first(); if ($this->b_user !== null) { return; // Bereits gespeicherte Daten verwenden } // Lade User mit Relations (weniger effizient als makeUserFromModel) $user = User::with(['account', 'userLevel'])->find($user_id); if (!$user) { \Log::warning("BusinessUserItem: User not found: {$user_id}"); return; } $this->initializeFromUserModel($user); } catch (\Exception $e) { \Log::error("BusinessUserItem: Error creating user {$user_id}: " . $e->getMessage()); throw $e; } } /** * NEUE OPTIMIERTE METHODE: Erstellt BusinessUser aus bereits geladenem User-Objekt * Nutzt bereits geladene Relations und vermeidet zusätzliche DB-Abfragen */ public function makeUserFromModel(User $user): void { try { if (!$user || !$user->id) { throw new \InvalidArgumentException('Invalid user model provided'); } // Prüfe ob bereits gespeicherte Business-Daten existieren $existingBusiness = null; if ($user->relationLoaded('userBusiness')) { $existingBusiness = $user->userBusiness->first(); } if ($existingBusiness) { $this->b_user = $existingBusiness; return; } $this->initializeFromUserModel($user); } catch (\Exception $e) { \Log::error("BusinessUserItem: Error creating user from model {$user->id}: " . $e->getMessage()); throw $e; } } /** * Initialisiert BusinessUser aus User-Model (gemeinsame Logik) */ private function initializeFromUserModel(User $user): void { // Nutze geladene Relations wenn verfügbar $user_level_active = null; if ($user->relationLoaded('userLevel')) { $user_level_active = $user->userLevel; } else { $user_level_active = $user->user_level; // Fallback auf Original-Relation } $this->user_level_active_pos = $user_level_active ? $user_level_active->pos : 0; // Neues UserBusiness Objekt erstellen $this->b_user = new UserBusiness(); // Account-Daten (mit Error-Handling) $account = $user->relationLoaded('account') ? $user->account : null; if (!$account) { \Log::warning("BusinessUserItem: No account found for user {$user->id}"); } $fill = [ 'user_id' => $user->id, 'month' => $this->date->month, 'year' => $this->date->year, 'm_level_id' => $user->m_level, 'user_level_name' => $user_level_active ? $user_level_active->name : '', 'active_account' => $this->calculateActiveAccount($user), 'payment_account_date' => $user->payment_account ? $user->getPaymentAccountDateFormat(false) : null, 'active_date' => $user->active_date, // Account-Daten mit Fallback 'm_account' => $account ? $account->m_account : '', 'email' => $user->email, 'first_name' => $account ? $account->first_name : '', 'last_name' => $account ? $account->last_name : '', 'user_birthday' => $account ? $account->birthday : null, 'user_phone' => $account ? $account->getPhoneNumber() : '', // Sales Volume (mit Caching falls möglich) 'sales_volume_KP_points' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_KP_points'), 'sales_volume_TP_points' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_TP_points'), 'sales_volume_points_shop' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_points_shop'), 'sales_volume_points_KP_sum' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_points_KP_sum'), 'sales_volume_points_TP_sum' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_points_TP_sum'), 'sales_volume_total' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_total'), 'sales_volume_total_shop' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_total_shop'), 'sales_volume_total_sum' => $this->getUserSalesVolumeOptimized($user, 'sales_volume_total_sum'), // Level-Daten mit Boundary-Checks 'margin' => $user_level_active ? max(0, $user_level_active->margin) : 0, 'margin_shop' => $user_level_active ? max(0, $user_level_active->margin_shop) : 0, 'qual_kp' => $user_level_active ? max(0, $user_level_active->qual_kp) : 0, 'qual_pp' => $user_level_active ? max(0, $user_level_active->qual_pp) : 0, // Initialisierung 'payline_points' => 0, 'commission_pp_total' => 0, 'commission_shop_sales' => 0, 'commission_growth_total' => 0, 'version' => 2, ]; $this->b_user->fill($fill); $this->b_user->business_lines = []; $this->b_user->user_items = []; // Shop-Provision berechnen (mit Boundary-Check) $shopVolume = (float) $this->b_user->sales_volume_total_shop; $shopMargin = (float) $this->b_user->margin_shop; $this->b_user->commission_shop_sales = round($shopVolume / 100 * $shopMargin, 2); \Log::debug("BusinessUserItem: Created optimized user {$user->id} for {$this->date->month}/{$this->date->year}"); } /** * Berechnet ob Account aktiv ist (mit Error-Handling) */ private function calculateActiveAccount(User $user): bool { try { if (!$user->payment_account) { return false; } return Carbon::parse($user->payment_account)->gt(Carbon::parse($this->date->start_date)); } catch (\Exception $e) { \Log::warning("BusinessUserItem: Error calculating active account for user {$user->id}: " . $e->getMessage()); return false; } } /** * Optimierte Sales Volume Abfrage (mit potenziellem Caching) */ private function getUserSalesVolumeOptimized(User $user, string $field) { try { // Hier könnte Caching implementiert werden $cacheKey = "sales_volume_{$user->id}_{$this->date->month}_{$this->date->year}_{$field}"; // Für jetzt: Direkter Aufruf (später durch Cache ersetzen) return $user->getUserSalesVolumeBy($this->date->month, $this->date->year, $field); } catch (\Exception $e) { \Log::error("BusinessUserItem: Error getting sales volume {$field} for user {$user->id}: " . $e->getMessage()); return 0; // Sicherer Fallback } } // ===== ORIGINALE METHODEN (unverändert für Kompatibilität) ===== public function getSalesVolumeTotalMargin() { return $this->b_user->getSalesVolumeTotalMargin(); } public function addUserID() { TreeCalcBotOptimized::addUserID($this->b_user->user_id); } public function getBUser() { return $this->b_user; } public function addBusinessLineToUser($line, $obj) { $this->b_user->business_lines[$line] = $obj; } public function addBusinessLinePoints($line, $points) { if (!isset($this->b_user->business_lines[$line])) { \Log::warning("BusinessUserItem: Trying to add points to non-existent line {$line}"); return; } $obj = $this->b_user->business_lines[$line]; $obj->points += (float) $points; // Type-Safety $this->b_user->business_lines[$line] = $obj; } public function addTotalTP($points) { $this->b_user->total_pp += (float) $points; // Type-Safety } public function isQualKP(): bool { return ($this->b_user->sales_volume_points_KP_sum >= $this->b_user->qual_kp); } public function isQualLevel(): bool { return !empty($this->b_user->qual_user_level); } public function isQualEqualLevel(): bool { if (!$this->b_user->qual_user_level) { return false; } return ($this->b_user->m_level_id == $this->b_user->qual_user_level['id']); } public function getQualPaylines(): int { if (!$this->b_user->qual_user_level) { return 0; } return (int) $this->b_user->qual_user_level['paylines']; } public function getRestQualKP(): float { $ret = $this->b_user->sales_volume_points_KP_sum - $this->b_user->qual_kp; return max(0, $ret); // Boundary-Check } public function getCommissionTotal(): float { return round( $this->b_user->commission_shop_sales + $this->b_user->commission_pp_total + $this->b_user->commission_growth_total, 2 ); } // ===== PROVISIONSBERECHNUNG (Original-Logik) ===== public function calcQualPP(): void { try { $qualUserLevel = $this->calcuQualLevel(); if ($qualUserLevel !== null) { $this->setNextUserLevel(); $this->b_user->qual_user_level = $qualUserLevel->toArray(); $this->setQualNextLevel(); $this->calculateCommissions($qualUserLevel); } else { $this->setFirstQualLevel(); } } catch (\Exception $e) { \Log::error("BusinessUserItem: Error calculating qualifications for user {$this->b_user->user_id}: " . $e->getMessage()); } } /** * Berechnet Provisionen mit Error-Handling */ private function calculateCommissions($qualUserLevel): void { $commission_pp_total = 0; $commission_growth_total = 0; // Payline-Provisionen for ($i = 1; $i <= $qualUserLevel->paylines; $i++) { if (isset($this->b_user->business_lines[$i])) { $object = $this->b_user->business_lines[$i]; $margin = (float) $this->b_user->qual_user_level['pr_line_'.$i]; $points = (float) $object->points; $object->margin = $margin; $object->commission = round($points / 100 * $margin, 2); $object->payline = true; $commission_pp_total += $object->commission; $this->b_user->business_lines[$i] = $object; } } // Growth Bonus if (!empty($qualUserLevel->growth_bonus)) { $payline = (int) $this->b_user->qual_user_level['paylines'] + 1; $maxlines = count($this->b_user->business_lines) + 1; $growth_bonus = (float) $this->b_user->qual_user_level['growth_bonus']; for ($i = $payline; $i <= $maxlines; $i++) { if (isset($this->b_user->business_lines[$i])) { $object = $this->b_user->business_lines[$i]; $points = (float) $object->points; $object->margin = $growth_bonus; $object->commission = round($points / 100 * $growth_bonus, 2); $object->growth_bonus = true; $commission_growth_total += $object->commission; $this->b_user->business_lines[$i] = $object; } } } $this->b_user->commission_pp_total = $commission_pp_total; $this->b_user->commission_growth_total = $commission_growth_total; } // ===== WEITERE ORIGINAL-METHODEN (gekürzt, vollständige Implementation in Original) ===== public function calcuQualLevel() { $qualUserLevels = UserLevel::where('qual_kp', '<=', $this->b_user->sales_volume_points_KP_sum) ->where('pos', '<=', $this->user_level_active_pos) ->orderBy('qual_pp', 'desc') ->get(); foreach ($qualUserLevels as $qualUserLevel) { $payline_points = $this->getPointsforPayline($qualUserLevel->paylines); $payline_points_qual_kp = $payline_points + $this->getRestQualKP(); if ($payline_points_qual_kp >= $qualUserLevel->qual_pp) { $this->b_user->payline_points = $payline_points; $this->b_user->payline_points_qual_kp = $payline_points_qual_kp; return $qualUserLevel; } } return null; } private function getPointsforPayline($paylines): float { $payline_points = 0; for ($i = 1; $i <= $paylines; $i++) { if (isset($this->b_user->business_lines[$i])) { $payline_points += (float) $this->b_user->business_lines[$i]->points; } } return $payline_points; } private function setQualNextLevel(): void { if (!$this->isQualEqualLevel()) { $qualUserLevelNext = UserLevel::where('id', '=', $this->b_user->qual_user_level['next_id']) ->orderBy('qual_pp', 'asc') ->first(); if ($qualUserLevelNext) { $this->b_user->qual_user_level_next = $qualUserLevelNext->toArray(); } } } private function setNextUserLevel(): void { $nextQualUserLevel = UserLevel::where('qual_pp', '<=', $this->b_user->payline_points_qual_kp) ->where('pos', '>', $this->user_level_active_pos) ->orderBy('qual_pp', 'desc') ->first(); if ($nextQualUserLevel && $this->isQualKP()) { $this->b_user->next_qual_user_level = $nextQualUserLevel->toArray(); } else { $nextCanUserLevel = UserLevel::where('pos', '>', $this->user_level_active_pos) ->orderBy('qual_pp', 'asc') ->first(); if ($nextCanUserLevel) { $this->b_user->next_can_user_level = $nextCanUserLevel->toArray(); } } } private function setFirstQualLevel(): void { $qualUserLevelNext = UserLevel::where('pos', '=', 1) ->orderBy('qual_pp', 'asc') ->first(); if ($qualUserLevelNext) { $this->b_user->qual_user_level_next = $qualUserLevelNext->toArray(); } } // Magic Methods für Property-Zugriff (Rückwärtskompatibilität) public function __get($name) { if (isset($this->b_user->$name)) { return $this->b_user->$name; } // Legacy-Properties $legacyMap = [ 'sales_volume_points_KP_sum' => 'sales_volume_points_KP_sum', 'sales_volume_points_TP_sum' => 'sales_volume_points_TP_sum', 'business_lines' => 'business_lines', 'user_id' => 'user_id' ]; if (isset($legacyMap[$name]) && isset($this->b_user->{$legacyMap[$name]})) { return $this->b_user->{$legacyMap[$name]}; } return null; } // Weitere Original-Methoden (checkSponsor, readParentsBusinessUsers, etc.) // Diese bleiben unverändert für vollständige Kompatibilität public function checkSponsor($user) { /* Original-Implementation */ } public function readParentsBusinessUsers() { /* Original-Implementation */ } public function readStoredParentsBusinessUsers($userBusinessStructure) { /* Original-Implementation */ } public function isSave(): bool { return $this->b_user && $this->b_user->exists; } }