mivita/app/Console/Commands/TestGrowthBonusCalculation.php
2026-01-23 17:35:23 +01:00

319 lines
12 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\BusinessPlan\TreeCalcBotOptimized;
use App\Services\BusinessPlan\BusinessUserItemOptimized;
use App\Services\BusinessPlan\GrowthBonusCalculator;
use App\User;
use App\Models\UserBusiness;
use Carbon\Carbon;
class TestGrowthBonusCalculation extends Command
{
protected $signature = 'test:growth-bonus
{user_id : Die User-ID für den Test}
{--month=12 : Der Monat}
{--year=2025 : Das Jahr}
{--debug : Zeigt detaillierte Debug-Informationen}
{--from-db : Verwendet gespeicherte Daten und simuliert Berechnung}';
protected $description = 'Testet die Growth Bonus Berechnung für einen User';
public function handle()
{
$userId = $this->argument('user_id');
$month = (int) $this->option('month');
$year = (int) $this->option('year');
$debug = $this->option('debug');
$fromDb = $this->option('from-db');
$this->info("=== Growth Bonus Test ===");
$this->info("User: {$userId}, Monat: {$month}/{$year}");
$this->newLine();
// User laden
$user = User::find($userId);
if (!$user) {
$this->error("User {$userId} nicht gefunden!");
return 1;
}
$date = Carbon::createFromDate($year, $month, 1);
// Gespeicherte UserBusiness-Daten laden
$userBusiness = UserBusiness::where('user_id', $userId)
->where('month', $month)
->where('year', $year)
->first();
if ($userBusiness) {
$this->info("=== GESPEICHERTE DATEN (UserBusiness) ===");
$qualLevel = $userBusiness->qual_user_level;
$this->table(
['Feld', 'Wert'],
[
['user_id', $userBusiness->user_id],
['qual_user_level (Name)', $qualLevel['name'] ?? 'NULL'],
['Growth Bonus (aus qual_user_level)', $qualLevel['growth_bonus'] ?? 'NULL'],
['active_growth_bonus (gespeichert)', $userBusiness->active_growth_bonus ?? 'NULL'],
['commission_growth_total', $userBusiness->commission_growth_total ?? 0],
]
);
} else {
$this->warn("Keine gespeicherten UserBusiness-Daten für {$month}/{$year}");
if (!$fromDb) {
$this->info("Versuche Live-Berechnung...");
} else {
$this->error("--from-db erfordert gespeicherte Daten!");
return 1;
}
}
if ($fromDb && $userBusiness) {
$this->testFromDatabase($userId, $month, $year, $debug);
} else {
$this->testLiveCalculation($user, $date, $month, $year, $debug);
}
$this->newLine();
$this->info("=== TEST ABGESCHLOSSEN ===");
return 0;
}
private function testFromDatabase(int $userId, int $month, int $year, bool $debug): void
{
$this->newLine();
$this->info("=== ANALYSE AUS DATENBANK ===");
// Lade User und seine Firstlines
$userBusiness = UserBusiness::where('user_id', $userId)
->where('month', $month)
->where('year', $year)
->first();
$qualLevel = $userBusiness->qual_user_level;
$myGrowthBonus = (float) ($qualLevel['growth_bonus'] ?? 0);
$this->info("Mein Growth Bonus Anspruch: {$myGrowthBonus}%");
if ($myGrowthBonus <= 0) {
$this->warn("Kein Growth Bonus Anspruch!");
return;
}
// Lade Firstlines
$firstlineIds = User::where('m_sponsor', $userId)->pluck('id')->toArray();
$this->info("Anzahl Firstlines: " . count($firstlineIds));
$this->newLine();
$this->info("=== FIRSTLINE ANALYSE ===");
$totalExpectedGrowth = 0;
$problemsFound = false;
foreach ($firstlineIds as $flId) {
$flBusiness = UserBusiness::where('user_id', $flId)
->where('month', $month)
->where('year', $year)
->first();
if (!$flBusiness) {
continue;
}
$flQualLevel = $flBusiness->qual_user_level;
$flGrowthBonus = (float) ($flQualLevel['growth_bonus'] ?? 0);
$flLevelName = $flQualLevel['name'] ?? 'Kein Level';
$flTPSum = (float) ($flBusiness->sales_volume_points_TP_sum ?? 0);
if ($flTPSum <= 0) {
continue;
}
// Berechne erwartete Differenz
$expectedDiff = max(0, $myGrowthBonus - $flGrowthBonus);
$expectedCommission = round($flTPSum / 100 * $expectedDiff, 2);
// Problem-Erkennung: Wenn FL einen Growth Bonus hat aber wir
// trotzdem den vollen Betrag bekommen
$isPotentialProblem = $flGrowthBonus > 0 && $expectedDiff < $myGrowthBonus;
$this->info("--- Firstline User {$flId} ---");
$this->table(
['Feld', 'Wert'],
[
['Level erreicht', $flLevelName],
['Growth Bonus (FL)', $flGrowthBonus . '%'],
['Team-Punkte (TP_sum)', number_format($flTPSum, 0, ',', '.')],
['Mein Anspruch', $myGrowthBonus . '%'],
['Differenz (erwartet)', $expectedDiff . '%'],
['Erwartete Provision', number_format($expectedCommission, 2, ',', '.') . ' €'],
['ACHTUNG: Blockade?', $isPotentialProblem ? 'JA - FL sollte blockieren!' : 'Nein'],
]
);
if ($isPotentialProblem) {
$problemsFound = true;
$this->error(" ⚠️ User {$flId} hat {$flLevelName} ({$flGrowthBonus}%) erreicht!");
$this->error(" Differenz sollte nur {$expectedDiff}% sein, nicht {$myGrowthBonus}%!");
}
$totalExpectedGrowth += $expectedCommission;
}
$this->newLine();
$this->info("=== ZUSAMMENFASSUNG ===");
$this->info("Erwartete Growth Bonus Summe (mit korrekter Differenz): " . number_format($totalExpectedGrowth, 2, ',', '.') . ' €');
$this->info("Gespeicherte Growth Bonus Summe: " . number_format($userBusiness->commission_growth_total ?? 0, 2, ',', '.') . ' €');
if ($problemsFound) {
$this->newLine();
$this->error("⚠️ PROBLEME GEFUNDEN! Die Blockade durch qualifizierte Firstlines funktioniert möglicherweise nicht korrekt.");
}
// Detailanalyse: Wie wurde die Berechnung durchgeführt?
if ($debug) {
$this->newLine();
$this->info("=== DEBUG: Rekursive Volumen-Analyse ===");
$this->analyzeVolumeDistribution($userId, $month, $year, $myGrowthBonus, 1);
}
}
private function analyzeVolumeDistribution(int $userId, int $month, int $year, float $myPercent, int $depth = 1): array
{
if ($depth > 10) {
return ['0.0' => 0];
}
$userBusiness = UserBusiness::where('user_id', $userId)
->where('month', $month)
->where('year', $year)
->first();
if (!$userBusiness) {
return ['0.0' => 0];
}
$qualLevel = $userBusiness->qual_user_level;
$myProtection = (float) ($qualLevel['growth_bonus'] ?? 0);
$indent = str_repeat(" ", $depth);
// Eigenes Volumen (TP_sum - aber nur direkte Punkte, nicht Team)
// Bei gespeicherten Daten ist das schwer zu unterscheiden
// Vereinfachung: Für den Test nehmen wir TP_sum als Gesamt-Volumen
$this->line("{$indent}User {$userId}: Protection={$myProtection}%");
// Lade Kinder
$childIds = User::where('m_sponsor', $userId)->pluck('id')->toArray();
$volumes = [];
foreach ($childIds as $childId) {
$childBusiness = UserBusiness::where('user_id', $childId)
->where('month', $month)
->where('year', $year)
->first();
if (!$childBusiness) {
continue;
}
$childTP = (float) ($childBusiness->sales_volume_points_TP_sum ?? 0);
if ($childTP <= 0) {
continue;
}
$childQual = $childBusiness->qual_user_level;
$childProtection = (float) ($childQual['growth_bonus'] ?? 0);
$childLevelName = $childQual['name'] ?? 'Kein Level';
// Berechne Differenz
$diff = max(0, $myPercent - $childProtection);
$commission = round($childTP / 100 * $diff, 2);
$this->line("{$indent} └─ Child {$childId}: {$childLevelName}, Protection={$childProtection}%, TP={$childTP}");
$this->line("{$indent} Differenz: {$myPercent}% - {$childProtection}% = {$diff}%");
$this->line("{$indent} Provision: {$childTP} * {$diff}% = {$commission}");
if ($childProtection > 0) {
$this->warn("{$indent} ⚠️ BLOCKADE durch {$childLevelName}!");
}
}
return $volumes;
}
private function testLiveCalculation(User $user, Carbon $date, int $month, int $year, bool $debug): void
{
$this->newLine();
$this->info("=== LIVE-BERECHNUNG ===");
// TreeCalcBot erstellen
$treeCalcBot = new TreeCalcBotOptimized($month, $year, 'member', true);
// BusinessUserItem erstellen
$businessUserItem = new BusinessUserItemOptimized($date, $treeCalcBot);
$businessUserItem->makeUserFromModel($user, true);
$businessUserItem->addUserID();
// Kinder laden
$businessUserItem->readParentsBusinessUsers(true, 0);
// Qualifikation berechnen
$businessUserItem->calcQualPP(true);
$qualUserLevel = $businessUserItem->getQualUserLevel();
$this->table(
['Feld', 'Wert'],
[
['user_id', $businessUserItem->user_id],
['isQualLevel()', $businessUserItem->isQualLevel() ? 'JA' : 'NEIN'],
['isQualificationCalculated()', $businessUserItem->isQualificationCalculated() ? 'JA' : 'NEIN'],
['getQualUserLevel() (Name)', $qualUserLevel['name'] ?? 'NULL'],
['Growth Bonus (qual_user_level)', $qualUserLevel['growth_bonus'] ?? 'NULL'],
['getActiveGrowthBonus()', $businessUserItem->getActiveGrowthBonus()],
['getQualifiedGrowthBonus()', $businessUserItem->getQualifiedGrowthBonus()],
]
);
$this->newLine();
$this->info("=== FIRSTLINES (Kinder) ===");
if (empty($businessUserItem->businessUserItems)) {
$this->warn("Keine Firstlines geladen!");
} else {
foreach ($businessUserItem->businessUserItems as $index => $childItem) {
$childQual = $childItem->getQualUserLevel();
$this->info("--- Firstline " . ($index + 1) . " ---");
$this->table(
['Feld', 'Wert'],
[
['user_id', $childItem->user_id],
['isQualLevel()', $childItem->isQualLevel() ? 'JA' : 'NEIN'],
['getQualUserLevel() (Name)', $childQual['name'] ?? 'NULL'],
['Growth Bonus (qual_user_level)', $childQual['growth_bonus'] ?? 'NULL'],
['getActiveGrowthBonus()', $childItem->getActiveGrowthBonus()],
['getQualifiedGrowthBonus()', $childItem->getQualifiedGrowthBonus()],
['sales_volume_points_TP_sum', $childItem->sales_volume_points_TP_sum ?? 0],
]
);
}
}
if ($qualUserLevel && ($qualUserLevel['growth_bonus'] ?? 0) > 0) {
$calculator = new GrowthBonusCalculator();
$qualData = (object) $qualUserLevel;
$totalGrowthBonus = $calculator->calculate($businessUserItem, $qualData);
$this->newLine();
$this->info("Berechneter Growth Bonus: {$totalGrowthBonus}");
}
}
}