diff --git a/app/Services/Abo/PaylineForecastService.php b/app/Services/Abo/PaylineForecastService.php index 24c5b86a..0ab75e1f 100644 --- a/app/Services/Abo/PaylineForecastService.php +++ b/app/Services/Abo/PaylineForecastService.php @@ -590,7 +590,9 @@ class PaylineForecastService return [['paylines' => 0, 'member_ids' => [], 'is_career_fallback' => false], $failed]; } - $memberIds = collect($this->dashboardService->lineBuckets($user->id)) + // Mitglieder aus dem Provisionsbaum, wie lineByUserId() und die Team-Statistik + // (Audit A07): Wer dort ausgefiltert oder gekappt ist, zaehlt fuer die Payline nicht. + $memberIds = collect($this->dashboardService->commissionLineBuckets($user->id, $month, $year)) ->filter(fn ($users, int $line) => $line <= $paylines) ->flatMap(fn ($users) => $users->pluck('id')) ->map(fn ($id) => (int) $id) diff --git a/tests/Feature/PaylineForecastServiceTest.php b/tests/Feature/PaylineForecastServiceTest.php index d76f5fe2..bc9c6e85 100644 --- a/tests/Feature/PaylineForecastServiceTest.php +++ b/tests/Feature/PaylineForecastServiceTest.php @@ -312,6 +312,36 @@ it('ermittelt den Payline-Kontext aus dem UserBusiness-Level und den Linien', fu ->and($context['member_ids'])->not->toContain($ben->id); }); +it('nimmt die Payline-Mitglieder aus dem Provisionsbaum wie die Team-Statistik (A07)', function (): void { + $root = pflMakeUser(); + $anna = pflMakeUser($root->id); // Linie 1, im Provisionsbaum + $carl = pflMakeUser($root->id); // Linie 1, ohne Abrechnungskonto + $carl->forceFill(['payment_account' => null])->save(); + $dora = pflMakeUser($carl->id); // Linie 2 unter Carl: gekappt + $emil = pflMakeUser($anna->id); // Linie 2 unter Anna: zaehlt + + UserBusiness::forceCreate([ + 'user_id' => $root->id, + 'month' => 7, + 'year' => 2026, + 'version' => 1, + 'qual_user_level' => ['paylines' => 2], + ]); + + pflMakeAbo($dora->id, 'me', '2026-07-20', 50); + pflMakeAbo($emil->id, 'me', '2026-07-20', 30); + + $service = app(PaylineForecastService::class); + $context = $service->paylineContext($root, 7, 2026); + $turnover = $service->aboTurnover($root, 7, 2026); + + expect($context['member_ids'])->toEqualCanonicalizing([$anna->id, $emil->id]) + ->and($context['member_ids'])->not->toContain($carl->id) + ->and($context['member_ids'])->not->toContain($dora->id) + ->and($turnover['team_abo_count'])->toBe(1) + ->and($turnover['target'])->toBe(30.0); +}); + it('rendert die Payline-Prognose auf der Monatsstatistik-Card', function (): void { URL::resolveMissingNamedRoutesUsing(fn (string $name, $parameters = []) => '/'.$name);