update 20.10.2025
This commit is contained in:
parent
8c11130b5d
commit
a939cd51ef
616 changed files with 84821 additions and 4121 deletions
|
|
@ -7,6 +7,8 @@ use stdClass;
|
|||
use Carbon\Carbon;
|
||||
use App\Models\UserLevel;
|
||||
use App\Models\UserBusiness;
|
||||
use App\Models\UserAccount;
|
||||
use App\Models\UserSalesVolume;
|
||||
use App\Services\TranslationHelper;
|
||||
use App\Models\UserBusinessStructure;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
|
@ -26,12 +28,14 @@ class BusinessUserItemOptimized
|
|||
|
||||
private $date;
|
||||
private $b_user;
|
||||
private ?TreeCalcBotOptimized $treeCalcBot = null;
|
||||
private $user_level_active_pos;
|
||||
private $needsQualificationRecalculation = false;
|
||||
|
||||
public function __construct($date)
|
||||
public function __construct($date, ?TreeCalcBotOptimized $treeCalcBot = null)
|
||||
{
|
||||
$this->date = $date;
|
||||
$this->treeCalcBot = $treeCalcBot;
|
||||
$this->businessUserItems = []; // Initialize array
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -51,22 +55,22 @@ class BusinessUserItemOptimized
|
|||
->where('month', $this->date->month)
|
||||
->where('year', $this->date->year)
|
||||
->first();
|
||||
|
||||
|
||||
if ($this->b_user !== null) {
|
||||
\Log::debug("BusinessUserItem: Using stored data for user {$user_id} ({$this->date->month}/{$this->date->year})");
|
||||
|
||||
|
||||
// WICHTIG: Auch bei gespeicherten Daten User-Model laden für Grunddaten
|
||||
$user = User::with(['account', 'user_level'])->find($user_id);
|
||||
if ($user) {
|
||||
$this->enrichStoredDataWithUserModel($user);
|
||||
|
||||
|
||||
// Prüfe ob Level-Qualifikationsdaten nachberechnet werden müssen
|
||||
if ($this->needsQualificationRecalculation) {
|
||||
\Log::debug("BusinessUserItem: Triggering qualification recalculation for user {$user_id}");
|
||||
$this->calcQualPP(); // Berechne fehlende Level-Qualifikationsdaten
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return; // Bereits gespeicherte Daten verwenden
|
||||
}
|
||||
} else {
|
||||
|
|
@ -75,20 +79,19 @@ class BusinessUserItemOptimized
|
|||
|
||||
// Lade User mit Relations (weniger effizient als makeUserFromModel)
|
||||
$user = User::with(['account', 'user_level'])->find($user_id);
|
||||
|
||||
|
||||
if (!$user) {
|
||||
\Log::warning("BusinessUserItem: User not found: {$user_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
$this->initializeFromUserModel($user);
|
||||
|
||||
|
||||
// WICHTIG: Bei Live-Berechnung auch Level-Qualifikationsdaten berechnen
|
||||
// (nicht bei forceLiveCalculation=false, da dort gespeicherte Daten bevorzugt werden)
|
||||
if ($forceLiveCalculation) {
|
||||
$this->calcQualPP();
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("BusinessUserItem: Error creating user {$user_id}: " . $e->getMessage());
|
||||
throw $e;
|
||||
|
|
@ -115,19 +118,19 @@ class BusinessUserItemOptimized
|
|||
->where('month', $this->date->month)
|
||||
->where('year', $this->date->year)
|
||||
->first();
|
||||
|
||||
|
||||
if ($this->b_user !== null) {
|
||||
\Log::debug("BusinessUserItem: Using stored data for user {$user->id} ({$this->date->month}/{$this->date->year})");
|
||||
|
||||
|
||||
// WICHTIG: Auch bei gespeicherten Daten User-Grunddaten anreichern
|
||||
$this->enrichStoredDataWithUserModel($user);
|
||||
|
||||
|
||||
// Prüfe ob Level-Qualifikationsdaten nachberechnet werden müssen
|
||||
if ($this->needsQualificationRecalculation) {
|
||||
\Log::debug("BusinessUserItem: Triggering qualification recalculation for user {$user->id}");
|
||||
$this->calcQualPP(); // Berechne fehlende Level-Qualifikationsdaten
|
||||
}
|
||||
|
||||
|
||||
return; // Bereits berechnete Daten verwenden
|
||||
}
|
||||
} else {
|
||||
|
|
@ -136,13 +139,12 @@ class BusinessUserItemOptimized
|
|||
|
||||
// Erstelle neuen User und führe Live-Berechnung durch
|
||||
$this->initializeFromUserModel($user);
|
||||
|
||||
|
||||
// WICHTIG: Bei Live-Berechnung auch Level-Qualifikationsdaten berechnen
|
||||
// (nicht bei forceLiveCalculation=false, da dort gespeicherte Daten bevorzugt werden)
|
||||
if ($forceLiveCalculation) {
|
||||
$this->calcQualPP();
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("BusinessUserItem: Error creating user from model {$user->id}: " . $e->getMessage());
|
||||
throw $e;
|
||||
|
|
@ -157,7 +159,7 @@ class BusinessUserItemOptimized
|
|||
// Nutze geladene Relations wenn verfügbar
|
||||
$user_level_active = null;
|
||||
if ($user->relationLoaded('user_level')) {
|
||||
$user_level_active = $user->user_level;
|
||||
$user_level_active = $user->user_level;
|
||||
} else {
|
||||
$user_level_active = $user->user_level; // Fallback auf Original-Relation
|
||||
}
|
||||
|
|
@ -166,11 +168,8 @@ class BusinessUserItemOptimized
|
|||
// 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}");
|
||||
}
|
||||
// Account-Daten (mit intelligentem Laden und Error-Handling)
|
||||
$account = $this->getAccountForUser($user);
|
||||
$fill = [
|
||||
'user_id' => $user->id,
|
||||
'month' => $this->date->month,
|
||||
|
|
@ -180,12 +179,12 @@ class BusinessUserItemOptimized
|
|||
'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 : '',
|
||||
|
||||
// Account-Daten mit korrekten Fallback-Werten
|
||||
'm_account' => $account ? ($account->m_account ?? null) : null,
|
||||
'email' => $user->email,
|
||||
'first_name' => $account ? $account->first_name : '',
|
||||
'last_name' => $account ? $account->last_name : '',
|
||||
'first_name' => $account ? ($account->first_name ?? '') : '',
|
||||
'last_name' => $account ? ($account->last_name ?? '') : '',
|
||||
'user_birthday' => $account ? $account->birthday : null,
|
||||
'user_phone' => $account ? ($account->getPhoneNumber() ?? '') : '',
|
||||
|
||||
|
|
@ -212,17 +211,18 @@ class BusinessUserItemOptimized
|
|||
'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)
|
||||
// Shop-Provision berechnen (mit verbessertem Logging)
|
||||
$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);
|
||||
$calculatedCommission = round($shopVolume / 100 * $shopMargin, 2);
|
||||
$this->b_user->commission_shop_sales = $calculatedCommission;
|
||||
|
||||
\Log::debug("BusinessUserItem: Created optimized user {$user->id} for {$this->date->month}/{$this->date->year}");
|
||||
\Log::debug("BusinessUserItem: Created optimized user {$user->id} for {$this->date->month}/{$this->date->year} - Shop commission: {$calculatedCommission} (Volume: {$shopVolume}, Margin: {$shopMargin}%)");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -232,38 +232,92 @@ class BusinessUserItemOptimized
|
|||
private function enrichStoredDataWithUserModel(User $user): void
|
||||
{
|
||||
try {
|
||||
$account = $user->account;
|
||||
|
||||
$account = $this->getAccountForUser($user);
|
||||
|
||||
// Ergänze fehlende User-Grunddaten in gespeicherten UserBusiness-Daten
|
||||
$this->b_user->user_id = $user->id;
|
||||
$this->b_user->email = $user->email;
|
||||
$this->b_user->first_name = $account ? $account->first_name : '';
|
||||
$this->b_user->last_name = $account ? $account->last_name : '';
|
||||
$this->b_user->first_name = $account ? ($account->first_name ?? '') : '';
|
||||
$this->b_user->last_name = $account ? ($account->last_name ?? '') : '';
|
||||
$this->b_user->user_birthday = $account ? $account->birthday : null;
|
||||
$this->b_user->user_phone = $account ? ($account->getPhoneNumber() ?? '') : '';
|
||||
$this->b_user->m_account = $account ? $account->m_account : '';
|
||||
|
||||
$this->b_user->m_account = $account ? ($account->m_account ?? null) : null;
|
||||
|
||||
// Berechne aktiven Account-Status
|
||||
$this->b_user->active_account = $this->calculateActiveAccount($user);
|
||||
$this->b_user->payment_account_date = $user->payment_account;
|
||||
|
||||
|
||||
// User-Level Informationen
|
||||
$user_level_active = $user->user_level;
|
||||
if ($user_level_active) {
|
||||
$this->b_user->user_level_name = $user_level_active->name;
|
||||
$this->user_level_active_pos = $user_level_active->pos;
|
||||
}
|
||||
|
||||
|
||||
// WICHTIG: Validiere Level-Qualifikationsdaten für Struktur-Ansicht
|
||||
$this->validateLevelQualificationData();
|
||||
|
||||
|
||||
// Prüfe ob Sales Volume Felder aktualisiert werden müssen
|
||||
$this->updateSalesVolumeFields($user);
|
||||
|
||||
\Log::debug("BusinessUserItem: Enriched stored data for user {$user->id} with current user model data");
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("BusinessUserItem: Error enriching stored data for user {$user->id}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Aktualisiert Sales Volume und Commission Felder bei gespeicherten Daten
|
||||
*/
|
||||
private function updateSalesVolumeFields(User $user): void
|
||||
{
|
||||
try {
|
||||
// Prüfe ob Sales Volume Felder leer sind
|
||||
$fieldsToUpdate = [
|
||||
'sales_volume_KP_points',
|
||||
'sales_volume_TP_points',
|
||||
'sales_volume_points_shop',
|
||||
'sales_volume_points_KP_sum',
|
||||
'sales_volume_points_TP_sum',
|
||||
'sales_volume_total',
|
||||
'sales_volume_total_shop',
|
||||
'sales_volume_total_sum'
|
||||
];
|
||||
|
||||
$needsUpdate = false;
|
||||
foreach ($fieldsToUpdate as $field) {
|
||||
if (!isset($this->b_user->{$field}) || $this->b_user->{$field} === null || $this->b_user->{$field} === 0) {
|
||||
$newValue = $this->getUserSalesVolumeOptimized($user, $field);
|
||||
$this->b_user->{$field} = $newValue;
|
||||
|
||||
if ($newValue > 0) {
|
||||
$needsUpdate = true;
|
||||
\Log::debug("BusinessUserItem: Updated {$field} for user {$user->id}: {$newValue}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Aktualisiere Shop Commission falls nötig
|
||||
if (!isset($this->b_user->commission_shop_sales) || $this->b_user->commission_shop_sales === 0) {
|
||||
$shopVolume = (float) $this->b_user->sales_volume_total_shop;
|
||||
$shopMargin = (float) $this->b_user->margin_shop;
|
||||
|
||||
if ($shopVolume > 0 && $shopMargin > 0) {
|
||||
$calculatedCommission = round($shopVolume / 100 * $shopMargin, 2);
|
||||
$this->b_user->commission_shop_sales = $calculatedCommission;
|
||||
$needsUpdate = true;
|
||||
\Log::debug("BusinessUserItem: Updated commission_shop_sales for user {$user->id}: {$calculatedCommission}");
|
||||
}
|
||||
}
|
||||
|
||||
if ($needsUpdate) {
|
||||
\Log::info("BusinessUserItem: Updated sales volume fields for user {$user->id}");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("BusinessUserItem: Error updating sales volume fields for user {$user->id}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validiert und aktualisiert Level-Qualifikationsdaten wenn nötig
|
||||
* Stellt sicher, dass next_qual_user_level und next_can_user_level für Struktur-Ansicht verfügbar sind
|
||||
|
|
@ -278,11 +332,10 @@ class BusinessUserItemOptimized
|
|||
// Wenn Level-Qualifikationsdaten fehlen, führe Neuberechnung durch
|
||||
if (!$hasNextQual && !$hasNextCan && !$hasQualUserLevel) {
|
||||
\Log::debug("BusinessUserItem: Level qualification data missing for user {$this->b_user->user_id}, triggering recalculation");
|
||||
|
||||
|
||||
// Setze Flag für notwendige Neuberechnung
|
||||
$this->needsQualificationRecalculation = true;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::warning("BusinessUserItem: Error validating level qualification data for user {$this->b_user->user_id}: " . $e->getMessage());
|
||||
}
|
||||
|
|
@ -307,17 +360,41 @@ class BusinessUserItemOptimized
|
|||
}
|
||||
|
||||
/**
|
||||
* Optimierte Sales Volume Abfrage (mit potenziellem Caching)
|
||||
* Optimierte Sales Volume Abfrage mit detailliertem Logging
|
||||
*/
|
||||
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);
|
||||
|
||||
// Direkter Aufruf mit detailliertem Logging
|
||||
$value = $user->getUserSalesVolumeBy($this->date->month, $this->date->year, $field);
|
||||
|
||||
// Log nur bei ersten Aufruf für diesen User (Performance)
|
||||
static $loggedUsers = [];
|
||||
if (!isset($loggedUsers[$user->id])) {
|
||||
$loggedUsers[$user->id] = true;
|
||||
|
||||
// Prüfe ob UserSalesVolume Daten existieren
|
||||
$userSalesVolume = $user->getUserSalesVolume($this->date->month, $this->date->year, 'first');
|
||||
if (!$userSalesVolume) {
|
||||
\Log::info("BusinessUserItem: No UserSalesVolume found for user {$user->id} in {$this->date->month}/{$this->date->year}");
|
||||
|
||||
// Prüfe neueste verfügbare Daten
|
||||
$latestVolume = \App\Models\UserSalesVolume::where('user_id', $user->id)
|
||||
->orderBy('year', 'desc')
|
||||
->orderBy('month', 'desc')
|
||||
->first();
|
||||
|
||||
if ($latestVolume) {
|
||||
\Log::info("BusinessUserItem: Latest UserSalesVolume for user {$user->id}: {$latestVolume->month}/{$latestVolume->year}");
|
||||
} else {
|
||||
\Log::warning("BusinessUserItem: No UserSalesVolume records found for user {$user->id} at all");
|
||||
}
|
||||
} else {
|
||||
\Log::debug("BusinessUserItem: UserSalesVolume found for user {$user->id} in {$this->date->month}/{$this->date->year}");
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("BusinessUserItem: Error getting sales volume {$field} for user {$user->id}: " . $e->getMessage());
|
||||
return 0; // Sicherer Fallback
|
||||
|
|
@ -333,7 +410,12 @@ class BusinessUserItemOptimized
|
|||
|
||||
public function addUserID()
|
||||
{
|
||||
TreeCalcBotOptimized::addUserID($this->b_user->user_id);
|
||||
if ($this->treeCalcBot) {
|
||||
$this->treeCalcBot->addProcessedUserId($this->b_user->user_id);
|
||||
} else {
|
||||
// Fallback für Rückwärtskompatibilität - sollte in Logs sichtbar sein
|
||||
\Log::warning("BusinessUserItemOptimized: TreeCalcBotOptimized Referenz fehlt für User ID: " . $this->b_user->user_id);
|
||||
}
|
||||
}
|
||||
|
||||
public function getBUser()
|
||||
|
|
@ -345,7 +427,7 @@ class BusinessUserItemOptimized
|
|||
{
|
||||
$this->b_user->business_lines[$line] = $obj;
|
||||
}
|
||||
|
||||
|
||||
public function addBusinessLinePoints($line, $points)
|
||||
{
|
||||
if (!isset($this->b_user->business_lines[$line])) {
|
||||
|
|
@ -354,7 +436,7 @@ class BusinessUserItemOptimized
|
|||
}
|
||||
|
||||
$obj = $this->b_user->business_lines[$line];
|
||||
|
||||
|
||||
// Handle both array and object types (JSON deserialization inconsistency)
|
||||
if (is_array($obj)) {
|
||||
$obj['points'] = ($obj['points'] ?? 0) + (float) $points;
|
||||
|
|
@ -365,7 +447,7 @@ class BusinessUserItemOptimized
|
|||
}
|
||||
$obj->points = ($obj->points ?? 0) + (float) $points;
|
||||
}
|
||||
|
||||
|
||||
$this->b_user->business_lines[$line] = $obj;
|
||||
}
|
||||
|
||||
|
|
@ -373,7 +455,7 @@ class BusinessUserItemOptimized
|
|||
{
|
||||
$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);
|
||||
|
|
@ -409,9 +491,9 @@ class BusinessUserItemOptimized
|
|||
public function getCommissionTotal(): float
|
||||
{
|
||||
return round(
|
||||
$this->b_user->commission_shop_sales +
|
||||
$this->b_user->commission_pp_total +
|
||||
$this->b_user->commission_growth_total,
|
||||
$this->b_user->commission_shop_sales +
|
||||
$this->b_user->commission_pp_total +
|
||||
$this->b_user->commission_growth_total,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
|
@ -452,8 +534,8 @@ class BusinessUserItemOptimized
|
|||
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];
|
||||
|
||||
$margin = (float) $this->b_user->qual_user_level['pr_line_' . $i];
|
||||
|
||||
// Handle both array and object types (JSON deserialization inconsistency)
|
||||
if (is_array($object)) {
|
||||
$points = (float) ($object['points'] ?? 0);
|
||||
|
|
@ -468,7 +550,7 @@ class BusinessUserItemOptimized
|
|||
$object->payline = true;
|
||||
$commission_pp_total += $object->commission;
|
||||
}
|
||||
|
||||
|
||||
$this->b_user->business_lines[$i] = $object;
|
||||
}
|
||||
}
|
||||
|
|
@ -482,7 +564,7 @@ class BusinessUserItemOptimized
|
|||
for ($i = $payline; $i <= $maxlines; $i++) {
|
||||
if (isset($this->b_user->business_lines[$i])) {
|
||||
$object = $this->b_user->business_lines[$i];
|
||||
|
||||
|
||||
// Handle both array and object types (JSON deserialization inconsistency)
|
||||
if (is_array($object)) {
|
||||
$points = (float) ($object['points'] ?? 0);
|
||||
|
|
@ -497,7 +579,7 @@ class BusinessUserItemOptimized
|
|||
$object->growth_bonus = true;
|
||||
$commission_growth_total += $object->commission;
|
||||
}
|
||||
|
||||
|
||||
$this->b_user->business_lines[$i] = $object;
|
||||
}
|
||||
}
|
||||
|
|
@ -519,7 +601,7 @@ class BusinessUserItemOptimized
|
|||
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;
|
||||
|
|
@ -535,7 +617,7 @@ class BusinessUserItemOptimized
|
|||
for ($i = 1; $i <= $paylines; $i++) {
|
||||
if (isset($this->b_user->business_lines[$i])) {
|
||||
$line = $this->b_user->business_lines[$i];
|
||||
|
||||
|
||||
// Handle both array and object types (JSON deserialization inconsistency)
|
||||
if (is_array($line)) {
|
||||
$payline_points += (float) ($line['points'] ?? 0);
|
||||
|
|
@ -561,17 +643,17 @@ class BusinessUserItemOptimized
|
|||
->first();
|
||||
if ($qualUserLevelNext) {
|
||||
$this->b_user->qual_user_level_next = $qualUserLevelNext->toArray();
|
||||
}else{
|
||||
} else {
|
||||
$this->b_user->qual_user_level_next = null;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
$this->b_user->qual_user_level_next = null;
|
||||
}
|
||||
}
|
||||
|
||||
private function setNextUserLevel($force = false): void
|
||||
{
|
||||
//sucht den nächsten level, der mehr points hat als das aktuelle level
|
||||
//sucht den nächsten level, der mehr points hat als das aktuelle level
|
||||
$nextQualUserLevel = UserLevel::where('qual_pp', '<=', $this->b_user->payline_points_qual_kp)
|
||||
->where('pos', '>', $this->user_level_active_pos)
|
||||
->orderBy('qual_pp', 'desc')
|
||||
|
|
@ -608,7 +690,7 @@ class BusinessUserItemOptimized
|
|||
if (isset($this->b_user->$name)) {
|
||||
return $this->b_user->$name;
|
||||
}
|
||||
|
||||
|
||||
// Legacy-Properties
|
||||
$legacyMap = [
|
||||
'sales_volume_points_KP_sum' => 'sales_volume_points_KP_sum',
|
||||
|
|
@ -616,11 +698,11 @@ class BusinessUserItemOptimized
|
|||
'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;
|
||||
}
|
||||
|
||||
|
|
@ -648,13 +730,15 @@ class BusinessUserItemOptimized
|
|||
if ($user->user_sponsor) {
|
||||
$sponsor->is_sponsor = true;
|
||||
$sponsor->user_id = $user->user_sponsor->id;
|
||||
|
||||
|
||||
if ($user->user_sponsor->account) {
|
||||
$sponsor->full_name = substr(
|
||||
'Sponsor: ' . $user->user_sponsor->account->first_name . ' ' .
|
||||
$user->user_sponsor->account->last_name . ' | ' .
|
||||
$user->user_sponsor->email . ' | ' .
|
||||
$user->user_sponsor->account->m_account, 0, 250
|
||||
'Sponsor: ' . $user->user_sponsor->account->first_name . ' ' .
|
||||
$user->user_sponsor->account->last_name . ' | ' .
|
||||
$user->user_sponsor->email . ' | ' .
|
||||
$user->user_sponsor->account->m_account,
|
||||
0,
|
||||
250
|
||||
);
|
||||
$sponsor->first_name = $user->user_sponsor->account->first_name;
|
||||
$sponsor->last_name = $user->user_sponsor->account->last_name;
|
||||
|
|
@ -676,9 +760,17 @@ class BusinessUserItemOptimized
|
|||
|
||||
/**
|
||||
* Lädt Parent Business Users rekursiv (Original-Implementation mit Optimierungen)
|
||||
* BUGFIX: Schutz vor unendlicher Rekursion durch zirkuläre Referenzen
|
||||
*/
|
||||
public function readParentsBusinessUsers($forceLiveCalculation = false): void
|
||||
public function readParentsBusinessUsers($forceLiveCalculation = false, $depth = 0): void
|
||||
{
|
||||
// Schutz vor zu tiefer Rekursion (maximale Tiefe: 20 Levels)
|
||||
$maxDepth = 20;
|
||||
if ($depth > $maxDepth) {
|
||||
Log::warning("BusinessUserItem: Maximale Rekursionstiefe ({$maxDepth}) erreicht für User {$this->b_user->user_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Optimiert: Lade mit Relations
|
||||
$users = User::with(['account'])
|
||||
|
|
@ -694,45 +786,64 @@ class BusinessUserItemOptimized
|
|||
|
||||
if ($users->isNotEmpty()) {
|
||||
foreach ($users as $user) {
|
||||
$businessUserItem = new BusinessUserItemOptimized($this->date);
|
||||
// KRITISCHER BUGFIX: Prüfe ob User bereits verarbeitet wurde
|
||||
if ($this->treeCalcBot && $this->treeCalcBot->isUserProcessed($user->id)) {
|
||||
Log::debug("BusinessUserItem: Überspringe bereits verarbeiteten User {$user->id} (zirkuläre Referenz verhindert)");
|
||||
continue;
|
||||
}
|
||||
|
||||
$businessUserItem = new BusinessUserItemOptimized($this->date, $this->treeCalcBot);
|
||||
$businessUserItem->makeUserFromModel($user, $forceLiveCalculation);
|
||||
$businessUserItem->addUserID();
|
||||
$this->businessUserItems[] = $businessUserItem;
|
||||
}
|
||||
}
|
||||
|
||||
// Rekursiver Aufruf für alle Child-Items
|
||||
// Rekursiver Aufruf für alle Child-Items mit Tiefenprüfung
|
||||
foreach ($this->businessUserItems as $businessUserItem) {
|
||||
$businessUserItem->readParentsBusinessUsers($forceLiveCalculation);
|
||||
$businessUserItem->readParentsBusinessUsers($forceLiveCalculation, $depth + 1);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error("BusinessUserItem: Error reading parent users for {$this->b_user->user_id}: " . $e->getMessage());
|
||||
Log::error("BusinessUserItem: Error reading parent users for {$this->b_user->user_id} at depth {$depth}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt Parent Business Users aus gespeicherter Struktur (Original-Implementation)
|
||||
* BUGFIX: Schutz vor unendlicher Rekursion durch zirkuläre Referenzen
|
||||
*/
|
||||
public function readStoredParentsBusinessUsers($structure): void
|
||||
public function readStoredParentsBusinessUsers($structure, $depth = 0): void
|
||||
{
|
||||
// Schutz vor zu tiefer Rekursion (maximale Tiefe: 50 Levels)
|
||||
$maxDepth = 50;
|
||||
if ($depth > $maxDepth) {
|
||||
Log::warning("BusinessUserItem: Maximale Rekursionstiefe ({$maxDepth}) erreicht für gespeicherte User {$this->b_user->user_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$parents = $this->findParentsBusinessOnStored($this->b_user->user_id, $structure);
|
||||
|
||||
|
||||
if ($parents) {
|
||||
foreach ($parents as $obj) {
|
||||
$businessUserItem = new BusinessUserItemOptimized($this->date);
|
||||
// KRITISCHER BUGFIX: Prüfe ob User bereits verarbeitet wurde
|
||||
if ($this->treeCalcBot && $this->treeCalcBot->isUserProcessed($obj->user_id)) {
|
||||
Log::debug("BusinessUserItem: Überspringe bereits verarbeiteten gespeicherten User {$obj->user_id} (zirkuläre Referenz verhindert)");
|
||||
continue;
|
||||
}
|
||||
|
||||
$businessUserItem = new BusinessUserItemOptimized($this->date, $this->treeCalcBot);
|
||||
$businessUserItem->makeUser($obj->user_id);
|
||||
$businessUserItem->addUserID();
|
||||
$this->businessUserItems[] = $businessUserItem;
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->businessUserItems as $businessUserItem) {
|
||||
$businessUserItem->readStoredParentsBusinessUsers($parents);
|
||||
$businessUserItem->readStoredParentsBusinessUsers($parents, $depth + 1);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error("BusinessUserItem: Error reading stored parent users: " . $e->getMessage());
|
||||
Log::error("BusinessUserItem: Error reading stored parent users at depth {$depth}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -749,7 +860,7 @@ class BusinessUserItemOptimized
|
|||
if ($user_id === $obj->user_id) {
|
||||
return $obj->parents ?? null;
|
||||
}
|
||||
|
||||
|
||||
if (!empty($obj->parents)) {
|
||||
$result = $this->findParentsBusinessOnStored($user_id, $obj->parents);
|
||||
if ($result) {
|
||||
|
|
@ -757,7 +868,7 @@ class BusinessUserItemOptimized
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -794,4 +905,43 @@ class BusinessUserItemOptimized
|
|||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intelligentes Laden des UserAccount für einen User
|
||||
* Prüft zuerst geladene Relations, lädt nach wenn nötig
|
||||
*/
|
||||
private function getAccountForUser(User $user): ?UserAccount
|
||||
{
|
||||
try {
|
||||
// Prüfe ob Account-Relation bereits geladen ist
|
||||
if ($user->relationLoaded('account')) {
|
||||
$account = $user->account;
|
||||
if ($account instanceof UserAccount) {
|
||||
\Log::debug("BusinessUserItem: Using pre-loaded account for user {$user->id}");
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
|
||||
// Wenn User keine account_id hat, gibt es definitiv kein Account
|
||||
if (!$user->account_id) {
|
||||
\Log::info("BusinessUserItem: User {$user->id} has no account_id - no account available");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Account nachladen falls nötig
|
||||
\Log::info("BusinessUserItem: Loading account for user {$user->id} (account_id: {$user->account_id})");
|
||||
$account = UserAccount::find($user->account_id);
|
||||
|
||||
if (!$account) {
|
||||
\Log::warning("BusinessUserItem: Account {$user->account_id} not found for user {$user->id}");
|
||||
return null;
|
||||
}
|
||||
|
||||
\Log::debug("BusinessUserItem: Successfully loaded account {$account->id} for user {$user->id}");
|
||||
return $account;
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("BusinessUserItem: Error loading account for user {$user->id}: " . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue