@extends('layouts.layout-2') @section('content')

{{ __('navigation.team_statistics') }} VIP

{{ __('navigation.statistics') }} / Backoffice MVP

Linienbasierte Übersicht für alle vorhandenen Team-Linien. Klickbare Zahlen führen direkt in die passenden Namen- und Detaillisten.

Baum-Definition: {{ $treeLabels[$selectedTree] ?? $selectedTree }} @if ($selectedTree === \App\Services\Backoffice\BackofficeDashboardService::TREE_COMMISSION) — dieselben Mitglieder und dieselben Punkte (Provisionspunkte) wie die Team-Struktur. @if (($statistics['tree_source'] ?? 'live') === 'stored_structure') Mitglieder je Linie stammen aus dem gespeicherten Provisionslauf dieses Monats. @else Im laufenden Monat rechnen beide Seiten live; die Provisions-Kachel ist bis zu 6 Stunden zwischengespeichert. @endif @else — jeder nicht gelöschte Teampartner zählt, auch ohne Mitgliedsebene oder Abrechnungskonto und unterhalb solcher Partner. Diese Sicht weicht bewusst von der Team-Struktur ab. @endif

@if (!empty($performance))
Datenquelle: {{ $performance['source_label'] }} Berechnet in {{ number_format($performance['duration_ms'], 2, ',', '.') }} ms @if (!empty($performance['calculated_at'])) Snapshot vom {{ $performance['calculated_at'] }} @endif @if (($performance['source'] ?? null) === 'snapshot') Monat abgeschlossen · Stand eingefroren @endif
@endif
CSV
@php $clickableMetrics = ['consultants', 'total_points', 'team_partner_abos', 'team_customer_abos']; $metricHeadings = [ 'consultants' => 'Berater', 'total_points' => 'Umsatz (Punkte)', 'team_partner_abos' => 'Teamabos', 'team_customer_abos' => 'Teamkundenabos', ]; $formatValue = function ($value, string $metric): string { if ($metric === 'total_points') { return \App\Services\Util::formatNumber($value); } return number_format((float) $value, 0, ',', '.'); }; $newAboMetric = function (array $row, string $metric): ?string { return match ($metric) { 'consultants' => 'new_partners', 'team_partner_abos' => 'team_partner_abos_new', 'team_customer_abos' => 'team_customer_abos_new', default => null, }; }; // Ziel-Link des grünen "+N"-Badges: Neupartner-Liste bzw. Abo-Drilldown // gefiltert auf die im Monat neuen Abos (only_new). $newBadgeLink = function (int $lineNo, string $metric) use ($selectedMonth, $selectedYear, $selectedTree): string { if ($metric === 'consultants') { return route('user_backoffice_statistics_details', [ 'line' => $lineNo, 'metric' => 'new_partners', 'month' => $selectedMonth, 'year' => $selectedYear, 'tree' => $selectedTree, ]); } return route('user_backoffice_statistics_details', [ 'line' => $lineNo, 'metric' => $metric, 'month' => $selectedMonth, 'year' => $selectedYear, 'tree' => $selectedTree, 'only_new' => 1, ]); }; $selectedMonthName = $filterMonths[(int) $selectedMonth] ?? $selectedMonth; @endphp
Neupartner ({{ $selectedMonthName }} {{ $selectedYear }})
{{ number_format((float) ($statistics['totals']['new_partners'] ?? 0), 0, ',', '.') }}
Liste anzeigen
1000-Punkte-Shops ({{ $selectedMonthName }} {{ $selectedYear }})
{{ number_format((float) ($statistics['totals']['shop_1000'] ?? 0), 0, ',', '.') }}
Liste anzeigen
@if (isset($commission))
Provision ({{ $selectedMonthName }} {{ $selectedYear }}) @if (! empty($commission['is_live'])) Live @endif
{{ number_format((float) ($commission['total'] ?? 0), 2, ',', '.') }} €
Payline {{ number_format((float) ($commission['pp'] ?? 0), 2, ',', '.') }} € · Shop {{ number_format((float) ($commission['shop'] ?? 0), 2, ',', '.') }} € · WB {{ number_format((float) ($commission['growth'] ?? 0), 2, ',', '.') }} €
@endif
@foreach ($clickableMetrics as $metric) @endforeach @foreach ($statistics['lines'] as $line) @foreach ($clickableMetrics as $metric) @endforeach @endforeach @foreach ($clickableMetrics as $metric) @endforeach
Linie{{ $metricHeadings[$metric] }}
{{ $line['label'] }} @if ($line[$metric] != 0) {{ $formatValue($line[$metric], $metric) }} @php $newMetric = $newAboMetric($line, $metric); @endphp @if ($newMetric && $line[$newMetric] != 0) +{{ number_format($line[$newMetric], 0, ',', '.') }} @endif @else 0 @endif
{{ $statistics['totals']['label'] }} @if ($statistics['totals'][$metric] != 0) {{ $formatValue($statistics['totals'][$metric], $metric) }} @php $newMetric = $newAboMetric($statistics['totals'], $metric); @endphp @if ($newMetric && $statistics['totals'][$newMetric] != 0) +{{ number_format($statistics['totals'][$newMetric], 0, ',', '.') }} @endif @else 0 @endif
@php $nonPaylinePoints = $statistics['non_payline_points'] ?? null; $stornoFloorPoints = $statistics['storno_floor_points'] ?? null; $isLegacyPayload = (int) ($statistics['payload_version'] ?? 1) < 3; @endphp

@if ($isLegacyPayload) Umsatz (Punkte) = Eigen- + Kundenpunkte (ältere Berechnung dieses Monats, inkl. Punkte ohne Payline-Wirkung). @if ($nonPaylinePoints !== null && $nonPaylinePoints > 0) Davon {{ \App\Services\Util::formatNumber($nonPaylinePoints) }} Punkte ohne Payline-Wirkung — die Team-Struktur fällt um diesen Betrag niedriger aus. @endif @else Umsatz (Punkte) = Provisionspunkte (Teampunkte + Kundenpunkte), so wie sie in der Team-Struktur je Linie stehen und verprovisioniert werden. @if ($nonPaylinePoints !== null && $nonPaylinePoints > 0) Nicht enthalten: {{ \App\Services\Util::formatNumber($nonPaylinePoints) }} Punkte ohne Payline-Wirkung (z. B. Neupartner-Einschreibungspunkte) — sie zählen nur als Karrierepunkte des jeweiligen Beraters. @endif @if ($stornoFloorPoints !== null && $stornoFloorPoints > 0) Nicht abgezogen: {{ \App\Services\Util::formatNumber($stornoFloorPoints) }} Punkte aus negativen Monatssalden einzelner Berater (Stornos über die Buchungen des Monats hinaus) — die Provisionsberechnung wertet einen negativen Saldo mit 0. @endif @endif

@php $newCustomerAbos = $statistics['new_customer_abos'] ?? null; $leaderAbos = $statistics['leader_abos'] ?? null; @endphp
Neue Kundenabos
{{ $selectedMonthName }} {{ $selectedYear }} · nach Anzahl sortiert
{{ number_format((float) ($statistics['totals']['team_customer_abos_new'] ?? 0), 0, ',', '.') }}
@if ($newCustomerAbos === null)

Für diesen Monat liegt noch ein älterer Snapshot ohne diese Liste vor.

@elseif (count($newCustomerAbos) === 0)

In diesem Monat wurden keine neuen Kundenabos abgeschlossen.

@else
@foreach ($newCustomerAbos as $row) @endforeach
Berater Gesamt Neu
{{ $row['name'] }} @if (!empty($row['is_self'])) ich @endif
{{ !empty($row['is_self']) ? 'Eigene Kundenabos' : 'Linie '.$row['line'] }} · {{ $row['career_level'] }}
{{ number_format((float) ($row['total_abo_count'] ?? 0), 0, ',', '.') }} +{{ number_format((float) $row['abo_count'], 0, ',', '.') }}
@endif
Abos Führungskräfte
ab Stufe {{ $leaderAbos['level_name'] ?? 'Vertriebsleiter' }} · aktueller Stand
{{ number_format((float) ($leaderAbos['total'] ?? 0), 0, ',', '.') }} @if ($leaderAbos !== null)
{{ number_format((float) ($leaderAbos['total_own'] ?? 0), 0, ',', '.') }} eigene · {{ number_format((float) ($leaderAbos['total_customer'] ?? 0), 0, ',', '.') }} Kunden · {{ number_format((float) ($leaderAbos['total_team'] ?? 0), 0, ',', '.') }} Team · {{ number_format((float) ($leaderAbos['total_team_customer'] ?? 0), 0, ',', '.') }} Teamkunden
@endif
@if ($leaderAbos === null)

Für diesen Monat liegt noch ein älterer Snapshot ohne diese Liste vor.

@elseif (count($leaderAbos['rows']) === 0)

Im Team gibt es aktuell keine Führungskräfte ab Stufe {{ $leaderAbos['level_name'] }}.

@else
@foreach ($leaderAbos['rows'] as $row) @php $leaderTotal = $row['total_abo_count_full'] ?? (($row['own_abo_count'] ?? 0) + ($row['customer_abo_count'] ?? 0) + ($row['team_abo_count_total'] ?? ($row['team_abo_count'] ?? 0)) + ($row['team_customer_abo_count_total'] ?? ($row['team_customer_abo_count'] ?? 0))); @endphp {{-- Die "direkt"-Spalten sind auf Kundenwunsch (07.09.2026) raus; die Kopf-Summe rechnet intern weiter mit ihnen, weil nur sie ueberschneidungsfrei ist (siehe Fussnote unter der Tabelle). --}} @foreach (['own_abo_count', 'customer_abo_count', 'team_abo_count_total', 'team_customer_abo_count_total'] as $countKey) @endforeach @endforeach
Führungskraft Eigene Abos Kundenabos Teamabos (gesamt) Team-Kundenabos (gesamt) Gesamt
{{ $row['name'] }}
Linie {{ $row['line'] }} · {{ $row['career_level'] }}
@if (($row[$countKey] ?? 0) > 0) {{ number_format((float) $row[$countKey], 0, ',', '.') }} @else 0 @endif {{ number_format((float) $leaderTotal, 0, ',', '.') }}

gesamt = komplette Downline inklusive der Teams untergeordneter Führungskräfte — dieselben Abos können dort bei mehreren Führungskräften zählen, die Spalten lassen sich deshalb nicht aufsummieren. Die Summe oben rechts zählt jedes Abo genau einmal (Team jeweils nur bis zur nächsten Führungskraft) und ist deshalb kleiner als die Spaltensummen.

@endif
@php $recruiterRanking = $statistics['recruiter_ranking'] ?? null; // Aeltere Snapshots kennen die Summenzeile noch nicht -> dann bleibt sie weg. $recruiterTotals = $statistics['recruiter_totals'] ?? null; @endphp
Recruiter des Monats
{{ $selectedMonthName }} {{ $selectedYear }} · nach Anzahl gesponserter Neupartner
{{ number_format((float) ($statistics['totals']['new_partners'] ?? 0), 0, ',', '.') }}
@if ($recruiterRanking === null)

Für diesen Monat liegt noch ein älterer Snapshot ohne diese Liste vor.

@elseif (count($recruiterRanking) === 0)

In diesem Monat wurden keine Neupartner gesponsert.

@else
@foreach ($recruiterRanking as $row) @endforeach @if ($recruiterTotals !== null) {{-- Summe ueber die deduplizierte Neupartner-Menge, NICHT ueber die Spalte: dort steckt jeder Neupartner durch das Kettenvolumen mehrfach drin (Kundenwunsch 2026-09-07). --}} @endif
Sponsor Neupartner neues Volumen
{{ $row['name'] }} @if (!empty($row['is_self'])) ich @endif
{{ !empty($row['is_self']) ? 'Eigene Neupartner' : 'Linie '.$row['line'] }} · {{ $row['career_level'] }}
+{{ number_format((float) $row['new_partner_count'], 0, ',', '.') }} {{ \App\Services\Util::formatNumber($row['volume_points']) }} P.
    @foreach ($row['partners'] ?? [] as $partner)
  • {{ $partner['name'] }} · {{ $partner['career_level'] }} · {{ \App\Services\Util::formatNumber($partner['total_points']) }} P. @if (!empty($partner['children']))
      @foreach ($partner['children'] as $child)
    • ↳ {{ $child['name'] }} · {{ $child['career_level'] }} · {{ \App\Services\Util::formatNumber($child['total_points']) }} P.
    • @endforeach
    @endif
  • @endforeach
Summe {{ number_format((float) $recruiterTotals['new_partner_count'], 0, ',', '.') }} {{ \App\Services\Util::formatNumber($recruiterTotals['volume_points']) }}

neues Volumen = Monats-Gesamtpunkte (Eigen- und Kundenpunkte, inkl. Starterpaket) der geworbenen Neupartner — plus rekursiv die Punkte der Neupartner, die diese im selben Monat selbst geworben haben. Klick auf eine Zeile zeigt, wer geworben wurde. @if ($recruiterTotals !== null)
Summe = Volumen aller Neupartner des Monats, jeder genau einmal gezählt. Sie ist kleiner als die Spalte darüber, weil ein Neupartner dort zusätzlich im Kettenvolumen seines Sponsors steckt. @endif

@endif
@php $topCustomerAbos = $statistics['top_customer_abos'] ?? null; @endphp
Top 10 Kundenabos (Anzahl)
aktueller Bestand aktiver Kundenabos · weicht bewusst von der Incentive-Zählung ab
@if ($topCustomerAbos === null)

Für diesen Monat liegt noch ein älterer Snapshot ohne diese Liste vor.

@elseif (count($topCustomerAbos['by_count']) === 0)

Im Team gibt es aktuell keine aktiven Kundenabos.

@else
@foreach ($topCustomerAbos['by_count'] as $row) @endforeach
Platz Berater Kundenabos
{{ $loop->iteration }}.
{{ $row['name'] }} @if (!empty($row['is_self'])) ich @endif
{{ !empty($row['is_self']) ? 'Eigene Kundenabos' : 'Linie '.$row['line'] }} · {{ $row['career_level'] }}
{{ number_format((float) $row['abo_count'], 0, ',', '.') }}
@endif
Top 10 Kundenabos (Umsatz)
sortiert nach abgerechneten Kundenabo-Punkten {{ $selectedMonthName }} {{ $selectedYear }}
@if ($topCustomerAbos === null)

Für diesen Monat liegt noch ein älterer Snapshot ohne diese Liste vor.

@elseif (count($topCustomerAbos['by_points']) === 0)

Im Team gibt es aktuell keine Kundenabo-Umsätze.

@else
@foreach ($topCustomerAbos['by_points'] as $row) {{-- Aufteilung erst ab 06/2026 erfasst; aeltere Snapshots haben die Schluessel gar nicht -> dann bleiben die Zellen leer. --}} @endforeach
Platz Berater Abos Abgerechnet (Punkte) davon reine Abo-Punkte einmalig dazu Bestand/Lieferung
{{ $loop->iteration }}.
{{ $row['name'] }} @if (!empty($row['is_self'])) ich @endif
{{ !empty($row['is_self']) ? 'Eigene Kundenabos' : 'Linie '.$row['line'] }} · {{ $row['career_level'] }}
{{ number_format((float) ($row['abo_count'] ?? 0), 0, ',', '.') }} {{ \App\Services\Util::formatNumber($row['points_actual']) }} {{ isset($row['points_recurring']) ? \App\Services\Util::formatNumber($row['points_recurring']) : '–' }} {{ isset($row['points_addon']) ? \App\Services\Util::formatNumber($row['points_addon']) : '–' }} {{ \App\Services\Util::formatNumber($row['points_target']) }}
@endif
Begriffe

Teamabos sind Berater-/Eigenabos im Team. Teamkundenabos sind Kundenabos, die einem Berater aus der jeweiligen Linie zugeordnet sind.

Umsatz = Gesamtpunkte der Linie (Eigen- und Kundenpunkte zusammen). Ein Klick auf eine Zahl öffnet die zugehörige Namensliste.

Nächster Ausbau

Die Detailansichten liefern bereits Namen und Basisdaten. Im nächsten Schritt werden Abo-Punkte und Umsatzarten noch feiner nach Abo, Einzelbestellung und Shop getrennt.

@endsection