mivita/app/Services/BusinessPlan/Growth-Bonus-Matrix.md
2026-01-23 17:35:23 +01:00

193 lines
8.1 KiB
Markdown

# Konzept: Erweiterte Detailansicht für Growth Bonus (Matrix-View)
Die Anforderung ist, eine **Matrix-Ansicht** zu erstellen, bei der die Ebenen (Level 1, 2, 3...) als Spalten und die einzelnen Linien (Legs/Beine) als Zeilen dargestellt werden. Dies soll auch dann geschehen, wenn der Bonus gekappt ist, um volle Transparenz zu gewährleisten.
## 1. Datenstruktur-Erweiterung (`GrowthBonusCalculator`)
Die bisherige Aggregation (`getVolumeByProtectionLevel`) gruppiert Volumen nach "Schutz-Level". Das ist gut für die Berechnung, aber für die Visualisierung "Ebene für Ebene" brauchen wir die Rohdaten pro Ebene.
Wir benötigen eine neue Methode `getMatrixDetails`, die rekursiv die Struktur traversiert und für jedes Bein eine flache Liste von Ebenen-Volumen zurückgibt, angereichert mit Status-Informationen.
### Struktur des Ergebnis-Arrays:
```php
[
// Ein Eintrag pro Firstline (Bein)
[
'user' => [ 'id' => 123, 'name' => 'Max Mustermann', 'level' => 'Gold' ],
'levels' => [
1 => [ // Ebene 1 (relativ zu mir, also der Firstline-User selbst)
'volume' => 500,
'user_level' => 'Gold',
'protection_percent' => 2.0, // Was der User für sich beansprucht
'my_percent' => 2.5, // Mein Anspruch
'diff_percent' => 0.5, // Resultierende Provision
'commission' => 2.50,
'is_blocked' => false
],
2 => [ // Ebene 2 (User unter Max)
'volume' => 1000,
'user_level' => 'Silver',
'protection_percent' => 1.5,
'my_percent' => 2.5,
'diff_percent' => 1.0,
'commission' => 10.00,
'is_blocked' => false
],
// ... weitere Ebenen bis max Tiefe oder Abbruchbedingung
],
'totals' => [ 'volume' => 1500, 'commission' => 12.50 ]
],
// ... weitere Beine
]
```
## 2. Implementierungsschritte
1. **`GrowthBonusCalculator.php`**: Methode `getMatrixDetails` hinzufügen.
* Muss rekursiv durch die `businessUserItems` laufen.
* Muss tracken, welcher "Schutz-Level" von oben kommt (rekursiv weitergegeben).
* Muss aber `protection_percent` lokal pro User neu bewerten (max(incoming, own)).
2. **`BusinessUserItemOptimized.php`**: Aufruf in `getGrowthBonusBreakdown` anpassen oder neue Methode `getGrowthBonusMatrix` hinzufügen.
3. **View `_user_detail_in.blade.php`**: Umbau der Tabelle zu einer Matrix.
### Herausforderung: Tiefe und Breite
Eine komplette Matrix kann sehr breit und lang werden.
* **Begrenzung:** Wir sollten die Tiefe standardmäßig begrenzen (z.B. 10-20 Ebenen) oder nur relevante Ebenen (wo Volumen > 0) anzeigen.
* **Breite:** In der Tabelle werden die Spalten "Ebene 1", "Ebene 2", ... sein.
## 3. Code-Anpassung `GrowthBonusCalculator.php`
```php
/**
* Liefert eine Matrix-Sicht für die detaillierte Darstellung
* Zeilen = Beine (Legs), Spalten = Ebenen (Levels)
*/
public function getMatrixDetails(BusinessUserItemOptimized $userItem, $qualUserLevel): array
{
$details = [];
if (empty($qualUserLevel->growth_bonus) || $qualUserLevel->growth_bonus <= 0) {
return $details;
}
$myGrowthPercent = (float) $qualUserLevel->growth_bonus;
foreach ($userItem->businessUserItems as $childItem) {
$legData = [
'user' => [
'id' => $childItem->user_id,
'name' => $childItem->first_name . ' ' . $childItem->last_name,
'level' => $childItem->user_level_name
],
'levels' => [],
'total_commission' => 0.0,
'total_volume' => 0.0
];
// Rekursiv die Ebenen dieses Beins einsammeln
// Start bei Ebene 1 (das ist das Kind selbst)
// Initial Protection ist 0 (vom Upline/Mir kommt kein Schutz, der relevant wäre, da ICH ja der Empfänger bin)
$this->collectLegLevels($childItem, 1, 0.0, $myGrowthPercent, $legData);
if (!empty($legData['levels'])) {
// Sortieren nach Ebenen-Index
ksort($legData['levels']);
$details[] = $legData;
}
}
// Sortieren nach Gesamt-Provision
usort($details, function($a, $b) {
return $b['total_commission'] <=> $a['total_commission'];
});
return $details;
}
private function collectLegLevels(BusinessUserItemOptimized $item, int $level, float $incomingProtection, float $myPercent, array &$legData)
{
// 1. Eigenen Status ermitteln (Schutz für Downline)
$myProtection = 0.0;
if ($item->isQualLevel()) {
$qual = $item->qual_user_level;
$growth = is_array($qual) ? ($qual['growth_bonus'] ?? 0) : ($qual->growth_bonus ?? 0);
if ($growth > 0) {
$myProtection = (float) $growth;
}
}
// Der effektive Schutz, der AUF diesen User wirkt (von oben kommend + sein eigener Anspruch)
// WICHTIG: Für die Provision auf DIESEN User zählt der $incomingProtection (Schutz von oben).
// Für die Weitergabe nach unten zählt max($incoming, $myProtection).
// Berechnung für diesen User (Ebene)
$volume = (float) ($item->sales_volume_points_TP_sum ?? 0);
if ($volume > 0) {
// Differenz: Mein Anspruch - Schutz von oben
$diffPercent = max(0, $myPercent - $incomingProtection);
$commission = round($volume / 100 * $diffPercent, 2);
// Speichern in Matrix
// Wir summieren Volumen pro Ebene (falls durch parallele Zweige im Bein mehrere User auf gleicher Ebene sind - hier aber linearer Abstieg)
// Moment, businessUserItems ist ein Baum. Ein Bein kann breit werden.
// Wir müssen pro Ebene summieren.
if (!isset($legData['levels'][$level])) {
$legData['levels'][$level] = [
'volume' => 0.0,
'commission' => 0.0,
'details' => [] // Optional für Hover
];
}
$legData['levels'][$level]['volume'] += $volume;
$legData['levels'][$level]['commission'] += $commission;
// Metadaten für Anzeige (nur beim ersten Eintrag pro Ebene oder aggregiert?)
// Bei Matrix-View (Spalten=Ebenen) summieren wir alles auf Ebene X in diesem Bein.
// Das "Problem": In Ebene X können User mit unterschiedlichem Schutz-Status sein.
// Daher ist eine einfache Summe evtl. irreführend bei der %-Anzeige.
// Alternative: Wir zeigen pro Ebene den "dominanten" Status oder listen auf.
// Für die Tabelle ist eine Zelle pro Ebene vorgesehen.
// Wir speichern Detail-Infos für Tooltip.
$legData['levels'][$level]['details'][] = [
'u' => $item->user_id,
'v' => $volume,
'p' => $incomingProtection, // Protected by
'd' => $diffPercent
];
$legData['total_volume'] += $volume;
$legData['total_commission'] += $commission;
}
// Protection für nächste Ebene: Maximum aus was von oben kam und was dieser User beansprucht
$nextProtection = max($incomingProtection, $myProtection);
// Rekursion
// Max Tiefe z.B. 20
if ($level < 20 && !empty($item->businessUserItems)) {
foreach ($item->businessUserItems as $child) {
$this->collectLegLevels($child, $level + 1, $nextProtection, $myPercent, $legData);
}
}
}
```
## 4. Design der Tabelle (Blade)
Spalten: Leg (Partner) | Ebene 1 | Ebene 2 | Ebene 3 | ... | Ebene 10 | Total
Zeilen: Partner A | ... | ... | ...
Zellen-Inhalt:
* Oben: Provision (€)
* Unten: Volumen (Pkt)
* Farbe: Grün (Volle %), Gelb (Teil %), Rot (0% / Block)
Da die Ebenen dynamisch sind, ermitteln wir `max_level` über alle Legs.