Team-Abo-Uebersicht: nur aktive Berater zaehlen
Die Linientabelle zaehlte alle Downline-User statt nur aktive Berater (m_level + gueltiges payment_account), wodurch zu viele Berater angezeigt wurden. Filter-Logik aus BackofficeDashboardService (isActiveConsultant, activeTeamUserIds) wiederverwendet und in TeamAboOverviewService (buildLineRow, teamKpis, monthlyGrowth) angewendet. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
386851aee8
commit
9565814221
3 changed files with 74 additions and 11 deletions
|
|
@ -57,7 +57,7 @@ class TeamAboOverviewService
|
|||
*/
|
||||
public function teamKpis(User $user, int $month, int $year): array
|
||||
{
|
||||
$teamUserIds = $this->dashboardService->teamUserIds($user->id);
|
||||
$teamUserIds = $this->dashboardService->activeTeamUserIds($user->id);
|
||||
|
||||
if ($teamUserIds === []) {
|
||||
return [
|
||||
|
|
@ -116,7 +116,7 @@ class TeamAboOverviewService
|
|||
*/
|
||||
public function monthlyGrowth(User $user, int $year): array
|
||||
{
|
||||
$teamUserIds = $this->dashboardService->teamUserIds($user->id);
|
||||
$teamUserIds = $this->dashboardService->activeTeamUserIds($user->id);
|
||||
$monthNames = \App\Services\HTMLHelper::getTransMonths();
|
||||
|
||||
$ownByMonth = $teamUserIds === [] ? [] : $this->newAbosByMonth($teamUserIds, 'user_id', 'me', $year);
|
||||
|
|
@ -250,6 +250,11 @@ class TeamAboOverviewService
|
|||
*/
|
||||
private function buildLineRow(int $line, Collection $users, int $month, int $year): array
|
||||
{
|
||||
// Nur aktive Berater zählen/anzeigen (konsistent mit der Backoffice-Statistik).
|
||||
// Die Baum-Traversierung in lineBuckets() bleibt unberührt, damit auch die
|
||||
// Downline inaktiver Zwischen-Berater weiterhin erreicht wird.
|
||||
$users = $users->filter(fn (User $teamUser) => $this->dashboardService->isActiveConsultant($teamUser))->values();
|
||||
|
||||
$userIds = $users->pluck('id')->map(fn ($id) => (int) $id)->all();
|
||||
|
||||
if ($userIds === []) {
|
||||
|
|
|
|||
|
|
@ -175,6 +175,31 @@ class BackofficeDashboardService
|
|||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* IDs der gesamten Downline, aber nur aktive Berater
|
||||
* (gleiche Definition wie die "Berater"-Spalte der Backoffice-Statistik).
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function activeTeamUserIds(int $rootUserId): array
|
||||
{
|
||||
return collect($this->lineBuckets($rootUserId))
|
||||
->flatMap(fn (Collection $users) => $users)
|
||||
->filter(fn (User $user) => $this->isActiveConsultant($user))
|
||||
->map(fn (User $user) => (int) $user->id)
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ein aktiver Berater hat eine Mitgliedsebene und ein gesetztes Abrechnungskonto.
|
||||
* Maßgeblich für die "Berater"-Zählung in den Team-Übersichten.
|
||||
*/
|
||||
public function isActiveConsultant(User $user): bool
|
||||
{
|
||||
return $user->m_level !== null && $user->payment_account !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Support\Collection<int, \App\User> $users
|
||||
* @return array<string, mixed>
|
||||
|
|
@ -261,7 +286,7 @@ class BackofficeDashboardService
|
|||
private function activeConsultants(Collection $users): int
|
||||
{
|
||||
return $users
|
||||
->filter(fn (User $user) => $user->m_level !== null && $user->payment_account !== null)
|
||||
->filter(fn (User $user) => $this->isActiveConsultant($user))
|
||||
->count();
|
||||
}
|
||||
|
||||
|
|
@ -324,12 +349,12 @@ class BackofficeDashboardService
|
|||
->whereIn('user_id', $userIds)
|
||||
->where('month', $month)
|
||||
->where('year', $year)
|
||||
->selectRaw('COALESCE(SUM(month_KP_points), 0) as own_points')
|
||||
->selectRaw('COALESCE(SUM(month_shop_points), 0) as external_points')
|
||||
->selectRaw('COALESCE(SUM(CASE WHEN shopping_orders.is_abo = 1 THEN month_shop_points ELSE 0 END), 0) as customer_abo_points')
|
||||
->selectRaw('COALESCE(SUM(CASE WHEN shopping_orders.id IS NOT NULL AND (shopping_orders.is_abo = 0 OR shopping_orders.is_abo IS NULL) THEN month_shop_points ELSE 0 END), 0) as customer_single_order_points')
|
||||
->selectRaw('COALESCE(SUM(CASE WHEN shopping_orders.id IS NULL THEN month_shop_points ELSE 0 END), 0) as customer_other_points')
|
||||
->selectRaw('COALESCE(SUM(month_total_net), 0) + COALESCE(SUM(month_shop_total_net), 0) as turnover_net')
|
||||
->selectRaw(SalesVolumePoints::ownPoints().' as own_points')
|
||||
->selectRaw(SalesVolumePoints::externalPoints().' as external_points')
|
||||
->selectRaw(SalesVolumePoints::customerAboPoints().' as customer_abo_points')
|
||||
->selectRaw(SalesVolumePoints::customerSingleOrderPoints().' as customer_single_order_points')
|
||||
->selectRaw(SalesVolumePoints::customerOtherPoints().' as customer_other_points')
|
||||
->selectRaw(SalesVolumePoints::turnoverNet().' as turnover_net')
|
||||
->first();
|
||||
|
||||
$ownPoints = (float) ($summary->own_points ?? 0);
|
||||
|
|
@ -382,9 +407,9 @@ class BackofficeDashboardService
|
|||
->where('month', $month)
|
||||
->where('year', $year)
|
||||
->select('user_id')
|
||||
->selectRaw('COALESCE(SUM(month_KP_points), 0) + COALESCE(SUM(month_shop_points), 0) as total_points')
|
||||
->selectRaw(SalesVolumePoints::totalPoints().' as total_points')
|
||||
->groupBy('user_id')
|
||||
->havingRaw('COALESCE(SUM(month_KP_points), 0) + COALESCE(SUM(month_shop_points), 0) >= 1000')
|
||||
->havingRaw(SalesVolumePoints::totalPoints().' >= 1000')
|
||||
->get()
|
||||
->count();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,38 @@ it('gruppiert Team-Abos nach Ebenen mit Eigen- und Kundenabos', function (): voi
|
|||
->and($totals['total_abos'])->toBe(5);
|
||||
});
|
||||
|
||||
it('zählt nur aktive Berater und blendet inaktive/fehlerhafte aus', function (): void {
|
||||
$root = makeUser();
|
||||
|
||||
// Aktiver Berater (m_level + gültiges payment_account)
|
||||
$anna = makeUser($root->id);
|
||||
|
||||
// Inaktiv: kein payment_account
|
||||
$noPayment = makeUser($root->id);
|
||||
$noPayment->forceFill(['payment_account' => null])->save();
|
||||
|
||||
// Inaktiv: keine Mitgliedsebene
|
||||
$noLevel = makeUser($root->id);
|
||||
$noLevel->forceFill(['m_level' => null])->save();
|
||||
|
||||
// Abos der inaktiven Berater dürfen nicht in die Übersicht einfließen
|
||||
makeAbo($anna->id, $anna->id, 'me', '2026-06-05', 50);
|
||||
makeAbo($noPayment->id, $noPayment->id, 'me', '2026-06-05', 10);
|
||||
makeAbo($noLevel->id, $noLevel->id, 'ot', '2026-06-05', 10);
|
||||
|
||||
$service = app(TeamAboOverviewService::class);
|
||||
$overview = $service->linesOverview($root, 6, 2026);
|
||||
|
||||
$line1 = $overview['lines'][1];
|
||||
|
||||
expect($line1['consultants'])->toBe(1)
|
||||
->and($line1['members'])->toHaveCount(1)
|
||||
->and($line1['members'][0]['user_id'])->toBe($anna->id)
|
||||
->and($line1['own_abos'])->toBe(1)
|
||||
->and($line1['customer_abos'])->toBe(0)
|
||||
->and($overview['totals']['consultants'])->toBe(1);
|
||||
});
|
||||
|
||||
it('liefert pro Mitglied das Eigen-Abo-Flag und Punkte', function (): void {
|
||||
$root = makeUser();
|
||||
$anna = makeUser($root->id);
|
||||
|
|
@ -229,6 +261,7 @@ it('liefert leichtgewichtige Dashboard-KPIs inkl. 1000-Punkte-Shop', function ()
|
|||
'year' => 2026,
|
||||
'month_KP_points' => 600,
|
||||
'month_shop_points' => 500,
|
||||
'points' => 1100,
|
||||
'status' => 1,
|
||||
]);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue