10.April 2026

This commit is contained in:
Kevin Adametz 2026-04-10 17:15:27 +02:00
parent a00c42e770
commit f58c709945
208 changed files with 19280 additions and 2914 deletions

View file

@ -1,55 +1,55 @@
<?php
namespace App\Services\BusinessPlan;
use App\User;
use stdClass;
use Carbon\Carbon;
use App\Models\UserLevel;
use App\Models\UserBusiness;
use App\Services\TranslationHelper;
use App\Models\UserBusinessStructure;
use App\Models\UserLevel;
use App\User;
use Carbon\Carbon;
use stdClass;
class BusinessUserItem
{
public $businessUserItems = [];
private $date;
private $b_user;
private $user_level_active_pos;
private $b_user;
private $user_level_active_pos;
public function __construct($date)
{
$this->date = $date;
return $this;
}
public function makeUser($user_id){
public function makeUser($user_id)
{
//check for user an load is saved
// check for user an load is saved
$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){
if ($this->b_user !== null) {
return;
}
//read User here, can delete in stored data.
// read User here, can delete in stored data.
$user = User::find($user_id);
if(!$user){
if (! $user) {
return;
}
$user_level_active = $user->user_level ? $user->user_level : null;
$this->user_level_active_pos = $user_level_active ? $user_level_active->pos : 0;
$this->b_user = new UserBusiness();
$this->b_user = new UserBusiness;
$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 : '',
'user_level_name' => $user_level_active ? $user_level_active->name : '',
'active_account' => $user->payment_account ? Carbon::parse($user->payment_account)->gt(Carbon::parse($this->date->start_date)) : false,
'payment_account_date' => $user->payment_account ? $user->getPaymentAccountDateFormat(false) : NULL,
'active_date' => $user->active_date ? $user->active_date : NULL,
'payment_account_date' => $user->payment_account ? $user->getPaymentAccountDateFormat(false) : null,
'active_date' => $user->active_date ? $user->active_date : null,
'm_account' => $user->account->m_account,
'email' => $user->email,
'first_name' => $user->account->first_name,
@ -61,17 +61,17 @@ class BusinessUserItem
'sales_volume_TP_points' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_TP_points'),
'sales_volume_points_shop' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points_shop'),
'sales_volume_points_KP_sum' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points_KP_sum'), //KP + Shop Points
'sales_volume_points_TP_sum' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points_TP_sum'), //TP + Shop Points
'sales_volume_points_KP_sum' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points_KP_sum'), // KP + Shop Points
'sales_volume_points_TP_sum' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points_TP_sum'), // TP + Shop Points
'sales_volume_total' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_total'),
'sales_volume_total_shop' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_total_shop'),
'sales_volume_total_sum' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_total_sum'),
'margin' => $user_level_active ? $user_level_active->margin : 0, //is fix Rabatt für Kundenbestellungen
'margin_shop' => $user_level_active ? $user_level_active->margin_shop : 0, //is fix Rabatt für Shopbestellungen
'qual_kp' => $user_level_active ? $user_level_active->qual_kp : 0, //KP Kundenpoints from level
'qual_pp' => $user_level_active ? $user_level_active->qual_pp : 0, //PP Payline Points from level
'margin' => $user_level_active ? $user_level_active->margin : 0, // is fix Rabatt für Kundenbestellungen
'margin_shop' => $user_level_active ? $user_level_active->margin_shop : 0, // is fix Rabatt für Shopbestellungen
'qual_kp' => $user_level_active ? $user_level_active->qual_kp : 0, // KP Kundenpoints from level
'qual_pp' => $user_level_active ? $user_level_active->qual_pp : 0, // PP Payline Points from level
'payline_points' => 0,
'commission_pp_total' => 0,
@ -83,116 +83,133 @@ class BusinessUserItem
$this->b_user->business_lines = [];
$this->b_user->user_items = [];
$this->b_user->commission_shop_sales = round($this->b_user->sales_volume_total_shop / 100 * $this->b_user->margin_shop, 2);
}
public function getSalesVolumeTotalMargin()
{
return $this->b_user->getSalesVolumeTotalMargin();
}
public function getSalesVolumeTotalMargin(){
return $this->b_user->getSalesVolumeTotalMargin();
}
public function addUserID(){
public function addUserID()
{
TreeCalcBot::addUserID($this->b_user->user_id);
}
public function getBUser(){
public function getBUser()
{
return $this->b_user;
}
public function addBusinessLineToUser($line, $obj){
public function addBusinessLineToUser($line, $obj)
{
$this->b_user->business_lines[$line] = $obj;
}
public function addBusinessLinePoints($line, $points){
public function addBusinessLinePoints($line, $points)
{
$obj = $this->business_lines[$line];
$obj->points += $points;
$this->b_user->business_lines[$line] = $obj;
}
public function addTotalTP($points){
public function addTotalTP($points)
{
$this->b_user->total_pp += $points;
}
public function isQualKP(){
public function isQualKP()
{
return ($this->sales_volume_points_KP_sum >= $this->qual_kp) ? true : false;
}
public function isQualLevel(){
public function isQualLevel()
{
return ($this->qual_user_level) ? true : false;
}
public function isQualEqualLevel(){
if($this->qual_user_level){
public function isQualEqualLevel()
{
if ($this->qual_user_level) {
return ($this->m_level_id == $this->qual_user_level['id']) ? true : false;
}
return false;
}
public function getQualLevelPaylines(){
if($this->qual_user_level){
public function getQualLevelPaylines()
{
if ($this->qual_user_level) {
return $this->qual_user_level['paylines'];
}
return 0;
}
public function isQualLevelGrowth($line){
if(isset($this->business_lines[$line])){
public function isQualLevelGrowth($line)
{
if (isset($this->business_lines[$line])) {
$object = $this->business_lines[$line];
if(isset($object->growth_bonus)){
if (isset($object->growth_bonus)) {
return true;
}
}
return false;
}
public function getRestQualKP(){
public function getRestQualKP()
{
$ret = $this->sales_volume_points_KP_sum - $this->qual_kp;
return $ret > 0 ? $ret : 0;
}
public function getCommissionTotal(){
public function getCommissionTotal()
{
return round($this->commission_shop_sales + $this->commission_pp_total + $this->commission_growth_total, 2);
}
//Provisierungslevel brechnen, Berechnung der Provisionen nach Level
public function calcQualPP(){
//das ist der erreichte Provisierungslevel, nach paylinePoints und KP
// Provisierungslevel brechnen, Berechnung der Provisionen nach Level
public function calcQualPP()
{
// das ist der erreichte Provisierungslevel, nach paylinePoints und KP
$qualUserLevel = $this->calcuQualLevel();
if($qualUserLevel !== NULL){
//prüfe einen Aufsieg im KarriereLevel
if ($qualUserLevel !== null) {
// prüfe einen Aufsieg im KarriereLevel
$this->setNextUserLevel();
$this->b_user->qual_user_level = $qualUserLevel->toArray();
//setzen nächsten ProvisionsLevel wenn not isQualEqualLevel
// setzen nächsten ProvisionsLevel wenn not isQualEqualLevel
$this->setQualNextLevel();
//Berechnung der Provisionen in der Payline
// Berechnung der Provisionen in der Payline
$commission_pp_total = 0;
$commission_growth_total = 0;
for ($i=1; $i <= $qualUserLevel->paylines ; $i++) {
if(isset($this->business_lines[$i])){
for ($i = 1; $i <= $qualUserLevel->paylines; $i++) {
if (isset($this->business_lines[$i])) {
$object = $this->business_lines[$i];
$object->margin = $this->qual_user_level['pr_line_'.$i]; //provision in %
$object->commission = round($object->points / 100 * $object->margin, 2); //provision in points/euro
$object->margin = $this->qual_user_level['pr_line_'.$i]; // provision in %
$object->commission = round($object->points / 100 * $object->margin, 2); // provision in points/euro
$object->payline = true;
$commission_pp_total += $object->commission;
$this->b_user->business_lines[$i] = $object;
$this->b_user->business_lines[$i] = $object;
}
}
//Berechnung der Provisionen nach WB
if($qualUserLevel->growth_bonus){
//['growth_bonus'] //
// Berechnung der Provisionen nach WB
if ($qualUserLevel->growth_bonus) {
// ['growth_bonus'] //
$payline = (int) $this->b_user->qual_user_level['paylines'] + 1;
$maxlines = count($this->business_lines) + 1;
$growth_bonus = (float) $this->b_user->qual_user_level['growth_bonus'];
for ($i=$payline; $i <= $maxlines ; $i++) {
if(isset($this->business_lines[$i])){
for ($i = $payline; $i <= $maxlines; $i++) {
if (isset($this->business_lines[$i])) {
$object = $this->business_lines[$i];
$object->margin = $growth_bonus; //provision in %
$object->commission = round($object->points / 100 * $object->margin, 2); //provision in points/euro
$object->margin = $growth_bonus; // provision in %
$object->commission = round($object->points / 100 * $object->margin, 2); // provision in points/euro
$object->growth_bonus = true;
$commission_growth_total += $object->commission;
$this->b_user->business_lines[$i] = $object;
$this->b_user->business_lines[$i] = $object;
}
}
@ -200,73 +217,78 @@ class BusinessUserItem
$this->b_user->commission_pp_total = $commission_pp_total;
$this->b_user->commission_growth_total = $commission_growth_total;
}else{
//erste Provisierungslevel als next setzen, hat keine oder wenig points
} else {
// erste Provisierungslevel als next setzen, hat keine oder wenig points
$qualUserLevelNext = UserLevel::where('pos', '=', 1)->orderBy('qual_pp', 'asc')->first();
if($qualUserLevelNext){
if ($qualUserLevelNext) {
$this->b_user->qual_user_level_next = $qualUserLevelNext->toArray();
}
}
}
//qualifikation nach qual_kp (KundenPoints) und qual_pp (PaylinePoints)
public function calcuQualLevel(){
//alle levels wo die qual_kp erreicht ist, sortiert nach Rang >
$qualUserLevels = UserLevel::where('qual_kp', '<=', $this->sales_volume_points_KP_sum)->where('pos', '<=', $this->user_level_active_pos)->orderBy('qual_pp', 'desc')->get();
foreach($qualUserLevels as $qualUserLevel){
//brechnet die Points nach der Payline
// qualifikation nach qual_kp (KundenPoints) und qual_pp (PaylinePoints)
public function calcuQualLevel()
{
// alle levels wo die qual_kp erreicht ist, sortiert nach Rang >
$qualUserLevels = UserLevel::where('qual_kp', '<=', $this->sales_volume_points_KP_sum)->where('pos', '<=', $this->user_level_active_pos)->orderBy('qual_pp', 'desc')->get();
foreach ($qualUserLevels as $qualUserLevel) {
// brechnet die Points nach der Payline
$payline_points = $this->getPointsforPayline($qualUserLevel->paylines);
$payline_points_qual_kp = $payline_points + $this->getRestQualKP();
if($payline_points_qual_kp >= $qualUserLevel->qual_pp){
//match payline_points erreicht, ist der akutelle Level für die Provision
if ($payline_points_qual_kp >= $qualUserLevel->qual_pp) {
// match payline_points erreicht, ist der akutelle Level für die Provision
$this->b_user->payline_points = $payline_points;
$this->b_user->payline_points_qual_kp = $payline_points_qual_kp;
return $qualUserLevel;
}
}
return NULL;
}
return null;
}
// PaylinePoints nach paylines / welche ebenen gezählt werden, 3,4,5,6 ...
private function getPointsforPayline($paylines){
private function getPointsforPayline($paylines)
{
$payline_points = 0;
for ($i=1; $i <= $paylines ; $i++) {
if(isset($this->business_lines[$i])){
for ($i = 1; $i <= $paylines; $i++) {
if (isset($this->business_lines[$i])) {
$payline_points += $this->business_lines[$i]->points;
}
}
return $payline_points;
}
//wenn nicht erreicht, was wäre der nächste Provisionslevel?
private function setQualNextLevel(){
if(!$this->isQualEqualLevel()){
// wenn nicht erreicht, was wäre der nächste Provisionslevel?
private function setQualNextLevel()
{
if (! $this->isQualEqualLevel()) {
$qualUserLevelNext = UserLevel::where('id', '=', $this->b_user->qual_user_level['next_id'])->orderBy('qual_pp', 'asc')->first();
if($qualUserLevelNext){
if ($qualUserLevelNext) {
$this->b_user->qual_user_level_next = $qualUserLevelNext->toArray();
}
}
}
}
private function setNextUserLevel(){
// $this->b_user->payline_points_qual_kp // das sind die Payline Points + Rest KP
//$this->b_user->total_qual_pp = $this->total_pp + $this->getRestQualKP(); //hier werden alle Linien TP gezähle
//$this->b_user->total_qual_pp = $this->total_pp + $this->getRestQualKP(); //hier werden alle Linien TP gezähle
$nextQualUserLevel = UserLevel::where('qual_pp', '<=', $this->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{
//wenn nicht erreicht, was wäre der nächste Karrierelevel?
$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 setNextUserLevel()
{
// $this->b_user->payline_points_qual_kp // das sind die Payline Points + Rest KP
// $this->b_user->total_qual_pp = $this->total_pp + $this->getRestQualKP(); //hier werden alle Linien TP gezähle
// $this->b_user->total_qual_pp = $this->total_pp + $this->getRestQualKP(); //hier werden alle Linien TP gezähle
$nextQualUserLevel = UserLevel::where('qual_pp', '<=', $this->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 {
// wenn nicht erreicht, was wäre der nächste Karrierelevel?
$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();
}
}
}
/*public function storeUser(){
@ -286,75 +308,81 @@ class BusinessUserItem
$obj->line = $line;
$obj->points = $userItem->sales_volume_points_sum;
$obj->parents = $temp;
$ret[] = $obj;
$ret[] = $obj;
}
return $ret;
}*/
public function readParentsBusinessUsers(){
$users = User::with('account')->select('users.*')
->where('users.deleted_at', '=', null)
->where('users.id', '!=', 1)
->where('users.admin', "<", 4)
->where('users.m_level', "!=", null)
->where('users.m_sponsor', "=", $this->b_user->user_id) //<- need the id for parents / sponsors
->where('users.payment_account', "!=", null)
->where('users.active_date', "<=", $this->date->end_date) // wurde in dem Monat freigeschaltet
->get();
public function readParentsBusinessUsers()
{
if($users){
foreach($users as $user){
$BusinessUserItem = new BusinessUserItem($this->date);
$BusinessUserItem->makeUser($user->id);
$BusinessUserItem->addUserID();
$this->businessUserItems[] = $BusinessUserItem;
}
}
foreach($this->businessUserItems as $businessUserItem){
$businessUserItem->readParentsBusinessUsers();
$users = User::with('account')->select('users.*')
->where('users.deleted_at', '=', null)
->where('users.id', '!=', 1)
->where('users.admin', '<', 4)
->where('users.m_level', '!=', null)
->whereColumn('users.id', '!=', 'users.m_sponsor')
->where('users.m_sponsor', '=', $this->b_user->user_id) // <- need the id for parents / sponsors
->where('users.payment_account', '!=', null)
->where('users.active_date', '<=', $this->date->end_date) // wurde in dem Monat freigeschaltet
->get();
if ($users) {
foreach ($users as $user) {
$BusinessUserItem = new BusinessUserItem($this->date);
$BusinessUserItem->makeUser($user->id);
$BusinessUserItem->addUserID();
$this->businessUserItems[] = $BusinessUserItem;
}
}
foreach ($this->businessUserItems as $businessUserItem) {
$businessUserItem->readParentsBusinessUsers();
}
}
public function readStoredParentsBusinessUsers($structure){
public function readStoredParentsBusinessUsers($structure)
{
$parents = $this->findParentsBusinessOnStored($this->b_user->user_id, $structure);
if($parents){
foreach($parents as $obj){
if ($parents) {
foreach ($parents as $obj) {
$BusinessUserItem = new BusinessUserItem($this->date);
$BusinessUserItem->makeUser($obj->user_id);
$BusinessUserItem->addUserID();
$this->businessUserItems[] = $BusinessUserItem;
$this->businessUserItems[] = $BusinessUserItem;
}
foreach($this->businessUserItems as $businessUserItem){
foreach ($this->businessUserItems as $businessUserItem) {
$businessUserItem->readStoredParentsBusinessUsers($parents);
}
}
}
private function findParentsBusinessOnStored($user_id, $structures){
if($structures){
foreach($structures as $obj){
if($user_id === $obj->user_id){
private function findParentsBusinessOnStored($user_id, $structures)
{
if ($structures) {
foreach ($structures as $obj) {
if ($user_id === $obj->user_id) {
return $obj->parents;
}
if($obj->parents){
if($ret = $this->findParentsBusinessOnStored($user_id, $obj->parents)){
if ($obj->parents) {
if ($ret = $this->findParentsBusinessOnStored($user_id, $obj->parents)) {
return $ret;
}
}
}
}
}
}
return null;
}
public function checkSponsor($user){
public function checkSponsor($user)
{
//check is store? has ID
if($this->b_user->isSave()){
// check is store? has ID
if ($this->b_user->isSave()) {
return;
}
$sponsor = new stdClass();
$sponsor = new stdClass;
$sponsor->is_sponsor = false;
$sponsor->user_id = false;
@ -364,34 +392,36 @@ class BusinessUserItem
$sponsor->m_account = '';
$sponsor->full_name = 'Keinen Sponsor zugewiesen';
if($user->m_sponsor){
if ($user->m_sponsor) {
if($user->user_sponsor){
if ($user->user_sponsor) {
$sponsor->is_sponsor = true;
$sponsor->user_id = $user->user_sponsor->id;
if($user->user_sponsor->account){
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->first_name = $user->user_sponsor->account->last_name;
$sponsor->last_name = $user->user_sponsor->account->first_name;
$sponsor->m_account = $user->user_sponsor->account->m_account;
}else{
} else {
$sponsor->full_name = 'Sponsor: '.$user->user_sponsor->email;
}
$sponsor->email = $user->user_sponsor->email;
}else{
$sponsor->full_name = 'Sponsor wurde gelöscht.';
} else {
$sponsor->full_name = 'Sponsor wurde gelöscht.';
}
}
$this->b_user->sponsor = $sponsor;
return;
}
public function isSave(){
public function isSave()
{
return $this->b_user->isSave();
}
public function __get($property) {
if($this->b_user === null){
public function __get($property)
{
if ($this->b_user === null) {
return null;
}
if (property_exists($this->b_user, $property)) {
@ -400,6 +430,5 @@ class BusinessUserItem
if (isset($this->b_user->{$property})) {
return $this->b_user->{$property};
}
}
}
}

View file

@ -2,21 +2,20 @@
namespace App\Services\BusinessPlan;
use App\User;
use stdClass;
use Carbon\Carbon;
use App\Models\UserLevel;
use App\Models\UserBusiness;
use App\Models\UserAccount;
use App\Models\UserBusiness;
use App\Models\UserLevel;
use App\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use stdClass;
/**
* Optimierte Version der BusinessUserItem Klasse
*
*
* Hauptverbesserungen:
* - makeUserFromModel() für bereits geladene User-Objekte
* - Bessere Error-Behandlung mit Logging
* - Bessere Error-Behandlung mit Logging
* - Optimierte Datenbankzugriffe durch Relations-Nutzung
* - Input-Validierung und Boundary-Checks
*/
@ -25,10 +24,15 @@ class BusinessUserItemOptimized
public $businessUserItems = [];
private $date;
private $b_user;
private ?TreeCalcBotOptimized $treeCalcBot = null;
private $user_level_active_pos;
private $needsQualificationRecalculation = false;
private $qualificationCalculated = false;
public function __construct($date, ?TreeCalcBotOptimized $treeCalcBot = null)
@ -36,6 +40,7 @@ class BusinessUserItemOptimized
$this->date = $date;
$this->treeCalcBot = $treeCalcBot;
$this->businessUserItems = []; // Initialize array
return $this;
}
@ -44,18 +49,17 @@ class BusinessUserItemOptimized
return $this->qualificationCalculated;
}
/**
* Erstellt BusinessUser aus User-ID (Original-Methode für Rückwärtskompatibilität)
*
* @param int $user_id Die User-ID
* @param bool $forceLiveCalculation Erzwingt Live-Berechnung und überspringt gespeicherte Daten
*
* @param int $user_id Die User-ID
* @param bool $forceLiveCalculation Erzwingt Live-Berechnung und überspringt gespeicherte Daten
*/
public function makeUser($user_id, bool $forceLiveCalculation = false): void
{
try {
// Prüfe nur nach gespeicherten Daten, wenn keine Live-Berechnung erzwungen wird
if (!$forceLiveCalculation) {
if (! $forceLiveCalculation) {
$this->b_user = UserBusiness::where('user_id', $user_id)
->where('month', $this->date->month)
->where('year', $this->date->year)
@ -85,8 +89,9 @@ class BusinessUserItemOptimized
// Lade User mit Relations (weniger effizient als makeUserFromModel)
$user = User::with(['account', 'user_level'])->find($user_id);
if (!$user) {
if (! $user) {
\Log::warning("BusinessUserItem: User not found: {$user_id}");
return;
}
@ -98,7 +103,7 @@ class BusinessUserItemOptimized
$this->calcQualPP();
}
} catch (\Exception $e) {
\Log::error("BusinessUserItem: Error creating user {$user_id}: " . $e->getMessage());
\Log::error("BusinessUserItem: Error creating user {$user_id}: ".$e->getMessage());
throw $e;
}
}
@ -106,20 +111,20 @@ class BusinessUserItemOptimized
/**
* NEUE OPTIMIERTE METHODE: Erstellt BusinessUser aus bereits geladenem User-Objekt
* Konsistent zur ursprünglichen makeUser Logik - prüft explizit nach bereits berechneten Daten
*
* @param User $user Das User-Model
* @param bool $forceLiveCalculation Erzwingt Live-Berechnung und überspringt gespeicherte Daten
*
* @param User $user Das User-Model
* @param bool $forceLiveCalculation Erzwingt Live-Berechnung und überspringt gespeicherte Daten
*/
public function makeUserFromModel(User $user, bool $forceLiveCalculation = false): void
{
\Log::debug("BusinessUserItemOptimized: makeUserFromModel for user {$user->id} ({$this->date->month}/{$this->date->year})");
try {
if (!$user || !$user->id) {
if (! $user || ! $user->id) {
throw new \InvalidArgumentException('Invalid user model provided');
}
// Prüfe nur nach gespeicherten Daten, wenn keine Live-Berechnung erzwungen wird
if (!$forceLiveCalculation) {
if (! $forceLiveCalculation) {
$this->b_user = UserBusiness::where('user_id', $user->id)
->where('month', $this->date->month)
->where('year', $this->date->year)
@ -147,10 +152,10 @@ class BusinessUserItemOptimized
// WICHTIG: Bei Live-Berechnung auch Level-Qualifikationsdaten berechnen
// (nicht bei forceLiveCalculation=false, da dort gespeicherte Daten bevorzugt werden)
if ($forceLiveCalculation) {
//$this->calcQualPP();
// $this->calcQualPP();
}
} catch (\Exception $e) {
\Log::error("BusinessUserItemOptimized: Error creating user from model {$user->id}: " . $e->getMessage());
\Log::error("BusinessUserItemOptimized: Error creating user from model {$user->id}: ".$e->getMessage());
throw $e;
}
}
@ -170,7 +175,7 @@ class BusinessUserItemOptimized
$this->user_level_active_pos = $user_level_active ? $user_level_active->pos : 0;
// Neues UserBusiness Objekt erstellen
$this->b_user = new UserBusiness();
$this->b_user = new UserBusiness;
// Account-Daten (mit intelligentem Laden und Error-Handling)
$account = $this->getAccountForUser($user);
@ -208,7 +213,7 @@ class BusinessUserItemOptimized
'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,
'active_growth_bonus' => $user_level_active ? (float)$user_level_active->growth_bonus : 0,
'active_growth_bonus' => $user_level_active ? (float) $user_level_active->growth_bonus : 0,
'growth_bonus_details' => null,
// Initialisierung
@ -230,7 +235,7 @@ class BusinessUserItemOptimized
$this->b_user->commission_shop_sales = $calculatedCommission;
\Log::debug("BusinessUserItem: Created optimized user {$user->id} for {$this->date->month}/{$this->date->year} - Shop commission: {$calculatedCommission} (Volume: {$shopVolume}, Margin: {$shopMargin}%)");
\Log::debug("BusinessUserItemOptimized: b_user: " . json_encode($this->b_user));
\Log::debug('BusinessUserItemOptimized: b_user: '.json_encode($this->b_user));
}
/**
@ -270,7 +275,7 @@ class BusinessUserItemOptimized
\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());
\Log::error("BusinessUserItem: Error enriching stored data for user {$user->id}: ".$e->getMessage());
}
}
@ -289,12 +294,12 @@ class BusinessUserItemOptimized
'sales_volume_points_TP_sum',
'sales_volume_total',
'sales_volume_total_shop',
'sales_volume_total_sum'
'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) {
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;
@ -306,7 +311,7 @@ class BusinessUserItemOptimized
}
// Aktualisiere Shop Commission falls nötig
if (!isset($this->b_user->commission_shop_sales) || $this->b_user->commission_shop_sales === 0) {
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;
@ -322,7 +327,7 @@ class BusinessUserItemOptimized
\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());
\Log::error("BusinessUserItem: Error updating sales volume fields for user {$user->id}: ".$e->getMessage());
}
}
@ -334,18 +339,18 @@ class BusinessUserItemOptimized
{
try {
// Prüfe ob Level-Qualifikationsdaten vorhanden sind
$hasNextQual = !empty($this->b_user->next_qual_user_level);
$hasNextCan = !empty($this->b_user->next_can_user_level);
$hasQualUserLevel = !empty($this->b_user->qual_user_level);
$hasNextQual = ! empty($this->b_user->next_qual_user_level);
$hasNextCan = ! empty($this->b_user->next_can_user_level);
$hasQualUserLevel = ! empty($this->b_user->qual_user_level);
// Wenn Level-Qualifikationsdaten fehlen, führe Neuberechnung durch
if (!$hasNextQual && !$hasNextCan && !$hasQualUserLevel) {
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());
\Log::warning("BusinessUserItem: Error validating level qualification data for user {$this->b_user->user_id}: ".$e->getMessage());
}
}
@ -355,14 +360,15 @@ class BusinessUserItemOptimized
private function calculateActiveAccount(User $user): bool
{
try {
if (!$user->payment_account) {
if (! $user->payment_account) {
return false;
}
// Verwende aktuelles Datum, nicht das Berechnungs-Startdatum
return Carbon::parse($user->payment_account)->gt(Carbon::now());
} catch (\Exception $e) {
\Log::warning("BusinessUserItem: Error calculating active account for user {$user->id}: " . $e->getMessage());
\Log::warning("BusinessUserItem: Error calculating active account for user {$user->id}: ".$e->getMessage());
return false;
}
}
@ -378,12 +384,12 @@ class BusinessUserItemOptimized
// Log nur bei ersten Aufruf für diesen User (Performance)
static $loggedUsers = [];
if (!isset($loggedUsers[$user->id])) {
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) {
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
@ -404,7 +410,8 @@ class BusinessUserItemOptimized
return $value;
} catch (\Exception $e) {
\Log::error("BusinessUserItem: Error getting sales volume {$field} for user {$user->id}: " . $e->getMessage());
\Log::error("BusinessUserItem: Error getting sales volume {$field} for user {$user->id}: ".$e->getMessage());
return 0; // Sicherer Fallback
}
}
@ -422,7 +429,7 @@ class BusinessUserItemOptimized
$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);
\Log::warning('BusinessUserItemOptimized: TreeCalcBotOptimized Referenz fehlt für User ID: '.$this->b_user->user_id);
}
}
@ -441,7 +448,7 @@ class BusinessUserItemOptimized
*/
public function initBusinessLines(): void
{
if (!isset($this->b_user->business_lines) || !is_array($this->b_user->business_lines)) {
if (! isset($this->b_user->business_lines) || ! is_array($this->b_user->business_lines)) {
$this->b_user->business_lines = [];
}
}
@ -456,8 +463,9 @@ class BusinessUserItemOptimized
public function addBusinessLinePoints($line, $points)
{
if (!isset($this->b_user->business_lines[$line])) {
if (! isset($this->b_user->business_lines[$line])) {
\Log::warning("BusinessUserItem: Trying to add points to non-existent line {$line}");
return;
}
@ -468,7 +476,7 @@ class BusinessUserItemOptimized
$obj['points'] = ($obj['points'] ?? 0) + (float) $points;
} else {
// Ensure it's an object
if (!is_object($obj)) {
if (! is_object($obj)) {
$obj = (object) $obj;
}
$obj->points = ($obj->points ?? 0) + (float) $points;
@ -490,18 +498,19 @@ class BusinessUserItemOptimized
return [];
}
if (!$this->isQualLevel() || empty($this->b_user->qual_user_level['growth_bonus'])) {
if (! $this->isQualLevel() || empty($this->b_user->qual_user_level['growth_bonus'])) {
return [];
}
try {
$calculator = new GrowthBonusCalculator();
$calculator = new GrowthBonusCalculator;
// Array zu Object konvertieren für Calculator
$qualData = (object) $this->b_user->qual_user_level;
return $calculator->getCalculationDetails($this, $qualData);
} catch (\Exception $e) {
\Log::error("BusinessUserItem: Error getting growth bonus breakdown: " . $e->getMessage());
\Log::error('BusinessUserItem: Error getting growth bonus breakdown: '.$e->getMessage());
return [];
}
}
@ -519,12 +528,12 @@ class BusinessUserItemOptimized
return [];
}
if (!$this->isQualLevel() || empty($this->b_user->qual_user_level['growth_bonus'])) {
if (! $this->isQualLevel() || empty($this->b_user->qual_user_level['growth_bonus'])) {
return [];
}
// Use stored details if available (avoid recalculation)
if (!empty($this->b_user->growth_bonus_details)) {
if (! empty($this->b_user->growth_bonus_details)) {
if (is_object($this->b_user->growth_bonus_details) && method_exists($this->b_user->growth_bonus_details, 'toArray')) {
return $this->b_user->growth_bonus_details->toArray();
}
@ -538,13 +547,14 @@ class BusinessUserItemOptimized
}
try {
$calculator = new GrowthBonusCalculator();
$calculator = new GrowthBonusCalculator;
// Array zu Object konvertieren für Calculator
$qualData = (object) $this->b_user->qual_user_level;
return $calculator->getMatrixDetails($this, $qualData);
} catch (\Exception $e) {
\Log::error("BusinessUserItem: Error getting growth bonus matrix: " . $e->getMessage());
\Log::error('BusinessUserItem: Error getting growth bonus matrix: '.$e->getMessage());
return [];
}
}
@ -556,12 +566,12 @@ class BusinessUserItemOptimized
public function isQualKP(): bool
{
return ($this->b_user->sales_volume_points_KP_sum >= $this->b_user->qual_kp);
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);
return ! empty($this->b_user->qual_user_level);
}
/**
@ -587,15 +597,15 @@ class BusinessUserItemOptimized
/**
* Gibt den Growth Bonus basierend auf dem ERREICHTEN Qualifikations-Level zurück.
*
*
* WICHTIG: Diese Methode gibt den Growth Bonus nur zurück, wenn der Partner
* in dem Monat tatsächlich das entsprechende Level qualifiziert hat.
* Das ist entscheidend für die korrekte Differenz-Berechnung im GrowthBonusCalculator.
*
*
* Die Methode funktioniert sowohl für:
* - Live-berechnete Daten (qualificationCalculated = true)
* - Gespeicherte/geladene Daten aus UserBusiness (qual_user_level bereits vorhanden)
*
*
* @return float Der Growth Bonus des erreichten Qualifikations-Levels (0 wenn nicht qualifiziert)
*/
public function getQualifiedGrowthBonus(): float
@ -627,23 +637,26 @@ class BusinessUserItemOptimized
public function isQualEqualLevel(): bool
{
if (!$this->b_user->qual_user_level) {
if (! $this->b_user->qual_user_level) {
return false;
}
return ($this->b_user->m_level_id == $this->b_user->qual_user_level['id']);
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) {
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
}
@ -661,7 +674,7 @@ class BusinessUserItemOptimized
public function calcQualPP($force = false): void
{
if ($this->qualificationCalculated && !$force) {
if ($this->qualificationCalculated && ! $force) {
return;
}
@ -670,9 +683,9 @@ class BusinessUserItemOptimized
try {
$qualUserLevel = $this->calcuQualLevel();
\Log::debug("BusinessUserItemOptimized: calcQualPP for user {$this->b_user->user_id}: " . json_encode($qualUserLevel));
\Log::debug("BusinessUserItemOptimized: calcQualPP for user {$this->b_user->user_id}: ".json_encode($qualUserLevel));
if ($qualUserLevel !== null) {
//das erreichte level setzen
// das erreichte level setzen
$this->b_user->qual_user_level = $qualUserLevel->toArray();
// Wichtig: Setze die qual_kp und qual_pp des erreichten Levels im b_user Objekt
// Diese Werte ändern sich je nach erreichtem Level und müssen hier aktualisiert werden
@ -681,17 +694,17 @@ class BusinessUserItemOptimized
\Log::debug("BusinessUserItemOptimized: Set qual_kp={$qualUserLevel->qual_kp}, qual_pp={$qualUserLevel->qual_pp} for user {$this->b_user->user_id}");
//next_qual_user_level nächster qualifizierten level
// next_qual_user_level nächster qualifizierten level
$this->setNextUserLevel($force);
//qual_user_level_next nächste Provisions-Stufe,
// qual_user_level_next nächste Provisions-Stufe,
$this->setQualNextLevel($force);
//provisionen berechnen
// provisionen berechnen
$this->calculateCommissions($qualUserLevel);
} else {
$this->setFirstQualLevel();
}
} catch (\Exception $e) {
\Log::error("BusinessUserItem: Error calculating qualifications for user {$this->b_user->user_id}: " . $e->getMessage());
\Log::error("BusinessUserItem: Error calculating qualifications for user {$this->b_user->user_id}: ".$e->getMessage());
}
}
@ -708,7 +721,7 @@ 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)) {
@ -730,7 +743,7 @@ class BusinessUserItemOptimized
}
// Growth Bonus
if (!empty($qualUserLevel->growth_bonus)) {
if (! empty($qualUserLevel->growth_bonus)) {
// Fallback für alte Monate (vor November 2025)
// Stichtag: 01.11.2025 - Alles davor nutzt die Legacy-Berechnung
$isLegacy = ($this->date->year < 2025) || ($this->date->year == 2025 && $this->date->month < 11);
@ -741,10 +754,9 @@ class BusinessUserItemOptimized
} else {
// Neue Logik ab Dezember 2025 - delegated to new Calculator service
try {
$growthCalculator = new GrowthBonusCalculator();
$growthCalculator = new GrowthBonusCalculator;
$commission_growth_total = $growthCalculator->calculate($this, $qualUserLevel);
// Calculate matrix details for storage and total sum
// This ensures that the stored details match the calculated total exactly
$matrixDetails = $growthCalculator->getMatrixDetails($this, $qualUserLevel);
@ -752,7 +764,7 @@ class BusinessUserItemOptimized
// Store details in the model so they can be retrieved later without recalculation
$this->b_user->growth_bonus_details = $matrixDetails;
} catch (\Exception $e) {
\Log::error("BusinessUserItem: Error calculating growth bonus for user {$this->b_user->user_id}: " . $e->getMessage());
\Log::error("BusinessUserItem: Error calculating growth bonus for user {$this->b_user->user_id}: ".$e->getMessage());
// Fallback to 0 if calculation fails
$commission_growth_total = 0;
$this->b_user->growth_bonus_details = null;
@ -789,7 +801,7 @@ class BusinessUserItemOptimized
$object['growth_bonus'] = true;
$commission_growth_total += $object['commission'];
} else {
if (!is_object($object)) {
if (! is_object($object)) {
$object = (object) $object;
}
$points = (float) ($object->points ?? 0);
@ -824,13 +836,12 @@ class BusinessUserItemOptimized
foreach ($qualUserLevels as $qualUserLevel) {
// Berechne die Payline-Punkte für die spezifischen Paylines dieses Levels
$payline_points = $this->getPointsforPayline($qualUserLevel->paylines);
\Log::debug("BusinessUserItemOptimized: payline_points: " . $payline_points);
\Log::debug('BusinessUserItemOptimized: payline_points: '.$payline_points);
// WICHTIG: Berechne die Rest-KP basierend auf der qual_kp DES AKTUELL GEPRÜFTEN LEVELS
// nicht der qual_kp des bereits gesetzten Levels (das war der Fehler!)
$rest_kp = max(0, $this->b_user->sales_volume_points_KP_sum - $qualUserLevel->qual_kp);
$payline_points_qual_kp = $payline_points + $rest_kp;
// Prüfe ob die Qualifikation für diesen spezifischen Level erfüllt ist
if ($payline_points_qual_kp >= $qualUserLevel->qual_pp) {
// Setze die berechneten Werte
@ -848,12 +859,13 @@ class BusinessUserItemOptimized
}
\Log::debug("BusinessUserItemOptimized: User {$this->b_user->user_id} does not qualify for any level");
return null;
}
private function getPointsforPayline($paylines): float
{
\Log::debug("BusinessUserItemOptimized: getPointsforPayline for user {$this->b_user->user_id} ({$this->date->month}/{$this->date->year}) with paylines: " . $paylines . " and business_lines: " . json_encode($this->b_user->business_lines));
\Log::debug("BusinessUserItemOptimized: getPointsforPayline for user {$this->b_user->user_id} ({$this->date->month}/{$this->date->year}) with paylines: ".$paylines.' and business_lines: '.json_encode($this->b_user->business_lines));
$payline_points = 0;
for ($i = 1; $i <= $paylines; $i++) {
if (isset($this->b_user->business_lines[$i])) {
@ -867,18 +879,20 @@ class BusinessUserItemOptimized
}
}
}
return $payline_points;
}
/**
* Setzt das nächste Provision-Level
* Wenn das aktuelle Level nicht erreicht ist, dann wird bei aktuelle Provisions-Stufe die erreichte level angezeigt und berechnet
* Zur Info wird das nächste level angezeigt, der folgt, sonst leer
* Zur Info wird das nächste level angezeigt, der folgt, sonst leer
*/
private function setQualNextLevel($force = false): void
{
//ist der level nicht das aktuelle level, dann sucht es den nächsten level
//isQualEqualLevel wenn das erreichte level das akutelle user level ist.
if (!$this->isQualEqualLevel() && $this->b_user->qual_user_level['next_id'] != null) {
// ist der level nicht das aktuelle level, dann sucht es den nächsten level
// isQualEqualLevel wenn das erreichte level das akutelle user level ist.
if (! $this->isQualEqualLevel() && $this->b_user->qual_user_level['next_id'] != null) {
$qualUserLevelNext = UserLevel::where('id', '=', $this->b_user->qual_user_level['next_id'])
->orderBy('qual_pp', 'asc')
->first();
@ -910,10 +924,11 @@ class BusinessUserItemOptimized
->first();
// Wenn kein nächster Level existiert, beende
if (!$nextLevel) {
if (! $nextLevel) {
$this->b_user->next_qual_user_level = null;
$this->b_user->next_can_user_level = null;
\Log::debug("BusinessUserItemOptimized: No next level found for user {$this->b_user->user_id} (already at highest level)");
return;
}
@ -935,6 +950,7 @@ class BusinessUserItemOptimized
$this->b_user->next_can_user_level = $levelData;
$this->b_user->next_qual_user_level = null;
\Log::debug("BusinessUserItemOptimized: User {$this->b_user->user_id} does not meet KP requirement for next level {$nextLevel->name} ({$this->b_user->sales_volume_points_KP_sum} < {$nextLevel->qual_kp})");
return;
}
@ -982,7 +998,7 @@ class BusinessUserItemOptimized
'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'
'user_id' => 'user_id',
];
if (isset($legacyMap[$name]) && isset($this->b_user->{$legacyMap[$name]})) {
@ -1003,7 +1019,7 @@ class BusinessUserItemOptimized
return;
}
$sponsor = new stdClass();
$sponsor = new stdClass;
$sponsor->is_sponsor = false;
$sponsor->user_id = false;
$sponsor->first_name = '';
@ -1019,9 +1035,9 @@ class BusinessUserItemOptimized
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 . ' | ' .
'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
@ -1030,7 +1046,7 @@ class BusinessUserItemOptimized
$sponsor->last_name = $user->user_sponsor->account->last_name;
$sponsor->m_account = $user->user_sponsor->account->m_account;
} else {
$sponsor->full_name = 'Sponsor: ' . $user->user_sponsor->email;
$sponsor->full_name = 'Sponsor: '.$user->user_sponsor->email;
}
$sponsor->email = $user->user_sponsor->email;
} else {
@ -1040,7 +1056,7 @@ class BusinessUserItemOptimized
$this->b_user->sponsor = $sponsor;
} catch (\Exception $e) {
Log::error("BusinessUserItem: Error checking sponsor for user {$user->id}: " . $e->getMessage());
Log::error("BusinessUserItem: Error checking sponsor for user {$user->id}: ".$e->getMessage());
}
}
@ -1054,6 +1070,7 @@ class BusinessUserItemOptimized
$maxDepth = 20;
if ($depth > $maxDepth) {
Log::warning("BusinessUserItem: Maximale Rekursionstiefe ({$maxDepth}) erreicht für User {$this->b_user->user_id}");
return;
}
@ -1065,6 +1082,7 @@ class BusinessUserItemOptimized
->where('users.id', '!=', 1)
->where('users.admin', '<', 4)
->where('users.m_level', '!=', null)
->whereColumn('users.id', '!=', 'users.m_sponsor')
->where('users.m_sponsor', '=', $this->b_user->user_id)
->where('users.payment_account', '!=', null)
->where('users.active_date', '<=', $this->date->end_date)
@ -1075,6 +1093,7 @@ class BusinessUserItemOptimized
// 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;
}
@ -1090,7 +1109,7 @@ class BusinessUserItemOptimized
$businessUserItem->readParentsBusinessUsers($forceLiveCalculation, $depth + 1);
}
} catch (\Exception $e) {
Log::error("BusinessUserItem: Error reading parent users for {$this->b_user->user_id} at depth {$depth}: " . $e->getMessage());
Log::error("BusinessUserItem: Error reading parent users for {$this->b_user->user_id} at depth {$depth}: ".$e->getMessage());
}
}
@ -1104,6 +1123,7 @@ class BusinessUserItemOptimized
$maxDepth = 50;
if ($depth > $maxDepth) {
Log::warning("BusinessUserItem: Maximale Rekursionstiefe ({$maxDepth}) erreicht für gespeicherte User {$this->b_user->user_id}");
return;
}
@ -1115,6 +1135,7 @@ class BusinessUserItemOptimized
// 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;
}
@ -1129,7 +1150,7 @@ class BusinessUserItemOptimized
}
}
} catch (\Exception $e) {
Log::error("BusinessUserItem: Error reading stored parent users at depth {$depth}: " . $e->getMessage());
Log::error("BusinessUserItem: Error reading stored parent users at depth {$depth}: ".$e->getMessage());
}
}
@ -1138,7 +1159,7 @@ class BusinessUserItemOptimized
*/
private function findParentsBusinessOnStored($user_id, $structures)
{
if (!$structures) {
if (! $structures) {
return null;
}
@ -1147,7 +1168,7 @@ class BusinessUserItemOptimized
return $obj->parents ?? null;
}
if (!empty($obj->parents)) {
if (! empty($obj->parents)) {
$result = $this->findParentsBusinessOnStored($user_id, $obj->parents);
if ($result) {
return $result;
@ -1175,6 +1196,7 @@ class BusinessUserItemOptimized
if ($this->b_user && isset($this->b_user->qual_user_level) && $this->b_user->qual_user_level) {
return $this->b_user->qual_user_level['paylines'] ?? 0;
}
return 0;
}
@ -1189,6 +1211,7 @@ class BusinessUserItemOptimized
return $object->growth_bonus > 0;
}
}
return false;
}
@ -1204,13 +1227,15 @@ class BusinessUserItemOptimized
$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) {
if (! $user->account_id) {
\Log::info("BusinessUserItem: User {$user->id} has no account_id - no account available");
return null;
}
@ -1218,15 +1243,18 @@ class BusinessUserItemOptimized
\Log::info("BusinessUserItem: Loading account for user {$user->id} (account_id: {$user->account_id})");
$account = UserAccount::find($user->account_id);
if (!$account) {
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());
\Log::error("BusinessUserItem: Error loading account for user {$user->id}: ".$e->getMessage());
return null;
}
}

View file

@ -4,6 +4,7 @@ namespace App\Services\BusinessPlan;
use App\Models\ShoppingOrder;
use App\Models\UserSalesVolume;
use App\Services\Incentive\IncentiveTracker;
use App\Services\Util;
use App\User;
use stdClass;
@ -122,7 +123,7 @@ class SalesPointsVolume
}
}
public static function addSalesPointsVolumeUser(ShoppingOrder $shoppingOrder)
public static function User(ShoppingOrder $shoppingOrder)
{
/*
@ -311,6 +312,9 @@ class SalesPointsVolume
// Neuberechnung für aktuellen Monat
self::reCalculateSalesPointsVolume($original_sales_volume->user_id, $month, $year);
// Incentive: Track storno
IncentiveTracker::trackStorno($original_sales_volume, $cancellation_sales_volume);
\Log::info('Punktekorrektur für Stornorechnung durchgeführt', [
'original_invoice_id' => $original_sales_volume->user_invoice_id,
'cancellation_invoice_id' => $cancellation_invoice_id,