23-01-2026
This commit is contained in:
parent
a939cd51ef
commit
a8b395e20d
248 changed files with 29342 additions and 4805 deletions
193
app/Services/BusinessPlan/Growth-Bonus-Matrix.md
Normal file
193
app/Services/BusinessPlan/Growth-Bonus-Matrix.md
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
# 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.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue