Berater faellt aus (B2): Berater ohne Sponsor gehen an das Firmenkonto

Der Dry-Run auf Produktion (25.09.) listet einen Berater, der ohne Sponsor
registriert wurde (m_sponsor und pre_sponsor leer). terminate() haette ihn
jede Nacht mit "kein aktiver Sponsor" uebersprungen. Pausieren und harter
Cut nehmen jetzt den naechsten aktiven Sponsor ueber m_sponsor/pre_sponsor
und sonst das Firmenkonto (ohne Mail).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin 2026-09-25 10:38:22 +00:00
parent 979a12d1cb
commit 42d2a9c0ab
2 changed files with 33 additions and 4 deletions

View file

@ -133,8 +133,8 @@ class ConsultantSuspensionService
return null; return null;
} }
$sponsor = $user->m_sponsor ? UserUtil::findNextActiveSponsor($user->m_sponsor) : null; $sponsor = $this->sponsorFor($user);
if (! $sponsor || (int) $sponsor->id === (int) $user->id) { if (! $sponsor) {
Log::channel('cleanup')->error('ConsultantSuspension::suspend kein aktiver Sponsor fuer user_id '.$user->id.' '.$info); Log::channel('cleanup')->error('ConsultantSuspension::suspend kein aktiver Sponsor fuer user_id '.$user->id.' '.$info);
return null; return null;
@ -194,8 +194,8 @@ class ConsultantSuspensionService
return null; return null;
} }
$sponsor = UserUtil::findNextActiveSponsor($user->id); $sponsor = $this->sponsorFor($user);
if (! $sponsor || (int) $sponsor->id === (int) $user->id) { if (! $sponsor) {
Log::channel('cleanup')->error('ConsultantSuspension::terminate kein aktiver Sponsor fuer user_id '.$user->id); Log::channel('cleanup')->error('ConsultantSuspension::terminate kein aktiver Sponsor fuer user_id '.$user->id);
return null; return null;
@ -388,6 +388,22 @@ class ConsultantSuspensionService
return $lists; return $lists;
} }
/**
* Nächster aktiver Sponsor über m_sponsor bzw. pre_sponsor. Berater ganz ohne
* Sponsor (ohne Sponsor registriert) gehen an das Firmenkonto.
*/
private function sponsorFor(User $user): ?User
{
$sponsorId = $user->m_sponsor ?: $user->pre_sponsor;
$sponsor = $sponsorId ? UserUtil::findNextActiveSponsor($sponsorId) : null;
if (! $sponsor || (int) $sponsor->id === (int) $user->id) {
$sponsor = User::find((int) config('mivita.company_user_id'));
}
return $sponsor && (int) $sponsor->id !== (int) $user->id ? $sponsor : null;
}
private function logTransfer(User $user, User $sponsor, string $type, int $recordId): void private function logTransfer(User $user, User $sponsor, string $type, int $recordId): void
{ {
ConsultantSuspensionTransfer::create([ ConsultantSuspensionTransfer::create([

View file

@ -282,6 +282,19 @@ describe('Stufe 2: harter Cut', function () {
->and($s['abo']->fresh()->member_id)->toBe($s['sponsor']->id) ->and($s['abo']->fresh()->member_id)->toBe($s['sponsor']->id)
->and($s['portal']->fresh()->member_id)->toBe($s['sponsor']->id); ->and($s['portal']->fresh()->member_id)->toBe($s['sponsor']->id);
}); });
it('gibt Berater ganz ohne Sponsor an das Firmenkonto', function () {
// Live 25.09.: ein Berater war ohne Sponsor registriert und waere jede Nacht uebersprungen worden.
$company = User::forceCreate(['id' => 6, 'email' => 'firma@example.com', 'password' => 'x', 'lang' => 'de', 'active' => 1, 'payment_account' => '2030-01-01']);
$consultant = susConsultant(null, '2026-09-01 10:00:00');
$customer = susCustomer($consultant);
$this->artisan('user:cleanup')->assertSuccessful();
expect(User::withTrashed()->find($consultant->id)->deleted_at)->not->toBeNull()
->and($customer->fresh()->member_id)->toBe($company->id);
Mail::assertNothingSent();
});
}); });
describe('Admin setzt das Ablaufdatum', function () { describe('Admin setzt das Ablaufdatum', function () {