Abo-Uebersichten: Team-Ansicht konsolidiert, Monatsfilter, Wachstum & Dashboard-KPIs
- /user/abos/ot: Filter nach Eingangsmonat (start_date) ueber neuen UserAbo-Scope - Konsolidierte Team-Abo-Ansicht nach Ebenen/Linien (Bestand, neue Abos im Monat, Eigen-/Kundenabos, Punkte je Ebene + Summen) via TeamAboOverviewService - team/customers leitet auf konsolidierte Ansicht um; Navigation bereinigt - Mitglieder-Detail-Modal mit Abo-Zusammenfassung (Eigen-Abo, Kundenabos, Punkte, Beginn, naechste Ausfuehrung, Ausfuehrungen) - Wachstums-Tabelle (Jahr x Monate) + Liniendiagramm (neue Eigen-/Kundenabos) - Dashboard-KPI-Kachel (Gesamtabos, Kundenabos, 1000-Punkte-Shops) - i18n de/en/es/fr, Tests (Filter, Overview, Wachstum, Modal, Redirect) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
65b867f8ee
commit
4135726772
15 changed files with 967 additions and 174 deletions
|
|
@ -703,68 +703,73 @@ class TeamController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Abos der Team-Mitglieder an
|
||||
* Konsolidierte Team-Abo-Übersicht: Abos im Team nach Ebenen/Linien gruppiert,
|
||||
* inkl. Eigen-Abos, Kundenabos und neuer Abos im gewählten Monat.
|
||||
*/
|
||||
public function showAbos()
|
||||
public function showAbos(\App\Services\Abo\TeamAboOverviewService $overviewService)
|
||||
{
|
||||
$user = User::find(\Auth::user()->id);
|
||||
$this->setFilterVars();
|
||||
$now = now();
|
||||
|
||||
// Hole Team-Mitglieder-IDs effizient via Sponsor-Hierarchie
|
||||
$teamUserIds = AboHelper::getTeamUserIds($user->id);
|
||||
// Bestandsübersicht: immer aktueller Bestand; "neu"-Badges = laufender Monat.
|
||||
$overview = $overviewService->linesOverview($user, (int) $now->month, (int) $now->year);
|
||||
|
||||
$selectedYear = (int) Request::get('year', now()->year);
|
||||
$baseQuery = \App\Models\UserAbo::whereIn('user_id', $teamUserIds)
|
||||
->where('is_for', 'me')
|
||||
->where('status', '>', 1);
|
||||
|
||||
// Hole Abos der Team-Mitglieder
|
||||
$abos = (clone $baseQuery)
|
||||
->with(['user', 'user.account', 'user_abo_items', 'user_abo_items.product'])
|
||||
->orderBy('next_date', 'asc')
|
||||
->get();
|
||||
// Wachstums-Tabelle: wählbares Jahr (GET-Param), Default aktuelles Jahr.
|
||||
$growthYear = (int) Request::get('year', $now->year);
|
||||
$growth = $overviewService->monthlyGrowth($user, $growthYear);
|
||||
|
||||
$data = [
|
||||
'filter_months' => HTMLHelper::getTransMonths(),
|
||||
'filter_years' => HTMLHelper::getYearRange(2022),
|
||||
'abos' => $abos,
|
||||
'chartData' => AboHelper::getMonthlyAboCounts($baseQuery, $selectedYear, 'team_abos', $user->id),
|
||||
'chartYear' => $selectedYear,
|
||||
'chartYears' => HTMLHelper::getYearRange(2026),
|
||||
'chartMonths' => HTMLHelper::getTransMonths(),
|
||||
'currentMonthName' => HTMLHelper::getTransMonths()[(int) $now->month] ?? '',
|
||||
'overview' => $overview,
|
||||
'growth' => $growth,
|
||||
'growthChart' => $this->buildGrowthChart($growth),
|
||||
'growthYear' => $growthYear,
|
||||
'filterYears' => HTMLHelper::getYearRange(2022),
|
||||
];
|
||||
|
||||
return view('user.team.abos', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt eine Übersicht der Kunden-Abos aller Team-Mitglieder (anonymisiert)
|
||||
* Bereitet die Datenreihen für das Wachstums-Liniendiagramm auf.
|
||||
*
|
||||
* @param array{months: array<int, array{label: string, own_new: int, customer_new: int}>} $growth
|
||||
* @return array{labels: list<string>, own: list<int>, customer: list<int>, step: int, suggested_max: int}
|
||||
*/
|
||||
public function showTeamCustomerAbos(): \Illuminate\View\View
|
||||
private function buildGrowthChart(array $growth): array
|
||||
{
|
||||
$user = User::find(\Auth::user()->id);
|
||||
$teamUserIds = AboHelper::getTeamUserIds($user->id);
|
||||
$labels = array_map(fn (array $row): string => $row['label'], $growth['months']);
|
||||
$own = array_map(fn (array $row): int => $row['own_new'], $growth['months']);
|
||||
$customer = array_map(fn (array $row): int => $row['customer_new'], $growth['months']);
|
||||
|
||||
$selectedYear = (int) Request::get('year', now()->year);
|
||||
$baseQuery = \App\Models\UserAbo::whereIn('member_id', $teamUserIds)
|
||||
->where('is_for', 'ot')
|
||||
->where('status', '>', 1);
|
||||
$max = max(array_merge($own, $customer, [0]));
|
||||
$step = match (true) {
|
||||
$max <= 5 => 1,
|
||||
$max <= 10 => 2,
|
||||
$max <= 20 => 5,
|
||||
$max <= 50 => 10,
|
||||
$max <= 100 => 20,
|
||||
$max <= 200 => 50,
|
||||
default => 100,
|
||||
};
|
||||
|
||||
$abos = (clone $baseQuery)
|
||||
->with(['member', 'member.account', 'user_abo_items', 'user_abo_items.product'])
|
||||
->orderBy('member_id')
|
||||
->orderBy('next_date', 'asc')
|
||||
->get();
|
||||
return [
|
||||
'labels' => array_values($labels),
|
||||
'own' => array_values($own),
|
||||
'customer' => array_values($customer),
|
||||
'step' => $step,
|
||||
'suggested_max' => $max + $step,
|
||||
];
|
||||
}
|
||||
|
||||
$groupedByMember = $abos->groupBy('member_id');
|
||||
|
||||
return view('user.team.customer_abos', [
|
||||
'groupedByMember' => $groupedByMember,
|
||||
'chartData' => AboHelper::getMonthlyAboCounts($baseQuery, $selectedYear, 'team_cust_abos', $user->id),
|
||||
'chartYear' => $selectedYear,
|
||||
'chartYears' => HTMLHelper::getYearRange(2026),
|
||||
'chartMonths' => HTMLHelper::getTransMonths(),
|
||||
]);
|
||||
/**
|
||||
* Die Kundenabos im Team sind in die konsolidierte Team-Abo-Übersicht
|
||||
* (`user_abos_team_show`) eingeflossen. Diese Route bleibt für Bookmarks/Altlinks
|
||||
* bestehen und leitet dauerhaft dorthin weiter.
|
||||
*/
|
||||
public function showTeamCustomerAbos(): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return redirect()->route('user_abos_team_show');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue